emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 5736e85 3/3: Merge branch 'master' of git+ssh://git.sv.gnu


From: Artur Malabarba
Subject: [elpa] master 5736e85 3/3: Merge branch 'master' of git+ssh://git.sv.gnu.org/srv/git/emacs/elpa
Date: Sat, 07 Mar 2015 20:38:34 +0000

branch: master
commit 5736e852fd48a0f1ba1c328dd4d03e3fa008a406
Merge: fe25187 3c1f421
Author: Artur Malabarba <address@hidden>
Commit: Artur Malabarba <address@hidden>

    Merge branch 'master' of git+ssh://git.sv.gnu.org/srv/git/emacs/elpa
---
 externals-list                                     |    2 +
 packages/ahungry-theme/ahungry-theme.el            |   20 +-
 packages/ahungry-theme/color-theme-ahungry.el      |    3 +-
 packages/auto-overlays/README                      |  391 +
 packages/auto-overlays/auto-overlay-common.el      |  229 +
 packages/auto-overlays/auto-overlay-flat.el        |  193 +
 packages/auto-overlays/auto-overlay-line.el        |  106 +
 packages/auto-overlays/auto-overlay-manual.info    | 2248 +++++
 packages/auto-overlays/auto-overlay-nested.el      |  219 +
 packages/auto-overlays/auto-overlay-self.el        |  321 +
 packages/auto-overlays/auto-overlay-word.el        |   70 +
 packages/auto-overlays/auto-overlays-compat.el     |   51 +
 packages/auto-overlays/auto-overlays.el            | 1714 ++++
 packages/auto-overlays/dir                         |   19 +
 packages/cl-generic/cl-generic.el                  |  118 +
 packages/company-statistics/company-statistics.el  |    7 +-
 packages/company/company.el                        |   37 +-
 packages/company/test/async-tests.el               |   56 +
 packages/company/test/frontends-tests.el           |   20 +
 packages/context-coloring/.gitignore               |    3 +
 packages/context-coloring/.travis.yml              |   21 +
 packages/context-coloring/Makefile                 |   40 +
 packages/context-coloring/README.md                |  181 +
 .../benchmark/context-coloring-benchmark.el        |  172 +
 .../benchmark/fixtures/.dir-locals.el              |    1 +
 .../benchmark/fixtures/async-0.9.0.js              | 1123 +++
 .../benchmark/fixtures/jquery-2.1.1.js             | 9190 ++++++++++++++++++++
 .../benchmark/fixtures/lodash-2.4.1.js             | 6785 +++++++++++++++
 .../benchmark/fixtures/mkdirp-0.5.0.js             |   97 +
 packages/context-coloring/context-coloring.el      |  859 ++
 packages/context-coloring/scopifier.png            |  Bin 0 -> 2609 bytes
 packages/context-coloring/screenshot.png           |  Bin 0 -> 22006 bytes
 .../scripts/download-dependencies.el               |   52 +
 .../context-coloring/test/context-coloring-test.el |  722 ++
 .../context-coloring/test/fixtures/block-scopes.js |    6 +
 packages/context-coloring/test/fixtures/catch.js   |    8 +
 .../test/fixtures/comments-and-strings.js          |    3 +
 .../test/fixtures/function-scopes.js               |    5 +
 packages/context-coloring/test/fixtures/global.js  |    3 +
 .../context-coloring/test/fixtures/key-names.js    |    6 +
 .../context-coloring/test/fixtures/key-values.js   |    8 +
 .../test/fixtures/property-lookup.js               |    5 +
 packages/debbugs/Debbugs.wsdl                      |    2 +-
 packages/debbugs/debbugs-gnu.el                    |   44 +-
 packages/debbugs/debbugs-org.el                    |    2 +-
 packages/debbugs/debbugs.el                        |   13 +-
 packages/debbugs/debbugs.texi                      |    2 +-
 packages/hydra/Makefile                            |    8 +-
 packages/hydra/README.md                           |  172 +-
 packages/hydra/hydra-examples.el                   |  275 +-
 packages/hydra/hydra-ox.el                         |  118 +
 packages/hydra/hydra-test.el                       | 1093 +++-
 packages/hydra/hydra.el                            | 1028 ++-
 packages/hydra/lv.el                               |   75 +
 packages/jgraph-mode/jgraph-mode.el                |   26 +-
 packages/load-relative/.gitignore                  |   16 +
 packages/load-relative/.travis.yml                 |   17 +
 packages/load-relative/AUTHORS                     |    1 +
 packages/load-relative/COPYING                     |  674 ++
 packages/load-relative/ChangeLog                   |  228 +
 packages/load-relative/INSTALL                     |  246 +
 packages/load-relative/Makefile.am                 |   55 +
 packages/load-relative/README.md                   |  136 +
 packages/load-relative/THANKS                      |    2 +
 packages/load-relative/autogen.sh                  |    6 +
 packages/load-relative/common.mk                   |    5 +
 packages/load-relative/configure.ac                |   28 +
 packages/load-relative/elisp-comp                  |   87 +
 packages/load-relative/install-from-git.sh         |   99 +
 packages/load-relative/load-relative.el            |  302 +
 packages/load-relative/make-check-filter.rb        |   23 +
 packages/load-relative/test/.gitignore             |    3 +
 packages/load-relative/test/Makefile.am            |   68 +
 packages/load-relative/test/install-pkgs.el        |   24 +
 packages/load-relative/test/load-file1.el          |   18 +
 packages/load-relative/test/load-file2.el          |   17 +
 packages/load-relative/test/load-file3.el          |   17 +
 packages/load-relative/test/require-file1.el       |   17 +
 packages/load-relative/test/require-file2.el       |   17 +
 packages/load-relative/test/require-file3.el       |   17 +
 packages/load-relative/test/simple.txt             |    1 +
 packages/load-relative/test/subdir/.gitignore      |    1 +
 packages/load-relative/test/subdir/Makefile        |    7 +
 .../test/subdir/test-require-list-from-subdir.el   |   34 +
 packages/load-relative/test/test-file.el           |   62 +
 packages/load-relative/test/test-load.el           |   97 +
 packages/load-relative/test/test-require-list.el   |   28 +
 packages/loc-changes/.gitignore                    |   14 +
 packages/loc-changes/.travis.yml                   |   18 +
 packages/loc-changes/AUTHORS                       |    1 +
 packages/loc-changes/COPYING                       |  674 ++
 packages/loc-changes/INSTALL                       |  370 +
 packages/loc-changes/Makefile.am                   |   48 +
 packages/loc-changes/README                        |    1 +
 packages/loc-changes/README.md                     |   15 +
 packages/loc-changes/THANKS                        |    1 +
 packages/loc-changes/autogen.sh                    |    6 +
 packages/loc-changes/common.mk                     |    5 +
 packages/loc-changes/configure.ac                  |   13 +
 packages/loc-changes/elisp-comp                    |   93 +
 packages/loc-changes/loc-changes.el                |  257 +
 packages/loc-changes/test/Makefile.am              |   72 +
 packages/loc-changes/test/install-pkgs.el          |   24 +
 packages/loc-changes/test/make-check-filter.rb     |   25 +
 packages/loc-changes/test/sample.txt               |   14 +
 packages/loc-changes/test/test-basic.el            |  107 +
 packages/nlinum/nlinum.el                          |   26 +-
 packages/rainbow-mode/rainbow-mode.el              |    8 +-
 packages/seq/seq.el                                |   92 +-
 packages/seq/tests/seq-tests.el                    |   40 +-
 packages/sml-mode/sml-mode.el                      |   44 +-
 packages/sotlisp/sotlisp.el                        | 1067 ++--
 packages/test-simple/.gitignore                    |   14 +
 packages/test-simple/.travis.yml                   |    8 +
 packages/test-simple/AUTHORS                       |    2 +
 packages/test-simple/COPYING                       |  674 ++
 packages/test-simple/Carton                        |    4 +
 packages/test-simple/INSTALL                       |   18 +
 packages/test-simple/Makefile.am                   |   64 +
 packages/test-simple/NEWS                          |    5 +
 packages/test-simple/README.md                     |   71 +
 packages/test-simple/THANKS                        |    1 +
 packages/test-simple/autogen.sh                    |    7 +
 packages/test-simple/common.mk                     |    5 +
 packages/test-simple/compute-lispdir.sh            |   46 +
 packages/test-simple/configure.ac                  |   44 +
 packages/test-simple/elisp-comp                    |   94 +
 packages/test-simple/example/gcd.el                |   34 +
 packages/test-simple/example/test-gcd.el           |   41 +
 packages/test-simple/install-from-git.sh           |   94 +
 packages/test-simple/make-check-filter.rb          |   21 +
 packages/test-simple/test-simple.el                |  334 +
 packages/test-simple/test/.gitignore               |    2 +
 packages/test-simple/test/Makefile.am              |   29 +
 packages/test-simple/test/test-basic.el            |   29 +
 packages/test-simple/test/test-fns.el              |   39 +
 packages/test-simple/test/test-no-clear.el         |   27 +
 packages/timerfunctions/timerfunctions.el          |  458 +
 138 files changed, 34578 insertions(+), 947 deletions(-)

diff --git a/externals-list b/externals-list
index 19b5af1..bc6a82b 100644
--- a/externals-list
+++ b/externals-list
@@ -23,6 +23,7 @@
  ("chess"              :external nil) ;; Was 
https://github.com/jwiegley/emacs-chess.git
  ("coffee-mode"                :subtree 
"https://github.com/defunkt/coffee-mode";)
  ("company"            :subtree 
"https://github.com/company-mode/company-mode.git";)
+ ("context-coloring"   :subtree 
"https://github.com/jacksonrayhamilton/context-coloring.git";)
  ("darkroom"            :subtree 
"https://github.com/capitaomorte/darkroom.git";)
  ("diff-hl"            :subtree "https://github.com/dgutov/diff-hl.git";)
  ("dismal"             :external nil)
@@ -39,6 +40,7 @@
  ;;FIXME:("org"                :external ??) ;; Need to introduce snapshots!!
  ("rudel"              :external nil) ;; Was 
bzr::bzr://rudel.bzr.sourceforge.net/bzrroot/rudel/trunk
  ("temp-buffer-browse"  :subtree 
"https://github.com/leoliu/temp-buffer-browse";)
+ ("test-simple"         :subtree "https://github.com/rocky/emacs-test-simple";)
  ;;FIXME:("vlf"                :subtree ??)
  ("w3"                 :external nil)
  ("wcheck-mode"                :subtree 
"https://github.com/tlikonen/wcheck-mode.git";)
diff --git a/packages/ahungry-theme/ahungry-theme.el 
b/packages/ahungry-theme/ahungry-theme.el
index d17cee7..a5457e2 100644
--- a/packages/ahungry-theme/ahungry-theme.el
+++ b/packages/ahungry-theme/ahungry-theme.el
@@ -1,11 +1,11 @@
-;;; ahungry-theme.el --- Ahungry color theme for Emacs.
+;;; ahungry-theme.el --- Ahungry color theme for Emacs.  Make sure to 
(load-theme 'ahungry).
 
 ;; Copyright (C) 2015  Free Software Foundation, Inc.
 
 ;; Author: Matthew Carter <address@hidden>
 ;; Maintainer: Matthew Carter <address@hidden>
 ;; URL: https://github.com/ahungry/color-theme-ahungry
-;; Version: 1.0.3
+;; Version: 1.0.5
 ;; Keywords: ahungry palette color theme emacs color-theme deftheme
 ;; Package-Requires: ((emacs "24"))
 
@@ -34,6 +34,16 @@
 ;; transparent background.  If you load it from a GUI, it will default
 ;; to a dark background.
 
+;;; News:
+
+;;;; Changes since 1.0.4:
+;; - Don't circumvent normal autoloads functionality, use the comment load 
method
+
+;;;; Changes since 1.0.3:
+;; - Manually include an autoloads file to make sure
+;;   custom-theme-load-path is filled out
+;; - Update description to make mention of (load-theme 'ahungry) for new users
+
 ;;; Code:
 
 (deftheme ahungry
@@ -179,6 +189,12 @@
    '(red "#ffffff"))
   )
 
+;;;###autoload
+(when (and load-file-name (boundp 'custom-theme-load-path))
+ (add-to-list
+      'custom-theme-load-path
+      (file-name-as-directory (file-name-directory load-file-name))))
+
 (provide-theme 'ahungry)
 
 ;;; ahungry-theme.el ends here
diff --git a/packages/ahungry-theme/color-theme-ahungry.el 
b/packages/ahungry-theme/color-theme-ahungry.el
index 53d26ba..ba76b25 100644
--- a/packages/ahungry-theme/color-theme-ahungry.el
+++ b/packages/ahungry-theme/color-theme-ahungry.el
@@ -36,8 +36,7 @@
 
 ;;; Code:
 
-(eval-when-compile
-  (require 'color-theme))
+(declare-function color-theme-install "color-theme" (theme))
 
 ;; Currently background-color and foreground-color are intentionally left
 ;; commented out, so that the color-theme in terminal mode will not overwrite
diff --git a/packages/auto-overlays/README b/packages/auto-overlays/README
new file mode 100644
index 0000000..120b901
--- /dev/null
+++ b/packages/auto-overlays/README
@@ -0,0 +1,391 @@
+
+   An Emacs overlay demarcates a region of text in a buffer, often
+giving it a different face or changing other properties for that
+region. There are many circumstance in which it might be useful to
+create, update, and delete overlays automatically when text matches
+some criterion, specified for example by regular expressions. This is
+what the auto-overlays package addresses. It is intended as an Elisp
+library, providing functions to be used by other Elisp packages, so
+does not itself define any new interactive commands or minor modes.
+
+This documentation is an extract from the extensive Auto Overlays
+Manual that comes with the package. For more detailed information and
+examples, please read the manual.
+
+
+1 Overview
+**********
+
+The auto-overlays package automatically creates, updates and destroys
+overlays based on regular expression matches in the buffer text. The
+overlay is created when text is typed that matches an auto-overlay
+regexp, and is destroyed if and when the matching text is changed so
+that it no longer matches.
+
+   The regexps are grouped into sets, and any number of different sets
+of regexps can be active in the same buffer simultaneously. Regexps in
+different sets are completely independent, and each set can be activated
+and deactivated independently (*note Defining Regexps::). This allows
+different Emacs modes to simultaneously make use of auto-overlays in the
+same buffer.
+
+   There are different "classes" of auto-overlay, used to define
+different kinds of overlay behaviour. Some classes only require a single
+regexp, others require separate regexps to define the start and end of
+the overlay (*note Defining Regexps::). Any additional regexps, beyond
+the minimum requirements, act as alternatives; if more than one of the
+regexps matches overlapping regions of text, the one that appears
+earlier in the list will take precedence. The predefined regexp classes
+are: `word', `line', `self', `nested' and `flat', but the auto-overlay
+package can easily be extended with new classes.
+
+`word'
+     These are used to define overlays that cover the text matched by
+     the regexp itself, so require a single regexp. An example use
+     would be to create overlays covering single words.
+
+`line'
+     These are used to define overlays that stretch from the text
+     matching the regexp to the end of the line, and require a single
+     regexp to define the start of the overlay. An example use would be
+     to create overlays covering single-line comments in programming
+     languages such as c.
+
+`self'
+     These are used to define overlays that stretch from one regexp
+     match to the next match for the same regexp, so naturally require
+     a single regexp. An example use would be to create overlays
+     covering strings delimited by `""'.
+
+     Note that for efficiency reasons, `self' overlays are _not_ fully
+     updated when a new match is found. Instead, when a modification is
+     subsequently made at any position in the buffer after the new
+     match, the overlays are updated _up to_ that position. The update
+     occurs just _before_ the modification is made. Therefore, the
+     overlays at a given buffer position will not necessarily be
+     correct until a modification is made at or after that position
+     (*note To-Do::).
+
+`nested'
+     These are used to define overlays that start and end at different
+     regexp matches, and that can be nested one inside another. This
+     class requires separate start and end regexps. An example use
+     would be to create overlays between matching braces `{}'.
+
+`flat'
+     These are used to define overlays that start and end at different
+     regexp matches, but that can not be nested. Extra start matches
+     within one of these overlays are ignored. This class requires
+     separate start and end regexps. An example use would be to create
+     overlays covering multi-line comments in code, e.g. c++ block
+     comments delimited by `/*' and `*/'.
+
+   By default, the entire text matching a regexp acts as the
+"delimeter". For example, a `word' overlay will cover all the text
+matching its regexp, and a `nested' overlay will start at the end of
+the text matching its start regexp. Sometimes it is useful to be able
+to have only part of the regexp match act as the delimeter. This can be
+done by grouping that part of the regexp (*note Defining Regexps::).
+Overlays will then start and end at the text matching the group,
+instead of the text matching the entire regexp.
+
+   Of course, automatically creating overlays isn't much use without
+some way of setting their properties too. Overlay properties can be
+defined along with the regexp, and are applied to any overlays created
+by a match to that regexp. Certain properties have implications for
+auto-overlay behaviour.
+
+`priority'
+     This is a standard Emacs overlay property (*note Overlay
+     Properties: (elisp)Overlay Properties.), but it is also used to
+     determine which regexp takes precedence when two or more regexps
+     in the same auto-overlay definition match overlapping regions of
+     text. It is also used to determine which regexp's properties take
+     precedence for overlays that are defined by separate start and end
+     matches.
+
+`exclusive'
+     Normally, different auto-overlay regexps coexist, and act
+     completely independently of one-another. However, if an
+     auto-overlay has non-nil `exclusive' and `priority' properties,
+     regexp matches within the overlay are ignored if they have lower
+     priority. An example use is ignoring other regexp matches within
+     comments in code.
+
+
+2 Auto-Overlay Functions
+************************
+
+To use auto-overlays in an Elisp package, you must load the overlay
+classes that you require by including lines of the form
+     (require 'auto-overlay-CLASS)
+   near the beginning of your package, where CLASS is the class name.
+The standard classes are: `word', `line', `self', `nested' and `flat'
+(*note Overview::), though new classes can easily be added (*note
+Extending the Auto-Overlays Package::).
+
+   Sometimes it is useful for a package to make use of auto-overlays if
+any are defined, without necessarily requiring them. To facilitate
+this, the relevant functions can be loaded separately from the rest of
+the auto-overlays package with the line
+     (require 'auto-overlay-common)
+   This provides all the functions related to searching for overlays and
+retrieving overlay properties. *Note Searching for Overlays::. Note that
+there is no need to include this line if any auto-overlay classes are
+`require'd, though it will do no harm.
+
+   This section describes the functions that are needed in order to make
+use of auto-overlays in an Elisp package. It does _not_ describe
+functions related to extending the auto-overlays package. *Note
+Extending the Auto-Overlays Package::.
+
+2.1 Defining Regexps
+====================
+
+An auto-overlay definition is a list of the form:
+     (CLASS &optional :id ENTRY-ID REGEXP1 REGEXP2 ...)
+   CLASS is one of the regexp classes described in the previous section
+(*note Overview::). The optional `:id' property should be a symbol that
+can be used to uniquely identify the auto-overlay definition.
+
+   Each REGEXP defines one of the regexps that make up the auto-overlay
+definition. It should be a list of the form
+     (RGXP &optional :edge EDGE :id SUBENTRY-ID @rest PROPERTY1 PROPERTY2 ...)
+   The `:edge' property should be one of the symbols `'start' or
+`'end', and determines which edge of the auto-overlay this regexp
+corresponds to. If `:edge' is not specified, it is assumed to be
+`'start'. Auto-overlay classes that do not require separate `start' and
+`end' regexps ignore this property. The `:id' property should be a
+symbol that can be used to uniquely identify the regexp. Any further
+elements in the list are cons cells of the form `(property . value)',
+where PROPERTY is an overlay property name (a symbol) and VALUE its
+value. In its simplest form, RGXP is a single regular expression.
+
+   If only part of the regexp should act as the delimeter (*note
+Overview::), RGXP should instead be a cons cell:
+     (RX . GROUP)
+   where RX is a regexp that contains at least one group (*note Regular
+Expressions: (elisp)Regular Expressions.), and GROUP is an integer
+identifying which group should act as the delimeter.
+
+   If the overlay class requires additional groups to be specified,
+RGXP should instead be a list:
+     (RX GROUP0 GROUP1 ...)
+   where RX is a regexp. The first GROUP0 still specifies the part that
+acts as the delimeter, as before. If the entire regexp should act as
+the delimeter, GROUP0 must still be supplied but should be set to 0
+(meaning the entire regexp). None of the standard classes make use of
+any additional groups, but extensions to the auto-overlays package that
+define new classes may. *Note Extending the Auto-Overlays Package::.
+
+   The following functions are used to load and unload regexp
+definitions: 
+
+`(auto-overlay-load-definition SET-ID DEFINITION &optional POS)'
+     Load a new auto-overlay DEFINITION, which should be a list of the
+     form described above, into the set identified by the symbol
+     SET-ID. The optional parameter POS determines where in the set's
+     regexp list the new regexp is inserted. If it is `nil', the regexp
+     is added at the end. If it is `t', the regexp is added at the
+     beginning. If it is an integer, the regexp is added at that
+     position in the list. Whilst the position in the list has no
+     effect on overlay behaviour, it does determine the order in which
+     regexps are checked, so can affect efficiency.
+
+`(auto-overlay-load-regexp SET-ID ENTRY-ID REGEXP &optional POS)'
+     Load a new REGEXP, which should be a list of the form described
+     above, into the auto-overlay definition identified by the symbol
+     ENTRY-ID, in the set identified by the symbol SET-ID. REGEXP
+     should be a list of the form described above.  The optional POS
+     determines the position of the regexp in the list of regexps
+     defining the auto-overlay, which can be significant for overlay
+     behaviour since it determines which regexp takes precedence when
+     two match the same text.
+
+`(auto-overlay-unload-set SET-ID)'
+     Unload the entire regexp set identified by the symbol SET-ID.
+
+`(auto-overlay-unload-definition SET-ID ENTRY-ID)'
+     Unload the auto-overlay definition identified by the symbol
+     ENTRY-ID from the set identified by the symbol SET-ID.
+
+`(auto-overlay-unload-regexp SET-ID ENTRY-ID SUBENTRY-ID)'
+     Unload the auto-overlay regexp identified by the symbol
+     SUBENTRY-ID from the auto-overlay definition identified by the
+     symbol ENTRY-ID in the set identified by the symbol SET-ID.
+
+`(auto-overlay-share-regexp-set SET-ID FROM-BUFFER @optional TO-BUFFER)'
+     Share the set of regexp definitions identified by the symbol
+     SET-ID in buffer `from-buffer' with the buffer TO-BUFFER, or the
+     current buffer if TO-BUFFER is null. The regexp set becomes common
+     to both buffers, and any changes made to it in one buffer, such as
+     loading and unloading regexp definitions, are also reflected in
+     the other buffer. However, the regexp set can still be enabled and
+     disabled independently in both buffers. The same regexp set can be
+     shared between any number of buffers. To remove a shared regexp
+     set from one of the buffers, simply unload the entire set from that
+     buffer using `auto-overlay-unload-regexp'. The regexp set will
+     remain defined in all the other buffers it was shared with.
+
+2.2 Starting and Stopping Auto-Overlays
+=======================================
+
+A set of regexps is not active until it has been "started", and can be
+deactivated by "stopping" it. When a regexp set is activated, the
+entire buffer is scanned for regexp matches, and the corresponding
+overlays created. Similarly, when a set is deactivated, all the overlays
+are deleted. Note that regexp definitions can be loaded and unloaded
+whether the regexp set is active or inactive, and that deactivating a
+regexp set does _not_ delete its regexp definitions.
+
+   Since scanning the whole buffer for regexp matches can take some
+time, especially for large buffers, auto-overlay data can be saved to an
+auxiliary file so that the overlays can be restored more quickly if the
+same regexp set is subsequently re-activated. Of course, if the text in
+the buffer is modified whilst the regexp set is disabled, or the regexp
+definitions differ from those that were active when the overlay data was
+saved, the saved data will be out of date. Auto-overlays automatically
+checks if the text has been modified and, if it has, ignores the saved
+data and re-scans the buffer. However, no check is made to ensure the
+regexp definitions used in the buffer and saved data are consistent
+(*note To-Do::); the saved data will be used even if the definitions
+have changed.
+
+   The usual time to save and restore overlay data is when a regexp set
+is deactivated or activated. The auxilliary file name is then
+constructed automatically from the buffer name and the set-id. However,
+auto-overlays can also be saved and restored manually.
+
+`(auto-overlay-start SET-ID @optional BUFFER SAVE-FILE NO-REGEXP-CHECK)'
+     Activate the auto-overlay regexp set identified by the symbol
+     SET-ID in BUFFER, or the current buffer if the latter is `nil'. If
+     there is an file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the
+     containing up-to-date overlay data, it will be used to restore the
+     auto-overlays (BUFFER-NAME is the name of the file visited by the
+     buffer, or the buffer name itself if there is none). Otherwise, the
+     entire buffer will be scanned for regexp matches.
+
+     The string SAVE-FILE specifies the where to look for the file of
+     saved overlay data. If it is nil, it defaults to the current
+     directory. If it is a string specifying a relative path, then it is
+     relative to the current directory, whereas an absolute path
+     specifies exactly where to look. If it is a string specifying a
+     file name (with or without a full path, relative or absolute),
+     then it overrides the default file name and/or location. Any other
+     value of SAVE-FILE will cause the file of overlay data to be
+     ignored, even if it exists.
+
+     If the overlays are being loaded from a file, but optional argument
+     no-regexp-check is non-nil, the file of saved overlays will be
+     used, but no check will be made to ensure regexp refinitions are
+     the same as when the overlays were saved.
+
+`(auto-overlay-stop SET-ID @optional BUFFER SAVE-FILE LEAVE-OVERLAYS)'
+     Deactivate the auto-overlay regexp set identified by the symbol
+     SET-ID in BUFFER, or the current buffer if the latter is `nil'.
+     All corresponding overlays will be deleted (unless the
+     LEAVE-OVERLAYS option is non-nil, which should only be used if the
+     buffer is about to be killed), but the regexp definitions are
+     preserved and can be reactivated later.
+
+     If SAVE-FILE is non-nil, overlay data will be saved in an
+     auxilliary file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the
+     current directory, to speed up subsequent reactivation of the
+     regexp set in the same buffer (BUFFER-NAME is the name of the file
+     visited by the buffer, or the buffer name itself if there is
+     none). If SAVE-FILE is a string, it overrides the default save
+     location, overriding either the directory if it only specifies a
+     path (relative paths are relative to the current directory), or
+     the file name if it only specifies a file name, or both.
+
+`(auto-overlay-save-overlays SET-ID @optional BUFFER FILE)'
+     Save auto-overlay data for the regexp set identified by the symbol
+     SET-ID in BUFFER, or the current buffer if `nil', to an auxilliary
+     file called FILE. If FILE is nil, the overlay data are saved to a
+     file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the current
+     directory (BUFFER-NAME is the name of the file visited by the
+     buffer, or the buffer name itself if there is none). Note that
+     this is the only name that will be recognized by
+     `auto-overlay-start'.
+
+`(auto-overlay-load-overlays SET-ID @optional BUFFER FILE NO-REGEXP-CHECK)'
+     Load auto-overlay data for the regexp set identified by the symbol
+     SET-ID into BUFFER, or the current buffer if `nil', from an
+     auxilliary file called FILE. If FILE is nil, it attempts to load
+     the overlay data from a file called
+     `auto-overlay-'BUFFER-NAME`-'SET-ID in the current directory
+     (BUFFER-NAME is the name of the file visited by the buffer, or the
+     buffer name itself if there is none). If NO-REGEXP-CHECK is
+     no-nil, the saved overlays will be loaded even if different regexp
+     definitions were active when the overlays were saved. Returns `t'
+     if the overlays were successfully loaded, `nil' otherwise.
+
+2.3 Searching for Overlays
+==========================
+
+Auto-overlays are just normal Emacs overlays, so any of the standard
+Emacs functions can be used to search for overlays and retrieve overlay
+properties. The auto-overlays package provides some additional
+functions.
+
+`(auto-overlays-at-point @optional POINT PROP-TEST INACTIVE)'
+     Return a list of overlays overlapping POINT, or the point if POINT
+     is null. The list includes _all_ overlays, not just auto-overlays
+     (but see below). The list can be filtered to only return overlays
+     with properties matching criteria specified by PROP-TEST. This
+     should be a list defining a property test, with one of the
+     following forms (or a list of such lists, if more than one
+     property test is required):
+          (FUNCTION PROPERTY)
+          (FUNCTION PROPERTY VALUE)
+          (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...))
+     where FUNCTION is a function, PROPERTY is an overlay property name
+     (a symbol), and VALUE can be any value or lisp expression. For
+     each overlay, first the values corresponding to the PROPERTY names
+     are retrieved from the overlay and any VALUEs that are lisp
+     expressions are evaluated. Then FUNCTION is called with the
+     property values followed by the other values as its arguments. The
+     test is satisfied if the result is non-nil, otherwise it fails.
+     Tests are evaluated in order, but only up to the first failure.
+     Only overlays that satisfy all property tests are returned.
+
+     All auto-overlays are given a non-nil `auto-overlay' property, so
+     to restrict the list to auto-overlays, PROP-TEST should include
+     the following property test:
+          ('identity 'auto-overlay)
+     For efficiency reasons, the auto-overlays package sometimes leaves
+     overlays hanging around in the buffer even when they should have
+     been deleted. These are marked with a non-nil `inactive' property.
+     By default, `auto-overlays-at-point' ignores these. A non-nil
+     INACTIVE will override this, causing inactive overlays to be
+     included in the returned list (assuming they pass all property
+     tests).
+
+`(auto-overlays-in START END @optional PROP-TEST WITHIN INACTIVE)'
+     Return a list of overlays overlapping the region between START and
+     END. The PROP-TEST and INACTIVE arguments have the same behaviour
+     as in `auto-overlays-at-point', above. If WITHIN is non-nil, only
+     overlays that are entirely within the region from START to END
+     will be returned, not overlays that extend outside that region.
+
+`(auto-overlay-highest-priority-at-point @optional POINT PROP-TEST)'
+     Return the highest priority overlay at POINT (or the point, of
+     POINT is null). The PROP-TEST argument has the same behaviour as
+     in `auto-overlays-at-point', above. An overlay's priority is
+     determined by the value of its `priority' property (*note Overlay
+     Properties: (elisp)Overlay Properties.). If two overlays have the
+     same priority, the innermost one takes precedence (i.e. the one
+     that begins later in the buffer, or if they begin at the same
+     point the one that ends earlier; if two overlays have the same
+     priority and extend over the same region, there is no way to
+     predict which will be returned).
+
+`(auto-overlay-local-binding SYMBOL @optional POINT)'
+     Return the "overlay-local" binding of SYMBOL at POINT (or the
+     point if POINT is null), or the current local binding if there is
+     no overlay binding. An "overlay-local" binding for SYMBOL is the
+     value of the overlay property called SYMBOL. If more than one
+     overlay at POINT has a non-nil SYMBOL property, the value from the
+     highest priority overlay is returned (see
+     `auto-overlay-highest-priority-at-point', above, for an
+     explanation of "highest priority").
diff --git a/packages/auto-overlays/auto-overlay-common.el 
b/packages/auto-overlays/auto-overlay-common.el
new file mode 100644
index 0000000..994b20d
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-common.el
@@ -0,0 +1,229 @@
+;;; auto-overlay-common.el --- general overlay functions
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(provide 'auto-overlay-common)
+
+
+;;;###autoload
+(defun auto-overlays-at-point (&optional point prop-test inactive)
+  "Return overlays overlapping POINT
+(or the point, if POINT is null). If PROP-TEST is supplied, it
+should be a list which specifies a property test with one of the
+following forms (or a list of such lists if more than one
+property test is required):
+
+  (FUNCTION PROPERTY)
+
+  (FUNCTION PROPERTY VALUE)
+
+  (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...))
+
+where PROPERTY indicates an overlay property name (a symbol), and
+VALUE indicates an arbitrary value or lisp expression.
+
+For each overlay overlapping POINT, first the values
+corresponding to the property names are retrieved from the
+overlay, then FUNCTION is called with the properties values
+followed by the other values as its arguments. The test is
+satisfied if the result is non-nil, otherwise it fails. Tests are
+evaluated in order, but only up to the first failure. Only
+overlays that satisfy all property tests are returned.
+
+If INACTIVE is non-nil, both active and inactive overlays are
+returned (usually inactive ones are ignored).
+
+Note that this function returns any overlay. If you want to
+restrict it to auto overlays, include '(identity auto-overlay) in
+PROP-TEST."
+  (when (null point) (setq point (point)))
+
+  (let (overlay-list)
+    ;; get overlays overlapping POINT and zero-length overlays at POINT
+    (setq overlay-list
+         (auto-overlays-in point point prop-test nil inactive))
+    ;; get overlays that end at POINT
+    (dolist (o (auto-overlays-in (1- point) point prop-test nil inactive))
+      (when (and (< (overlay-start o) point)
+                (= (overlay-end o) point))
+       (push o overlay-list)))
+    ;; get overlays that start at POINT
+    (dolist (o (auto-overlays-in point (1+ point) prop-test nil inactive))
+      (when (and (> (overlay-end o) point)
+                (= (overlay-start o) point))
+       (push o overlay-list)))
+
+    overlay-list))
+
+
+
+;;;###autoload
+(defun auto-overlays-in (start end &optional prop-test within inactive)
+;; FIXME: get rid of INACTIVE argument?
+  "Return auto overlays overlapping region between START and END.
+
+If PROP-TEST is supplied, it should be a list which specifies a
+property test with one of the following forms (or a list of such
+lists if more than one property test is required):
+
+  (FUNCTION PROPERTY)
+
+  (FUNCTION PROPERTY VALUE)
+
+  (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...))
+
+where PROPERTY indicates an overlay property name (a symbol), and
+VALUE indicates an arbitrary value or lisp expression.
+
+For each overlay between START and END, first the values
+corresponding to the property names are retrieved from the
+overlay, then FUNCTION is called with the properties values
+followed by the other values as its arguments. The test is
+satisfied if the result is non-nil, otherwise it fails. Tests are
+evaluated in order, but only up to the first failure. Only
+overlays that satisfy all property tests are returned.
+
+If WITHIN is non-nil, only overlays entirely within START and END
+are returned. If INACTIVE is non-nil, both active and inactive
+overlays are returned (usually inactive ones are ignored).
+
+Note that this function returns any overlay. If you want to
+restrict it to auto overlays, include '(identity auto-overlay) in
+PROP-TEST."
+
+  ;; make sure prop-test is a list of lists, even if there's only one, and
+  ;; exclude inactive overlays unless told not to
+  (cond
+   ((null prop-test)
+    (unless inactive (setq prop-test '((null inactive)))))
+   ((functionp (car prop-test))
+    (if inactive
+       (setq prop-test (list prop-test))
+      (setq prop-test (list '(null inactive) prop-test))))
+   (t
+    (unless inactive (setq prop-test (push '(null inactive) prop-test)))))
+
+  (let (overlay-list function prop-list value-list result)
+    ;; check properties of each overlay in region
+    (dolist (o (overlays-in start end))
+      ;; check overlay is entirely within region
+      (if (and within
+              (or (< (overlay-start o) start) (> (overlay-end o) end)))
+         (setq result nil)
+
+       ;; if it is, or we don't care
+       (setq result t)
+       (catch 'failed
+         ;; check if properties match
+         (dolist (test prop-test)
+           ;; (Note: the whole thing would be neater with something like
+           ;; (apply 'and (map ...)) but 'and is a special form, not a
+           ;; function, so can't be applied)
+           (setq function (nth 0 test))
+           (unless (listp (setq prop-list (nth 1 test)))
+             (setq prop-list (list prop-list)))
+           (setq value-list nil)
+           (unless (or (< (length test) 3)
+                       (and (setq value-list (nth 2 test))  ; nil isn't list
+                            (listp value-list)))
+             (setq value-list (list value-list)))
+
+           ;; apply the test
+           (setq result
+                 (and result
+                      (apply function
+                             (append (mapcar (lambda (p) (overlay-get o p))
+                                             prop-list)
+                                     value-list))))
+           (when (null result) (throw 'failed nil)))))
+
+      ;; add overlay to result list if its properties matched
+      (when result (push o overlay-list)))
+    ;; return result list
+    overlay-list))
+
+
+
+;;;###autoload
+(defun auto-overlay-highest-priority-at-point (&optional point proptest)
+  "Return highest priority overlay at POINT (defaults to the point).
+
+If two overlays have the same priority, the innermost one takes
+precedence (i.e. the one that begins later, or if they begin at
+the same point the one that ends earlier).
+
+See `auto-overlays-at' for ane explanation of the PROPTEST argument."
+
+  (unless point (setq point (point)))
+
+  ;; get all overlays at point with a non-nil SYMBOL property
+  (let* ((overlay-list (auto-overlays-at-point point proptest))
+        (overlay (pop overlay-list))
+        p p1)
+
+    ;; find the highest priority, innermost overlay
+    (dolist (o1 overlay-list)
+      (setq p (overlay-get overlay 'priority))
+      (setq p1 (overlay-get o1 'priority))
+      (when (or (and (null p) p1)
+               (and p p1 (> p1 p))
+               (and (equal p1 p)
+                    (or (> (overlay-start o1) (overlay-start overlay))
+                        (and (= (overlay-start o1) (overlay-start overlay))
+                             (< (overlay-end o1) (overlay-end o1))))))
+       (setq overlay o1)))
+
+    ;; return the overlay
+    overlay))
+
+
+
+;;;###autoload
+(defun auto-overlay-local-binding (symbol &optional point only-overlay)
+  "Return \"overlay local \" binding of SYMBOL at POINT,
+or the current local binding if there is no overlay binding. If
+there is no overlay binding and SYMBOL is not bound, return
+nil. POINT defaults to the point.
+
+If ONLY-OVERLAY is non-nil, only overlay bindings are
+returned. If none exists at POINT, nil is returned
+
+An \"overlay local\" binding is created by giving an overlay a
+non-nil value for a property named SYMBOL. If more than one
+overlay at POINT has a non-nil SYMBOL property, the value from
+the highest priority overlay is returned.
+
+See `auto-overlay-highest-priority-at-point' for a definition of
+\"highest priority\"."
+
+  (let ((overlay (auto-overlay-highest-priority-at-point
+                 point `(identity ,symbol))))
+    (if overlay
+       (overlay-get overlay symbol)
+      (and (not only-overlay) (boundp symbol) (symbol-value symbol)))))
+
+;; auto-overlay-common.el ends here
diff --git a/packages/auto-overlays/auto-overlay-flat.el 
b/packages/auto-overlays/auto-overlay-flat.el
new file mode 100644
index 0000000..c790059
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-flat.el
@@ -0,0 +1,193 @@
+;;; auto-overlay-flat.el --- flat start/end-delimited automatic overlays
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(require 'auto-overlays)
+(provide 'auto-overlay-flat)
+
+
+;; set flat overlay parsing and suicide functions, and indicate class requires
+;; separate start and end regexps
+(put 'flat 'auto-overlay-parse-function 'auto-o-parse-flat-match)
+(put 'flat 'auto-overlay-suicide-function 'auto-o-flat-suicide)
+(put 'flat 'auto-overlay-complex-class t)
+
+
+
+(defun auto-o-parse-flat-match (o-match)
+  ;; Perform any necessary updates of auto overlays due to a match for a flat
+  ;; regexp.
+
+  (let (o-parent)
+    (cond
+
+     ;; if match is for a start regexp...
+     ((eq (auto-o-edge o-match) 'start)
+      ;; if match is within an existing overlay, ignore match
+      (unless (auto-overlays-at-point
+              (overlay-get o-match 'delim-end)  ; FIXME: is this right?
+              `((identity auto-overlay)
+                (eq set-id ,(overlay-get o-match 'set-id))
+                (eq definition-id ,(overlay-get o-match 'definition-id))))
+
+       ;; otherwise, look for next end-match...
+       (let ((o-end (auto-o-next-flat-match o-match 'end)))
+         (cond
+          ;; if there is one that has a parent, steal start of the parent
+          ;; overlay
+          ((and o-end (overlay-get o-end 'parent))
+           (auto-o-match-overlay (overlay-get o-end 'parent) o-match)
+           nil)  ; return nil since haven't created any overlays
+
+          ;; if there is one but it's parentless, make a new overlay, match
+          ;; it with O-MATCH and the next end-match, and return it
+          (o-end
+           (let ((pos (overlay-get o-match 'delim-end)))
+             (setq o-parent (make-overlay pos pos nil nil 'rear-advance)))
+           (overlay-put o-parent 'auto-overlay t)
+           (overlay-put o-parent 'set-id (overlay-get o-match 'set-id))
+           (overlay-put o-parent 'definition-id
+                        (overlay-get o-match 'definition-id))
+           (auto-o-match-overlay o-parent o-match o-end)
+           o-parent)
+
+          (t ;; otherwise, make a new, end-unmatched overlay and return it
+           (let ((pos (overlay-get o-match 'delim-end)))
+             (setq o-parent (make-overlay pos pos nil nil 'read-advance))
+             (overlay-put o-parent 'auto-overlay t)
+             (overlay-put o-parent 'set-id (overlay-get o-match 'set-id))
+             (overlay-put o-parent 'definition-id
+                          (overlay-get o-match 'definition-id))
+             (auto-o-match-overlay o-parent o-match 'unmatched)
+             o-parent))
+          ))))
+
+
+     (t ;; if match is for an end regexp...
+      ;; if match is within existing overlay with same set-d and 
definition-id...
+      (when (setq o-parent
+               (car  ; FIXME: is this right?
+                (auto-overlays-at-point
+                 (overlay-get o-match 'delim-start)  ; FIXME: is this right?
+                 `((identity auto-overlay)
+                   (eq set-id ,(overlay-get o-match 'set-id))
+                   (eq definition-id ,(overlay-get o-match 'definition-id))))))
+
+       ;; if overlay can simply be re-matched with new end-match, do so
+       (let ((o-end (overlay-get o-parent 'end))
+             (o-start (auto-o-next-flat-match o-match 'start)))
+         (if (not (and o-end o-start
+                       (<= (overlay-get o-start 'delim-end)
+                           (overlay-get o-end 'delim-start))))
+             (progn (auto-o-match-overlay o-parent nil o-match) nil)
+
+           ;; if overlay was end-matched, and there's a start match within
+           ;; existing overlay that will be "unmasked" when end is stolen,
+           ;; create a new overlay between that start match and the end match
+           ;; we're stealing from
+           (auto-o-match-overlay o-parent nil o-match)
+           (let ((pos (overlay-get o-start 'delim-end)))
+             (setq o-parent (make-overlay pos pos nil nil 'read-advance))
+             (overlay-put o-parent 'auto-overlay t)
+             (overlay-put o-parent 'set-id (overlay-get o-match 'set-id))
+             (overlay-put o-parent 'definition-id
+                          (overlay-get o-match 'definition-id))
+             (auto-o-match-overlay o-parent o-start o-end))
+           o-parent))  ; return newly created overlay
+       ))))
+)
+
+
+
+(defun auto-o-flat-suicide (o-self)
+  ;; Called when match no longer matches. Unmatch the match overlay O-SELF,
+  ;; re-matching or deleting its parent overlay as necessary.
+
+  (let ((o-parent (overlay-get o-self 'parent)))
+    (cond
+     ;; if we have no parent, don't need to do anything
+     ((null o-parent))
+
+     ;; if we're a start-match...
+     ((eq (auto-o-edge o-self) 'start)
+      ;; if parent is end-unmatched, delete parent
+      (if (null (overlay-get o-parent 'end))
+         (auto-o-delete-overlay o-parent)
+
+       ;; otherwise, look for next start match...
+       (let ((o-start (auto-o-next-flat-match o-self 'start)))
+         ;; if there is one, match parent with it
+         (if o-start
+             (auto-o-match-overlay o-parent o-start)
+           ;; otherwise, delete parent
+           (auto-o-delete-overlay o-parent)))))
+
+
+     (t ;; if we're an end-match, look for next end-match...
+      (let ((o-start (overlay-get o-parent 'start))
+           (o-end (auto-o-next-flat-match o-self 'end)))
+       (cond
+        ;; if there is one, match parent with it
+        (o-end
+         ;; if end-match already has a parent, delete it as its now
+         ;; superfluous (note: no need to parse, since parent overlay will be
+         ;; extended to cover same region anyway)
+         (when (overlay-get o-end 'parent)
+           (auto-o-delete-overlay (overlay-get o-end 'parent) 'no-parse))
+         (auto-o-match-overlay o-parent nil o-end))
+
+        (t ;; otherwise, make parent end-unmatched
+         (auto-o-match-overlay o-parent nil 'unmatched)))))
+     ))
+)
+
+
+
+(defun auto-o-next-flat-match (o-match edge)
+  ;; Find first match overlay for EDGE ('start of 'end) after match overlay
+  ;; O-MATCH in buffer, with same set-id and definition-id as O-MATCH.
+
+  ;; get sorted list of matching overlays after O-MATCH
+  (let ((o-list
+        (sort (auto-overlays-in
+               (overlay-start o-match) (point-max)  ; FIXME: is start right?
+               `((identity auto-overlay-match)
+                 (eq set-id ,(overlay-get o-match 'set-id))
+                 (eq definition-id ,(overlay-get o-match 'definition-id))
+                 (,(lambda (set-id definition-id regexp-id edge)
+                     (eq (auto-o-entry-edge set-id definition-id regexp-id)
+                         edge))
+                  (set-id definition-id regexp-id) (,edge))))
+              (lambda (a b) (<= (overlay-start a) (overlay-start b))))))
+    ;; if searching for same EDGE as O-MATCH, first overlay in list is always
+    ;; O-MATCH itself, so we drop it
+    (if (eq (auto-o-edge o-match) edge) (nth 1 o-list) (car o-list)))
+)
+
+
+
+;;; auto-overlay-flat.el ends here
diff --git a/packages/auto-overlays/auto-overlay-line.el 
b/packages/auto-overlays/auto-overlay-line.el
new file mode 100644
index 0000000..0241e97
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-line.el
@@ -0,0 +1,106 @@
+;;; auto-overlay-line.el --- automatic overlays for single lines
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(require 'auto-overlays)
+(provide 'auto-overlay-line)
+
+
+;; set line overlay parsing and suicide funtions
+(put 'line 'auto-overlay-parse-function 'auto-o-parse-line-match)
+(put 'line 'auto-overlay-suicide-function
+     (lambda (o) (auto-o-delete-overlay (overlay-get o 'parent))))
+
+
+
+(defun auto-o-parse-line-match (o-match)
+  ;; Create overlay for a new line match.
+  (let ((o-new (make-overlay (overlay-get o-match 'delim-end)
+                            (save-excursion
+                              (goto-char (overlay-get o-match 'delim-end))
+                              (1+ (line-end-position))))))
+
+    ;; give new overlay some basic properties
+    (overlay-put o-new 'auto-overlay t)
+    (overlay-put o-new 'set-id (overlay-get o-match 'set-id))
+    (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id))
+    ;; match start of new overlay with match
+    (auto-o-match-overlay o-new o-match nil)
+    ;; set overlay's modification hooks to ensure that it always extends to
+    ;; end of line
+    (overlay-put o-new 'modification-hooks
+                (cons 'auto-o-schedule-extend-line
+                      (overlay-get o-new 'modification-hooks)))
+    ;; return new overlay
+    o-new))
+
+
+(defun auto-o-schedule-extend-line (o-self modified &rest unused)
+  ;; All line overlay modification hooks are set to this function, which
+  ;; schedules `auto-o-extend-line' to run after any suicide functions have
+  ;; been called, but before the overlays are updated.
+  (unless modified
+    (push (list 'auto-o-extend-line o-self) auto-o-pending-post-suicide)))
+
+
+
+(defun auto-o-extend-line (o-self)
+  ;; Checks if overlay still extends to end of line, and update the necessary
+  ;; if not.
+
+  ;; if we haven't been deleted by a suicide function...
+  (when (overlay-buffer o-self)
+    (save-match-data
+      (let ((start (overlay-start o-self))
+           (end (overlay-end o-self)))
+       (cond
+        ;; if we no longer extend to end of line...
+        ((null (string-match "\n" (buffer-substring-no-properties
+                                   (overlay-start o-self)
+                                   (overlay-end o-self))))
+         ;; grow ourselves so we extend till end of line
+         (move-overlay o-self start (save-excursion
+                                      (goto-char (overlay-end o-self))
+                                      (1+ (line-end-position))))
+         ;; if we're exclusive, delete lower priority overlays in newly
+         ;; covered region
+         (auto-o-update-exclusive (overlay-get o-self 'set-id)
+                                  end (overlay-end o-self)
+                                  nil (overlay-get o-self 'priority)))
+
+        ;; if we extend beyond end of line...
+        ((/= (overlay-end o-self) (+ start (match-end 0)))
+         ;; shrink ourselves so we extend till end of line
+         (move-overlay o-self start (+ start (match-end 0)))
+         ;; if we're exclusive, re-parse region that is no longer covered
+         (auto-o-update-exclusive (overlay-get o-self 'set-id)
+                                  (overlay-end o-self) end
+                                  (overlay-get o-self 'priority) nil))
+        )))))
+
+
+;; auto-overlay-line.el ends here
diff --git a/packages/auto-overlays/auto-overlay-manual.info 
b/packages/auto-overlays/auto-overlay-manual.info
new file mode 100644
index 0000000..2bd3bf4
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-manual.info
@@ -0,0 +1,2248 @@
+This is auto-overlay-manual/auto-overlay-manual.info, produced by
+makeinfo version 4.13 from
+auto-overlay-manual/auto-overlay-manual.texinfo.
+
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* auto-overlays: (auto-overlay-manual).  Automatic regexp-delimited overlays
+END-INFO-DIR-ENTRY
+
+   This manual describes the Emacs Auto-Overlays package, version 0.10.9
+
+   Copyright (C) 2007-2015 Free Software Foundation, Inc
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.2 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, no Front-Cover Texts, and
+     no Back-Cover Texts. A copy of the license is included in the
+     section entitled "GNU Free Documentation License".
+
+
+File: auto-overlay-manual.info,  Node: Top,  Next: Overview,  Up: (dir)
+
+Emacs Auto-Overlays Manual
+**************************
+
+This manual describes the Emacs Auto-Overlays package, version 0.10.9
+
+   Copyright (C) 2007-2015 Free Software Foundation, Inc
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.2 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, no Front-Cover Texts, and
+     no Back-Cover Texts. A copy of the license is included in the
+     section entitled "GNU Free Documentation License".
+
+   An Emacs overlay demarcates a region of text in a buffer, often
+giving it a different face or changing other properties for that
+region. There are many circumstance in which it might be useful to
+create, update, and delete overlays automatically when text matches
+some criterion, specified for example by regular expressions. This is
+what the auto-overlays package addresses. It is intended as an Elisp
+library, providing functions to be used by other Elisp packages, so
+does not itself define any new interactive commands or minor modes.
+
+* Menu:
+
+* Overview::
+* Auto-Overlay Functions::
+* Worked Example::
+* Extending the Auto-Overlays Package::
+* To-Do::
+* Function Index::
+* Variable Index::
+* Concept Index::
+* Copying this Manual::
+
+ --- The Detailed Node Listing ---
+
+Emacs Auto-Overlays Manual
+
+* Overview::
+* Auto-Overlay Functions::
+* Worked Example::
+* Extending the Auto-Overlays Package::
+* To-Do::
+
+Auto-Overlay Functions
+
+* Defining Regexps::
+* Starting and Stopping Auto-Overlays::
+* Searching for Overlays::
+
+Extending the Auto-Overlays Package
+
+* Auto-Overlays in Depth::
+* Integrating New Overlay Classes::
+* Functions for Writing New Overlay Classes::
+* Auto-Overlay Hooks::
+* Auto-Overlay Modification Pseudo-Hooks::
+
+Functions for Writing New Overlay Classes
+
+* Functions for Modifying Overlays::
+* Functions for Querying Overlays::
+
+Copying this Manual
+
+* GNU Free Documentation License::
+
+
+File: auto-overlay-manual.info,  Node: Overview,  Next: Auto-Overlay 
Functions,  Prev: Top,  Up: Top
+
+1 Overview
+**********
+
+The auto-overlays package automatically creates, updates and destroys
+overlays based on regular expression matches in the buffer text. The
+overlay is created when text is typed that matches an auto-overlay
+regexp, and is destroyed if and when the matching text is changed so
+that it no longer matches.
+
+   The regexps are grouped into sets, and any number of different sets
+of regexps can be active in the same buffer simultaneously. Regexps in
+different sets are completely independent, and each set can be activated
+and deactivated independently (*note Defining Regexps::). This allows
+different Emacs modes to simultaneously make use of auto-overlays in the
+same buffer.
+
+   There are different "classes" of auto-overlay, used to define
+different kinds of overlay behaviour. Some classes only require a single
+regexp, others require separate regexps to define the start and end of
+the overlay (*note Defining Regexps::). Any additional regexps, beyond
+the minimum requirements, act as alternatives; if more than one of the
+regexps matches overlapping regions of text, the one that appears
+earlier in the list will take precedence. The predefined regexp classes
+are: `word', `line', `self', `nested' and `flat', but the auto-overlays
+package can easily be extended with new classes.
+
+`word'
+     These are used to define overlays that cover the text matched by
+     the regexp itself, so require a single regexp. An example use
+     would be to create overlays covering single words.
+
+`line'
+     These are used to define overlays that stretch from the text
+     matching the regexp to the end of the line, and require a single
+     regexp to define the start of the overlay. An example use would be
+     to create overlays covering single-line comments in programming
+     languages such as c.
+
+`self'
+     These are used to define overlays that stretch from one regexp
+     match to the next match for the same regexp, so naturally require
+     a single regexp. An example use would be to create overlays
+     covering strings delimited by `""'.
+
+     Note that for efficiency reasons, `self' overlays are _not_ fully
+     updated when a new match is found. Instead, when a modification is
+     subsequently made at any position in the buffer after the new
+     match, the overlays are updated _up to_ that position. The update
+     occurs just _before_ the modification is made. Therefore, the
+     overlays at a given buffer position will not necessarily be
+     correct until a modification is made at or after that position
+     (*note To-Do::).
+
+`nested'
+     These are used to define overlays that start and end at different
+     regexp matches, and that can be nested one inside another. This
+     class requires separate start and end regexps. An example use
+     would be to create overlays between matching braces `{}'.
+
+`flat'
+     These are used to define overlays that start and end at different
+     regexp matches, but that can not be nested. Extra start matches
+     within one of these overlays are ignored. This class requires
+     separate start and end regexps. An example use would be to create
+     overlays covering multi-line comments in code, e.g. c++ block
+     comments delimited by `/*' and `*/'.
+
+   By default, the entire text matching a regexp acts as the
+"delimeter". For example, a `word' overlay will cover all the text
+matching its regexp, and a `nested' overlay will start at the end of
+the text matching its start regexp. Sometimes it is useful to be able
+to have only part of the regexp match act as the delimeter. This can be
+done by grouping that part of the regexp (*note Defining Regexps::).
+Overlays will then start and end at the text matching the group,
+instead of the text matching the entire regexp.
+
+   Of course, automatically creating overlays isn't much use without
+some way of setting their properties too. Overlay properties can be
+defined along with the regexp, and are applied to any overlays created
+by a match to that regexp. Certain properties have implications for
+auto-overlay behaviour.
+
+`priority'
+     This is a standard Emacs overlay property (*note Overlay
+     Properties: (elisp)Overlay Properties.), but it is also used to
+     determine which regexp takes precedence when two or more regexps
+     in the same auto-overlay definition match overlapping regions of
+     text. It is also used to determine which regexp's properties take
+     precedence for overlays that are defined by separate start and end
+     matches.
+
+`exclusive'
+     Normally, different auto-overlay regexps coexist, and act
+     completely independently of one-another. However, if an
+     auto-overlay has non-nil `exclusive' and `priority' properties,
+     regexp matches within the overlay are ignored if they have lower
+     priority. An example use is ignoring other regexp matches within
+     comments in code.
+   
+
+File: auto-overlay-manual.info,  Node: Auto-Overlay Functions,  Next: Worked 
Example,  Prev: Overview,  Up: Top
+
+2 Auto-Overlay Functions
+************************
+
+To use auto-overlays in an Elisp package, you must load the overlay
+classes that you require by including lines of the form
+     (require 'auto-overlay-CLASS)
+   near the beginning of your package, where CLASS is the class name.
+The standard classes are: `word', `line', `self', `nested' and `flat'
+(*note Overview::), though new classes can easily be added (*note
+Extending the Auto-Overlays Package::).
+
+   Sometimes it is useful for a package to make use of auto-overlays if
+any are defined, without necessarily requiring them. To facilitate
+this, the relevant functions can be loaded separately from the rest of
+the auto-overlays package with the line
+     (require 'auto-overlay-common)
+   This provides all the functions related to searching for overlays and
+retrieving overlay properties. *Note Searching for Overlays::. Note that
+there is no need to include this line if any auto-overlay classes are
+`require'd, though it will do no harm.
+
+   This section describes the functions that are needed in order to make
+use of auto-overlays in an Elisp package. It does _not_ describe
+functions related to extending the auto-overlays package. *Note
+Extending the Auto-Overlays Package::.
+
+* Menu:
+
+* Defining Regexps::
+* Starting and Stopping Auto-Overlays::
+* Searching for Overlays::
+
+
+File: auto-overlay-manual.info,  Node: Defining Regexps,  Next: Starting and 
Stopping Auto-Overlays,  Up: Auto-Overlay Functions
+
+2.1 Defining Regexps
+====================
+
+An auto-overlay definition is a list of the form:
+     (CLASS &optional :id ENTRY-ID REGEXP1 REGEXP2 ...)
+   CLASS is one of the regexp classes described in the previous section
+(*note Overview::). The optional `:id' property should be a symbol that
+can be used to uniquely identify the auto-overlay definition.
+
+   Each REGEXP defines one of the regexps that make up the auto-overlay
+definition. It should be a list of the form
+     (RGXP &optional :edge EDGE :id SUBENTRY-ID @rest PROPERTY1 PROPERTY2 ...)
+   The `:edge' property should be one of the symbols `'start' or
+`'end', and determines which edge of the auto-overlay this regexp
+corresponds to. If `:edge' is not specified, it is assumed to be
+`'start'. Auto-overlay classes that do not require separate `start' and
+`end' regexps ignore this property. The `:id' property should be a
+symbol that can be used to uniquely identify the regexp. Any further
+elements in the list are cons cells of the form `(property . value)',
+where PROPERTY is an overlay property name (a symbol) and VALUE its
+value. In its simplest form, RGXP is a single regular expression.
+
+   If only part of the regexp should act as the delimeter (*note
+Overview::), RGXP should instead be a cons cell:
+     (RX . GROUP)
+   where RX is a regexp that contains at least one group (*note Regular
+Expressions: (elisp)Regular Expressions.), and GROUP is an integer
+identifying which group should act as the delimeter.
+
+   If the overlay class requires additional groups to be specified,
+RGXP should instead be a list:
+     (RX GROUP0 GROUP1 ...)
+   where RX is a regexp. The first GROUP0 still specifies the part that
+acts as the delimeter, as before. If the entire regexp should act as
+the delimeter, GROUP0 must still be supplied but should be set to 0
+(meaning the entire regexp). None of the standard classes make use of
+any additional groups, but extensions to the auto-overlays package that
+define new classes may. *Note Extending the Auto-Overlays Package::.
+
+   The following functions are used to load and unload regexp
+definitions: 
+
+`(auto-overlay-load-definition SET-ID DEFINITION &optional POS)'
+     Load a new auto-overlay DEFINITION, which should be a list of the
+     form described above, into the set identified by the symbol
+     SET-ID. The optional parameter POS determines where in the set's
+     regexp list the new regexp is inserted. If it is `nil', the regexp
+     is added at the end. If it is `t', the regexp is added at the
+     beginning. If it is an integer, the regexp is added at that
+     position in the list. Whilst the position in the list has no
+     effect on overlay behaviour, it does determine the order in which
+     regexps are checked, so can affect efficiency.
+
+`(auto-overlay-load-regexp SET-ID ENTRY-ID REGEXP &optional POS)'
+     Load a new REGEXP, which should be a list of the form described
+     above, into the auto-overlay definition identified by the symbol
+     ENTRY-ID, in the set identified by the symbol SET-ID. REGEXP
+     should be a list of the form described above.  The optional POS
+     determines the position of the regexp in the list of regexps
+     defining the auto-overlay, which can be significant for overlay
+     behaviour since it determines which regexp takes precedence when
+     two match the same text.
+
+`(auto-overlay-unload-set SET-ID)'
+     Unload the entire regexp set identified by the symbol SET-ID.
+
+`(auto-overlay-unload-definition SET-ID ENTRY-ID)'
+     Unload the auto-overlay definition identified by the symbol
+     ENTRY-ID from the set identified by the symbol SET-ID.
+
+`(auto-overlay-unload-regexp SET-ID ENTRY-ID SUBENTRY-ID)'
+     Unload the auto-overlay regexp identified by the symbol
+     SUBENTRY-ID from the auto-overlay definition identified by the
+     symbol ENTRY-ID in the set identified by the symbol SET-ID.
+
+`(auto-overlay-share-regexp-set SET-ID FROM-BUFFER @optional TO-BUFFER)'
+     Share the set of regexp definitions identified by the symbol
+     SET-ID in buffer `from-buffer' with the buffer TO-BUFFER, or the
+     current buffer if TO-BUFFER is null. The regexp set becomes common
+     to both buffers, and any changes made to it in one buffer, such as
+     loading and unloading regexp definitions, are also reflected in
+     the other buffer. However, the regexp set can still be enabled and
+     disabled independently in both buffers. The same regexp set can be
+     shared between any number of buffers. To remove a shared regexp
+     set from one of the buffers, simply unload the entire set from that
+     buffer using `auto-overlay-unload-regexp'. The regexp set will
+     remain defined in all the other buffers it was shared with.
+
+
+File: auto-overlay-manual.info,  Node: Starting and Stopping Auto-Overlays,  
Next: Searching for Overlays,  Prev: Defining Regexps,  Up: Auto-Overlay 
Functions
+
+2.2 Starting and Stopping Auto-Overlays
+=======================================
+
+A set of regexps is not active until it has been "started", and can be
+deactivated by "stopping" it. When a regexp set is activated, the
+entire buffer is scanned for regexp matches, and the corresponding
+overlays created. Similarly, when a set is deactivated, all the overlays
+are deleted. Note that regexp definitions can be loaded and unloaded
+whether the regexp set is active or inactive, and that deactivating a
+regexp set does _not_ delete its regexp definitions.
+
+   Since scanning the whole buffer for regexp matches can take some
+time, especially for large buffers, auto-overlay data can be saved to an
+auxiliary file so that the overlays can be restored more quickly if the
+same regexp set is subsequently re-activated. Of course, if either the
+text in the buffer or the overlay definitions are modified whilst the
+regexp set is disabled, then the saved data will be out of date.
+Auto-overlays automatically checks whether the text or overlay
+definitions have been modified since the data was saved. If so, it
+ignores the saved data and re-scans the buffer.
+
+   The usual time to save and restore overlay data is when a regexp set
+is deactivated or activated. The auxilliary file name is then
+constructed automatically from the buffer name and the set-id. However,
+auto-overlays can also be saved and restored manually.
+
+`(auto-overlay-start SET-ID @optional BUFFER SAVE-FILE NO-REGEXP-CHECK)'
+     Activate the auto-overlay regexp set identified by the symbol
+     SET-ID in BUFFER, or the current buffer if the latter is `nil'. If
+     there is a file called `auto-overlay-'BUFFER-NAME`-'SET-ID
+     containing up-to-date overlay data, it will be used to restore the
+     auto-overlays (BUFFER-NAME is the name of the file visited by the
+     buffer, or the buffer name itself if there is none). Otherwise,
+     the entire buffer will be scanned for regexp matches.
+
+     The string SAVE-FILE specifies the where to look for the file of
+     saved overlay data. If it is nil, it defaults to the current
+     directory. If it is a string specifying a relative path, then it is
+     relative to the current directory, whereas an absolute path
+     specifies exactly where to look. If it is a string specifying a
+     file name (with or without a full path, relative or absolute),
+     then it overrides the default file name and/or location. Any other
+     value of SAVE-FILE will cause the file of overlay data to be
+     ignored, even if it exists.
+
+     If the overlays are being loaded from a file, but optional argument
+     no-regexp-check is non-nil, the file of saved overlays will be
+     used, but no check will be made to ensure regexp refinitions are
+     the same as when the overlays were saved.
+
+`(auto-overlay-stop SET-ID @optional BUFFER SAVE-FILE LEAVE-OVERLAYS)'
+     Deactivate the auto-overlay regexp set identified by the symbol
+     SET-ID in BUFFER, or the current buffer if the latter is `nil'.
+     All corresponding overlays will be deleted (unless the
+     LEAVE-OVERLAYS option is non-nil, which should only be used if the
+     buffer is about to be killed), but the regexp definitions are
+     preserved and can be reactivated later.
+
+     If SAVE-FILE is non-nil, overlay data will be saved in an
+     auxilliary file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the
+     current directory, to speed up subsequent reactivation of the
+     regexp set in the same buffer (BUFFER-NAME is the name of the file
+     visited by the buffer, or the buffer name itself if there is
+     none). If SAVE-FILE is a string, it overrides the default save
+     location, overriding either the directory if it only specifies a
+     path (relative paths are relative to the current directory), or
+     the file name if it only specifies a filename, or both if it
+     specifies a full path.
+
+`(auto-overlay-save-overlays SET-ID @optional BUFFER FILE)'
+     Save auto-overlay data for the regexp set identified by the symbol
+     SET-ID in BUFFER, or the current buffer if `nil', to an auxilliary
+     file called FILE. If FILE is nil, the overlay data are saved to a
+     file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the current
+     directory (BUFFER-NAME is the name of the file visited by the
+     buffer, or the buffer name itself if it's not visiting a file). If
+     `file' is a directory name (either an absolute path or relative to
+     the current directory), the overlay data are saved to the default
+     file name under that directory.
+
+`(auto-overlay-load-overlays SET-ID @optional BUFFER FILE NO-REGEXP-CHECK)'
+     Load auto-overlay data for the regexp set identified by the symbol
+     SET-ID into BUFFER, or the current buffer if `nil', from an
+     auxilliary file called FILE. If FILE is nil, it attempts to load
+     the overlay data from a file called
+     `auto-overlay-'BUFFER-NAME`-'SET-ID in the current directory
+     (BUFFER-NAME is the name of the file visited by the buffer, or the
+     buffer name itself if it's not visiting a file). If `file' is a
+     directory name (either an absolute path or relative to the current
+     directory), it attempts to load the overlay data from the default
+     file name under that directory. If NO-REGEXP-CHECK is no-nil, the
+     saved overlays will be loaded even if different regexp definitions
+     were active when the overlays were saved. Returns `t' if the
+     overlays were successfully loaded, `nil' otherwise.
+
+
+File: auto-overlay-manual.info,  Node: Searching for Overlays,  Prev: Starting 
and Stopping Auto-Overlays,  Up: Auto-Overlay Functions
+
+2.3 Searching for Overlays
+==========================
+
+Auto-overlays are just normal Emacs overlays, so any of the standard
+Emacs functions can be used to search for overlays and retrieve overlay
+properties. The auto-overlays package provides some additional
+functions.
+
+`(auto-overlays-at-point @optional POINT PROP-TEST INACTIVE)'
+     Return a list of overlays overlapping POINT, or the point if POINT
+     is null. The list includes _all_ overlays, not just auto-overlays
+     (but see below). The list can be filtered to only return overlays
+     with properties matching criteria specified by PROP-TEST. This
+     should be a list defining a property test, with one of the
+     following forms (or a list of such lists, if more than one
+     property test is required):
+          (FUNCTION PROPERTY)
+          (FUNCTION PROPERTY VALUE)
+          (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...))
+     where FUNCTION is a function, PROPERTY is an overlay property name
+     (a symbol), and VALUE can be any value or lisp expression. For
+     each overlay, first the values corresponding to the PROPERTY names
+     are retrieved from the overlay and any VALUEs that are lisp
+     expressions are evaluated. Then FUNCTION is called with the
+     property values followed by the other values as its arguments. The
+     test is satisfied if the result is non-nil, otherwise it fails.
+     Tests are evaluated in order, but only up to the first failure.
+     Only overlays that satisfy all property tests are returned.
+
+     All auto-overlays are given a non-nil `auto-overlay' property, so
+     to restrict the list to auto-overlays, PROP-TEST should include
+     the following property test:
+          ('identity 'auto-overlay)
+     For efficiency reasons, the auto-overlays package sometimes leaves
+     overlays hanging around in the buffer even when they should have
+     been deleted. These are marked with a non-nil `inactive' property.
+     By default, `auto-overlays-at-point' ignores these. A non-nil
+     INACTIVE will override this, causing inactive overlays to be
+     included in the returned list (assuming they pass all property
+     tests).
+
+`(auto-overlays-in START END @optional PROP-TEST WITHIN INACTIVE)'
+     Return a list of overlays overlapping the region between START and
+     END. The PROP-TEST and INACTIVE arguments have the same behaviour
+     as in `auto-overlays-at-point', above. If WITHIN is non-nil, only
+     overlays that are entirely within the region from START to END
+     will be returned, not overlays that extend outside that region.
+
+`(auto-overlay-highest-priority-at-point @optional POINT PROP-TEST)'
+     Return the highest priority overlay at POINT (or the point, if
+     POINT is null). The PROP-TEST argument has the same behaviour as
+     in `auto-overlays-at-point', above. An overlay's priority is
+     determined by the value of its `priority' property (*note Overlay
+     Properties: (elisp)Overlay Properties.). If two overlays have the
+     same priority, the innermost one takes precedence (i.e. the one
+     that begins later in the buffer, or if they begin at the same
+     point the one that ends earlier; if two overlays have the same
+     priority and extend over the same region, there is no way to
+     predict which will be returned).
+
+`(auto-overlay-local-binding SYMBOL @optional POINT)'
+     Return the "overlay-local" binding of SYMBOL at POINT (or the
+     point if POINT is null), or the current local binding if there is
+     no overlay binding. An "overlay-local" binding for SYMBOL is the
+     value of the overlay property called SYMBOL. If more than one
+     overlay at POINT has a non-nil SYMBOL property, the value from the
+     highest priority overlay is returned (see
+     `auto-overlay-highest-priority-at-point', above, for an
+     explanation of "highest priority").
+
+
+File: auto-overlay-manual.info,  Node: Worked Example,  Next: Extending the 
Auto-Overlays Package,  Prev: Auto-Overlay Functions,  Up: Top
+
+3 Worked Example
+****************
+
+The interaction of all the different regexp definitions, overlay
+properties and auto-overlay classes provided by the auto-overlays
+package can be a little daunting. This section will go through an
+example of how the auto-overlay regexps could be defined to create
+overlays for a subset of LaTeX, which is complex enough to demonstrate
+most of the features.
+
+   LaTeX is a markup language, so a LaTeX document combines markup
+commands with normal text. Commands start with `\', and end at the
+first non-word-constituent character. We want to highlight all LaTeX
+commands in blue. Two commands that will particularly interest us are
+`\begin' and `\end', which begin and end a LaTeX environment. The
+environment name is enclosed in braces: `\begin{ENVIRONMENT-NAME}', and
+we want it to be highlighted in pink. LaTeX provides many environments,
+used to create lists, tables, titles, etc. We will take the example of
+an `equation' environment, used to typeset mathematical equations. Thus
+equations are enclosed by `\begin{equation}' and `\end{equation}', and
+we would like to highlight these equations in yellow. Another example
+we will use is the `$' delimiter. Pairs of `$'s delimit mathematical
+expressions that appear in the middle of a paragraph of normal text
+(whereas `equation' environments appear on their own, slightly
+separated from surrounding text). Again, we want to highlight these
+mathematical expressions, this time in green. The final piece of LaTeX
+markup we will need to consider is the `%' character, which creates a
+comment that lasts till the end of the line (i.e. text after the `%' is
+ignored by the LaTeX processor up to the end of the line).
+
+   LaTeX commands are a good example of when to use `word' regular
+expressions (*note Overview::). The appropriate regexp definition is
+loaded by
+
+     (auto-overlay-load-definition
+      'latex
+      '(word ("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)"
+              (face . (background-color . "blue")))))
+
+We have called the regexp set `latex'. The `face' property is a
+standard Emacs overlay property that sets font properties within the
+overlay. *Note Overlay Properties: (elisp)Overlay Properties. `"\\\\"'
+is the string defining the regexp that matches a _single_ `\'. (Note
+that the `\' character has a special meaning in regular expressions, so
+to include a literal one it must be escaped: `\\'. However, `\' also
+has a special meaning in lisp strings, so both `\' characters must be
+escaped there too, giving `\\\\'.) `[[:alpha:]]*?' matches a sequence
+of zero or more letter characters. The `?' ensures that it matches the
+_shortest_ sequence of letters consistent with matching the regexp,
+since we want the region to end at the first non-letter character,
+matched by `[^[:alpha:]]'. The `\|' defines an alternative, to allow
+the LaTeX command to be terminated either by a non-letter character or
+by the end of the line (`$'). *Note Regular Expressions: (elisp)Regular
+Expressions, for more details on Emacs regular expressions.
+
+   However, there's a small problem. We only want the blue background to
+cover the characters making up a LaTeX command. But as we've defined
+things so far, it will cover all the text matched by the regexp, which
+includes the leading `\' and the trailing non-letter character. To
+rectify this, we need to group the part of the regexp that matches the
+command (i.e. by surround it with `\(' and `\)'), and put the regexp
+inside a cons cell containing the regexp in its `car' and a number
+indicating which subgroup to use in its `cdr':
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+   The `$' delimiter is an obvious example of when to use a `self'
+regexp (*note Overview::). We can update our example to include this
+(note that `$' also has a special meaning in regular expressions, so it
+must be escaped with `\' which itself must be escaped in lisp strings):
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (face . (background-color . "green")))))
+
+This won't quite work though. LaTeX maths commands also start with a
+`\' character, which will match the `word' regexp. For the sake of
+example we want the entire equation highlighted in green, without
+highlighting any LaTeX maths commands it contains in blue. Since the
+`word' overlay will be within the `self' overlay, the blue highlighting
+will take precedence. We can change this by giving the `self' overlay a
+higher priority (any priority is higher than a non-existent one; we use
+3 here for later convenience). For efficiency reasons, it's a good idea
+to put higher priority regexp definitions before lower priority ones,
+so we get:
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+   The `\begin{equation}' and `\end{equation}' commands also enclose
+maths regions, which we would like to highlight in yellow. Since the
+opening and closing delimiters are different in this case, we must use
+`nested' overlays (*note Overview::). Our example now looks like:
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+Notice how we've used separate `start' and `end' regexps to define the
+auto-overlay. Once again, we have had to escape the `\' characters, and
+increase the priority of the new regexp definition to avoid any LaTeX
+commands within the maths region being highlighted in blue.
+
+   LaTeX comments start with `%' and last till the end of the line: a
+perfect demonstration of a `line' regexp. Here's a first attempt:
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+We use the standard Emacs `face-attribute' function to retrieve the
+default background colour, which is evaluated before the regexp
+definition is loaded. (This will of course go wrong if the default
+background colour is subsequently changed, but it's sufficient for this
+example). Let's think about this a bit. We probably don't want anything
+within a comment to be highlighted at all, even if it matches one of the
+other regexps. In fact, creating overlays for `\begin' and `\end'
+commands which are within a comment could cause havoc! If they don't
+occur in pairs within the commented region, they will erroneously pair
+up with ones outside the comment. We need comments to take precedence
+over everything else, and we need them to block other regexp matches,
+so we boost the overlay's priority and set the exclusive property:
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+   We're well on our way to creating a useful setup, at least for the
+LaTeX commands we're considering in this example. There is one last
+type of overlay to create, but it is the most complicated. We want
+environment names to be highlighted in pink, i.e. the region between
+`\begin{' and `}'. A first attempt at this might result in:
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("}"
+         :edge end
+         (priority . 2)
+         (face . (background-color . "pink")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+However, we'll hit a problem with this. The `}' character also closes
+the `\end{' command. Since we haven't told auto-overlays about `\end{',
+every `}' that should close an `\end{' command will instead be
+interpreted as the end of a `\start{' command, probably resulting in
+lots of unmatched `}' characters, creating pink splodges everywhere!
+Clearly, since we also want environment names between `\end{' and `}'
+to be pink, we need something more along the lines of:
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\end{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("}"
+         :edge end
+         (priority . 2)
+         (face . (background-color . "pink")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+We still haven't solved the problem though. The `}' character doesn't
+only close `\begin{' and `\end{' commands in LaTeX. _All_ arguments to
+LaTeX commands are surrounded by `{' and `}'. We could add all the
+commands that take arguments, but we don't really want to bother about
+any other commands (at least in this example). All we want to do is
+prevent predictive mode incorrectly pairing the `}' characters used for
+other commands. Instead, we can just add `{' to the list:
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("{"
+         :edge start
+         (priority . 2))
+        ("\\begin{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\end{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("}"
+         :edge end
+         (priority . 2))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+Notice how the `{' and `}' regexps do not define a background colour
+(or indeed any other properties), so that any overlays they create will
+have no effect other than making sure all `{' and `}' characters are
+correctly paired.
+
+   We've made one mistake though: by putting the `{' regexp at the
+beginning of the list, it will take priority over any other regexp in
+the list that could match the same text. And since `{' will match
+whenever `\begin{' or `\end{' matches, environments will never be
+highlighted! The `{' regexp must come _after_ the `\begin{' and `\end{'
+regexps, to ensure it is only used if neither of them match (it doesn't
+matter whether it appears before or after the `{' regexp, since the
+latter will never match the same text):
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\end{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("{"
+         :edge start
+         (priority . 2))
+        ("}"
+         :edge end
+         (priority . 2))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+   There is one last issue. A literal `{' or `}' character can be
+included in a LaTeX document by escaping it with `\': `\{' and `\}'. In
+this situation, the characters do not match anything and should not be
+treated as delimiters. We can modify the `{' and `}' regexps to exclude
+these cases:
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\end{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\([^\\]\\|^\\){"
+         :edge start
+         (priority . 2))
+        ("\\([^\\]\\|^\\)}"
+         :edge end
+         (priority . 2))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+The new, complicated-looking regexps will only match `{' and `}'
+characters if they are _not_ preceded by a `\' character (*note Regular
+Expressions: (elisp)Regular Expressions.). Note that the character
+alternative `[^\]\|^' can match any character that isn't a `\' _or_ the
+start of a line. This is required because matches to auto-overlay
+regexps are not allowed to span more than one line. If `{' or `}'
+appear at the beginning of a line, there will be no character in front
+(the newline character doesn't count, since it isn't on the same line),
+so the `[^\]' will not match.
+
+   However, when it does match, the `}' regexp will now match an
+additional character before the `}', causing the overlay to end one
+character early. (The `{' regexp will also match one additional
+character before the `{', but since the beginning of the overlay starts
+from the _end_ of the `start' delimiter, this poses less of a problem.)
+We need to group the part of the regexp that should define the
+delimiter, i.e. the `}', by surrounding it with `\(' and `\)', and put
+the regexp in the `car' of a cons cell whose `cdr' specifies the new
+subgroup (i.e. the 2nd subgroup, since the regexp already included a
+group for other reasons; we could alternatively replace the original
+group by a shy-group, since we don't actually need to capture match
+data for that group). Our final version looks like this:
+
+     (auto-overlay-load-definition
+      'latex
+      `(line ("%" (priority . 4) (exclusive . t)
+                  (face . (background-color
+                           . ,(face-attribute 'default :background))))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(self ("\\$" (priority . 3) (face . (background-color . "green")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\end{"
+         :edge start
+         (priority . 2)
+         (face . (background-color . "pink")))
+        ("\\([^\\]\\|^\\){"
+         :edge start
+         (priority . 2))
+        (("\\([^\\]\\|^\\)\\(}\\)" . 2)
+         :edge end
+         (priority . 2))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(nested
+        ("\\begin{equation}"
+         :edge start
+         (priority . 1)
+         (face . (background-color . "yellow")))
+        ("\\end{equation}"
+         :edge end
+         (priority . 1)
+         (face . (background-color . "yellow")))))
+
+     (auto-overlay-load-definition
+      'latex
+      '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1)
+              (face . (background-color . "blue")))))
+
+   With these regexp definitions, LaTeX commands will automatically be
+highlighted in blue, equation environments in yellow, inline maths
+commands in green, and environment names in pink. LaTeX markup within
+comments will be ignored. And `{' and `}' characters from other
+commands will be correctly taken into account. All this is done in
+"real-time"; it doesn't wait until Emacs is idle to update the
+overlays. Not bad for a bundle of regexps!
+
+   Of course, this could all be done more easily using Emacs' built-in
+syntax highlighting features, but the highlighting was only an example
+to show the location of the overlays. The main point is that the
+overlays are automatically created and kept up to date, and can be given
+any properties you like and used for whatever purpose is required by
+your Elisp package.
+
+
+File: auto-overlay-manual.info,  Node: Extending the Auto-Overlays Package,  
Next: To-Do,  Prev: Worked Example,  Up: Top
+
+4 Extending the Auto-Overlays Package
+*************************************
+
+The auto-overlays package can easily be extended by adding new overlay
+classes(1). The next sections document the functions and interfaces
+provided by the auto-overlays package for this purpose.
+
+   Often, a new class is a minor modification of one of the standard
+classes. For example, it may work exactly like one of the standard
+classes, but in addition call some function whenever an overlay is
+created or destroyed. In this case, it is far better to build the new
+class on top of the existing class, using functions from the
+class-specific Elisp files, rather than starting from scratch. *Note
+Standard Parse and Suicide Functions::.
+
+* Menu:
+
+* Auto-Overlays in Depth::
+* Integrating New Overlay Classes::
+* Functions for Writing New Overlay Classes::
+* Auto-Overlay Hooks::
+* Auto-Overlay Modification Pseudo-Hooks::
+
+   ---------- Footnotes ----------
+
+   (1) Or rather, it is easy to integrate new overlay classes into the
+package. Whether writing a new overlay class is easy or not depends on
+what you're trying to do, and how good your coding skills are ;-)
+
+
+File: auto-overlay-manual.info,  Node: Auto-Overlays in Depth,  Next: 
Integrating New Overlay Classes,  Up: Extending the Auto-Overlays Package
+
+4.1 Auto-Overlays in Depth
+==========================
+
+In order to write new classes, a deeper understanding is required of how
+the auto-overlays package works. In fact, two kinds of overlays are
+automatically created, updated and destroyed when auto-overlays are
+active: the auto-overlays themselves, and "match" overlays, used to
+mark text that matches an auto-overlay regexp.
+
+   For overlay classes that only require one regexp to fully define an
+overlay (the `word' and `line' classes are the only standard classes
+like this(1)), the auto-overlays are always matched with the
+corresponding match overlay. For classes that require two regexp
+matches to define the start and end of an overlay (all other standard
+classes), each edge of an auto-overlay can be matched with a match
+overlay. The match overlays define where the edge of the auto-overlay
+is located. There will always be at least one matched edge, since an
+auto-overlay is only created when a regexp match is found, but it is
+possible for the second edge to not yet be matched (for many classes,
+the unmatched edge will be located at the beginning or end of the
+buffer).
+
+   If a match overlay delimits the start of an auto-overlay, the match
+overlay is stored in the auto-overlay's `start' property. The match
+overlay is also stored in the `start' property for auto-overlays that
+only require a single match. If a match overlay delimits the end of an
+auto-overlay, the match overlay is stored in the auto-overlay's `end'
+property. Conversely, a "link" to the auto-overlay is always stored in
+the match overlay's `parent' property(2).
+
+   Whenever a buffer is modified, the lines containing the modifications
+are scanned for new regexp matches. If one is found, a new match overlay
+is created covering the matching text, and then passed as an argument to
+the appropriate "parse" function(3) for its class. This deals with
+creating or updating the auto-overlays, as appropriate. If the text
+within a match overlay is modified, the match overlay checks whether
+the text it covers still matches the regexp. If it no longer matches,
+the match overlay is passed as an argument to the appropriate "suicide"
+function for its class, which deals with updating or deleting its
+parent auto-overlay (and possibly more besides).
+
+   To summarise, the core of the auto-overlays package deals with
+searching for regexp matches, and creating or deleting the
+corresponding match overlays. It then hands over the task of creating,
+updating or deleting the auto-overlays themselves to class-specific
+functions, which implement the correct behaviour for that class.
+
+   ---------- Footnotes ----------
+
+   (1) Although the `self' class only requires one regexp definition,
+the auto-overlays themselves require two matches to that same regexp to
+set the start and end of the overlay.
+
+   (2) The "parent" terminology is admittedly very poor, and is a relic
+of a previous incarnation of the auto-overlays package, when it made
+more sense.
+
+   (3) More bad terminology.
+
+
+File: auto-overlay-manual.info,  Node: Integrating New Overlay Classes,  Next: 
Functions for Writing New Overlay Classes,  Prev: Auto-Overlays in Depth,  Up: 
Extending the Auto-Overlays Package
+
+4.2 Integrating New Overlay Classes
+===================================
+
+To add a new overlay class, all that is required is to write new
+"parse" and "suicide" functions, and inform the auto-overlays package
+of their existence. A "match" function can also optionally be defined.
+It is called whenever a match overlay in the class becomes matched with
+the edge of an auto-overlay (*note Functions for Modifying Overlays::).
+The parse, suicide and match functions are conventionally called
+`auto-o-parse-'CLASS`-match', `auto-o-'CLASS`-suicide' and
+`auto-o-match-'CLASS, where CLASS is the name of the class, though the
+convention is not enforced in any way.
+
+parse function
+     A parse function is passed a single argument containing a match
+     overlay. It should return a list containing any new auto-overlays
+     it creates, or `nil' if none were created.
+          O-LIST = (auto-o-parse-CLASS-match O-MATCH)
+     Note that the parse function itself is responsible for calling the
+     `auto-o-update-exclusive' function if a new exclusive overlay is
+     created. *Note Functions for Modifying Overlays::.
+
+suicide function
+     A suicide function is passed a single argument containing a match
+     overlay. Its return value is ignored.
+          (auto-o-CLASS-suicide O-MATCH)
+     The text covered by the match overlay should be considered to no
+     longer match its regexp, although in certain cases matches are
+     ignored for other reasons and this may not really be the case (for
+     example if a new, higher-priority, exclusive overlay overlaps the
+     match, *note Overview::).
+
+match function
+     A match function is passed a single argument containing a match
+     overlay that has just been matched with an edge of an auto-overlay
+     (*note Functions for Modifying Overlays::). Its return value is
+     ignored.
+          (auto-o-match-CLASS O-MATCH)
+     The auto-overlay it is matched with is stored in the match
+     overlay's `parent' property.
+
+   To integrate the new class into the auto-overlays package, the parse
+and suicide functions must be added to the property list of the symbol
+used to refer to the new class, denoted here by CLASS:
+     (put 'CLASS 'auto-overlay-parse-function
+          'auto-o-parse-CLASS-match)
+     (put 'CLASS 'auto-overlay-suicide-function
+          'auto-o-CLASS-suicide)
+   If the optional match function is defined, it should similarly be
+added to the symbol's property list:
+     (put 'CLASS 'auto-overlay-match-function
+          'auto-o-match-CLASS)
+
+
+File: auto-overlay-manual.info,  Node: Functions for Writing New Overlay 
Classes,  Next: Auto-Overlay Hooks,  Prev: Integrating New Overlay Classes,  
Up: Extending the Auto-Overlays Package
+
+4.3 Functions for Writing New Overlay Classes
+=============================================
+
+Some functions are provided by the auto-overlays package for use in new
+parse and suicide functions. The functions that modify overlays carry
+out tasks that require interaction with the core of the auto-overlays
+package, and provide the only reliable way of carrying out those tasks.
+The other functions are used to query various things about
+auto-overlays and match overlays. Again, they are the only reliable
+interface for this, since the internal implementation may change between
+releases of the auto-overlays package.
+
+* Menu:
+
+* Standard Parse and Suicide Functions::
+* Functions for Modifying Overlays::
+* Functions for Querying Overlays::
+
+
+File: auto-overlay-manual.info,  Node: Standard Parse and Suicide Functions,  
Next: Functions for Modifying Overlays,  Up: Functions for Writing New Overlay 
Classes
+
+4.3.1 Standard Parse and Suicide Functions
+------------------------------------------
+
+All the standard overlay classes define their own parse and suicide
+functions (none of them require a match function), which can be used to
+create new "derived" classes based on the standard ones. This is the
+easiest and most common way to create a new class. For example, the new
+class may behave exactly like one of the standard classes, but perform
+some additional processing whenever an overlay is created, destroyed, or
+matched. The parse and suicide functions for the new class should
+perform whatever additional processing is required, and call the
+standard class functions to deal with creating and destroying the
+overlay.
+
+   All the standard parse and suicide functions follow the same naming
+convention (*note Integrating New Overlay Classes::), where CLASS is
+the name of the overlay class (one of `word', `line', `self', `nested'
+or `flat', *note Overview::):
+
+`(auto-o-parse-CLASS-match O-MATCH)'
+     Parse a new match overlay O-MATCH whose class is CLASS. This will
+     create or update auto-overlays, as appropriate for the class.
+
+`(auto-o-CLASS-suicide O-MATCH)'
+     Delete or update auto-overlays as appropriate for overlay class
+     CLASS, due to the match overlay O-MATCH no longer matching.
+
+
+File: auto-overlay-manual.info,  Node: Functions for Modifying Overlays,  
Next: Functions for Querying Overlays,  Prev: Standard Parse and Suicide 
Functions,  Up: Functions for Writing New Overlay Classes
+
+4.3.2 Functions for Modifying Overlays
+--------------------------------------
+
+These functions modify auto-overlays and match overlays as necessary to
+perform a particular update. They should _always_ be used to carry out
+their corresponding tasks, rather than doing it separately, since these
+tasks require interaction with the core of the auto-overlays package.
+
+`(auto-o-update-exclusive SET-ID BEG END OLD-PRIORITY NEW-PRIORITY)'
+     Update the region between BEG and END in the current buffer as
+     necessary due to the priority of an exclusive overlay overlapping
+     the region changing from OLD-PRIORITY to NEW-PRIORITY. If the
+     exclusive overlay did not previously overlap the region,
+     OLD-PRIORITY should be null. If it no longer overlaps the region,
+     NEW-PRIORITY should be null. (If both are null, nothing will
+     happen!) The return value is meaningless.
+
+`(auto-o-match-overlay OVERLAY START @optional END NO-PROPS NO-PARSE 
PROTECT-MATCH)'
+     Match or unmatch the start and end of the auto-overlay OVERLAY,
+     update all appropriate properties (such as `parent', `start' and
+     `end' properties, and any properties specified in regexp
+     definitions), and update other auto-overlays in the region covered
+     by OVERLAY as necessary (usually because the `exclusive' or
+     `priority' properties of OVERLAY have changed).
+
+     If START or END are match overlays, match the corresponding edge
+     of OVERLAY. The edge is moved to the location defined by the match
+     overlay, and the `parent' property of the match overlay and the
+     `start' and `end' properties of OVERLAY are updated accordingly.
+     The START argument should be a match overlay corresponding either
+     to the unique regexp if only one is needed for that overlay class,
+     or to a start regexp if the overlay class uses separate start and
+     end regexps. The END argument should then be a match overlay
+     corresponding to an end regexp in the same class (*note
+     Overview::). You're responsible for enforcing this; no check is
+     made.
+
+     If START or END are numbers or markers, move the corresponding
+     edge of OVERLAY to that location and set it as unmatched. The
+     `start' or `end' property of OVERLAY and the `parent' property of
+     any corresponding match overlay are set to `nil'. If START or END
+     are non-nil but neither of the above, leave the corresponding edge
+     of OVERLAY where it is, but set it unmatched (as described above).
+     If START or END are null, don't change the corresponding edge.
+     However, for convenience, if END is null but START is a match
+     overlay corresponding to a match for an end-regexp, match the end
+     of OVERLAY rather than the start.
+
+     The remaining arguments disable some of the tasks normally carried
+     out by `auto-o-match-overlay'. If NO-PROPS is non-nil, overlay
+     properties specified in regexp definitions are ignored and not
+     updated. If NO-PARSE is non-nil, auto-overlays in the region
+     covered by OVERLAY are not updated, even if the `exclusive' or
+     `priority' properties of OVERLAY have changed. If PROTECT-MATCH is
+     non-nil, the `parent' properties of the START and END match
+     overlays are left alone.
+
+`(auto-o-delete-overlay OVERLAY @optional NO-PARSE PROTECT-MATCH)'
+     Delete auto-overlay OVERLAY from the buffer, and update overlays
+     and overlay properties as necessary. The optional arguments disable
+     parts of the updating process, as for `auto-o-match-overlay',
+     above.
+
+
+File: auto-overlay-manual.info,  Node: Functions for Querying Overlays,  Prev: 
Functions for Modifying Overlays,  Up: Functions for Writing New Overlay Classes
+
+4.3.3 Functions for Querying Overlays
+-------------------------------------
+
+These functions query certain things about auto-overlays or match
+overlays, or retrieve certain values associated with them. A few are
+merely convenience functions, but most depend on the internal
+implementation details of the auto-overlays package, and provide the
+only reliable interface for whatever they return.
+
+`(auto-o-class O-MATCH)'
+     Return the class of match overlay O-MATCH.
+
+`(auto-o-regexp O-MATCH)'
+     Return the regular expression matched by the text covered by match
+     overlay O-MATCH.
+
+`(auto-o-regexp-group O-MATCH)'
+     Return the regexp group defined in the regexp definition
+     corresponding to match overlay O-MATCH (*note Defining Regexps::).
+
+`(auto-o-props O-MATCH)'
+     Return the list of overlay properties defined in the regexp
+     definition corresponding to match overlay O-MATCH (*note Defining
+     Regexps::).
+
+`(auto-o-edge O-MATCH)'
+     Return edge (the symbol `start' or `end') of match overlay O-MATCH.
+
+`(auto-o-parse-function O-MATCH)'
+     Return appropriate parse function for match overlay O-MATCH.
+
+`(auto-o-suicide-function O-MATCH)'
+     Return appropriate suicide function for match overlay O-MATCH.
+
+`(auto-o-match-function O-MATCH)'
+     Return match function for match overlay O-MATCH, if any.
+
+`(auto-o-edge-matched-p OVERLAY EDGE)'
+     Return non-nil if EDGE (the symbol `start' or `end') of
+     auto-overlay `overlay' is matched.
+
+`(auto-o-start-matched-p OVERLAY)'
+     Return non-nil if auto-overlay OVERLAY is start-matched.
+
+`(auto-o-end-matched-p OVERLAY)'
+     Return non-nil if auto-overlay OVERLAY is end-matched.
+
+
+File: auto-overlay-manual.info,  Node: Auto-Overlay Hooks,  Next: Auto-Overlay 
Modification Pseudo-Hooks,  Prev: Functions for Writing New Overlay Classes,  
Up: Extending the Auto-Overlays Package
+
+4.4 Auto-Overlay Hooks
+======================
+
+The auto-overlays package defines two hooks, that are called when
+auto-overlays are enabled and disabled in a buffer. These are intended
+to be used by overlay classes to set up any extra buffer-local variables
+and settings they require, and clean them up afterwards. (There is no
+point leaving auto-overlay variables and settings hanging around in a
+buffer when auto-overlays are not in use.)
+
+`auto-overlay-load-hook'
+     This hook is run when the first auto-overlay regexp set in a
+     buffer is started, using the `auto-overlay-start' function. *Note
+     Starting and Stopping Auto-Overlays::.
+
+`auto-overlay-unload-hook'
+     This hook is run when the last auto-overlay regexp set in a buffer
+     is stopped, using the `auto-overlay-stop' function. *Note Starting
+     and Stopping Auto-Overlays::.
+
+
+File: auto-overlay-manual.info,  Node: Auto-Overlay Modification Pseudo-Hooks, 
 Prev: Auto-Overlay Hooks,  Up: Extending the Auto-Overlays Package
+
+4.5 Auto-Overlay Modification Pseudo-Hooks
+==========================================
+
+The auto-overlays package adds functions to buffer and overlay
+modification hooks in order to update the overlays as the buffer text is
+modified (*note Modification Hooks: (elisp)Modification Hooks.). The
+order in which all these modification hooks are called is undefined in
+Emacs(1). Therefore, the auto-overlays package provides a mechanism to
+schedule functions to run at particular points during the overlay
+update process.
+
+   There are two stages to the overlay update process: first, any match
+overlay suicide functions are called, then modified buffer lines are
+scanned for new regexp matches. Three pseudo-hooks are defined that are
+called before, after and in between these stages. Their values are lists
+containing elements of the form:
+     (FUNCTION ARG1 ARG2 ...)
+   where FUNCTION is the function to be called by the hook, and the
+ARG's are the arguments to be passed to that function. The list
+elements are evaluated in order. The pseudo-hooks are cleared each time
+after they have been called.
+
+`auto-o-pending-pre-suicide'
+     Pseudo-hook called before any suicide functions.
+
+`auto-o-pending-post-suicide'
+     Pseudo-hook called after any suicide functions but before scanning
+     for regexp matches.
+
+`auto-o-pending-post-update'
+     Pseudo-hook called after scanning for regexp matches.
+
+   These pseudo-hooks can be used to ensure that a function that would
+normally be added to a modification hook will be called at a particular
+point in the auto-overlay update process. To achieve this, a helper
+function must be added to the modification hook instead. The helper
+function should add the function itself to the appropriate pseudo-hook
+by adding a list element with the form described above. The `push' and
+`add-to-list' Elisp functions are the most useful ways to add elements
+to the list.
+
+   ---------- Footnotes ----------
+
+   (1) Or at least undocumented, and therefore unreliable.
+
+
+File: auto-overlay-manual.info,  Node: To-Do,  Next: Function Index,  Prev: 
Extending the Auto-Overlays Package,  Up: Top
+
+5 To-Do
+*******
+
+Things that still need to be implemented (in no particular order):
+
+  1. There needs to be an `eager-self' overlay class, similar to the
+     existing `self' class but updated immediately, rather than waiting
+     for buffer modifications. This will be significantly less
+     efficient, but is necessary for applications that require overlays
+     to be up to date all the time, not just when the buffer is being
+     modified.
+
+  2. Currently, it's difficult to deal with `nested' class regexps for
+     which the `end' regexps match some `start' regexps of interest but
+     also others that are irrelevant. E.g. `{' and `}' in LaTeX when
+     you're only interested in `\somecommand{' `start' regexps. Or
+     matching parens in LISP, when you're only interested in function
+     bodies, say. The only solution is to include all `start' regexps,
+     but not set any of their properties. This can end up creating a
+     lot of overlays! A variant of the `nested' class that avoids this
+     problem is needed.
+
+
+File: auto-overlay-manual.info,  Node: Function Index,  Next: Variable Index,  
Prev: To-Do,  Up: Top
+
+Appendix A Function Index
+*************************
+
+[index]
+* Menu:
+
+* auto-o-class:                          Functions for Querying Overlays.
+                                                               (line 13)
+* auto-o-delete-overlay:                 Functions for Modifying Overlays.
+                                                               (line 61)
+* auto-o-edge:                           Functions for Querying Overlays.
+                                                               (line 29)
+* auto-o-edge-matched-p:                 Functions for Querying Overlays.
+                                                               (line 41)
+* auto-o-end-matched-p:                  Functions for Querying Overlays.
+                                                               (line 48)
+* auto-o-match-function:                 Functions for Querying Overlays.
+                                                               (line 38)
+* auto-o-match-overlays:                 Functions for Modifying Overlays.
+                                                               (line 21)
+* auto-o-match-{class}:                  Integrating New Overlay Classes.
+                                                               (line 36)
+* auto-o-parse-function:                 Functions for Querying Overlays.
+                                                               (line 32)
+* auto-o-parse-{class}-match <1>:        Standard Parse and Suicide Functions.
+                                                               (line 23)
+* auto-o-parse-{class}-match:            Integrating New Overlay Classes.
+                                                               (line 17)
+* auto-o-props:                          Functions for Querying Overlays.
+                                                               (line 24)
+* auto-o-regexp:                         Functions for Querying Overlays.
+                                                               (line 16)
+* auto-o-regexp-group:                   Functions for Querying Overlays.
+                                                               (line 20)
+* auto-o-start-matched-p:                Functions for Querying Overlays.
+                                                               (line 45)
+* auto-o-suicide-function:               Functions for Querying Overlays.
+                                                               (line 35)
+* auto-o-update-exclusive:               Functions for Modifying Overlays.
+                                                               (line 12)
+* auto-o-{class}-suicide <1>:            Standard Parse and Suicide Functions.
+                                                               (line 27)
+* auto-o-{class}-suicide:                Integrating New Overlay Classes.
+                                                               (line 26)
+* auto-overlay-highest-priority-at-point: Searching for Overlays.
+                                                               (line 52)
+* auto-overlay-load-definition:          Defining Regexps.     (line 46)
+* auto-overlay-load-overlays:            Starting and Stopping Auto-Overlays.
+                                                               (line 84)
+* auto-overlay-load-regexp:              Defining Regexps.     (line 57)
+* auto-overlay-local-binding:            Searching for Overlays.
+                                                               (line 64)
+* auto-overlay-save-overlays:            Starting and Stopping Auto-Overlays.
+                                                               (line 73)
+* auto-overlay-share-regexp-set:         Defining Regexps.     (line 79)
+* auto-overlay-start:                    Starting and Stopping Auto-Overlays.
+                                                               (line 30)
+* auto-overlay-stop:                     Starting and Stopping Auto-Overlays.
+                                                               (line 54)
+* auto-overlay-unload-definition:        Defining Regexps.     (line 70)
+* auto-overlay-unload-regexp:            Defining Regexps.     (line 74)
+* auto-overlay-unload-set:               Defining Regexps.     (line 67)
+* auto-overlays-at-point:                Searching for Overlays.
+                                                               (line 12)
+* auto-overlays-in:                      Searching for Overlays.
+                                                               (line 45)
+
+
+File: auto-overlay-manual.info,  Node: Variable Index,  Next: Concept Index,  
Prev: Function Index,  Up: Top
+
+Appendix B Variable Index
+*************************
+
+[index]
+* Menu:
+
+* auto-o-pending-post-suicide:           Auto-Overlay Modification 
Pseudo-Hooks.
+                                                               (line 28)
+* auto-o-pending-post-update:            Auto-Overlay Modification 
Pseudo-Hooks.
+                                                               (line 32)
+* auto-o-pending-pre-suicide:            Auto-Overlay Modification 
Pseudo-Hooks.
+                                                               (line 25)
+* auto-overlay-load-hook:                Auto-Overlay Hooks.   (line 13)
+* auto-overlay-unload-hook:              Auto-Overlay Hooks.   (line 18)
+
+
+File: auto-overlay-manual.info,  Node: Concept Index,  Next: Copying this 
Manual,  Prev: Variable Index,  Up: Top
+
+Appendix C Concept Index
+************************
+
+[index]
+* Menu:
+
+* adding new overlay classes:            Extending the Auto-Overlays Package.
+                                                              (line   6)
+* auto-overlay definitions:              Defining Regexps.    (line  46)
+* auto-overlay definitions, unloading:   Defining Regexps.    (line  67)
+* auto-overlays in depth:                Auto-Overlays in Depth.
+                                                              (line   6)
+* auto-overlays, defining:               Defining Regexps.    (line  46)
+* auto-overlays, loading:                Defining Regexps.    (line  46)
+* buffers, sharing regexp sets between:  Defining Regexps.    (line  79)
+* class, flat:                           Overview.            (line  63)
+* class, line:                           Overview.            (line  35)
+* class, line example:                   Worked Example.      (line 137)
+* class, nested:                         Overview.            (line  57)
+* class, nested example:                 Worked Example.      (line 106)
+* class, self:                           Overview.            (line  47)
+* class, self example:                   Worked Example.      (line  72)
+* class, standard parse functions:       Standard Parse and Suicide Functions.
+                                                              (line   6)
+* class, standard suicide functions:     Standard Parse and Suicide Functions.
+                                                              (line   6)
+* class, word:                           Overview.            (line  30)
+* class, word example:                   Worked Example.      (line  33)
+* classes of overlay:                    Overview.            (line  19)
+* classes, adding new:                   Extending the Auto-Overlays Package.
+                                                              (line   6)
+* classes, integrating new:              Integrating New Overlay Classes.
+                                                              (line   6)
+* defining auto-overlays:                Defining Regexps.    (line  46)
+* defining regexps:                      Defining Regexps.    (line   6)
+* deleting overlays:                     Functions for Modifying Overlays.
+                                                              (line  61)
+* delimeter:                             Overview.            (line  70)
+* example:                               Worked Example.      (line   6)
+* example, line class:                   Worked Example.      (line 137)
+* example, nested class:                 Worked Example.      (line 106)
+* example, self class:                   Worked Example.      (line  72)
+* example, word class:                   Worked Example.      (line  33)
+* exclusive property <1>:                Functions for Modifying Overlays.
+                                                              (line  12)
+* exclusive property:                    Overview.            (line  95)
+* extending the auto-overlays package:   Extending the Auto-Overlays Package.
+                                                              (line   6)
+* extending, deleting overlays:          Functions for Modifying Overlays.
+                                                              (line  61)
+* extending, functions:                  Functions for Writing New Overlay 
Classes.
+                                                              (line   6)
+* extending, functions for modifying overlays: Functions for Modifying 
Overlays.
+                                                              (line   6)
+* extending, functions for querying overlays: Functions for Querying Overlays.
+                                                              (line   6)
+* extending, integrating new overlay classes: Integrating New Overlay Classes.
+                                                              (line   6)
+* extending, matching overlays:          Functions for Modifying Overlays.
+                                                              (line  21)
+* extending, standard parse functions:   Standard Parse and Suicide Functions.
+                                                              (line   6)
+* extending, standard suicide functions: Standard Parse and Suicide Functions.
+                                                              (line   6)
+* extending, updating exclusive:         Functions for Modifying Overlays.
+                                                              (line  12)
+* FDL, GNU Free Documentation License:   GNU Free Documentation License.
+                                                              (line   6)
+* finding overlays:                      Searching for Overlays.
+                                                              (line   6)
+* flat overlay class:                    Overview.            (line  63)
+* functions:                             Auto-Overlay Functions.
+                                                              (line   6)
+* functions, defining regexps:           Defining Regexps.    (line   6)
+* functions, loading and saving overlays: Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* functions, loading and unloading regexps: Defining Regexps. (line   6)
+* functions, match function:             Integrating New Overlay Classes.
+                                                              (line  36)
+* functions, modifying overlays:         Functions for Modifying Overlays.
+                                                              (line   6)
+* functions, parse function:             Integrating New Overlay Classes.
+                                                              (line  17)
+* functions, querying overlays:          Functions for Querying Overlays.
+                                                              (line   6)
+* functions, scheduling:                 Auto-Overlay Modification 
Pseudo-Hooks.
+                                                              (line   6)
+* functions, searching for overlays:     Searching for Overlays.
+                                                              (line   6)
+* functions, starting and stopping overlays: Starting and Stopping 
Auto-Overlays.
+                                                              (line   6)
+* functions, suicide function:           Integrating New Overlay Classes.
+                                                              (line  26)
+* functions, writing new overlay classes: Functions for Writing New Overlay 
Classes.
+                                                              (line   6)
+* grouping in regexps:                   Overview.            (line  70)
+* highest priority overlay:              Searching for Overlays.
+                                                              (line  52)
+* hooks:                                 Auto-Overlay Hooks.  (line   6)
+* hooks, loading and unloading:          Auto-Overlay Hooks.  (line   6)
+* hooks, modification:                   Auto-Overlay Modification 
Pseudo-Hooks.
+                                                              (line   6)
+* integrating new classes, match function: Integrating New Overlay Classes.
+                                                              (line  36)
+* integrating new classes, parse function: Integrating New Overlay Classes.
+                                                              (line  17)
+* integrating new classes, suicide function: Integrating New Overlay Classes.
+                                                              (line  26)
+* integrating new overlay classes:       Integrating New Overlay Classes.
+                                                              (line   6)
+* LaTeX:                                 Worked Example.      (line   6)
+* line overlay class:                    Overview.            (line  35)
+* line overlay class example:            Worked Example.      (line 137)
+* loading auto-overlay definitions:      Defining Regexps.    (line  46)
+* loading overlays:                      Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* loading regexps:                       Defining Regexps.    (line  57)
+* loading the package:                   Auto-Overlay Functions.
+                                                              (line   6)
+* local-binding:                         Searching for Overlays.
+                                                              (line  64)
+* match function:                        Integrating New Overlay Classes.
+                                                              (line  36)
+* matching overlays:                     Functions for Modifying Overlays.
+                                                              (line  21)
+* modification pseudo-hooks:             Auto-Overlay Modification 
Pseudo-Hooks.
+                                                              (line   6)
+* nested overlay class:                  Overview.            (line  57)
+* nested overlay class example:          Worked Example.      (line 106)
+* overlay class, flat:                   Overview.            (line  63)
+* overlay class, line:                   Overview.            (line  35)
+* overlay class, line example:           Worked Example.      (line 137)
+* overlay class, nested:                 Overview.            (line  57)
+* overlay class, nested example:         Worked Example.      (line 106)
+* overlay class, self:                   Overview.            (line  47)
+* overlay class, self example:           Worked Example.      (line  72)
+* overlay class, word:                   Overview.            (line  30)
+* overlay class, word example:           Worked Example.      (line  33)
+* overlay classes:                       Overview.            (line  19)
+* overlay classes, functions for writing new: Functions for Writing New 
Overlay Classes.
+                                                              (line   6)
+* overlay classes, integrating new:      Integrating New Overlay Classes.
+                                                              (line   6)
+* overlay classes, match function:       Integrating New Overlay Classes.
+                                                              (line  36)
+* overlay classes, parse function:       Integrating New Overlay Classes.
+                                                              (line  17)
+* overlay classes, standard parse functions: Standard Parse and Suicide 
Functions.
+                                                              (line   6)
+* overlay classes, standard suicide functions: Standard Parse and Suicide 
Functions.
+                                                              (line   6)
+* overlay classes, suicide function:     Integrating New Overlay Classes.
+                                                              (line  26)
+* overlay properties <1>:                Searching for Overlays.
+                                                              (line   6)
+* overlay properties:                    Overview.            (line 101)
+* overlay property, exclusive <1>:       Functions for Modifying Overlays.
+                                                              (line  12)
+* overlay property, exclusive:           Overview.            (line  95)
+* overlay property, priority:            Overview.            (line  86)
+* overlay-local binding:                 Searching for Overlays.
+                                                              (line  64)
+* overlays, deleting:                    Functions for Modifying Overlays.
+                                                              (line  61)
+* overlays, finding:                     Searching for Overlays.
+                                                              (line   6)
+* overlays, functions for modifying:     Functions for Modifying Overlays.
+                                                              (line   6)
+* overlays, functions for querying:      Functions for Querying Overlays.
+                                                              (line   6)
+* overlays, local-binding:               Searching for Overlays.
+                                                              (line  64)
+* overlays, matching:                    Functions for Modifying Overlays.
+                                                              (line  21)
+* overlays, priority:                    Searching for Overlays.
+                                                              (line  52)
+* overlays, saving and loading:          Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* overlays, starting and stopping:       Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* Overview:                              Overview.            (line   6)
+* package, extending:                    Extending the Auto-Overlays Package.
+                                                              (line   6)
+* package, hooks:                        Auto-Overlay Hooks.  (line   6)
+* package, in depth:                     Auto-Overlays in Depth.
+                                                              (line   6)
+* package, loading:                      Auto-Overlay Functions.
+                                                              (line   6)
+* parse function:                        Integrating New Overlay Classes.
+                                                              (line  17)
+* priority property:                     Overview.            (line  86)
+* regexp definitions, unloading:         Defining Regexps.    (line  70)
+* regexp groups:                         Overview.            (line  70)
+* regexp sets:                           Overview.            (line  12)
+* regexp sets, sharing between buffers:  Defining Regexps.    (line  79)
+* regexp sets, starting and stopping:    Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* regexp sets, unloading:                Defining Regexps.    (line  67)
+* regexps, defining:                     Defining Regexps.    (line   6)
+* regexps, loading:                      Defining Regexps.    (line  57)
+* regexps, loading and unloading:        Defining Regexps.    (line   6)
+* regexps, unloading:                    Defining Regexps.    (line  74)
+* require:                               Auto-Overlay Functions.
+                                                              (line   6)
+* saving overlays:                       Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* scheduling functions after modification: Auto-Overlay Modification 
Pseudo-Hooks.
+                                                              (line   6)
+* searching for overlays:                Searching for Overlays.
+                                                              (line   6)
+* self overlay class:                    Overview.            (line  47)
+* self overlay class example:            Worked Example.      (line  72)
+* sets of regexps:                       Overview.            (line  12)
+* sharing regexp sets:                   Defining Regexps.    (line  79)
+* standard parse and suicide functions:  Standard Parse and Suicide Functions.
+                                                              (line   6)
+* starting and stopping auto-overlays:   Starting and Stopping Auto-Overlays.
+                                                              (line   6)
+* suicide function:                      Integrating New Overlay Classes.
+                                                              (line  26)
+* to-do:                                 To-Do.               (line   6)
+* unloading regexp definitions:          Defining Regexps.    (line  70)
+* unloading regexp sets:                 Defining Regexps.    (line  67)
+* unloading regexps:                     Defining Regexps.    (line  74)
+* updating exclusive regions:            Functions for Modifying Overlays.
+                                                              (line  12)
+* using auto-overlays:                   Auto-Overlay Functions.
+                                                              (line   6)
+* word overlay class:                    Overview.            (line  30)
+* word overlay class example:            Worked Example.      (line  33)
+* worked example:                        Worked Example.      (line   6)
+
+
+File: auto-overlay-manual.info,  Node: Copying this Manual,  Prev: Concept 
Index,  Up: Top
+
+Appendix D Copying this Manual
+******************************
+
+* Menu:
+
+* GNU Free Documentation License::
+
+
+File: auto-overlay-manual.info,  Node: GNU Free Documentation License,  Up: 
Copying this Manual
+
+D.1 GNU Free Documentation License
+==================================
+
+                      Version 1.2, November 2002
+
+     Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
+
+     Everyone is permitted to copy and distribute verbatim copies
+     of this license document, but changing it is not allowed.
+
+  0. PREAMBLE
+
+     The purpose of this License is to make a manual, textbook, or other
+     functional and useful document "free" in the sense of freedom: to
+     assure everyone the effective freedom to copy and redistribute it,
+     with or without modifying it, either commercially or
+     noncommercially.  Secondarily, this License preserves for the
+     author and publisher a way to get credit for their work, while not
+     being considered responsible for modifications made by others.
+
+     This License is a kind of "copyleft", which means that derivative
+     works of the document must themselves be free in the same sense.
+     It complements the GNU General Public License, which is a copyleft
+     license designed for free software.
+
+     We have designed this License in order to use it for manuals for
+     free software, because free software needs free documentation: a
+     free program should come with manuals providing the same freedoms
+     that the software does.  But this License is not limited to
+     software manuals; it can be used for any textual work, regardless
+     of subject matter or whether it is published as a printed book.
+     We recommend this License principally for works whose purpose is
+     instruction or reference.
+
+  1. APPLICABILITY AND DEFINITIONS
+
+     This License applies to any manual or other work, in any medium,
+     that contains a notice placed by the copyright holder saying it
+     can be distributed under the terms of this License.  Such a notice
+     grants a world-wide, royalty-free license, unlimited in duration,
+     to use that work under the conditions stated herein.  The
+     "Document", below, refers to any such manual or work.  Any member
+     of the public is a licensee, and is addressed as "you".  You
+     accept the license if you copy, modify or distribute the work in a
+     way requiring permission under copyright law.
+
+     A "Modified Version" of the Document means any work containing the
+     Document or a portion of it, either copied verbatim, or with
+     modifications and/or translated into another language.
+
+     A "Secondary Section" is a named appendix or a front-matter section
+     of the Document that deals exclusively with the relationship of the
+     publishers or authors of the Document to the Document's overall
+     subject (or to related matters) and contains nothing that could
+     fall directly within that overall subject.  (Thus, if the Document
+     is in part a textbook of mathematics, a Secondary Section may not
+     explain any mathematics.)  The relationship could be a matter of
+     historical connection with the subject or with related matters, or
+     of legal, commercial, philosophical, ethical or political position
+     regarding them.
+
+     The "Invariant Sections" are certain Secondary Sections whose
+     titles are designated, as being those of Invariant Sections, in
+     the notice that says that the Document is released under this
+     License.  If a section does not fit the above definition of
+     Secondary then it is not allowed to be designated as Invariant.
+     The Document may contain zero Invariant Sections.  If the Document
+     does not identify any Invariant Sections then there are none.
+
+     The "Cover Texts" are certain short passages of text that are
+     listed, as Front-Cover Texts or Back-Cover Texts, in the notice
+     that says that the Document is released under this License.  A
+     Front-Cover Text may be at most 5 words, and a Back-Cover Text may
+     be at most 25 words.
+
+     A "Transparent" copy of the Document means a machine-readable copy,
+     represented in a format whose specification is available to the
+     general public, that is suitable for revising the document
+     straightforwardly with generic text editors or (for images
+     composed of pixels) generic paint programs or (for drawings) some
+     widely available drawing editor, and that is suitable for input to
+     text formatters or for automatic translation to a variety of
+     formats suitable for input to text formatters.  A copy made in an
+     otherwise Transparent file format whose markup, or absence of
+     markup, has been arranged to thwart or discourage subsequent
+     modification by readers is not Transparent.  An image format is
+     not Transparent if used for any substantial amount of text.  A
+     copy that is not "Transparent" is called "Opaque".
+
+     Examples of suitable formats for Transparent copies include plain
+     ASCII without markup, Texinfo input format, LaTeX input format,
+     SGML or XML using a publicly available DTD, and
+     standard-conforming simple HTML, PostScript or PDF designed for
+     human modification.  Examples of transparent image formats include
+     PNG, XCF and JPG.  Opaque formats include proprietary formats that
+     can be read and edited only by proprietary word processors, SGML or
+     XML for which the DTD and/or processing tools are not generally
+     available, and the machine-generated HTML, PostScript or PDF
+     produced by some word processors for output purposes only.
+
+     The "Title Page" means, for a printed book, the title page itself,
+     plus such following pages as are needed to hold, legibly, the
+     material this License requires to appear in the title page.  For
+     works in formats which do not have any title page as such, "Title
+     Page" means the text near the most prominent appearance of the
+     work's title, preceding the beginning of the body of the text.
+
+     A section "Entitled XYZ" means a named subunit of the Document
+     whose title either is precisely XYZ or contains XYZ in parentheses
+     following text that translates XYZ in another language.  (Here XYZ
+     stands for a specific section name mentioned below, such as
+     "Acknowledgements", "Dedications", "Endorsements", or "History".)
+     To "Preserve the Title" of such a section when you modify the
+     Document means that it remains a section "Entitled XYZ" according
+     to this definition.
+
+     The Document may include Warranty Disclaimers next to the notice
+     which states that this License applies to the Document.  These
+     Warranty Disclaimers are considered to be included by reference in
+     this License, but only as regards disclaiming warranties: any other
+     implication that these Warranty Disclaimers may have is void and
+     has no effect on the meaning of this License.
+
+  2. VERBATIM COPYING
+
+     You may copy and distribute the Document in any medium, either
+     commercially or noncommercially, provided that this License, the
+     copyright notices, and the license notice saying this License
+     applies to the Document are reproduced in all copies, and that you
+     add no other conditions whatsoever to those of this License.  You
+     may not use technical measures to obstruct or control the reading
+     or further copying of the copies you make or distribute.  However,
+     you may accept compensation in exchange for copies.  If you
+     distribute a large enough number of copies you must also follow
+     the conditions in section 3.
+
+     You may also lend copies, under the same conditions stated above,
+     and you may publicly display copies.
+
+  3. COPYING IN QUANTITY
+
+     If you publish printed copies (or copies in media that commonly
+     have printed covers) of the Document, numbering more than 100, and
+     the Document's license notice requires Cover Texts, you must
+     enclose the copies in covers that carry, clearly and legibly, all
+     these Cover Texts: Front-Cover Texts on the front cover, and
+     Back-Cover Texts on the back cover.  Both covers must also clearly
+     and legibly identify you as the publisher of these copies.  The
+     front cover must present the full title with all words of the
+     title equally prominent and visible.  You may add other material
+     on the covers in addition.  Copying with changes limited to the
+     covers, as long as they preserve the title of the Document and
+     satisfy these conditions, can be treated as verbatim copying in
+     other respects.
+
+     If the required texts for either cover are too voluminous to fit
+     legibly, you should put the first ones listed (as many as fit
+     reasonably) on the actual cover, and continue the rest onto
+     adjacent pages.
+
+     If you publish or distribute Opaque copies of the Document
+     numbering more than 100, you must either include a
+     machine-readable Transparent copy along with each Opaque copy, or
+     state in or with each Opaque copy a computer-network location from
+     which the general network-using public has access to download
+     using public-standard network protocols a complete Transparent
+     copy of the Document, free of added material.  If you use the
+     latter option, you must take reasonably prudent steps, when you
+     begin distribution of Opaque copies in quantity, to ensure that
+     this Transparent copy will remain thus accessible at the stated
+     location until at least one year after the last time you
+     distribute an Opaque copy (directly or through your agents or
+     retailers) of that edition to the public.
+
+     It is requested, but not required, that you contact the authors of
+     the Document well before redistributing any large number of
+     copies, to give them a chance to provide you with an updated
+     version of the Document.
+
+  4. MODIFICATIONS
+
+     You may copy and distribute a Modified Version of the Document
+     under the conditions of sections 2 and 3 above, provided that you
+     release the Modified Version under precisely this License, with
+     the Modified Version filling the role of the Document, thus
+     licensing distribution and modification of the Modified Version to
+     whoever possesses a copy of it.  In addition, you must do these
+     things in the Modified Version:
+
+       A. Use in the Title Page (and on the covers, if any) a title
+          distinct from that of the Document, and from those of
+          previous versions (which should, if there were any, be listed
+          in the History section of the Document).  You may use the
+          same title as a previous version if the original publisher of
+          that version gives permission.
+
+       B. List on the Title Page, as authors, one or more persons or
+          entities responsible for authorship of the modifications in
+          the Modified Version, together with at least five of the
+          principal authors of the Document (all of its principal
+          authors, if it has fewer than five), unless they release you
+          from this requirement.
+
+       C. State on the Title page the name of the publisher of the
+          Modified Version, as the publisher.
+
+       D. Preserve all the copyright notices of the Document.
+
+       E. Add an appropriate copyright notice for your modifications
+          adjacent to the other copyright notices.
+
+       F. Include, immediately after the copyright notices, a license
+          notice giving the public permission to use the Modified
+          Version under the terms of this License, in the form shown in
+          the Addendum below.
+
+       G. Preserve in that license notice the full lists of Invariant
+          Sections and required Cover Texts given in the Document's
+          license notice.
+
+       H. Include an unaltered copy of this License.
+
+       I. Preserve the section Entitled "History", Preserve its Title,
+          and add to it an item stating at least the title, year, new
+          authors, and publisher of the Modified Version as given on
+          the Title Page.  If there is no section Entitled "History" in
+          the Document, create one stating the title, year, authors,
+          and publisher of the Document as given on its Title Page,
+          then add an item describing the Modified Version as stated in
+          the previous sentence.
+
+       J. Preserve the network location, if any, given in the Document
+          for public access to a Transparent copy of the Document, and
+          likewise the network locations given in the Document for
+          previous versions it was based on.  These may be placed in
+          the "History" section.  You may omit a network location for a
+          work that was published at least four years before the
+          Document itself, or if the original publisher of the version
+          it refers to gives permission.
+
+       K. For any section Entitled "Acknowledgements" or "Dedications",
+          Preserve the Title of the section, and preserve in the
+          section all the substance and tone of each of the contributor
+          acknowledgements and/or dedications given therein.
+
+       L. Preserve all the Invariant Sections of the Document,
+          unaltered in their text and in their titles.  Section numbers
+          or the equivalent are not considered part of the section
+          titles.
+
+       M. Delete any section Entitled "Endorsements".  Such a section
+          may not be included in the Modified Version.
+
+       N. Do not retitle any existing section to be Entitled
+          "Endorsements" or to conflict in title with any Invariant
+          Section.
+
+       O. Preserve any Warranty Disclaimers.
+
+     If the Modified Version includes new front-matter sections or
+     appendices that qualify as Secondary Sections and contain no
+     material copied from the Document, you may at your option
+     designate some or all of these sections as invariant.  To do this,
+     add their titles to the list of Invariant Sections in the Modified
+     Version's license notice.  These titles must be distinct from any
+     other section titles.
+
+     You may add a section Entitled "Endorsements", provided it contains
+     nothing but endorsements of your Modified Version by various
+     parties--for example, statements of peer review or that the text
+     has been approved by an organization as the authoritative
+     definition of a standard.
+
+     You may add a passage of up to five words as a Front-Cover Text,
+     and a passage of up to 25 words as a Back-Cover Text, to the end
+     of the list of Cover Texts in the Modified Version.  Only one
+     passage of Front-Cover Text and one of Back-Cover Text may be
+     added by (or through arrangements made by) any one entity.  If the
+     Document already includes a cover text for the same cover,
+     previously added by you or by arrangement made by the same entity
+     you are acting on behalf of, you may not add another; but you may
+     replace the old one, on explicit permission from the previous
+     publisher that added the old one.
+
+     The author(s) and publisher(s) of the Document do not by this
+     License give permission to use their names for publicity for or to
+     assert or imply endorsement of any Modified Version.
+
+  5. COMBINING DOCUMENTS
+
+     You may combine the Document with other documents released under
+     this License, under the terms defined in section 4 above for
+     modified versions, provided that you include in the combination
+     all of the Invariant Sections of all of the original documents,
+     unmodified, and list them all as Invariant Sections of your
+     combined work in its license notice, and that you preserve all
+     their Warranty Disclaimers.
+
+     The combined work need only contain one copy of this License, and
+     multiple identical Invariant Sections may be replaced with a single
+     copy.  If there are multiple Invariant Sections with the same name
+     but different contents, make the title of each such section unique
+     by adding at the end of it, in parentheses, the name of the
+     original author or publisher of that section if known, or else a
+     unique number.  Make the same adjustment to the section titles in
+     the list of Invariant Sections in the license notice of the
+     combined work.
+
+     In the combination, you must combine any sections Entitled
+     "History" in the various original documents, forming one section
+     Entitled "History"; likewise combine any sections Entitled
+     "Acknowledgements", and any sections Entitled "Dedications".  You
+     must delete all sections Entitled "Endorsements."
+
+  6. COLLECTIONS OF DOCUMENTS
+
+     You may make a collection consisting of the Document and other
+     documents released under this License, and replace the individual
+     copies of this License in the various documents with a single copy
+     that is included in the collection, provided that you follow the
+     rules of this License for verbatim copying of each of the
+     documents in all other respects.
+
+     You may extract a single document from such a collection, and
+     distribute it individually under this License, provided you insert
+     a copy of this License into the extracted document, and follow
+     this License in all other respects regarding verbatim copying of
+     that document.
+
+  7. AGGREGATION WITH INDEPENDENT WORKS
+
+     A compilation of the Document or its derivatives with other
+     separate and independent documents or works, in or on a volume of
+     a storage or distribution medium, is called an "aggregate" if the
+     copyright resulting from the compilation is not used to limit the
+     legal rights of the compilation's users beyond what the individual
+     works permit.  When the Document is included in an aggregate, this
+     License does not apply to the other works in the aggregate which
+     are not themselves derivative works of the Document.
+
+     If the Cover Text requirement of section 3 is applicable to these
+     copies of the Document, then if the Document is less than one half
+     of the entire aggregate, the Document's Cover Texts may be placed
+     on covers that bracket the Document within the aggregate, or the
+     electronic equivalent of covers if the Document is in electronic
+     form.  Otherwise they must appear on printed covers that bracket
+     the whole aggregate.
+
+  8. TRANSLATION
+
+     Translation is considered a kind of modification, so you may
+     distribute translations of the Document under the terms of section
+     4.  Replacing Invariant Sections with translations requires special
+     permission from their copyright holders, but you may include
+     translations of some or all Invariant Sections in addition to the
+     original versions of these Invariant Sections.  You may include a
+     translation of this License, and all the license notices in the
+     Document, and any Warranty Disclaimers, provided that you also
+     include the original English version of this License and the
+     original versions of those notices and disclaimers.  In case of a
+     disagreement between the translation and the original version of
+     this License or a notice or disclaimer, the original version will
+     prevail.
+
+     If a section in the Document is Entitled "Acknowledgements",
+     "Dedications", or "History", the requirement (section 4) to
+     Preserve its Title (section 1) will typically require changing the
+     actual title.
+
+  9. TERMINATION
+
+     You may not copy, modify, sublicense, or distribute the Document
+     except as expressly provided for under this License.  Any other
+     attempt to copy, modify, sublicense or distribute the Document is
+     void, and will automatically terminate your rights under this
+     License.  However, parties who have received copies, or rights,
+     from you under this License will not have their licenses
+     terminated so long as such parties remain in full compliance.
+
+ 10. FUTURE REVISIONS OF THIS LICENSE
+
+     The Free Software Foundation may publish new, revised versions of
+     the GNU Free Documentation License from time to time.  Such new
+     versions will be similar in spirit to the present version, but may
+     differ in detail to address new problems or concerns.  See
+     `http://www.gnu.org/copyleft/'.
+
+     Each version of the License is given a distinguishing version
+     number.  If the Document specifies that a particular numbered
+     version of this License "or any later version" applies to it, you
+     have the option of following the terms and conditions either of
+     that specified version or of any later version that has been
+     published (not as a draft) by the Free Software Foundation.  If
+     the Document does not specify a version number of this License,
+     you may choose any version ever published (not as a draft) by the
+     Free Software Foundation.
+
+D.1.1 ADDENDUM: How to use this License for your documents
+----------------------------------------------------------
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and license
+notices just after the title page:
+
+       Copyright (C)  YEAR  YOUR NAME.
+       Permission is granted to copy, distribute and/or modify this document
+       under the terms of the GNU Free Documentation License, Version 1.2
+       or any later version published by the Free Software Foundation;
+       with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+       Texts.  A copy of the license is included in the section entitled ``GNU
+       Free Documentation License''.
+
+   If you have Invariant Sections, Front-Cover Texts and Back-Cover
+Texts, replace the "with...Texts." line with this:
+
+         with the Invariant Sections being LIST THEIR TITLES, with
+         the Front-Cover Texts being LIST, and with the Back-Cover Texts
+         being LIST.
+
+   If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+   If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License, to
+permit their use in free software.
+
+
+
+Tag Table:
+Node: Top815
+Node: Overview2889
+Node: Auto-Overlay Functions7881
+Node: Defining Regexps9335
+Node: Starting and Stopping Auto-Overlays14194
+Node: Searching for Overlays19857
+Node: Worked Example23855
+Node: Extending the Auto-Overlays Package44688
+Ref: Extending the Auto-Overlays Package-Footnote-145751
+Node: Auto-Overlays in Depth45960
+Ref: Auto-Overlays in Depth-Footnote-148755
+Ref: Auto-Overlays in Depth-Footnote-248936
+Ref: Auto-Overlays in Depth-Footnote-349090
+Node: Integrating New Overlay Classes49120
+Node: Functions for Writing New Overlay Classes51839
+Node: Standard Parse and Suicide Functions52773
+Node: Functions for Modifying Overlays54246
+Node: Functions for Querying Overlays57988
+Node: Auto-Overlay Hooks59820
+Node: Auto-Overlay Modification Pseudo-Hooks60875
+Ref: Auto-Overlay Modification Pseudo-Hooks-Footnote-162968
+Node: To-Do63028
+Node: Function Index64185
+Node: Variable Index68765
+Node: Concept Index69560
+Node: Copying this Manual86298
+Node: GNU Free Documentation License86500
+
+End Tag Table
diff --git a/packages/auto-overlays/auto-overlay-nested.el 
b/packages/auto-overlays/auto-overlay-nested.el
new file mode 100644
index 0000000..c9a72f1
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-nested.el
@@ -0,0 +1,219 @@
+;;; auto-overlay-nested.el --- nested start/end-delimited automatic overlays
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(require 'auto-overlays)
+(provide 'auto-overlay-nested)
+
+
+;; set nested overlay parsing and suicide functions, and indicate class
+;; requires separate start and end regexps
+(put 'nested 'auto-overlay-parse-function 'auto-o-parse-nested-match)
+(put 'nested 'auto-overlay-suicide-function 'auto-o-nested-suicide)
+(put 'nested 'auto-overlay-complex-class t)
+
+
+
+(defun auto-o-parse-nested-match (o-match)
+  ;; Perform any necessary updates of auto overlays due to a match for a
+  ;; nested regexp.
+
+  (let* ((overlay-stack (auto-o-nested-stack o-match))
+        (o (car overlay-stack)))
+    (cond
+     ;; if the stack is empty, just create and return a new unmatched overlay
+     ((null overlay-stack)
+      (auto-o-make-nested o-match 'unmatched))
+
+     ;; if appropriate edge of innermost overlay is unmatched, just match it
+     ((or (and (eq (auto-o-edge o-match) 'start)
+              (not (auto-o-start-matched-p o)))
+         (and (eq (auto-o-edge o-match) 'end)
+              (not (auto-o-end-matched-p o))))
+      (auto-o-match-overlay o o-match)
+      ;; return nil since haven't created any new overlays
+      nil)
+
+     ;; otherwise...
+     (t
+      ;; create new innermost overlay and add it to the overlay stack
+      (push (auto-o-make-nested o-match) overlay-stack)
+      ;; sort out the overlay stack
+      (auto-o-nested-stack-cascade overlay-stack)
+      ;; return newly created overlay
+      (car overlay-stack)))
+    ))
+
+
+
+
+(defun auto-o-nested-suicide (o-self)
+  ;; Called when match no longer matches. Unmatch the match overlay O-SELF, if
+  ;; necessary deleting its parent overlay or cascading the stack.
+
+  (let* ((overlay-stack (auto-o-nested-stack o-self))
+       (o-parent (car overlay-stack)))
+
+    (cond
+     ;; if other end of parent is unmatched, just delete parent
+     ((not (auto-o-edge-matched-p
+           o-parent
+           (if (eq (auto-o-edge o-self) 'start) 'end 'start)))
+      (auto-o-delete-overlay o-parent))
+
+     ;; if parent is the only overlay in the stack...
+     ((= (length overlay-stack) 1)
+      ;; if we're a start match, make parent start-unmatched
+      (if (eq (auto-o-edge o-self) 'start)
+         (auto-o-match-overlay o-parent 'unmatched nil)
+           ;; if we're an end match, make parent end-unmatched
+       (auto-o-match-overlay o-parent nil 'unmatched)))
+
+      ;; otherwise, unmatch ourselves from parent and cascade the stack
+     (t
+      (overlay-put o-parent (auto-o-edge o-self) nil)
+      (overlay-put o-self 'parent nil)
+      (auto-o-nested-stack-cascade overlay-stack))
+     )))
+
+
+
+
+(defun auto-o-make-nested (o-match &optional unmatched)
+  ;; Create a nested overlay for match overlay O-MATCH.
+  ;; If UNMATCHED is nil, overlay will start and end at O-MATCH.
+  ;; If non-nil, overlay will start or end from O-MATCH (depending on whether
+  ;; O-MATCH is a 'start or 'end match) and stretch till end or beginning of
+  ;; buffer.
+
+  (let (o-new pos)
+    ;; create new nested overlay and match it with O-MATCH
+    (cond
+     ((eq (auto-o-edge o-match) 'start)
+      (setq pos (overlay-get o-match 'delim-end))
+      (setq o-new (make-overlay pos pos nil nil 'rear-advance))
+      (overlay-put o-new 'auto-overlay t)
+      (overlay-put o-new 'set-id (overlay-get o-match 'set-id))
+      (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id))
+      (auto-o-match-overlay o-new o-match 'unmatched))
+
+     ((eq (auto-o-edge o-match) 'end)
+      (setq pos (overlay-get o-match 'delim-start))
+      (setq o-new (make-overlay pos pos nil nil 'rear-advance))
+      (overlay-put o-new 'auto-overlay t)
+      (overlay-put o-new 'set-id (overlay-get o-match 'set-id))
+      (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id))
+      (auto-o-match-overlay o-new 'unmatched o-match)))
+
+    ;; return the new overlay
+    o-new))
+
+
+
+(defun auto-o-nested-stack-cascade (overlay-stack)
+  ;; Cascade the ends of the overlays in OVERLAY-STACK up or down the stack,
+  ;; so as to re-establish a valid stack. It assumes that only the innermost
+  ;; is incorrect.
+
+  (let ((o (car overlay-stack)) o1)
+    (cond
+
+     ;; if innermost overlay is start-matched (and presumably
+     ;; end-unmatched)...
+     ((auto-o-start-matched-p o)
+      ;; cascade overlay end matches up through stack until one is left
+      (dotimes (i (- (length overlay-stack) 1))
+       (setq o (nth i overlay-stack))
+       (setq o1 (nth (+ i 1) overlay-stack))
+       (auto-o-match-overlay o nil
+                             (if (overlay-get o1 'end)
+                                   (overlay-get o1 'end)
+                               'unmatched)
+                             nil nil 'protect-match))
+      ;; if final overlay is start-matched, make it end-unmatched, otherwise
+      ;; delete it
+      (if (auto-o-start-matched-p o1)
+         ;; FIXME: could postpone re-parsing here in case it can be avoided
+         (auto-o-match-overlay o1 nil 'unmatch nil nil 'protect-match)
+       (auto-o-delete-overlay o1 nil 'protect-match)))
+
+
+     ;; if innermost overlay is end-matched (and presumably
+     ;; start-unmatched)...
+     ((auto-o-end-matched-p o)
+      ;; cascade overlay start matches up through stack until one is left
+      (dotimes (i (- (length overlay-stack) 1))
+       (setq o (nth i overlay-stack))
+       (setq o1 (nth (+ i 1) overlay-stack))
+       (auto-o-match-overlay o (if (overlay-get o1 'start)
+                                   (overlay-get o1 'start)
+                                 'unmatched)
+                             nil nil nil 'protect-match))
+      ;; if final overlay is end-matched, make it start-unmatched, otherwise
+      ;; delete it
+      (if (auto-o-end-matched-p o1)
+         ;; FIXME: could postpone re-parsing here in case it can be avoided
+         (auto-o-match-overlay o1 'unmatch nil nil nil 'protect-match)
+       (auto-o-delete-overlay o1 nil 'protect-match))))
+    )
+)
+
+
+
+
+(defun auto-o-nested-stack (o-match)
+  ;; Return a list of the overlays that overlap and correspond to same entry
+  ;; as match overlay O-MATCH, ordered from innermost to outermost. (Assumes
+  ;; overlays are correctly stacked.) The parent of O-MATCH is guaranteed to
+  ;; come before any other overlay that has exactly the same length (which
+  ;; implies they cover identical regions if overlays are correctly
+  ;; stacked). For other overlays with identical lengths, the order is
+  ;; undefined.
+
+  ;; find overlays corresponding to same entry overlapping O-MATCH
+  (let ((overlay-stack (auto-overlays-at-point
+                       (if (eq (auto-o-edge o-match) 'start)
+                           (overlay-get o-match 'delim-end)
+                         (overlay-get o-match 'delim-start))
+                       (list '(eq auto-overlay t)
+                             (list 'eq 'set-id (overlay-get o-match 'set-id))
+                             (list 'eq 'definition-id
+                                   (overlay-get o-match 'definition-id)))))
+       (o-parent (overlay-get o-match 'parent)))
+    ;; sort the list by overlay length, i.e. from innermost to outermose
+    (sort overlay-stack
+         (lambda (a b)
+           (let ((len-a (- (overlay-end a) (overlay-start a)))
+                 (len-b (- (overlay-end b) (overlay-start b))))
+             ;; parent of O-MATCH comes before any other overlay with
+             ;; identical length, otherwise sort by length
+             (if (= len-a len-b) (eq o-parent a) (< len-a len-b)))))
+    )
+)
+
+
+;; auto-overlay-nested.el ends here
diff --git a/packages/auto-overlays/auto-overlay-self.el 
b/packages/auto-overlays/auto-overlay-self.el
new file mode 100644
index 0000000..b5c61cd
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-self.el
@@ -0,0 +1,321 @@
+;;; auto-overlay-self.el --- self-delimited automatic overlays
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(require 'auto-overlays)
+(provide 'auto-overlay-self)
+
+(defvar auto-o-pending-self-cascade nil)
+
+;; set self overlay parsing and suicide functions
+(put 'self 'auto-overlay-parse-function 'auto-o-parse-self-match)
+(put 'self 'auto-overlay-suicide-function 'auto-o-self-suicide)
+
+;; add initialisation and clear functions to hooks
+(add-hook 'auto-overlay-load-hook 'auto-o-self-load)
+(add-hook 'auto-overlay-unload-hook 'auto-o-self-unload)
+
+
+
+(defun auto-o-self-load ()
+  ;; Make sure `auto-o-perform-self-cascades' is in `before-change-functions',
+  ;; so that any cascading that is required is performed before anything else
+  ;; happens.
+  (add-hook 'before-change-functions 'auto-o-perform-self-cascades
+           nil t)
+  ;; initialise variables
+  (setq auto-o-pending-self-cascade nil)
+)
+
+
+(defun auto-o-self-unload ()
+  ;; Remove `auto-o-perform-self-cascades' from `before-change-functions'.
+  (remove-hook 'before-change-functions 'auto-o-perform-self-cascades t)
+)
+
+
+
+
+(defun auto-o-parse-self-match (o-match)
+  ;; perform any necessary updates of auto overlays due to a match for a self
+  ;; regexp
+
+  (let* ((overlay-list (auto-o-self-list o-match))
+        (o (car overlay-list)))
+
+    (cond
+     ;; if stack is empty, create a new end-unmatched overlay, adding it to
+     ;; the list of unascaded overlays (avoids treating it as a special
+     ;; case), and return it
+     ((null overlay-list)
+      (auto-o-make-self o-match nil))
+
+     ;; if new delimiter is inside the first existing overlay and existing one
+     ;; is end-unmatched, just match it
+     ((and (not (overlay-get o 'end))
+          (>= (overlay-get o-match 'delim-start) (overlay-start o)))
+      (auto-o-match-overlay o nil o-match 'no-props)
+      ;; remove it from the list of uncascaded overlays
+      (setq auto-o-pending-self-cascade (delq o auto-o-pending-self-cascade))
+      ;; return nil since haven't created any new overlays
+      nil)
+
+
+     ;; otherwise...
+     (t
+      (let (o-new)
+       ;; if the new match is outside existing overlays...
+       (if (< (overlay-get o-match 'delim-end) (overlay-start o))
+           ;; create overlay from new match till start of next match, and add
+           ;; it to the list of uncascaded overlays
+           (setq o-new (auto-o-make-self
+                        o-match
+                        (overlay-get (overlay-get o 'start) 'delim-start)))
+
+         ;; if the new match is inside an existing overlay...
+         (setq o (pop overlay-list))
+         ;; create overlay from end of existing one till start of the one
+         ;; after (or end of buffer if there isn't one), and add it to the
+         ;; list of uncascaded overlays
+         (setq o-new (auto-o-make-self
+                      (overlay-get o 'end)
+                      (when overlay-list
+                        (overlay-get (overlay-get (car overlay-list) 'start)
+                                     'delim-start))))
+         ;; match end of existing one with the new match, protecting its old
+         ;; end match which is now matched with start of new one
+         (auto-o-match-overlay o nil o-match 'no-props nil 'protect-match))
+
+      ;; return newly created overlay
+      o-new))
+     ))
+)
+
+
+
+
+(defun auto-o-self-suicide (o-self)
+  ;; Called when match no longer matches. Unmatch the match overlay O-SELF, if
+  ;; necessary deleting its parent overlay or cascading.
+
+  (let ((o-parent (overlay-get o-self 'parent)))
+    (cond
+     ;; if parent is end-unmatched, delete it from buffer and from list of
+     ;; uncascaded overlays
+     ((not (auto-o-end-matched-p o-parent))
+      (auto-o-delete-overlay o-parent)
+      (setq auto-o-pending-self-cascade
+           (delq o-parent auto-o-pending-self-cascade)))
+
+     ;; if we match the end of parent...
+     ((eq (overlay-get o-parent 'end) o-self)
+      ;; unmatch ourselves from parent and extend parent till next overlay, or
+      ;; end of buffer if there is none
+      (let ((o (nth 1 (auto-o-self-list o-self))))
+       (auto-o-match-overlay
+        o-parent nil (if o (overlay-get (overlay-get o 'start) 'delim-start)
+                       'unmatched)))
+      ;; add parent to uncascaded overlay list
+      (push o-parent auto-o-pending-self-cascade))
+
+     ;; if we match the start of parent...
+     (t
+      (let* ((o-end (overlay-get o-parent 'end))
+            (o (nth 1 (auto-o-self-list o-end))))
+       ;; unmatch ourselves from parent and "flip"
+       (auto-o-match-overlay
+        o-parent o-end
+        (if o (overlay-get (overlay-get o 'start) 'delim-start)
+          'unmatched)))
+      ;; add parent to uncascaded overlay list
+      (push o-parent auto-o-pending-self-cascade))
+     ))
+)
+
+
+
+
+(defun auto-o-make-self (o-start &optional end)
+  ;; Create a self overlay starting at match overlay O-START.
+  ;; If END is a number or marker, the new overlay is end-unmatched and ends
+  ;; at the buffer location specified by the number or marker.
+  ;; If END is nil, the new overlay is end-unmatched and ends at the end of
+  ;; the buffer.
+  (let (o-new)
+
+    ;; create new overlay (location ensures right things happen when matched)
+    (let (pos)
+      (cond
+       ((overlayp end) (setq pos (overlay-get end 'delim-start)))
+       ((number-or-marker-p end) (setq pos end))
+       (t (setq pos (point-max))))
+      (setq o-new (make-overlay pos pos nil nil 'rear-advance)))
+
+    ;; give overlay some basic properties
+    (overlay-put o-new 'auto-overlay t)
+    (overlay-put o-new 'set-id (overlay-get o-start 'set-id))
+    (overlay-put o-new 'definition-id (overlay-get o-start 'definition-id))
+
+    ;; if overlay is end-unmatched, add it to the list of uncascaded overlays
+    (unless (overlayp end) (push o-new auto-o-pending-self-cascade))
+
+    ;; match the new overlay and return it
+    (auto-o-match-overlay o-new o-start (if (overlayp end) end nil))
+    o-new)
+)
+
+
+
+
+(defun auto-o-perform-self-cascades (beg end)
+  ;; Perform any necessary self-overlay cascading before the text in the
+  ;; buffer is modified. Called from `before-change-functions'.
+
+  ;; check all overlays waiting to be cascaded, from first in buffer to last
+  (dolist (o (sort auto-o-pending-self-cascade
+                  (lambda (a b) (< (overlay-start a) (overlay-start b)))))
+    ;; if buffer modification occurs after the end of an overlay waiting to be
+    ;; cascaded, cascade all overlays between it and the modified text
+    (when (and (overlay-end o) (< (overlay-end o) end))
+      (auto-o-self-cascade (auto-o-self-list (overlay-get o 'start) end))))
+)
+
+
+
+
+(defun auto-o-self-cascade (overlay-list)
+  ;; "Flip" overlays down through buffer (assumes first overlay in list is
+  ;; end-unmatched).
+  (when (> (length overlay-list) 1)
+    (let ((o (car overlay-list))
+         (o1 (nth 1 overlay-list)))
+
+      ;; match first (presumably end-matched) overlay and remove it from list
+      (pop overlay-list)
+      (auto-o-match-overlay o nil (overlay-get o1 'start) 'no-props)
+      ;; remove it from list of uncascaded overlays
+      (setq auto-o-pending-self-cascade (delq o auto-o-pending-self-cascade))
+      ;; if we've hit an end-unmatched overlay, we can stop cascading
+      (if (not (auto-o-end-matched-p o1))
+         (progn
+           (auto-o-delete-overlay o1 nil 'protect-match)
+           (setq auto-o-pending-self-cascade
+                 (delq o1 auto-o-pending-self-cascade)))
+
+       ;; otherwise, cascade overlay list till one is left or we hit an
+       ;; end-unmached overlay
+       (unless
+           (catch 'stop
+             (dotimes (i (1- (length overlay-list)))
+               (setq o (nth i overlay-list))
+               (setq o1 (nth (1+ i) overlay-list))
+               (auto-o-match-overlay o (overlay-get o 'end)
+                                     (overlay-get o1 'start)
+                                     'no-props nil 'protect-match)
+               ;; if we hit an end-unmatched overlay, we can stop cascading
+               (when (not (auto-o-end-matched-p o1))
+                 (throw 'stop (progn
+                                ;; delete the end-unmatched overlay
+                                (auto-o-delete-overlay o1 nil 'protect-match)
+                                ;; remove it from uncascaded overlays list
+                                (setq auto-o-pending-self-cascade
+                                      (delq o1 auto-o-pending-self-cascade))
+                                ;; return t to indicate cascading ended early
+                                t)))))
+
+         ;; if there's an overlay left, "flip" it so it's end-unmatched and
+         ;; extends to next overlay in buffer, and add it to the list of
+         ;; unmatched overlays
+         (let (pos)
+           (setq o (car (last overlay-list)))
+           (if (setq o1 (nth 1 (auto-o-self-list (overlay-get o 'end))))
+               (setq pos (overlay-get (overlay-get o1 'start) 'delim-start))
+             (setq pos (point-max)))
+           (auto-o-match-overlay o (overlay-get o 'end) pos
+                                 'no-props nil 'protect-match))
+         (push o auto-o-pending-self-cascade)))
+      ))
+)
+
+
+
+
+;; (defun auto-o-self-list (o-start &optional end)
+;;   ;; Return list of self overlays ending at or after match overlay O-START 
and
+;;   ;; starting before or at END, corresponding to same entry as O-START. If 
END
+;;   ;; is null, all overlays after O-START are included.
+
+;;   (when (null end) (setq end (point-max)))
+
+;;   (let (overlay-list)
+;;     ;; create list of all overlays corresponding to same entry between 
O-START
+;;     ;; and END
+;;     (mapc (lambda (o) (when (and (>= (overlay-end o)
+;;                                  (overlay-get o-start 'delim-start))
+;;                              (<= (overlay-start o) end))
+;;                     (push o overlay-list)))
+;;       (auto-overlays-in
+;;        (point-min) (point-max)
+;;        (list
+;;         '(identity auto-overlay)
+;;         (list 'eq 'set-id (overlay-get o-start 'set-id))
+;;         (list 'eq 'definition-id (overlay-get o-start 'definition-id)))))
+;;     ;; sort the list by start position, from first to last
+;;     (sort overlay-list
+;;       (lambda (a b) (< (overlay-start a) (overlay-start b)))))
+;; )
+
+
+
+(defun auto-o-self-list (o-start &optional end)
+  ;; Return list of self overlays ending at or after match overlay O-START and
+  ;; starting before or at END, corresponding to same entry as O-START. If END
+  ;; is null, all overlays after O-START are included.
+
+  (when (null end) (setq end (point-max)))
+
+  (let (overlay-list)
+    ;; create list of all overlays corresponding to same entry between O-START
+    ;; and END
+    (setq overlay-list
+         ;; Note: We subtract 1 from start and add 1 to end to catch overlays
+         ;;       that end at start or start at end. This seems to give the
+         ;;       same results as the old version of `auto-o-self-list'
+         ;;       (above) in all circumstances.
+         (auto-overlays-in
+          (1- (overlay-get o-start 'delim-start)) (1+ end)
+          (list
+           '(identity auto-overlay)
+           (list 'eq 'set-id (overlay-get o-start 'set-id))
+           (list 'eq 'definition-id (overlay-get o-start 'definition-id)))))
+    ;; sort the list by start position, from first to last
+    (sort overlay-list
+         (lambda (a b) (< (overlay-start a) (overlay-start b)))))
+)
+
+
+;;; auto-overlay-self.el ends here
diff --git a/packages/auto-overlays/auto-overlay-word.el 
b/packages/auto-overlays/auto-overlay-word.el
new file mode 100644
index 0000000..59c81a0
--- /dev/null
+++ b/packages/auto-overlays/auto-overlay-word.el
@@ -0,0 +1,70 @@
+;;; auto-overlay-word.el --- automatic overlays for single "words"
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(require 'auto-overlays)
+(provide 'auto-overlay-word)
+
+
+;; set word overlay parsing and suicide functions
+(put 'word 'auto-overlay-parse-function 'auto-o-parse-word-match)
+(put 'word 'auto-overlay-suicide-function
+     (lambda (o) (auto-o-delete-overlay (overlay-get o 'parent))))
+
+
+
+(defun auto-o-parse-word-match (o-match)
+  ;; Create a new word overlay for new word match
+  (let ((o-new (make-overlay (overlay-get o-match 'delim-start)
+                            (overlay-get o-match 'delim-end)
+                            nil nil 'rear-advance)))
+    ;; give overlays appropriate properties
+    (overlay-put o-new 'auto-overlay t)
+    (overlay-put o-new 'set-id (overlay-get o-match 'set-id))
+    (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id))
+    (overlay-put o-new 'start o-match)
+    (overlay-put o-match 'parent o-new)
+    ;; bundle properties inside list if not already, then update overlay
+    ;; properties
+    (let ((props (auto-o-props o-match)))
+      (when (symbolp (car props)) (setq props (list props)))
+      (dolist (p (auto-o-props o-match))
+       (overlay-put o-new (car p) (cdr p))))
+
+    ;; if new overlay is exclusive, delete lower priority overlays within it
+    (when (and (overlay-get o-new 'exclusive)
+              (/= (overlay-start o-new) (overlay-end o-new)))
+      (auto-o-update-exclusive (overlay-get o-new 'set)
+                              (overlay-start o-new) (overlay-end o-new)
+                              nil (overlay-get o-new 'priority)))
+
+    ;; return new overlay
+    o-new)
+)
+
+
+;; auto-overlay-word.el ends here
diff --git a/packages/auto-overlays/auto-overlays-compat.el 
b/packages/auto-overlays/auto-overlays-compat.el
new file mode 100644
index 0000000..cd6fcd1
--- /dev/null
+++ b/packages/auto-overlays/auto-overlays-compat.el
@@ -0,0 +1,51 @@
+;;; auto-overlays-compat.el --- compatability functions for auto-overlays 
package
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Author: Toby Cubitt <address@hidden>
+;; Version: 0.3.2
+;; Keywords: auto-overlay, automatic, overlays, compatability
+;; URL: http://www.dr-qubit.org/emacs.php
+
+;; This file is NOT part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(provide 'auto-overlays-compat)
+
+
+(defun auto-overlays-compat-line-number-at-pos (&optional pos)
+  "Return (narrowed) buffer line number at position POS.
+\(Defaults to the point.\)"
+  (unless pos (setq pos (point)))
+  ;; note: need to add 1 if at beginning of line
+  (+ (count-lines (point-min) pos)
+     (if (save-excursion (goto-char pos) (bolp)) 1 0))
+)
+
+
+(defun auto-overlays-compat-replace-regexp-in-string (regexp rep string)
+  "Return a new string with all matches for REGEXP in STRING replaced
+with REP."
+  (let ((str string))
+    (while (string-match regexp str)
+      (setq str (replace-match rep nil nil str)))
+    str)
+)
+
+;;; auto-overlays-compat.el ends here
diff --git a/packages/auto-overlays/auto-overlays.el 
b/packages/auto-overlays/auto-overlays.el
new file mode 100644
index 0000000..cfb704d
--- /dev/null
+++ b/packages/auto-overlays/auto-overlays.el
@@ -0,0 +1,1714 @@
+;;; auto-overlays.el --- Automatic regexp-delimited overlays
+
+
+;; Copyright (C) 2005-2015  Free Software Foundation, Inc
+
+;; Version: 0.10.9
+;; Author: Toby Cubitt <address@hidden>
+;; Maintainer: Toby Cubitt <address@hidden>
+;; Keywords: extensions
+;; URL: http://www.dr-qubit.org/emacs.php
+;; Repository: http://www.dr-qubit.org/git/predictive.git
+
+;; This file is part of the Emacs.
+;;
+;; This file is free software: you can redistribute it and/or modify it under
+;; the terms of the GNU General Public License as published by the Free
+;; Software Foundation, either version 3 of the License, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+;; more details.
+;;
+;; You should have received a copy of the GNU General Public License along
+;; with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Code:
+
+(defvar auto-overlay-regexps nil)
+(make-variable-buffer-local 'auto-overlay-regexps)
+(defvar auto-overlay-load-hook nil)
+(defvar auto-overlay-unload-hook nil)
+
+
+(eval-when-compile (require 'cl))
+(require 'auto-overlay-common)
+(provide 'auto-overlays)
+
+
+;; (defvar auto-overlay-list nil)
+;; (make-variable-buffer-local 'auto-overlay-list)
+(defvar auto-o-pending-updates nil)
+(make-variable-buffer-local 'auto-o-pending-updates)
+(defvar auto-o-pending-suicides nil)
+(make-variable-buffer-local 'auto-o-pending-suicides)
+(defvar auto-o-pending-pre-suicide nil)
+(make-variable-buffer-local 'auto-o-pending-pre-suicide)
+(defvar auto-o-pending-post-suicide nil)
+(make-variable-buffer-local 'auto-o-pending-post-suicide)
+(defvar auto-o-pending-post-update nil)
+(make-variable-buffer-local 'auto-o-pending-post-update)
+
+
+
+
+;;;========================================================
+;;;                 Code-tidying macros
+
+(defmacro auto-o-create-set (set-id)
+  ;; Add blank entry for a new regexp set SET-ID to `auto-overlay-regexps'.
+  `(push (list ,set-id nil) auto-overlay-regexps))
+
+
+(defmacro auto-o-delete-set (set-id)
+  ;; Delete SET-ID entry from `auto-overlay-regexps'.
+  `(setq auto-overlay-regexps
+        (assq-delete-all ,set-id auto-overlay-regexps)))
+
+
+(defmacro auto-o-get-full-buffer-list (set-id)
+  ;; Return the list of buffers and associated properties for regexp set
+  ;; SET-ID.
+  `(nth 1 (assq ,set-id auto-overlay-regexps)))
+
+
+(defmacro auto-o-get-buffer-list (set-id)
+  ;; Return list of buffers using regexp set SET-ID.
+  `(mapcar 'car (auto-o-get-full-buffer-list ,set-id)))
+
+
+(defmacro auto-o-get-regexps (set-id)
+  ;; Return the list of regexp definitions for regexp set SET-ID.
+  `(cddr (assq ,set-id auto-overlay-regexps)))
+
+
+;; (defmacro auto-o-set-regexps (set-id regexps)
+;;   ;; Set the list of regexp definitions for regexp set SET-ID.
+;;   `(setcdr (cdr (assq ,set-id auto-overlay-regexps)) ,regexps))
+
+
+
+
+;; (defmacro auto-o-set-buffer-list (set-id list)
+;;   ;; Set the list of buffers that use the regexp set SET-ID to LIST.
+;;   `(let ((set (assq ,set-id auto-overlay-regexps)))
+;;      (and set (setcar (cddr set) ,list))))
+
+
+(defmacro auto-o-add-to-buffer-list (set-id buffer)
+  ;; Add BUFFER to the list of buffers using regexp set SET-ID.
+  `(let ((set (assq ,set-id auto-overlay-regexps)))
+     (and set
+         (null (assq ,buffer (cadr set)))
+         (setcar (cdr set) (cons (cons ,buffer nil) (cadr set))))))
+
+
+(defmacro auto-o-delete-from-buffer-list (set-id buffer)
+  ;; Remove BUFFER from the list of buffers using regexp set SET-ID.
+  `(let ((set (assq ,set-id auto-overlay-regexps)))
+     (and set
+         (setcar (cdr set) (assq-delete-all ,buffer (cadr set))))))
+
+
+
+
+(defmacro auto-o-enabled-p (set-id &optional buffer)
+  ;; Return non-nil if regexp set identified by SET-ID is enabled in BUFFER.
+  `(let ((buff (or ,buffer (current-buffer))))
+     (cdr (assq buff (auto-o-get-full-buffer-list ,set-id)))))
+
+
+(defmacro auto-o-enable-set (set-id buffer)
+  ;; Set enabled flag for BUFFER in regexp set SET-ID.
+  `(setcdr (assq ,buffer (auto-o-get-full-buffer-list ,set-id)) t))
+
+
+(defmacro auto-o-disable-set (set-id buffer)
+  ;; Unset enabled flag for BUFFER in regexp set SET-ID.
+  `(setcdr (assq ,buffer (auto-o-get-full-buffer-list ,set-id)) nil))
+
+
+
+
+(defmacro auto-o-append-regexp (set-id entry)
+  ;; Append regexp ENTRY to SET-ID's regexps.
+  `(nconc (auto-o-get-regexps ,set-id) (list ,entry)))
+
+
+(defmacro auto-o-prepend-regexp (set-id entry)
+  ;; Prepend regexp ENTRY to SET-ID's regexps.
+  `(setcdr (cdr (assq ,set-id auto-overlay-regexps))
+          (nconc (list ,entry) (auto-o-get-regexps ,set-id))))
+
+
+(defmacro auto-o-insert-regexp (set-id pos entry)
+  ;; Insert regexp ENTRY in SET-ID's regexps at POS.
+  `(setcdr (nthcdr (1- pos) (auto-o-get-regexps ,set-id))
+          (nconc (list ,entry) (nthcdr pos (auto-o-get-regexps ,set-id)))))
+
+
+
+(defmacro auto-o-entry (set-id definition-id &optional regexp-id)
+  ;; Return regexp entry identified by SET-ID, DEFINITION-ID and REGEXP-ID.
+  `(if ,regexp-id
+       (cdr (assq ,regexp-id
+                 (cdr (assq ,definition-id
+                            (auto-o-get-regexps ,set-id)))))
+     (cdr (assq ,definition-id (cddr (assq ,set-id auto-overlay-regexps))))))
+
+
+(defmacro auto-o-entry-class (set-id definition-id)
+  ;; Return class corresponding to SET-ID and DEFINITION-ID.
+  `(cadr (assq ,definition-id (auto-o-get-regexps ,set-id))))
+
+
+(defmacro auto-o-class (o-match)
+  ;; Return class of match overlay O-MATCH.
+  `(auto-o-entry-class (overlay-get ,o-match 'set-id)
+                      (overlay-get ,o-match 'definition-id)))
+
+
+(defmacro auto-o-entry-regexp (set-id definition-id &optional regexp-id)
+  ;; Return regexp corresponsing to SET-ID, DEFINITION-ID and REGEXP-ID.
+  `(let ((regexp (nth 1 (auto-o-entry ,set-id ,definition-id ,regexp-id))))
+     (if (atom regexp) regexp (car regexp))))
+
+
+(defmacro auto-o-regexp (o-match)
+  ;; Return match overlay O-MATCH's regexp.
+  `(auto-o-entry-regexp (overlay-get ,o-match 'set-id)
+                     (overlay-get ,o-match 'definition-id)
+                     (overlay-get ,o-match 'regexp-id)))
+
+
+(defmacro auto-o-entry-regexp-group (set-id definition-id &optional regexp-id)
+  ;; Return regexp group corresponsing to SET-ID, DEFINITION-ID and REGEXP-ID,
+  ;; or 0 if none is specified.
+  `(let ((regexp (nth 1 (auto-o-entry ,set-id ,definition-id ,regexp-id))))
+     (cond
+      ((atom regexp) 0)
+      ((atom (cdr regexp)) (cdr regexp))
+      (t (cadr regexp)))))
+
+
+(defmacro auto-o-regexp-group (o-match)
+  ;; Return match overlay O-MATCH's regexp group.
+  `(auto-o-entry-regexp-group (overlay-get ,o-match 'set-id)
+                           (overlay-get ,o-match 'definition-id)
+                           (overlay-get ,o-match 'regexp-id)))
+
+
+(defmacro auto-o-entry-regexp-group-nth (n set-id definition-id
+                                          &optional regexp-id)
+  ;; Return Nth regexp group entry corresponsing to SET-ID, DEFINITION-ID and
+  ;; REGEXP-ID, or 0 if there is no Nth entry.
+  `(let ((regexp (nth 1 (auto-o-entry ,set-id ,definition-id ,regexp-id))))
+     (cond
+      ((atom regexp) 0)
+      ((> (1+ ,n) (length (cdr regexp))) 0)
+      (t (nth ,n (cdr regexp))))))
+
+
+(defmacro auto-o-regexp-group-nth (n o-match)
+  ;; Return match overlay O-MATCH's Nth regexp group entry, or 0 if there is
+  ;; no Nth entry.
+  `(auto-o-entry-regexp-group-nth ,n
+                               (overlay-get ,o-match 'set-id)
+                               (overlay-get ,o-match 'definition-id)
+                               (overlay-get ,o-match 'regexp-id)))
+
+
+(defmacro auto-o-entry-props (set-id definition-id &optional regexp-id)
+  ;; Return properties of regexp corresponding to SET-ID, DEFINITION-ID and
+  ;; REGEXP-ID.
+  `(nthcdr 2 (auto-o-entry ,set-id ,definition-id ,regexp-id)))
+
+
+(defmacro auto-o-props (o-match)
+  ;; Return properties associated with match overlay O-MATCH.
+  `(auto-o-entry-props (overlay-get ,o-match 'set-id)
+                     (overlay-get ,o-match 'definition-id)
+                     (overlay-get ,o-match 'regexp-id)))
+
+
+(defmacro auto-o-entry-edge (set-id definition-id regexp-id)
+  ;; Return edge ('start or 'end) of regexp with SET-ID, DEFINITION-ID and
+  ;; REGEXP-ID
+  `(car (auto-o-entry ,set-id ,definition-id ,regexp-id)))
+
+
+(defmacro auto-o-edge (o-match)
+  ;; Return edge ('start or 'end) of match overlay O-MATCH
+  `(auto-o-entry-edge (overlay-get ,o-match 'set-id)
+                     (overlay-get ,o-match 'definition-id)
+                     (overlay-get ,o-match 'regexp-id)))
+
+
+(defmacro auto-o-parse-function (o-match)
+  ;; Return appropriate parse function for match overlay O-MATCH.
+  `(get (auto-o-class ,o-match) 'auto-overlay-parse-function))
+
+
+(defmacro auto-o-suicide-function (o-match)
+  ;; Return appropriate suicide function for match overlay O-MATCH.
+  `(get (auto-o-class ,o-match) 'auto-overlay-suicide-function))
+
+
+(defmacro auto-o-match-function (o-match)
+  ;; Return match function for match overlay O-MATCH, if any.
+  `(get (auto-o-class ,o-match) 'auto-overlay-match-function))
+
+
+(defmacro auto-o-edge-matched-p (overlay edge)
+  ;; test if EDGE of OVERLAY is matched
+  `(overlay-get ,overlay ,edge))
+
+
+(defmacro auto-o-start-matched-p (overlay)
+  ;; test if OVERLAY is start-matched
+  `(overlay-get ,overlay 'start))
+
+
+(defmacro auto-o-end-matched-p (overlay)
+  ;; test if OVERLAY is end-matched
+  `(overlay-get ,overlay 'end))
+
+
+;; (defmacro auto-o-entry-compound-class-p (set-id definition-id)
+;;   ;; Return non-nil if regexp corresponding to SET-ID and DEFINITION-ID
+;;   ;; contains a list of regexp entries rather than a single entry.
+;;   `(let ((entry (cadr (auto-o-entry ,set-id ,definition-id))))
+;;     (and (listp entry)
+;;      (or (symbolp (cdr entry))
+;;          (and (listp (cdr entry)) (symbolp (cadr entry)))))))
+
+;; (defmacro auto-o-compound-class-p (o-match)
+;;   ;; Return non-nil if O-MATCH's regexp class is a compound class
+;;   ;; (can just check for 'regexp-id property instead of checking regexp
+;;   ;; definitions, since this is always set for such match overlays)
+;;   `(overlay-get ,o-match 'regexp-id))
+
+
+(defmacro auto-o-entry-complex-class-p (set-id definition-id)
+  ;; Return non-nil if regexp corresponding to SET-ID and DEFINITION-ID
+  ;; requires separate start and end regexps
+  `(get (auto-o-entry-class ,set-id ,definition-id)
+       'auto-overlay-complex-class))
+
+
+(defmacro auto-o-complex-class-p (o-match)
+  ;; Return non-nil if O-MATCH's regexp class is a compound class
+  `(get (auto-o-class ,o-match) 'auto-overlay-complex-class))
+
+
+
+(defmacro auto-o-rank (o-match)
+  ;; Return the rank of match overlay O-MATCH
+  `(auto-o-assq-position
+    (overlay-get ,o-match 'regexp-id)
+    (cddr (assq (overlay-get ,o-match 'definition-id)
+               (auto-o-get-regexps (overlay-get ,o-match 'set-id))))))
+
+
+(defmacro auto-o-overlay-filename (set-id)
+  ;; Return the default filename to save overlays in
+  `(concat "auto-overlays-"
+          (replace-regexp-in-string
+           "\\." "-" (file-name-nondirectory (or (buffer-file-name)
+                                                 (buffer-name))))
+          "-" (symbol-name ,set-id)))
+
+
+
+
+;;;============================================================
+;;;           Replacements for CL functions
+
+(defun auto-o-assq-position (key alist)
+  "Find the first association of KEY in ALIST.
+Return the index of the matching item, or nil of not found.
+Comparison is done with 'eq."
+  (let (el (i 0))
+    (catch 'found
+      (while (setq el (nth i alist))
+       (when (eq key (car el)) (throw 'found i))
+       (setq i (1+ i))
+       nil))))
+
+
+
+(defun auto-o-position (item list)
+  "Find the first occurrence of ITEM in LIST.
+Return the index of the matching item, or nil of not found.
+Comparison is done with 'equal."
+  (let (el (i 0))
+    (catch 'found
+      (while (setq el (nth i list))
+       (when (equal item el) (throw 'found i))
+       (setq i (1+ i))
+       nil))))
+
+
+
+(defun auto-o-sublist (list start &optional end)
+  "Return the sub-list of LIST from START to END.
+If END is omitted, it defaults to the length of the list
+If START or END is negative, it counts from the end."
+  (let (len)
+    ;; sort out arguments
+    (if end
+       (when (< end 0) (setq end (+ end (setq len (length list)))))
+      (setq end (or len (setq len (length list)))))
+    (when (< start 0)
+      (setq start (+ start (or len (length list)))))
+
+    ;; construct sub-list
+    (let (res)
+      (while (< start end)
+       (push (nth start list) res)
+       (setq start (1+ start)))
+      (nreverse res))))
+
+
+(defmacro auto-o-adjoin (item list)
+  "Cons ITEM onto front of LIST if it's not already there.
+Comparison is done with `eq'."
+  `(if (memq ,item ,list) ,list (setf ,list (cons ,item ,list))))
+
+
+
+;;;=========================================================
+;;;          auto-overlay definition functions
+
+;;;###autoload
+(defun auto-overlay-load-definition (set-id definition &optional pos)
+  "Load DEFINITION into the set of auto-overlay definitions SET-ID
+in the current buffer. If SET-ID does not exist, it is created.
+
+If POS is nil, DEFINITION is added at the end of the list of
+auto-overlay definitions. If it is t, it is added at the
+beginning. If it is an integer, it is added at that position in
+the list. The position in the list makes no difference to the
+behaviour of the auto-overlays. But it can make a difference to
+the speed and efficiency. In general, higher-priority and
+exclusive DEFINITIONS should appear earlier in the list.
+
+If DEFINITION-ID is supplied, it should be a symbol that can be
+used to uniquely identify DEFINITION (see
+`auto-overlay-unload-definition').
+
+
+DEFINITION should be a list of the form:
+
+  (CLASS @optional :id DEFINITION-ID @rest REGEXP1 REGEXP2 ... )
+
+CLASS is a symbol specifying the auto-overlay class. The standard
+classes are 'word, 'line, 'self, 'flat and 'nested. The :id
+property is optional. It should be a symbol that can be used to
+uniquely identify DEFINITION (see
+`auto-overlay-unload-definition').
+
+The REGEXP's should be lists of the form:
+
+  (RGXP &optional :edge EDGE :id REGEXP-ID
+        &rest PROPERTY1 PROPERTY2 ... )
+
+RGXP is either a single regular expression (a string), or a cons
+cell of the form (RGXP . GROUP) where RGXP is a regular
+expression and GROUP is an integer specifying which group in the
+regular expression forms the delimiter for the auto-overlay. The
+rest of the PROPERTY entries should be cons cells of the
+form (NAME . VALUE) where NAME is an overlay property name (a
+symbol) and VALUE is its value.
+
+The properties :edge and :id are optional. The :edge property
+EDGE should be one of the symbols 'start or 'end. If it is not
+specified, :edge is assumed to be 'start. The :id property is a
+symbol that can be used to uniquely identify REGEXP (see
+`auto-overlay-unload-regexp')."
+
+  (let ((regexps (auto-o-get-regexps set-id))
+       (class (car definition))
+       definition-id)
+    ;; if SET-ID doesn't exist in regexp list, create empty set
+    (when (null regexps)
+      (auto-o-create-set set-id)
+      (auto-o-add-to-buffer-list set-id (current-buffer))
+      (setq regexps (auto-o-get-regexps set-id)))
+
+    (let (n)
+      (if (null (setq n (auto-o-position :id definition)))
+         ;; if DEFINITION-ID is not specified, create a unique numeric
+         ;; DEFINITION-ID
+         (setq definition-id
+               (1+ (apply 'max -1
+                          (mapcar (lambda (elt)
+                                    (if (integerp (car elt))
+                                        (car elt) -1))
+                                  regexps))))
+       ;; if DEFINITION-ID is specified, check it's unique
+       (setq definition-id (nth (1+ n) definition))
+       (setq definition (append (auto-o-sublist definition 0 n)
+                                (auto-o-sublist definition (+ n 2))))
+       (when (assq definition-id regexps)
+         (error "Definition ID \"%s\" is not unique"
+                (symbol-name definition-id)))
+       ))
+
+    (cond
+     ;; adding first entry or at start
+     ((or (eq pos t) (= (length regexps) 0)
+         (and (integerp pos) (<= pos 0)))
+      (auto-o-prepend-regexp set-id (list definition-id class)))
+     ;; adding at end
+     ((or (null pos) (and (integerp pos) (>= pos (length regexps))))
+      (auto-o-append-regexp set-id (list definition-id class)))
+     ;; adding at POS
+     ((integerp pos)
+      (auto-o-insert-regexp set-id pos (list definition-id class))))
+
+    ;; load regexp definitions
+    (dolist (regexp (cdr definition))
+      (auto-overlay-load-regexp set-id definition-id regexp))
+
+    definition-id))  ; return new entry ID
+
+
+
+;;;###autoload
+(defun auto-overlay-load-regexp (set-id definition-id regexp &optional pos)
+  "Load REGEXP into the auto-overlay definition identified by
+DEFINITION-ID in the regexp list named SET-ID in the current
+buffer.
+
+If POS is nil, REGEXP is added at the end of the definition. If
+it is t, it is added at the beginning. If it is an integer, it is
+added at that position.
+
+
+REGEXP should be a list of the form:
+
+  (RGXP &optional :edge EDGE :id REGEXP-ID
+        &rest PROPERTY1 PROPERTY2 ... )
+
+RGXP is either a single regular expression (a string), or a cons
+cell of the form (RGXP . GROUP) where RGXP is a regular
+expression and GROUP is an integer specifying which group in the
+regular expression forms the delimiter for the auto-overlay. The
+rest of the PROPERTY entries should be cons cells of the
+form (NAME . VALUE) where NAME is an overlay property name (a
+symbol) and VALUE is its value.
+
+The properties :edge and :id are optional. The :edge property
+EDGE should be one of the symbols 'start or 'end. If it is not
+specified, :edge is assumed to be 'start. The :id property is a
+symbol that can be used to uniquely identify REGEXP (see
+`auto-overlay-unload-regexp')."
+
+  (let ((defs (assq definition-id (auto-o-get-regexps set-id)))
+       regexp-id rgxp edge props)
+    (when (null defs)
+      (error "Definition \"%s\" not found in auto-overlay regexp set %s"
+            (symbol-name definition-id) (symbol-name set-id)))
+
+    ;; extract regexp
+    (setq rgxp (car regexp))
+    (setq regexp (cdr regexp))
+    (let (n)
+      ;; extract edge
+      (if (null (setq n (auto-o-position :edge regexp)))
+         (setq edge 'start)  ; assume 'start if unspecified
+       (setq edge (nth (1+ n) regexp))
+       (setq regexp (append (auto-o-sublist regexp 0 n)
+                            (auto-o-sublist regexp (+ n 2)))))
+      ;; extract regexp-id
+      (if (setq n (auto-o-position :id regexp))
+         (progn
+           (setq regexp-id (nth (1+ n) regexp))
+           (when (assq regexp-id defs)
+             (error "Regexp ID \"%s\" is not unique"
+                    (symbol-name regexp-id)))
+           (setq regexp (append (auto-o-sublist regexp 0 n)
+                                (auto-o-sublist regexp (+ n 2)))))
+       ;; if no id is specified, create a unique numeric ID
+       (setq regexp-id
+             (1+ (apply 'max -1
+                        (mapcar (lambda (elt)
+                                  (if (integerp (car elt)) (car elt) -1))
+                                (cddr defs))))))
+      ;; extract properties
+      (setq props regexp))
+
+    ;; create regexp definition
+    (setq regexp (append (list regexp-id edge rgxp) props))
+
+    (cond
+     ;; adding at end
+     ((or (null pos) (and (integerp pos) (>= pos (length (cddr defs)))))
+      (if (= (length (cddr defs)) 0)
+         (setcdr (cdr defs) (list regexp))
+       (nconc (cddr defs) (list regexp))))
+     ;; adding at start
+     ((or (eq pos t) (and (integerp pos) (<= pos 0)))
+      (setcdr (cdr defs) (nconc (list regexp) (cddr defs))))
+     ;; adding at POS
+     ((integerp pos)
+      (setcdr (nthcdr (1- pos) (cddr defs))
+             (nconc (list regexp) (nthcdr pos (cddr defs))))))
+
+    regexp-id))  ; return new subentry ID
+
+
+
+(defun auto-overlay-unload-set (set-id)
+  "Unload the entire regexp set SET-ID from the current buffer."
+
+  ;; disable regexp set to delete overlays, then delete regexp set from
+  ;; current buffer
+  (when (auto-o-enabled-p set-id)
+    (auto-overlay-stop set-id))
+  (auto-o-delete-from-buffer-list set-id (current-buffer))
+  (auto-o-delete-set set-id))
+
+
+
+(defun auto-overlay-unload-definition (set-id definition-id)
+  "Unload auto-overlay definition DEFINITION-ID in set SET-ID
+from the current buffer. Returns the deleted definition."
+
+  (save-excursion
+    ;; call suicide function for corresponding overlays in all buffers in
+    ;; which the set is enabled
+    (dolist (buff (auto-o-get-buffer-list set-id))
+      (set-buffer buff)
+      (when (auto-o-enabled-p set-id)
+       (mapc (lambda (o) (auto-o-suicide o 'force))
+             (auto-overlays-in (point-min) (point-max)
+                               `((eq set-id ,set-id)
+                                 (eq definition-id ,definition-id))))))
+    ;; delete definition
+    (let ((olddef (assq definition-id (auto-o-get-regexps set-id)))
+          def-id class regexps regexp edge regexp-id props)
+      ;; safe to delete by side effect here because definition is guaranteed
+      ;; not to be the first element of the list (the first two elements of a
+      ;; regexp set are always the set-id and the buffer list)
+      (assq-delete-all definition-id (assq set-id auto-overlay-regexps))
+
+
+      ;; massage deleted definition into form suitable for
+      ;; `auto-overlay-load-definition'
+      (setq def-id (nth 0 olddef)
+           class (nth 1 olddef)
+           regexps (nthcdr 2 olddef))
+      (setq olddef (list class :id def-id))
+      (dolist (rgxp regexps)
+       (setq regexp-id (nth 0 rgxp)
+             edge (nth 1 rgxp)
+             regexp (nth 2 rgxp)
+             props (nthcdr 3 rgxp))
+       (setq olddef
+             (append olddef
+                     (list (append (list regexp :edge edge :id regexp-id)
+                                   props)))))
+      olddef)))  ; return deleted definition
+
+
+
+(defun auto-overlay-unload-regexp (set-id definition-id regexp-id)
+  "Unload the regexp identified by REGEXP-ID from auto-overlay
+definition DEFINITION-ID in set SET-ID of the current buffer.
+Returns the deleted regexp."
+
+  (save-excursion
+    ;; call suicide function for corresponding overlays in all buffers in
+    ;; which the set is enabled
+    (dolist (buff (auto-o-get-buffer-list set-id))
+      (set-buffer buff)
+      (when (auto-o-enabled-p set-id)
+       (mapc (lambda (o) (auto-o-suicide o 'force))
+             (auto-overlays-in (point-min) (point-max)
+                               `((identity auto-overlay-match)
+                                 (eq set-id ,set-id)
+                                 (eq definition-id ,definition-id)
+                                 (eq regexp-id ,regexp-id))))))
+    ;; delete regexp entry
+    (let* ((def (cdr (assq definition-id (auto-o-get-regexps set-id))))
+          (oldregexp (assq regexp-id def))
+          id edge regexp props)
+      ;; can safely delete by side effect here because the regexp definition
+      ;; is guaranteed not to be the first element of the list (the first two
+      ;; elements of a definition are always the :id and class)
+      (assq-delete-all regexp-id def)
+
+      ;; massage deleted definition into form suitable for
+      ;; `auto-overlay-load-definition'
+      (setq id (nth 0 oldregexp)
+           edge (nth 1 oldregexp)
+           regexp (nth 2 oldregexp)
+           props (nthcdr 3 oldregexp))
+      (setq oldregexp (append (list regexp :edge edge :id id) props))
+      oldregexp))  ; return deleted regexp
+)
+
+
+
+;;;###autoload
+(defun auto-overlay-share-regexp-set (set-id from-buffer &optional to-buffer)
+  "Make TO-BUFFER share the regexp set identified by SET-ID with FROM-BUFFER.
+Any changes to that regexp set in either buffer will be reflected in the
+other. TO-BUFFER defaults to the current buffer."
+
+  (unless to-buffer (setq to-buffer (current-buffer)))
+  (let (regexps)
+    ;; get regexp set from FROM-BUFFER
+    (with-current-buffer from-buffer
+      (setq regexps (assq set-id auto-overlay-regexps))
+      ;; delete any existing set with same ID, and add regexp set to TO-BUFFER
+      (set-buffer to-buffer)
+      (setq auto-overlay-regexps
+           (assq-delete-all set-id auto-overlay-regexps))
+      (push regexps auto-overlay-regexps)
+      ;; add TO-BUFFER to list of buffers using regexp set SET-ID
+      (auto-o-add-to-buffer-list set-id to-buffer)
+      )))
+
+
+
+(defun auto-overlay-start (set-id &optional buffer save-file no-regexp-check)
+  "Activate the set of auto-overlay regexps identified by SET-ID
+in BUFFER, or the current buffer if none is specified.
+
+If optional argument SAVE-FILE is nil, it will try to load the
+overlays from the default save file if it exists. If SAVE-FILE is
+a string, it specifies the location of the file (if only a
+directory is given, it will look for the default filename in that
+directory). Anything else will cause the save file to be ignored,
+and the buffer will be reparsed from scratch, as it will be if
+the save file does not exist.
+
+If the overlays are being loaded from a save file, but optional
+argument NO-REGEXP-CHECK is non-nil, the file of saved overlays
+will be used, but no check will be made to ensure regexp
+refinitions are the same as when the overlays were saved."
+
+  (save-excursion
+    (when buffer (set-buffer buffer))
+    ;; run initialisation hooks
+    (run-hooks 'auto-overlay-load-hook)
+    ;; add hook to run all the various functions scheduled be run after a
+    ;; buffer modification
+    (add-hook 'after-change-functions 'auto-o-run-after-change-functions
+             nil t)
+    ;; add hook to schedule an update after a buffer modification
+    (add-hook 'after-change-functions 'auto-o-schedule-update nil t)
+    ;; add hook to simulate missing `delete-in-front-hooks' and
+    ;; `delete-behind-hooks' overlay properties
+    (add-hook 'after-change-functions
+             'auto-o-schedule-delete-in-front-or-behind-suicide nil t)
+
+    ;; set enabled flag for regexp set, and make sure buffer is in buffer list
+    ;; for the regexp set
+    (auto-o-enable-set set-id (current-buffer))
+
+    ;; try to load overlays from file
+    (unless (and (or (null save-file) (stringp save-file))
+                (auto-overlay-load-overlays set-id nil save-file
+                                            no-regexp-check))
+      ;; if loading was unsuccessful, search for new auto overlays
+      (let ((lines (count-lines (point-min) (point-max))))
+       (goto-char (point-min))
+       (message "Scanning for auto-overlays...(line 1 of %d)"
+                lines)
+       (dotimes (i lines)
+         (when (= 9 (mod i 10))
+           (message
+            "Scanning for auto-overlays...(line %d of %d)"
+            (+ i 1) lines))
+         (auto-overlay-update nil nil set-id)
+         (forward-line 1))
+       (message "Scanning for auto-overlays...done")))
+    ))
+
+
+
+(defun auto-overlay-stop (set-id &optional buffer save-file leave-overlays)
+  "Clear all auto-overlays in the set identified by SET-ID
+from BUFFER, or the current buffer if none is specified.
+
+If SAVE-FILE is non-nil and the buffer is associated with a file,
+save the overlays to a file to speed up loading if the same set
+of regexp definitions is enabled again. If SAVE-FILE is a string,
+it specifies the location of the file to save to (if it only
+specifies a directory, the default filename is used). Anything
+else will cause the overlays to be saved to the default file name
+in the current directory.
+
+If LEAVE-OVERLAYS is non-nil, don't bother deleting the overlays
+from the buffer \(this is generally a bad idea, unless the buffer
+is about to be killed in which case it speeds things up a bit\)."
+
+  (save-excursion
+    (when buffer (set-buffer buffer))
+    ;; disable overlay set
+    (auto-o-disable-set set-id (current-buffer))
+
+    ;; if SAVE-FILE is non-nil and buffer is associated with a file, save
+    ;; overlays to file
+    (when save-file
+      (unless (stringp save-file) (setq save-file nil))
+      (auto-overlay-save-overlays set-id nil save-file))
+
+    ;; delete overlays unless told not to bother
+    (unless leave-overlays
+      (mapc 'delete-overlay
+           (auto-overlays-in
+            (point-min) (point-max)
+            (list
+             (list (lambda (overlay match) (or overlay match))
+                   '(auto-overlay auto-overlay-match))
+             (list 'eq 'set-id set-id))
+            nil 'inactive)))
+
+    ;; if there are no more active auto-overlay definitions...
+    (unless (catch 'enabled
+             (dolist (set auto-overlay-regexps)
+               (when (auto-o-enabled-p (car set))
+                 (throw 'enabled t)))
+             nil)
+      ;; run clear hooks
+      (run-hooks 'auto-overlay-unload-hook)
+      ;; reset variables
+      (remove-hook 'after-change-functions 'auto-o-schedule-update t)
+      (remove-hook 'after-change-functions
+                  'auto-o-run-after-change-functions t)
+      (setq auto-o-pending-suicides nil
+           auto-o-pending-updates nil
+           auto-o-pending-post-suicide nil))))
+
+
+
+(defun auto-overlay-save-overlays (set-id &optional buffer file)
+  "Save overlays in set SET-ID in BUFFER to FILE.
+Defaults to the current buffer.
+
+If FILE is nil or a directory, and if the buffer is associated
+with a file, the filename is constructed from the buffer's file
+name and SET-ID. The directory is created if necessary. If the
+buffer is not associated with a file and FILE doesn't specify a
+filename, an error occurs.
+
+The overlays can be loaded again later using
+`auto-overlay-load-overlays'."
+
+  (save-excursion
+    (when buffer (set-buffer buffer))
+
+    ;; construct filename
+    (let ((path (or (and file (file-name-directory file)) ""))
+         (filename (or (and file (file-name-nondirectory file)) "")))
+      ;; use default filename if none supplied
+      (when (string= filename "")
+       (if (buffer-file-name)
+           (setq filename (auto-o-overlay-filename set-id))
+         (error "Can't save overlays to default filename when buffer isn't\
+ visiting a file")))
+      ;; create directory if it doesn't exist
+      (make-directory path t)
+      ;; construct full path to file, since that's all we need from now on
+      (setq file (concat path filename)))
+
+    ;; create temporary buffer
+    (let ((buff (generate-new-buffer " *auto-overlay-save*"))
+         overlay-list)
+      ;; write md5 digests to first two lines
+      (prin1 (md5 (current-buffer)) buff)
+      (terpri buff)
+      (prin1 (md5 (prin1-to-string (auto-o-get-regexps set-id))) buff)
+      (terpri buff)
+
+      ;; get sorted list of all match overlays in set SET-ID
+      (setq overlay-list
+           (auto-overlays-in (point-min) (point-max)
+                             (list '(identity auto-overlay-match)
+                                   (list 'eq 'set-id set-id))))
+      (setq overlay-list
+           (sort overlay-list
+                 (lambda (a b)
+                   (or (< (overlay-start a) (overlay-start b))
+                       (and (= (overlay-start a) (overlay-start b))
+                            (> (overlay-end a) (overlay-end b)))))))
+
+      ;; write overlay data to temporary buffer
+      (mapc (lambda (o)
+             (prin1 (list (overlay-get o 'definition-id)
+                          (overlay-get o 'regexp-id)
+                          (overlay-start o)
+                          (overlay-end o)
+                          (marker-position (overlay-get o 'delim-start))
+                          (marker-position (overlay-get o 'delim-end)))
+                    buff)
+             (terpri buff))
+           overlay-list)
+
+      ;; save the buffer and kill it
+      (with-current-buffer buff (write-file file))
+      (kill-buffer buff))
+    ))
+
+
+
+;;;###autoload
+(defun auto-overlay-load-overlays (set-id &optional buffer
+                                         file no-regexp-check)
+  "Load overlays for BUFFER from FILE.
+Returns t if successful, nil otherwise.
+Defaults to the current buffer.
+
+If FILE is null, or is a string that only specifies a directory,
+the filename is constructed from the buffer's file name and
+SET-ID. If the buffer is not associated with a file and FILE
+doesn't specify a full filename, an error occurs.
+
+The FILE should be generated by `auto-overlay-save-overlays'. By
+default, the buffer contents and regexp definitions for SET-ID
+will be checked to make sure neither have changed since the
+overlays were saved. If they don't match, the saved overlay data
+will not be loaded, and the function will return nil.
+
+If NO-REGEXP-CHECK is non-nil, the check for matching regexp
+definitions will be skipped; the saved overlays will be loaded
+even if different regexp definitions were active when the
+overlays were saved."
+
+  (save-excursion
+    (when buffer (set-buffer buffer))
+
+    ;; construct filename
+    (let ((path (or (and file (file-name-directory file)) ""))
+         (filename (and file (file-name-nondirectory file))))
+      ;; use default filename if none supplied
+      ;; FIXME: should we throw error if buffer not associated with file?
+      (when (string= filename "")
+       (setq filename (auto-o-overlay-filename set-id)))
+      ;; construct full path to file, since that's all we need from now on
+      (setq file (concat path filename)))
+
+
+    ;; return nil if file does not exist
+    (if (not (file-exists-p file))
+       nil
+
+      ;; otherwise...
+      (let ((buff (find-file-noselect file t))
+           md5-buff md5-regexp data o-match o-new lines
+           (i 0))
+
+       ;; read md5 digests from first two lines of FILE
+       (with-current-buffer buff (goto-char (point-min)))
+       (setq md5-buff (read buff))
+       (setq md5-regexp (read buff))
+
+
+       ;; if saved buffer md5 sum doesn't match buffer contents, or if saved
+       ;; regexp md5 sum doesn't match regexp definitions and checking is not
+       ;; overridden, return nil
+       (if (not (and (string= md5-buff (md5 (current-buffer)))
+                     (or no-regexp-check
+                         (string= md5-regexp
+                                  (md5 (prin1-to-string
+                                        (auto-o-get-regexps set-id)))))))
+           (progn (kill-buffer buff) nil)
+
+         ;; count number of overlays, for progress message
+         (with-current-buffer buff
+           (setq lines (count-lines (point) (point-max))))
+
+         ;; read overlay data from FILE until we reach the end
+         (message "Loading auto-overlays...(1 of %d)" lines)
+         (while (condition-case nil (setq data (read buff)) ('end-of-file))
+           ;; create a match overlay corresponding to the data
+           (setq o-match (auto-o-make-match
+                          set-id (nth 0 data) (nth 1 data) (nth 2 data)
+                          (nth 3 data) (nth 4 data) (nth 5 data)))
+           ;; call the appropriate parse function, unless match overlay is
+           ;; within a higher priority exclusive overlay
+           (unless (auto-o-within-exclusive-p
+                    (overlay-get o-match 'delim-start)
+                    (overlay-get o-match 'delim-end)
+                    (assq 'priority (auto-o-entry-props
+                                     (overlay-get o-match 'definition-id)
+                                     (overlay-get o-match 'regexp-id))))
+             (setq o-new
+                   (funcall (auto-o-parse-function o-match) o-match))
+             (unless (listp o-new) (setq o-new (list o-new)))
+             ;; give any new overlays some basic properties
+             (mapc (lambda (o)
+                     (overlay-put o 'auto-overlay t)
+                     (overlay-put o 'set-id set-id)
+                     (overlay-put o 'definition-id
+                                  (overlay-get o-match 'definition-id))
+                     (overlay-put o 'regexp-id
+                                  (overlay-get o-match 'regexp-id)))
+                   o-new)
+             ;; run match function if there is one
+             (let ((match-func (auto-o-match-function o-match)))
+               (when match-func (funcall match-func o-match))))
+           ;; display progress message
+           (setq i (1+ i))
+           (when (= 0 (mod i 10))
+             (message "Loading auto-overlays...(%d of %d)" i lines)))
+
+         (kill-buffer buff)
+         t)))))  ; return t to indicate successful loading)
+
+
+
+
+
+;;;=============================================================
+;;;               auto-overlay overlay functions
+
+(defun auto-o-run-after-change-functions (beg end len)
+  ;; Assigned to the `after-change-functions' hook. Run all the various
+  ;; functions that should run after a change to the buffer, in the correct
+  ;; order.
+
+  ;; ignore changes that aren't either insertions or deletions
+  (when (and (not undo-in-progress)
+            (or (and (/= beg end) (=  len 0))    ; insertion
+                (and (=  beg end) (/= len 0))))  ; deletion
+    ;; repeat until all the pending functions have been cleared (it may be
+    ;; necessary to run multiple times since the pending functions may
+    ;; themselves cause more functions to be added to the pending lists)
+    (while (or auto-o-pending-pre-suicide auto-o-pending-suicides
+              auto-o-pending-post-suicide auto-o-pending-updates
+              auto-o-pending-post-update)
+      ;; run pending pre-suicide functions
+      (when auto-o-pending-pre-suicide
+       (mapc (lambda (f) (apply (car f) (cdr f)))
+             auto-o-pending-pre-suicide)
+       (setq auto-o-pending-pre-suicide nil))
+      ;; run pending suicides
+      (when auto-o-pending-suicides
+       (mapc 'auto-o-suicide auto-o-pending-suicides)
+       (setq auto-o-pending-suicides nil))
+      ;; run pending post-suicide functions
+      (when auto-o-pending-post-suicide
+       (mapc (lambda (f) (apply (car f) (cdr f)))
+             auto-o-pending-post-suicide)
+       (setq auto-o-pending-post-suicide nil))
+      ;; run updates
+      (when auto-o-pending-updates
+       (mapc (lambda (l) (auto-overlay-update (car l) (cdr l)))
+             auto-o-pending-updates)
+       (setq auto-o-pending-updates nil))
+      ;; run pending post-update functions
+      (when auto-o-pending-post-update
+       (mapc (lambda (f) (apply (car f) (cdr f)))
+             auto-o-pending-post-update)
+       (setq auto-o-pending-post-update nil))
+      ))
+
+  ;; ;; FIXME: horrible hack to delete all marker update entries in latest
+  ;; ;;        `buffer-undo-list' change group, since undoing these can badly
+  ;; ;;        mess up the overlays
+  ;; (while (and (consp (car buffer-undo-list))
+  ;;         (markerp (caar buffer-undo-list)))
+  ;;   (setq buffer-undo-list (cdr buffer-undo-list)))
+  ;; (let ((p buffer-undo-list))
+  ;;   (while (cadr p)
+  ;;     (if (and (consp (cadr p)) (markerp (car (cadr p))))
+  ;;     (setcdr p (cddr p))
+  ;;   (setq p (cdr p)))))
+  )
+
+
+
+(defun auto-o-schedule-update (start &optional end unused set-id)
+  ;; Schedule `auto-overlay-update' of lines between positions START and END
+  ;; (including lines containing START and END), optionally restricted to
+  ;; SET-ID. If END is not supplied, schedule update for just line containing
+  ;; START. The update will be run by `auto-o-run-after-change-functions'
+  ;; after buffer modification is complete. This function is assigned to
+  ;; `after-change-functions'.
+
+  (save-restriction
+    (widen)   ; need to widen, since goto-line goes to absolute line
+    (setq start (line-number-at-pos start))
+    (setq end (if end (line-number-at-pos end) start))
+
+    (let ((pending auto-o-pending-updates))
+      (cond
+       ;; if pending list is empty, just add new entry to the list
+       ((null pending)
+       (setq auto-o-pending-updates (list (cons start end))))
+
+       ;; if start of the new entry is before start of the first entry in
+       ;; pending list, add new entry to front of the list
+       ((<= start (caar pending))
+       (setq auto-o-pending-updates (nconc (list (cons start end)) pending))
+       (setq pending auto-o-pending-updates))
+
+       ;; otherwise...
+       (t
+       ;; search for entry in pending list that new one should come after
+       ;; Note: we do an O(n) linear search here, as opposed to the O(log n)
+       ;; we would get were we to store the entries in a binary tree. But the
+       ;; pending list is unlikely to ever be all that long, so the
+       ;; optimisation almost certainly isn't worth the effort.
+       (catch 'found
+         (while (cdr pending)
+           (when (<= start (car (cadr pending))) (throw 'found t))
+           (setq pending (cdr pending))))
+       ;; if start of new entry is before end of entry it should come after,
+       ;; merge it with that entry
+       (if (<= start (1+ (cdar pending)))
+           (when (> end (cdar pending)) (setcdr (car pending) end))
+         ;; otherwise, insert new entry after it
+         (setcdr pending (nconc (list (cons start end)) (cdr pending)))
+         (setq pending (cdr pending)))
+       ))
+
+      ;; merge new entry with successive entries until end of merged entry is
+      ;; before start of next entry (see above note about O(n) vs. O(log n))
+      (while (and (cdr pending)
+                 (>= (1+ (cdar pending)) (car (cadr pending))))
+       (setcdr (car pending) (max (cdar pending) (cdr (cadr pending))))
+       (setcdr pending (cddr pending)))
+      )))
+
+
+
+(defun auto-o-schedule-delete-in-front-or-behind-suicide (start end len)
+  ;; Schedule `auto-o-suicide' for any overlay that has had characters deleted
+  ;; in front or behind it, to simulate missing `delete-in-front-hooks' and
+  ;; `delete-behind-hooks' overlay properties
+  (unless (= len 0)
+    (dolist (o (auto-overlays-at-point nil '(identity auto-overlay-match)))
+      (when (or (= (overlay-end o) start) (= (overlay-start o) end))
+       (auto-o-adjoin o auto-o-pending-suicides)))))
+
+
+
+(defun auto-o-schedule-suicide (o-self &optional modified &rest unused)
+  ;; Schedule `auto-o-suicide' to run after buffer modification is
+  ;; complete. It will be run by `auto-o-run-after-change-functions'. Assigned
+  ;; to overlay modification and insert in-front/behind hooks.
+  (unless modified (auto-o-adjoin o-self auto-o-pending-suicides)))
+
+
+
+(defun auto-overlay-update (&optional start end set-id)
+  ;; Parse lines from line number START to line number END. If only START is
+  ;; supplied, just parse that line. If neither are supplied, parse line
+  ;; containing the point. If SET-ID is specified, only look for matches in
+  ;; that set of overlay regexps definitions.
+
+  (save-restriction
+    (widen)
+    (let (regexp-entry definition-id class regexp group priority set-id
+                      regexp-id o-match o-overlap o-new)
+      (unless start (setq start (line-number-at-pos)))
+      (save-excursion
+       (save-match-data
+         ;; (goto-line start) without messing around with mark and messages
+         ;; Note: this is a bug in simple.el; there clearly can be a need for
+         ;;       non-interactive calls to goto-line from Lisp code, and
+         ;;       there's no warning about doing this. Yet goto-line *always*
+         ;;       calls push-mark, which usually *shouldn't* be invoked by
+         ;;       Lisp programs, as its docstring warns.
+         (goto-char 1)
+         (if (eq selective-display t)
+             (re-search-forward "[\n\C-m]" nil 'end (1- start))
+           (forward-line (1- start)))
+
+         (dotimes (i (if end (1+ (- end start)) 1))
+
+           ;; check each enabled set of overlays, or just the specified set
+           (dotimes (s (if set-id 1 (length auto-overlay-regexps)))
+             (setq set-id (or set-id (car (nth s auto-overlay-regexps))))
+             (when (auto-o-enabled-p set-id)
+
+               ;; check each auto-overlay definition in regexp set
+               (dolist (regexp-entry (auto-o-get-regexps set-id))
+                 (setq definition-id (pop regexp-entry))
+                 (setq class (pop regexp-entry))
+
+                 ;; check all regexps for current definition
+                 (dotimes (rank (length regexp-entry))
+                   (setq regexp-id (car (nth rank regexp-entry)))
+
+                   ;; extract regexp properties from current entry
+                   (setq regexp (auto-o-entry-regexp set-id definition-id
+                                                     regexp-id))
+                   (setq group (auto-o-entry-regexp-group
+                                set-id definition-id regexp-id))
+                   (setq priority
+                         (cdr (assq 'priority
+                                    (auto-o-entry-props
+                                     set-id definition-id regexp-id))))
+
+
+                   ;; look for matches in current line, ensuring case *is*
+                   ;; significant
+                   (forward-line 0)
+                   (while (let ((case-fold-search nil))
+                            (re-search-forward regexp (line-end-position) t))
+                     ;; sanity check regexp definition against match
+                     (when (or (null (match-beginning group))
+                               (null (match-end group)))
+                       (error "Match for regexp \"%s\" has no group %d"
+                              regexp group))
+
+                     (cond
+                      ;; ignore match if it already has a match overlay
+                      ((auto-o-matched-p (match-beginning 0) (match-end 0)
+                                         set-id definition-id regexp-id))
+
+
+                      ;; if existing match overlay corresponding to same entry
+                      ;; and edge but different subentry overlaps new match...
+                      ((setq o-overlap
+                             (auto-o-overlapping-match
+                              (match-beginning group) (match-end group)
+                              set-id definition-id regexp-id
+                              (auto-o-entry-edge set-id definition-id
+                                                 regexp-id)))
+                       ;; if new match takes precedence, replace existing one
+                       ;; with new one, otherwise ignore new match
+                       (when (< rank (auto-o-rank o-overlap))
+                         (delete-overlay o-overlap)
+                         (setq o-match (auto-o-make-match
+                                        set-id definition-id regexp-id
+                                        (match-beginning 0) (match-end 0)
+                                        (match-beginning group)
+                                        (match-end group)))
+                         (when (overlay-get o-overlap 'parent)
+                           (auto-o-match-overlay
+                            (overlay-get o-overlap 'parent)
+                            o-match))
+                         ;; run match function if there is one
+                         (let ((match-func (auto-o-match-function o-match)))
+                           (when match-func (funcall match-func o-match)))))
+
+                      ;; if match is within a higher priority exclusive
+                      ;; overlay, create match overlay but don't parse it
+                      ((auto-o-within-exclusive-p (match-beginning group)
+                                                  (match-end group)
+                                                  priority)
+                       (auto-o-make-match set-id definition-id regexp-id
+                                          (match-beginning 0) (match-end 0)
+                                          (match-beginning group)
+                                          (match-end group)))
+
+
+                      ;; if we're going to parse the new match...
+                      (t
+                       ;; create a match overlay for it
+                       (setq o-match (auto-o-make-match
+                                      set-id definition-id regexp-id
+                                      (match-beginning 0) (match-end 0)
+                                      (match-beginning group)
+                                      (match-end group)))
+                       ;; call the appropriate parse function
+                       (setq o-new
+                             (funcall (auto-o-parse-function o-match) o-match))
+                       (unless (listp o-new) (setq o-new (list o-new)))
+                       ;; give any new overlays some basic properties
+                       (mapc (lambda (o)
+                               (overlay-put o 'auto-overlay t)
+                               (overlay-put o 'set-id set-id)
+                               (overlay-put o 'definition-id definition-id)
+                               (overlay-put o 'regexp-id regexp-id))
+                             o-new)
+                       ;; run match function if there is one
+                       (let ((match-func (auto-o-match-function o-match)))
+                         (when match-func (funcall match-func o-match)))))
+
+
+                     ;; go to character one beyond the start of the match, to
+                     ;; make sure we don't miss the next match (if we find the
+                     ;; same one again, it will just be ignored)
+                     (goto-char (+ (match-beginning 0) 1)))))
+               (forward-line 1))
+             )))
+       ))))
+
+
+
+
+(defun auto-o-suicide (o-self &optional force)
+  ;; This function is assigned to all match overlay modification hooks, and
+  ;; calls the appropriate suicide function for match overlay O-SELF.
+  ;; If FORCE is non-nil, O-SELF is deleted irrespective of whether its
+  ;; overlay still matches.
+
+  ;; have to widen temporarily
+  (save-restriction
+    (widen)
+;;     ;; this condition is here to avoid a weird Emacs bug(?) where the
+;;     ;; modification-hooks seem to be called occasionally for overlays that
+;;     ;; have already been deleted
+;;     (when (overlay-buffer o-self)
+      ;; if match overlay no longer matches the text it covers...
+      (unless (and (not force)
+                  (overlay-buffer o-self)
+                  (save-excursion
+                    (goto-char (overlay-start o-self))
+                    (looking-at (auto-o-regexp o-self)))
+                  (= (match-end 0) (overlay-end o-self)))
+
+       ;; if we have a parent overlay...
+       (let ((o-parent (overlay-get o-self 'parent))
+             o-other)
+         (when o-parent
+           ;; if our regexp class is a compound class...
+           (when (auto-o-complex-class-p o-self)
+             (setq o-other
+                   (overlay-get o-parent (if (eq (auto-o-edge o-self) 'start)
+                                             'start 'end)))
+             ;; if parent's properties have been set by us, remove them
+             (when (or (null o-other)
+                       (>= (auto-o-rank o-self)
+                           (auto-o-rank o-other)))
+               (dolist (p (auto-o-props o-self))
+                 (overlay-put o-parent (car p) nil))))
+           ;; call appropriate suicide function
+           (funcall (auto-o-suicide-function o-self) o-self)))
+
+       ;; schedule an update (necessary since if match regexp contains
+       ;; "context", we may be comitting suicide only for the match overlay
+       ;; to be recreated in a slightly different place)
+       (auto-o-schedule-update (overlay-start o-self))
+       ;; delete ourselves
+       (delete-overlay o-self));)
+    ))
+
+
+
+
+(defun auto-o-update-exclusive (set-id beg end old-priority new-priority)
+  ;; If priority has increased, delete all overlays between BEG end END that
+  ;; have priority lower than NEW-PRIORITY. If priority has decreased, re-parse
+  ;; all matches with priority lower than OLD-PRIORITY.
+
+  (let (overlay-list)
+    (cond
+     ;; if priority has increased...
+     ((and new-priority
+          (or (null old-priority) (> new-priority old-priority)))
+      ;; find overlays entirely within BEG and END that are both start and end
+      ;; matched and have priority lower than NEW-PRIORITY
+      (setq overlay-list
+           (auto-overlays-in
+            beg end
+            (list '(identity auto-overlay)
+                  (list 'eq 'set-id set-id)
+                  '(identity start)
+                  (list (lambda (definition-id start end)
+                          (or (null (auto-o-entry-complex-class-p
+                                     set-id definition-id))
+                              (and start end)))
+                        '(definition-id start end))
+                  (list (lambda (pri new) (or (null pri) (< pri new)))
+                        'priority new-priority))
+            'within))
+      ;; mark overlays in list as inactive (more efficient than calling
+      ;; suicide functions or deleting the overlays, and leaves them intact in
+      ;; case the exclusivity of the region is later reduced - see below)
+      (dolist (o overlay-list) (overlay-put o 'inactive t))
+
+      ;; find match overlays between BEG and END that have priority lower then
+      ;; NEW-PRIORITY but still have an active parent overlay
+      (setq overlay-list
+           (auto-overlays-in
+            beg end
+            (list '(identity auto-overlay-match)
+                  (list 'eq 'set-id set-id)
+                  ;; note: parentless overlays are possible if a suicide is
+                  ;; in progress, so need to check overlay has a parent first
+                  '(identity parent)
+                  (list (lambda (parent)
+                          (not (overlay-get parent 'inactive)))
+                        'parent)
+                  (list (lambda (set-id definition-id regexp-id new-pri)
+                          (let ((pri (cdr (assq
+                                           'priority
+                                           (auto-o-entry-props
+                                            set-id definition-id regexp-id)))))
+                            (or (null pri) (< pri new-pri))))
+                        '(set-id definition-id regexp-id)
+                        (list new-priority)))))
+      ;; call appropriate suicide function for each match overlay in list
+      (dolist (o overlay-list) (funcall (auto-o-suicide-function o) o)))
+
+
+     ;; if priority has decreased...
+     ((and old-priority
+          (or (null new-priority) (< new-priority old-priority)))
+      ;; find inactive overlays entirely within BEG and END that have priority
+      ;; higher or equal to NEW-PRIORITY
+      (setq overlay-list
+           (auto-overlays-in
+            beg end
+            (list '(identity auto-overlay)
+                  (list 'eq 'set-id set-id)
+                  '(identity inactive)
+                  (list (lambda (pri new) (or (null new) (>= pri new)))
+                        'priority new-priority))
+            'within 'inactive))
+      ;; mark overlays in list as active again
+      (dolist (o overlay-list) (overlay-put o 'inactive nil))
+
+      ;; find match overlays between BEG and END that have priority higher or
+      ;; equal to NEW-PRIORITY but no parent overlay
+      (setq overlay-list
+           (auto-overlays-in
+            beg end
+            (list '(identity auto-overlay-match)
+                  (list 'eq 'set-id set-id)
+                  '(null parent)
+                  (list (lambda (set-id definition-id regexp-id new-pri)
+                          (let ((pri (cdr (assq
+                                           'priority
+                                           (auto-o-entry-props
+                                            set-id definition-id regexp-id)))))
+                            (or (null new-pri) (>= pri new-pri))))
+                        '(set-id definition-id regexp-id)
+                        (list new-priority)))))
+      ;; call appropriate parse function for each match overlay in list
+      (dolist (o-match overlay-list)
+       (when (not (auto-o-within-exclusive-p o-match))
+         (let ((o-new (funcall (auto-o-parse-function o-match) o-match)))
+           ;; give any new overlays the basic properties and add them to
+           ;; `auto-overlay-list'
+           (unless (listp o-new) (setq o-new (list o-new)))
+           (mapc (lambda (o)
+                   (overlay-put o 'auto-overlay t)
+                   (overlay-put o 'set-id set-id)
+                   (overlay-put o 'definition-id
+                                (overlay-get o-match 'definition-id))
+                   (overlay-put o 'regexp-id
+                                (overlay-get o-match 'regexp-id)))
+                 o-new)))))
+     )))
+
+
+
+
+(defun auto-o-make-match (set-id definition-id regexp-id start end
+                             &optional delim-start delim-end)
+  ;; Create a new match overlay and give it the appropriate properties.
+  (let ((o-match (make-overlay start end nil 'front-advance nil)))
+    (overlay-put o-match 'auto-overlay-match t)
+    (overlay-put o-match 'set-id set-id)
+    (overlay-put o-match 'definition-id definition-id)
+    (overlay-put o-match 'regexp-id regexp-id)
+    (overlay-put o-match 'delim-start
+                (set-marker (make-marker)
+                            (if delim-start delim-start start)))
+    (overlay-put o-match 'delim-end
+                (set-marker (make-marker)
+                            (if delim-end delim-end end)))
+    (set-marker-insertion-type (overlay-get o-match 'delim-start) t)
+    (set-marker-insertion-type (overlay-get o-match 'delim-end) nil)
+    (overlay-put o-match 'modification-hooks '(auto-o-schedule-suicide))
+    (overlay-put o-match 'insert-in-front-hooks '(auto-o-schedule-suicide))
+    (overlay-put o-match 'insert-behind-hooks '(auto-o-schedule-suicide))
+    ;; return the new match overlay
+    o-match))
+
+
+
+
+(defun auto-o-match-overlay (overlay start &optional end
+                                    no-props no-parse protect-match)
+  "Match start and end of OVERLAY with START and END match overlays.
+If START or END are numbers or markers, move that edge to the
+buffer location specified by the number or marker and make it
+unmatched.  If START or END are non-nil but neither of the above,
+make that edge unmatched.  If START or END are null, don't change
+that edge. However, if END is null, and START is an 'end overlay,
+match end of OVERLAY rather than start.
+
+If NO-PARSE is non-nil, block re-parsing due to exclusive overlay
+changes. If NO-PROPS is non-nil, block updating of overlay's
+properties. If PROTECT-MATCH is non-nil, don't modify any match
+overlays associated with OVERLAY (i.e. don't modify their 'parent
+properties)."
+
+  (let ((old-start (overlay-start overlay))
+       (old-end (overlay-end overlay))
+       (old-o-start (overlay-get overlay 'start))
+       (old-o-end (overlay-get overlay 'end))
+       (old-exclusive (overlay-get overlay 'exclusive))
+       (old-priority (overlay-get overlay 'priority)))
+
+    ;; if END is null, we're not unmatching, and START is an end overlay,
+    ;; match end of overlay instead of start (Note: assumes we're matching an
+    ;; overlay class with 'start and 'end regexps)
+    (when (and (null end) (overlayp start) (eq (auto-o-edge start) 'end))
+      (setq end start)
+      (setq start nil))
+
+
+    ;; move overlay to new location
+    (move-overlay overlay
+                 (cond
+                  ((overlayp start) (overlay-get start 'delim-end))
+                  ((number-or-marker-p start) start)
+                  (start (point-min))
+                  (t (overlay-start overlay)))
+                 (cond
+                  ((overlayp end) (overlay-get end 'delim-start))
+                  ((number-or-marker-p end) end)
+                  (end (point-max))
+                  (t (overlay-end overlay))))
+
+    ;; if changing start match...
+    (when start
+      ;; sort out parent property of old start match
+      (when (and old-o-start (not (eq old-o-start end)) (null protect-match))
+       (overlay-put old-o-start 'parent nil))
+      ;; if unmatching start, set start property to nil
+      (if (not (overlayp start))
+         (overlay-put overlay 'start nil)
+       ;; if matching start, set start property to new start match
+       (overlay-put overlay 'start start)
+       (overlay-put start 'parent overlay)))
+
+    ;; if changing end match...
+    (when end
+      ;; sort out parent property of old end match
+      (when (and old-o-end (not (eq old-o-end start)) (null protect-match))
+       (overlay-put old-o-end 'parent nil))
+      ;; if unmatching end, set end property to nil
+      (if (not (overlayp end))
+         (overlay-put overlay 'end nil)
+       ;; if matching end, set end property to new end match
+       (overlay-put overlay 'end end)
+       (overlay-put end 'parent overlay)))
+
+
+    ;; unless it's blocked, update properties if new match takes precedence
+    ;; (Note: this sometimes sets the overlay's properties to the ones it
+    ;; already had, but it hardly seems worth checking for that)
+    (unless no-props
+      ;; when start was previously matched and is being changed, remove
+      ;; properties due to old start match
+      ;; Note: no need to check if properties were really set by start match,
+      ;; since if not they will be recreated below
+      (when (and start old-o-start)
+       (dolist (p (auto-o-props old-o-start))
+         (overlay-put overlay (car p) nil)))
+      ;; when end was previously matched and is being changed, remove
+      ;; properties due to old end match (see note above)
+      (when (and end old-o-end)
+       (dolist (p (auto-o-props old-o-end))
+         (overlay-put overlay (car p) nil)))
+      ;; sort out properties due to new matches
+      (let (props)
+       (cond
+        ;; if start has been unmatched, use properties of end match
+        ((not (auto-o-start-matched-p overlay))
+         (setq props (auto-o-props (overlay-get overlay 'end))))
+        ;; if end has been unmatched, use properties of start match
+        ((not (auto-o-end-matched-p overlay))
+         (setq props (auto-o-props (overlay-get overlay 'start))))
+        (t  ;; otherwise, use properties of whichever match takes precedence
+         (let ((o-start (overlay-get overlay 'start))
+               (o-end (overlay-get overlay 'end)))
+           (if (<= (auto-o-rank o-start)
+                   (auto-o-rank o-end))
+               (setq props (auto-o-props o-start))
+             (setq props (auto-o-props o-end))))))
+       ;; bundle properties inside a list if not already, then update them
+       (when (symbolp (car props)) (setq props (list props)))
+       (dolist (p props) (overlay-put overlay (car p) (cdr p)))))
+
+
+    ;; unless it's blocked or overlay is inactive, check if anything needs
+    ;; reparsing due to exclusive overlay changes
+    (unless (or no-parse (overlay-get overlay 'inactive))
+      (let ((set-id (overlay-get overlay 'set-id))
+           (start (overlay-start overlay))
+           (end (overlay-end overlay))
+           (exclusive (overlay-get overlay 'exclusive))
+           (priority (overlay-get overlay 'priority)))
+       (cond
+
+       ;; if overlay wasn't and still isn't exclusive, do nothing
+        ((and (null exclusive) (null old-exclusive)))
+
+        ;; if overlay has become exclusive, delete lower priority overlays
+        ;; within it
+        ((and (null old-exclusive) exclusive)
+         (auto-o-update-exclusive set-id start end nil priority))
+
+        ;; if overlay was exclusive but no longer is, re-parse region it
+        ;; used to cover
+        ((and old-exclusive (null exclusive))
+         (auto-o-update-exclusive set-id old-start old-end old-priority nil))
+
+        ;; if overlay was and is exclusive, and has been moved to a
+        ;; completely different location re-parse old location and delete
+        ;; lower priority overlays within new location
+        ((or (< end old-start) (> start old-start))
+         (auto-o-update-exclusive set-id start end old-priority nil)
+         (auto-o-update-exclusive set-id start end nil priority))
+
+        ;; if overlay was and is exclusive, and overlaps its old location...
+        (t
+         ;; if priority has changed, re-parse/delete in overlap region
+         (when (/= old-priority priority)
+           (auto-o-update-exclusive set-id
+                                    (max start old-start) (min end old-end)
+                                    old-priority priority))
+         (cond
+          ;; if overlay was exclusive and start has shrunk, re-parse
+          ;; uncovered region
+          ((and (> start old-start) old-exclusive)
+           (auto-o-update-exclusive set-id old-start start old-priority nil))
+          ;; if overlay is exclusive and has grown, delete lower priority
+          ;; overlays in newly covered region
+          ((and (< start old-start) exclusive)
+           (auto-o-update-exclusive set-id start old-start nil priority)))
+         (cond
+          ;; if overlay was exclusive and end has shrunk, re-parse
+          ((and (< end old-end) old-exclusive)
+           (auto-o-update-exclusive set-id end old-end old-priority nil))
+           ;; if overlay is exclusive and has grown, delete lower priority
+          ((and (> end old-end) exclusive)
+           (auto-o-update-exclusive set-id old-end end nil priority))))
+        )))
+    ))
+
+
+
+
+(defun auto-o-delete-overlay (overlay &optional no-parse protect-match)
+  "Delete OVERLAY from buffer.
+
+If PROTECT-MATCH is non-nil, don't modify any match overlays
+associated with OVERLAY (i.e. leave their 'parent properties
+alone). If NO-PARSE is non-nil, block re-parsing due to exclusive
+overlay changes."
+
+  (let ((start (overlay-start overlay))
+       (end (overlay-end overlay))
+       o-match)
+    ;; delete overlay from buffer and `auto-overlay-list'
+    (delete-overlay overlay)
+    (unless (setq o-match (overlay-get overlay 'start))
+      (setq o-match (overlay-get overlay 'end)))
+;;    (auto-o-delete-from-overlay-list overlay)
+
+    ;; unless blocked, if overlay's exclusive flag was set, re-parse region it
+    ;; covered
+    (when (and (null no-parse) (overlay-get overlay 'exclusive))
+      (auto-o-update-exclusive (overlay-get overlay 'set-id) start end
+                              (overlay-get overlay 'priority) nil))
+
+    ;; Note: it's vital that the match overlays' parent properties are only
+    ;; set to nil *after* `auto-update-exclusive' is run: if the overlay
+    ;; overlapped one of its match overlays, the newly parentless match
+    ;; overlay would be re-parsed by `auto-update-exclusive', which would
+    ;; re-create the parent overlay that's just been deleted!
+
+    ;; unmatch match overlays
+    (unless protect-match
+      (when (setq o-match (overlay-get overlay 'start))
+       (overlay-put o-match 'parent nil))
+      (when (setq o-match (overlay-get overlay 'end))
+       (overlay-put o-match 'parent nil)))
+    ))
+
+
+
+
+(defun auto-o-matched-p (beg end set-id definition-id &optional regexp-id)
+  ;; Determine if characters between BEG end END are already matched by a
+  ;; match overlay corresponding to DEFINITION-ID (and optionally REGEXP-ID)
+  ;; of regexp set SET-ID.
+  (let (o-match)
+    (catch 'match
+      (mapc (lambda (o)
+             (when (and (overlay-get o 'auto-overlay-match)
+                        (eq (overlay-get o 'set-id) set-id)
+                        (eq (overlay-get o 'definition-id) definition-id)
+                        (eq (overlay-get o 'regexp-id) regexp-id)
+                        (= (overlay-start o) beg)
+                        (= (overlay-end o) end))
+               (setq o-match o)
+               (throw 'match t)))
+           (overlays-in beg end)))
+    o-match))
+
+
+
+
+(defun auto-o-within-exclusive-p (match &optional end priority)
+  ;; If MATCH is an overlay, determine if it is within a higher priority
+  ;; exclusive overlay. If MATCH is a number or marker, determine whether
+  ;; region between MATCH and END is within an exclusive overlay with higher
+  ;; priority than PRIORITY.
+
+  (when (null end)
+    (setq end (overlay-get match 'delim-end))
+    (setq priority (overlay-get match 'priority))
+    (setq match (overlay-get match 'delim-start)))
+
+  ;; look for higher priority exclusive overlays
+  (auto-overlays-in
+   match end
+   (list '(identity auto-overlay)
+        '(identity exclusive)
+        (list (lambda (p q) (and p (or (null q) (> p q))))
+              'priority priority)))
+)
+
+
+
+
+(defun auto-o-overlapping-match (beg end set-id definition-id regexp-id edge)
+  ;; Returns any match overlay corresponding to same SET-ID, DEFINITION-ID and
+  ;; EDGE but different REGEXP-ID whose delimiter overlaps region from BEG to
+  ;; END. (Only returns first one it finds; which is returned if more than one
+  ;; exists is undefined.)
+  (let (o-overlap)
+    (catch 'match
+      (mapc (lambda (o)
+             (when (and (overlay-get o 'auto-overlay-match)
+                        (eq (overlay-get o 'set-id) set-id)
+                        (eq (overlay-get o 'definition-id) definition-id)
+                        (not (eq (overlay-get o 'regexp-id) regexp-id))
+                        (eq (auto-o-edge o) edge)
+                        ;; check delimiter (not just o) overlaps BEG to END
+                        (< (overlay-get o 'delim-start) end)
+                        (> (overlay-get o 'delim-end) beg))
+               (setq o-overlap o)
+               (throw 'match t)))
+           (overlays-in beg end)))
+    o-overlap))
+
+
+
+
+;;; ===============================================================
+;;;                       Compatibility Stuff
+
+(unless (fboundp 'line-number-at-pos)
+  (require 'auto-overlays-compat)
+  (defalias 'line-number-at-pos
+            'auto-overlays-compat-line-number-at-pos))
+
+
+(unless (fboundp 'replace-regexp-in-string)
+  (require 'auto-overlays-compat)
+  (defalias 'replace-regexp-in-string
+    'auto-overlays-compat-replace-regexp-in-string))
+
+;;; auto-overlays.el ends here
diff --git a/packages/auto-overlays/dir b/packages/auto-overlays/dir
new file mode 100644
index 0000000..833235e
--- /dev/null
+++ b/packages/auto-overlays/dir
@@ -0,0 +1,19 @@
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+
+File: dir,     Node: Top       This is the top of the INFO tree
+
+  This (the Directory node) gives a menu of major topics.
+  Typing "q" exits, "?" lists all Info commands, "d" returns here,
+  "h" gives a primer for first-timers,
+  "mEmacs<Return>" visits the Emacs manual, etc.
+
+  In Emacs, you can click mouse button 2 on a menu item or cross reference
+  to select it.
+
+* Menu:
+
+Emacs
+* auto-overlays: (auto-overlay-manual).
+                                Automatic regexp-delimited overlays
diff --git a/packages/cl-generic/cl-generic.el 
b/packages/cl-generic/cl-generic.el
new file mode 100644
index 0000000..4b1a377
--- /dev/null
+++ b/packages/cl-generic/cl-generic.el
@@ -0,0 +1,118 @@
+;;; cl-generic.el --- Forward cl-generic compatibility for Emacs<25
+
+;; Copyright (C) 2015  Free Software Foundation, Inc
+
+;; Author: Stefan Monnier <address@hidden>
+;; vcomment: Emacs-25's version is 1.0 so this has to stay below.
+;; Version: 0.2
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a forward compatibility package, which provides (a subset of) the
+;; features of the cl-generic package introduced in Emacs-25, for use on
+;; previous emacsen.
+
+;; Make sure this is installed *late* in your `load-path`, i.e. after Emacs's
+;; built-in .../lisp/emacs-lisp directory, so that if/when you upgrade to
+;; Emacs≥25, the built-in version of the file will take precedence, otherwise
+;; you could get into trouble (although we try to hack our way around the
+;; problem in case it happens).
+
+;; AFAIK, the main incompatibilities between cl-generic and EIEIO's defmethod
+;;  are:
+;; - EIEIO does not support multiple dispatch.  We ignore this difference here
+;;   and rely on EIEIO to detect and signal the problem.
+;; - EIEIO only supports primary, :before, and :after qualifiers.  We ignore
+;;   this difference here and rely on EIEIO to detect and signal the problem.
+;; - EIEIO does not support specializers other than classes.  We ignore this
+;;   difference here and rely on EIEIO to detect and signal the problem.
+;; - EIEIO uses :static instead of (subclass <foo>) and :static methods match
+;;   both class arguments as well as object argument of that class.  Here we
+;;   turn (subclass <foo>) into a :static qualifier and ignore the semantic
+;;   difference, hoping noone will notice.
+;; - EIEIO's defgeneric does not reset the function.  We ignore this difference
+;;   and hope for the best.
+;; - EIEIO uses `call-next-method' and `next-method-p' while cl-defmethod uses 
+;;   `cl-next-method-p' and `cl-call-next-method' (simple matter of renaming).
+;;   We handle that by renaming the calls in the `cl-defmethod' macro.
+;; - The errors signaled are slightly different.  We make
+;;   cl-no-applicable-method into a "parent" error of no-method-definition,
+;;   which should cover the usual cases.
+;; - EIEIO's no-next-method and no-applicable-method have different calling
+;;   conventions from cl-generic's.  We don't try to handle this, so just
+;;   refrain from trying to call (or add methods to) `cl-no-next-method' or
+;;   `cl-no-applicable-method'.
+;; - EIEIO's `call-next-method' and `next-method-p' have dynamic scope whereas
+;;   cl-generic's `cl-next-method-p' and `cl-call-next-method' are lexically
+;;   scoped.  The cl-defmethod here handles the common subset between the two.
+
+;;; Code:
+
+;; We need to handle the situation where this package is used with an Emacs
+;; that comes with a real cl-generic (i.e. ≥25.1).
+
+;; First line of defense: try to make sure the built-in cl-lib comes earlier in
+;; load-path so we never get loaded:
+;;;###autoload (let ((d (file-name-directory #$)))
+;;;###autoload   (when (member d load-path)
+;;;###autoload     (setq load-path (append (remove d load-path) (list d)))))
+
+(require 'cl-lib nil 'noerror)
+
+;; In Emacs≥25, cl-lib autoloads cl-defmethod and friends.
+
+(unless (fboundp 'cl-defmethod)
+  (require 'eieio)
+  (require 'cl)                         ;For `labels'.
+
+  (defalias 'cl-defgeneric 'defgeneric)
+
+  ;; Compatibility with code which tries to catch
+  ;; `cl-no-applicable-method' errors.
+  (push 'cl-no-applicable-method (get 'no-method-definition 'error-conditions))
+
+  (defmacro cl-defmethod (name args &rest body)
+    (let ((qualifiers nil))
+      (while (not (listp args))
+        (push args qualifiers)
+        (setq args (pop body)))
+      (let ((arg1 (car args)))
+        (when (eq (car-safe (car (cdr-safe arg1))) 'subclass)
+          ;; There's no exact equivalent to `subclass', but :static
+          ;; provides a superset which should work just as well in practice.
+          (push :static qualifiers)
+          (setf (cadr arg1) (cadr (cadr arg1)))))
+      (let ((docstring (if (and (stringp (car body)) (cdr body)) (pop body))))
+        `(defmethod ,name ,@qualifiers ,args
+           ,@(if docstring (list docstring))
+           ;; We could just alias `cl-call-next-method' to `call-next-method',
+           ;; and that would work, but then files compiled with this cl-generic
+           ;; wouldn't work in Emacs-25 any more.
+           ;; Also we fallback on `labels' if `cl-flet' is not available
+           ;; (ELPA's cl-lib emulation doesn't provide cl-flet).
+           ;; We don't always use `labels' because that generates warnings
+           ;; in newer Emacsen where `cl-flet' is available.
+           ,@(if qualifiers
+                 ;; Must be :before or :after, so can't call next-method.
+                 body
+               `((,(if (fboundp 'cl-flet) 'cl-flet 'labels)
+                      ((cl-call-next-method (&rest args)
+                                            (apply #'call-next-method args))
+                       (cl-next-method-p () (next-method-p)))
+                   ,@body))))))))
+
+(provide 'cl-generic)
+;;; cl-generic.el ends here
diff --git a/packages/company-statistics/company-statistics.el 
b/packages/company-statistics/company-statistics.el
index a3fef23..3346c96 100644
--- a/packages/company-statistics/company-statistics.el
+++ b/packages/company-statistics/company-statistics.el
@@ -4,11 +4,11 @@
 
 ;; Author: Ingo Lohmar <address@hidden>
 ;; URL: https://github.com/company-mode/company-statistics
-;; Version: 0.1
+;; Version: 0.1.1
 ;; Keywords: abbrev, convenience, matching
 ;; Package-Requires: ((emacs "24.3") (company "0.8.5"))
 
-;; This file is not part of GNU Emacs.
+;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -153,7 +153,8 @@ number)."
     (write-file company-statistics-file)))
 
 (defun company-statistics--maybe-save ()
-  (when company-statistics-auto-save
+  (when (and (company-statistics--initialized-p)
+             company-statistics-auto-save)
     (company-statistics--save)))
 
 (defun company-statistics--load ()
diff --git a/packages/company/company.el b/packages/company/company.el
index 86d93c2..ce0b5a4 100644
--- a/packages/company/company.el
+++ b/packages/company/company.el
@@ -5,7 +5,7 @@
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
 ;; URL: http://company-mode.github.io/
-;; Version: 0.8.10
+;; Version: 0.8.12
 ;; Keywords: abbrev, convenience, matching
 ;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
 
@@ -934,26 +934,26 @@ means that `company-mode' is always turned on except in 
`message-mode' buffers."
       (cons
        :async
        (lambda (callback)
-         (let* (lst pending
+         (let* (lst
+                (pending (mapcar #'car pairs))
                 (finisher (lambda ()
                             (unless pending
                               (funcall callback
                                        (funcall merger
                                                 (nreverse lst)))))))
            (dolist (pair pairs)
-             (let ((val (car pair))
-                   (mapper (cdr pair)))
+             (push nil lst)
+             (let* ((cell lst)
+                    (val (car pair))
+                    (mapper (cdr pair))
+                    (this-finisher (lambda (res)
+                                     (setq pending (delq val pending))
+                                     (setcar cell (funcall mapper res))
+                                     (funcall finisher))))
                (if (not (eq :async (car-safe val)))
-                   (push (funcall mapper val) lst)
-                 (push nil lst)
-                 (let ((cell lst)
-                       (fetcher (cdr val)))
-                   (push fetcher pending)
-                   (funcall fetcher
-                            (lambda (res)
-                              (setq pending (delq fetcher pending))
-                              (setcar cell (funcall mapper res))
-                              (funcall finisher)))))))))))))
+                   (funcall this-finisher val)
+                 (let ((fetcher (cdr val)))
+                   (funcall fetcher this-finisher)))))))))))
 
 (defun company--prefix-str (prefix)
   (or (car-safe prefix) prefix))
@@ -2231,9 +2231,12 @@ If SHOW-VERSION is non-nil, show the version in the echo 
area."
                (string-match (regexp-quote company-search-string) value
                              (length company-prefix)))
           (let ((beg (+ margin (match-beginning 0)))
-                (end (+ margin (match-end 0))))
-            (add-text-properties beg end '(face company-tooltip-search)
-                                 line))
+                (end (+ margin (match-end 0)))
+                (width (- width (length right))))
+            (when (< beg width)
+              (add-text-properties beg (min end width)
+                                   '(face company-tooltip-search)
+                                   line)))
         (add-text-properties 0 width '(face company-tooltip-selection
                                        mouse-face company-tooltip-selection)
                              line)
diff --git a/packages/company/test/async-tests.el 
b/packages/company/test/async-tests.el
index 5d8be3e..c548898 100644
--- a/packages/company/test/async-tests.el
+++ b/packages/company/test/async-tests.el
@@ -159,3 +159,59 @@
                      (company-call-backend 'candidates "foo")))
       (let ((company-backend (list immediate)))
         (should (equal '("f") (company-call-backend 'candidates "foo")))))))
+
+(ert-deftest company-multi-backend-merges-deferred-candidates-2 ()
+  (with-temp-buffer
+    (let ((company-backend (list (lambda (command &optional _)
+                                   (pcase command
+                                     (`prefix "foo")
+                                     (`candidates
+                                      (cons :async
+                                            (lambda (cb) (funcall cb '("a" 
"b")))))))
+                                 (lambda (command &optional _)
+                                   (pcase command
+                                     (`prefix "foo")
+                                     (`candidates
+                                      (cons :async
+                                            (lambda (cb) (funcall cb '("c" 
"d")))))))
+                                 (lambda (command &optional _)
+                                   (pcase command
+                                     (`prefix "foo")
+                                     (`candidates
+                                      (cons :async
+                                            (lambda (cb) (funcall cb '("e" 
"f"))))))))))
+      (should (equal :async (car (company-call-backend-raw 'candidates 
"foo"))))
+      (should (equal '("a" "b" "c" "d" "e" "f")
+                     (company-call-backend 'candidates "foo"))))))
+
+(ert-deftest company-multi-backend-merges-deferred-candidates-3 ()
+  (with-temp-buffer
+    (let ((company-backend (list (lambda (command &optional _)
+                                   (pcase command
+                                     (`prefix "foo")
+                                     (`candidates
+                                      (cons :async
+                                            (lambda (cb) (funcall cb '("a" 
"b")))))))
+                                 (lambda (command &optional _)
+                                   (pcase command
+                                     (`prefix "foo")
+                                     (`candidates
+                                      (cons :async
+                                            (lambda (cb)
+                                              (run-with-timer
+                                               0.01 nil
+                                               (lambda ()
+                                                 (funcall cb '("c" "d")))))))))
+                                 (lambda (command &optional _)
+                                   (pcase command
+                                     (`prefix "foo")
+                                     (`candidates
+                                      (cons :async
+                                            (lambda (cb)
+                                              (run-with-timer
+                                               0.01 nil
+                                               (lambda ()
+                                                 (funcall cb '("e" 
"f"))))))))))))
+      (should (equal :async (car (company-call-backend-raw 'candidates 
"foo"))))
+      (should (equal '("a" "b" "c" "d" "e" "f")
+                     (company-call-backend 'candidates "foo"))))))
diff --git a/packages/company/test/frontends-tests.el 
b/packages/company/test/frontends-tests.el
index 35c94c9..613856e 100644
--- a/packages/company/test/frontends-tests.el
+++ b/packages/company/test/frontends-tests.el
@@ -245,6 +245,26 @@
                      " MIRAI発売2カ月 ")
                    (company--create-lines 0 999)))))
 
+(ert-deftest company-fill-propertize-truncates-search-highlight ()
+  (let ((company-search-string "foo")
+        (company-backend #'ignore)
+        (company-prefix ""))
+    (should (equal-including-properties
+             (company-fill-propertize "barfoo" nil 6 t nil nil)
+             #("barfoo"
+               0 3 (face company-tooltip mouse-face company-tooltip-mouse)
+               3 6 (face company-tooltip-search mouse-face 
company-tooltip-mouse))))
+    (should (equal-including-properties
+             (company-fill-propertize "barfoo" nil 5 t "" " ")
+             #("barfo "
+               0 3 (face company-tooltip mouse-face company-tooltip-mouse)
+               3 5 (face company-tooltip-search mouse-face 
company-tooltip-mouse)
+               5 6 (face company-tooltip mouse-face company-tooltip-mouse))))
+    (should (equal-including-properties
+             (company-fill-propertize "barfoo" nil 3 t " " " ")
+             #(" bar "
+               0 5 (face company-tooltip mouse-face company-tooltip-mouse))))))
+
 (ert-deftest company-column-with-composition ()
   :tags '(interactive)
   (with-temp-buffer
diff --git a/packages/context-coloring/.gitignore 
b/packages/context-coloring/.gitignore
new file mode 100644
index 0000000..f090318
--- /dev/null
+++ b/packages/context-coloring/.gitignore
@@ -0,0 +1,3 @@
+*.elc
+/benchmark/logs/
+/libraries/
diff --git a/packages/context-coloring/.travis.yml 
b/packages/context-coloring/.travis.yml
new file mode 100644
index 0000000..2dcc8a6
--- /dev/null
+++ b/packages/context-coloring/.travis.yml
@@ -0,0 +1,21 @@
+# https://github.com/rolandwalker/emacs-travis
+
+language: emacs-lisp
+
+node_js:
+  - "0.10"
+
+env:
+  matrix:
+    - EMACS=emacs24
+
+install:
+  - if [ "$EMACS" = "emacs24" ]; then
+        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo apt-get update -qq &&
+        sudo apt-get install -qq emacs24 emacs24-el;
+    fi
+  - npm install -g scopifier
+
+script:
+  make test EMACS=${EMACS}
diff --git a/packages/context-coloring/Makefile 
b/packages/context-coloring/Makefile
new file mode 100644
index 0000000..c265382
--- /dev/null
+++ b/packages/context-coloring/Makefile
@@ -0,0 +1,40 @@
+EMACS = emacs
+DEPENDENCIES = libraries/ert-async.el libraries/js2-mode.el
+
+all: uncompile compile test
+
+bench: ${DEPENDENCIES}
+       ${EMACS} -Q \
+       -L . \
+       -L libraries \
+       -l context-coloring \
+       -l benchmark/context-coloring-benchmark \
+       -f context-coloring-benchmark-run
+
+compile: ${DEPENDENCIES}
+       ${EMACS} -Q -batch \
+       -L . \
+       -L libraries \
+       -f batch-byte-compile *.el libraries/*.el
+
+uncompile:
+       rm -f *.elc libraries/*.elc
+
+clean: uncompile
+       rm -f ${DEPENDENCIES}
+
+${DEPENDENCIES}:
+       ${EMACS} -Q -batch \
+       -l scripts/download-dependencies.el
+
+test: ${DEPENDENCIES}
+       ${EMACS} -Q -batch \
+       -L . \
+       -L libraries \
+       -l ert \
+       -l ert-async \
+       -l context-coloring \
+       -l test/context-coloring-test.el \
+       -f ert-run-tests-batch-and-exit
+
+.PHONY: all bench compile uncompile clean test
diff --git a/packages/context-coloring/README.md 
b/packages/context-coloring/README.md
new file mode 100644
index 0000000..ff305c1
--- /dev/null
+++ b/packages/context-coloring/README.md
@@ -0,0 +1,181 @@
+# Context Coloring [![Build 
Status](https://travis-ci.org/jacksonrayhamilton/context-coloring.png?branch=develop)](https://travis-ci.org/jacksonrayhamilton/context-coloring)
+
+<p align="center">
+  <img alt="Screenshot of JavaScript code highlighted by context." 
src="screenshot.png" title="Screenshot">
+</p>
+
+Highlights code according to function context.
+
+- Code in the global scope is one color. Code in functions within the global
+  scope is a different color, and code within such functions is another color,
+  and so on.
+- Identifiers retain the color of the scope in which they are declared.
+
+Lexical scope information at-a-glance can assist a programmer in understanding
+the overall structure of a program. It can help to curb nasty bugs like name
+shadowing. A rainbow can indicate excessive complexity. State change within a
+closure is easily monitored.
+
+By default, context-coloring still highlights comments and strings
+syntactically. It is still easy to differentiate code from non-code, and 
strings
+cannot be confused for variables.
+
+This coloring strategy is probably more useful than conventional syntax
+highlighting. Highlighting keywords can help one to detect spelling errors, but
+a [linter][] could also spot those errors, and if integrated with [flycheck][],
+an extra spot opens up in your editing toolbelt.
+
+Give context-coloring a try; you may find that it *changes the way you write
+code*.
+
+## Features
+
+- Supported languages: JavaScript
+- Light and dark (customizable) color schemes.
+- Very fast for files under 1000 lines.
+
+## Installation
+
+Requires Emacs 24+.
+
+JavaScript language support requires either [js2-mode][], or
+[Node.js 0.10+][node] and the [scopifier][] executable.
+
+### ELPA
+
+- `M-x package-install RET context-coloring RET`
+
+### Git
+
+- Clone this repository.
+
+```bash
+cd ~/.emacs.d/
+git clone https://github.com/jacksonrayhamilton/context-coloring.git
+```
+
+- Byte-compile the package for improved speed.
+
+```bash
+cd context-coloring/
+make compile
+```
+
+- Add the following to your `~/.emacs` file:
+
+```lisp
+(add-to-list 'load-path "~/.emacs.d/context-coloring")
+(require 'context-coloring)
+```
+
+### scopifier (for non-js2-mode users)
+
+```bash
+npm install -g scopifier
+```
+
+## Usage
+
+Add the following to your `~/.emacs` file:
+
+```lisp
+;; non-js2-mode users:
+(add-hook 'js-mode-hook 'context-coloring-mode)
+
+;; js2-mode users:
+(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
+(add-hook 'js2-mode-hook 'context-coloring-mode)
+```
+
+## Customizing
+
+Color schemes for custom themes are automatically applied when those themes are
+active. Built-in theme support is available for: `ample`, `anti-zenburn`,
+`grandshell`, `leuven`, `monokai`, `solarized`, `spacegray`, `tango` and
+`zenburn`.
+
+You can define your own theme colors too:
+
+```lisp
+(context-coloring-define-theme
+ 'zenburn
+ :colors '("#DCDCCC"
+           "#93E0E3"
+           "#BFEBBF"
+           "#F0DFAF"
+           "#DFAF8F"
+           "#CC9393"
+           "#DC8CC3"
+           "#94BFF3"
+           "#9FC59F"
+           "#D0BF8F"
+           "#DCA3A3"))
+```
+
+See `C-h f context-coloring-define-theme` for more info on theme parameters.
+
+## Extending
+
+To add support for a new language, write a "scopifier" for it, and define a new
+coloring dispatch strategy with `context-coloring-define-dispatch`. Then the
+plugin should handle the rest. (See `C-h f context-coloring-define-dispatch` 
for
+more info on dispatch strategies.)
+
+A "scopifier" is a CLI program that reads a buffer's contents from stdin and
+writes a JSON array of numbers to stdout. Every three numbers in the array
+represent a range of color. For instance, if I fed the following string of
+JavaScript code to a scopifier,
+
+```js
+var a = function () {};
+```
+
+then the scopifier would produce the following array:
+
+```js
+[1,24,0,9,23,1]
+```
+
+Where, for every three numbers, the first number is a 1-indexed start 
[point][],
+the second number is an exclusive end point, and the third number is a scope
+level. The result of applying level 0 coloring to the range &#91;1, 24) and 
then
+applying level 1 coloring to the range &#91;9, 23) would result in the 
following
+coloring:
+
+<p align="center">
+  <img alt="Screenshot of ranges &#91;1, 24) and &#91;9, 23)." 
src="scopifier.png" title="Screenshot">
+</p>
+
+If there is an abstract syntax tree generator for your language, you can walk
+the syntax tree, find variables and scopes, and build their positions and 
levels
+into an array like the one above.
+
+For example, a Ruby scopifier might be defined and implemented like this:
+
+```lisp
+(context-coloring-define-dispatch
+ 'ruby
+ :modes '(ruby-mode)
+ :executable "ruby"
+ :command "/home/username/scopifier")
+```
+
+```ruby
+#!/usr/bin/env ruby
+def scopifier(code)
+    # Parse code.
+    # Return an array.
+end
+print scopifier ARGF.read
+```
+
+When a `--version` argument is passed, a scopifier should print its version
+number and exit. This allows context-coloring to determine if an update is
+required.
+
+[linter]: http://jshint.com/about/
+[flycheck]: http://www.flycheck.org/
+[point]: http://www.gnu.org/software/emacs/manual/html_node/elisp/Point.html
+[js2-mode]: https://github.com/mooz/js2-mode
+[node]: http://nodejs.org/download/
+[scopifier]: https://github.com/jacksonrayhamilton/scopifier
diff --git a/packages/context-coloring/benchmark/context-coloring-benchmark.el 
b/packages/context-coloring/benchmark/context-coloring-benchmark.el
new file mode 100644
index 0000000..3da8d79
--- /dev/null
+++ b/packages/context-coloring/benchmark/context-coloring-benchmark.el
@@ -0,0 +1,172 @@
+;;; benchmark/context-coloring-benchmark.el --- Benchmarks for context 
coloring. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2015  Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Benchmarks for context-coloring.
+
+;; `ert' instruments and benchmarks the package's functions, and the results 
are
+;; logged to `benchmark/logs'.
+
+;; To run, execute `make bench' from the project root.
+
+;;; Code:
+
+(require 'js2-mode)
+
+(defconst context-coloring-benchmark-path
+  (file-name-directory (or load-file-name buffer-file-name))
+  "This file's directory.")
+
+(defun context-coloring-benchmark-resolve-path (path)
+  "Resolve PATH from this file's directory."
+  (expand-file-name path context-coloring-benchmark-path))
+
+(defun context-coloring-benchmark-log-results (result-file fixture)
+  "Log benchmarking results to RESULT-FILE for fixture FIXTURE."
+  (elp-results)
+  (let ((results-buffer (current-buffer)))
+    (with-temp-buffer
+      (insert (concat fixture "\n"))
+      (prepend-to-buffer results-buffer (point-min) (point-max)))
+    (with-temp-buffer
+      (insert "\n")
+      (append-to-buffer results-buffer (point-min) (point-max))))
+  (make-directory (context-coloring-benchmark-resolve-path "./logs") t)
+  (append-to-file nil nil result-file))
+
+(defun context-coloring-benchmark-next-tick (function)
+  "Defer execution of FUNCTION to clear the stack and to ensure
+asynchrony."
+  (run-at-time 0.001 nil function))
+
+(defun context-coloring-benchmark-next (list continue stop)
+  "Run the next test in LIST by calling CONTINUE.  When LIST is
+exhausted, call STOP instead."
+  (if (null list)
+      (progn
+        (context-coloring-benchmark-next-tick stop))
+    (context-coloring-benchmark-next-tick
+     (lambda ()
+       (funcall
+        continue
+        (car list)
+        (lambda ()
+          (context-coloring-benchmark-next (cdr list) continue stop)))))))
+
+(defun context-coloring-benchmark-async (title setup teardown fixtures 
callback)
+  "Execute a benchmark titled TITLE with SETUP and TEARDOWN
+callbacks.  Measure the performance of all FIXTURES, calling
+CALLBACK when all are done."
+  (funcall setup)
+  (let ((result-file (context-coloring-benchmark-resolve-path
+                      (format "./logs/results-%s-%s.log"
+                              title (format-time-string "%s")))))
+    (context-coloring-benchmark-next
+     fixtures
+     (lambda (path next)
+       (let ((fixture (context-coloring-benchmark-resolve-path path))
+             advice)
+         (setq
+          advice
+          (let ((count 0))
+            (lambda (original-function)
+              (funcall
+               original-function
+               (lambda ()
+                 (setq count (+ count 1))
+                 ;; Test 5 times.
+                 (if (= count 5)
+                     (progn
+                       (advice-remove 'context-coloring-colorize advice)
+                       (kill-buffer)
+                       (context-coloring-benchmark-log-results
+                        result-file
+                        fixture)
+                       (funcall next))
+                   (funcall 'context-coloring-colorize)))))))
+         (advice-add 'context-coloring-colorize :around advice)
+         (find-file fixture)))
+     (lambda ()
+       (funcall teardown)
+       (when callback (funcall callback))))))
+
+(defconst context-coloring-benchmark-js-fixtures
+  '("./fixtures/jquery-2.1.1.js"
+    "./fixtures/lodash-2.4.1.js"
+    "./fixtures/async-0.9.0.js"
+    "./fixtures/mkdirp-0.5.0.js")
+  "Arbitrary JavaScript files for performance scrutiny.")
+
+(defun context-coloring-benchmark-js-mode-setup ()
+  "Preparation logic for `js-mode'."
+  (add-hook 'js-mode-hook 'context-coloring-mode)
+  (elp-instrument-package "context-coloring-"))
+
+(defun context-coloring-benchmark-js-mode-teardown ()
+  "Cleanup logic for `js-mode'."
+  (remove-hook 'js-mode-hook 'context-coloring-mode))
+
+(defun context-coloring-benchmark-js-mode-run (callback)
+  "Benchmark `js-mode', then call CALLBACK."
+  (context-coloring-benchmark-async
+   "js-mode"
+   'context-coloring-benchmark-js-mode-setup
+   'context-coloring-benchmark-js-mode-teardown
+   context-coloring-benchmark-js-fixtures
+   callback))
+
+(defun context-coloring-benchmark-js2-mode-setup ()
+  "Preparation logic for `js2-mode'."
+  (setq js2-mode-show-parse-errors nil)
+  (setq js2-mode-show-strict-warnings nil)
+  (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
+  (add-hook 'js2-mode-hook 'context-coloring-mode)
+  (elp-instrument-package "context-coloring-"))
+
+(defun context-coloring-benchmark-js2-mode-teardown ()
+  "Cleanup logic for `js2-mode'."
+  (remove-hook 'js2-mode-hook 'context-coloring-mode)
+  (setq auto-mode-alist (delete '("\\.js\\'" . js2-mode)
+                                auto-mode-alist))
+  (setq js2-mode-show-strict-warnings t)
+  (setq js2-mode-show-parse-errors t))
+
+(defun context-coloring-benchmark-js2-mode-run (callback)
+  "Benchmark `js2-mode', then call CALLBACK."
+  (context-coloring-benchmark-async
+   "js2-mode"
+   'context-coloring-benchmark-js2-mode-setup
+   'context-coloring-benchmark-js2-mode-teardown
+   context-coloring-benchmark-js-fixtures
+   callback))
+
+(defun context-coloring-benchmark-run ()
+  "Benchmark all modes, then exit."
+  (context-coloring-benchmark-next
+   '(context-coloring-benchmark-js-mode-run
+     context-coloring-benchmark-js2-mode-run)
+   (lambda (function next)
+     (funcall function next))
+   (lambda ()
+     (kill-emacs))))
+
+(provide 'context-coloring-benchmark)
+
+;;; context-coloring-benchmark.el ends here
diff --git a/packages/context-coloring/benchmark/fixtures/.dir-locals.el 
b/packages/context-coloring/benchmark/fixtures/.dir-locals.el
new file mode 100644
index 0000000..f3d5e97
--- /dev/null
+++ b/packages/context-coloring/benchmark/fixtures/.dir-locals.el
@@ -0,0 +1 @@
+((nil . ((buffer-read-only . t))))
diff --git a/packages/context-coloring/benchmark/fixtures/async-0.9.0.js 
b/packages/context-coloring/benchmark/fixtures/async-0.9.0.js
new file mode 100644
index 0000000..01e8afc
--- /dev/null
+++ b/packages/context-coloring/benchmark/fixtures/async-0.9.0.js
@@ -0,0 +1,1123 @@
+/*!
+ * async
+ * https://github.com/caolan/async
+ *
+ * Copyright 2010-2014 Caolan McMahon
+ * Released under the MIT license
+ */
+/*jshint onevar: false, indent:4 */
+/*global setImmediate: false, setTimeout: false, console: false */
+(function () {
+
+    var async = {};
+
+    // global on the server, window in the browser
+    var root, previous_async;
+
+    root = this;
+    if (root != null) {
+      previous_async = root.async;
+    }
+
+    async.noConflict = function () {
+        root.async = previous_async;
+        return async;
+    };
+
+    function only_once(fn) {
+        var called = false;
+        return function() {
+            if (called) throw new Error("Callback was already called.");
+            called = true;
+            fn.apply(root, arguments);
+        }
+    }
+
+    //// cross-browser compatiblity functions ////
+
+    var _toString = Object.prototype.toString;
+
+    var _isArray = Array.isArray || function (obj) {
+        return _toString.call(obj) === '[object Array]';
+    };
+
+    var _each = function (arr, iterator) {
+        if (arr.forEach) {
+            return arr.forEach(iterator);
+        }
+        for (var i = 0; i < arr.length; i += 1) {
+            iterator(arr[i], i, arr);
+        }
+    };
+
+    var _map = function (arr, iterator) {
+        if (arr.map) {
+            return arr.map(iterator);
+        }
+        var results = [];
+        _each(arr, function (x, i, a) {
+            results.push(iterator(x, i, a));
+        });
+        return results;
+    };
+
+    var _reduce = function (arr, iterator, memo) {
+        if (arr.reduce) {
+            return arr.reduce(iterator, memo);
+        }
+        _each(arr, function (x, i, a) {
+            memo = iterator(memo, x, i, a);
+        });
+        return memo;
+    };
+
+    var _keys = function (obj) {
+        if (Object.keys) {
+            return Object.keys(obj);
+        }
+        var keys = [];
+        for (var k in obj) {
+            if (obj.hasOwnProperty(k)) {
+                keys.push(k);
+            }
+        }
+        return keys;
+    };
+
+    //// exported async module functions ////
+
+    //// nextTick implementation with browser-compatible fallback ////
+    if (typeof process === 'undefined' || !(process.nextTick)) {
+        if (typeof setImmediate === 'function') {
+            async.nextTick = function (fn) {
+                // not a direct alias for IE10 compatibility
+                setImmediate(fn);
+            };
+            async.setImmediate = async.nextTick;
+        }
+        else {
+            async.nextTick = function (fn) {
+                setTimeout(fn, 0);
+            };
+            async.setImmediate = async.nextTick;
+        }
+    }
+    else {
+        async.nextTick = process.nextTick;
+        if (typeof setImmediate !== 'undefined') {
+            async.setImmediate = function (fn) {
+              // not a direct alias for IE10 compatibility
+              setImmediate(fn);
+            };
+        }
+        else {
+            async.setImmediate = async.nextTick;
+        }
+    }
+
+    async.each = function (arr, iterator, callback) {
+        callback = callback || function () {};
+        if (!arr.length) {
+            return callback();
+        }
+        var completed = 0;
+        _each(arr, function (x) {
+            iterator(x, only_once(done) );
+        });
+        function done(err) {
+          if (err) {
+              callback(err);
+              callback = function () {};
+          }
+          else {
+              completed += 1;
+              if (completed >= arr.length) {
+                  callback();
+              }
+          }
+        }
+    };
+    async.forEach = async.each;
+
+    async.eachSeries = function (arr, iterator, callback) {
+        callback = callback || function () {};
+        if (!arr.length) {
+            return callback();
+        }
+        var completed = 0;
+        var iterate = function () {
+            iterator(arr[completed], function (err) {
+                if (err) {
+                    callback(err);
+                    callback = function () {};
+                }
+                else {
+                    completed += 1;
+                    if (completed >= arr.length) {
+                        callback();
+                    }
+                    else {
+                        iterate();
+                    }
+                }
+            });
+        };
+        iterate();
+    };
+    async.forEachSeries = async.eachSeries;
+
+    async.eachLimit = function (arr, limit, iterator, callback) {
+        var fn = _eachLimit(limit);
+        fn.apply(null, [arr, iterator, callback]);
+    };
+    async.forEachLimit = async.eachLimit;
+
+    var _eachLimit = function (limit) {
+
+        return function (arr, iterator, callback) {
+            callback = callback || function () {};
+            if (!arr.length || limit <= 0) {
+                return callback();
+            }
+            var completed = 0;
+            var started = 0;
+            var running = 0;
+
+            (function replenish () {
+                if (completed >= arr.length) {
+                    return callback();
+                }
+
+                while (running < limit && started < arr.length) {
+                    started += 1;
+                    running += 1;
+                    iterator(arr[started - 1], function (err) {
+                        if (err) {
+                            callback(err);
+                            callback = function () {};
+                        }
+                        else {
+                            completed += 1;
+                            running -= 1;
+                            if (completed >= arr.length) {
+                                callback();
+                            }
+                            else {
+                                replenish();
+                            }
+                        }
+                    });
+                }
+            })();
+        };
+    };
+
+
+    var doParallel = function (fn) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments);
+            return fn.apply(null, [async.each].concat(args));
+        };
+    };
+    var doParallelLimit = function(limit, fn) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments);
+            return fn.apply(null, [_eachLimit(limit)].concat(args));
+        };
+    };
+    var doSeries = function (fn) {
+        return function () {
+            var args = Array.prototype.slice.call(arguments);
+            return fn.apply(null, [async.eachSeries].concat(args));
+        };
+    };
+
+
+    var _asyncMap = function (eachfn, arr, iterator, callback) {
+        arr = _map(arr, function (x, i) {
+            return {index: i, value: x};
+        });
+        if (!callback) {
+            eachfn(arr, function (x, callback) {
+                iterator(x.value, function (err) {
+                    callback(err);
+                });
+            });
+        } else {
+            var results = [];
+            eachfn(arr, function (x, callback) {
+                iterator(x.value, function (err, v) {
+                    results[x.index] = v;
+                    callback(err);
+                });
+            }, function (err) {
+                callback(err, results);
+            });
+        }
+    };
+    async.map = doParallel(_asyncMap);
+    async.mapSeries = doSeries(_asyncMap);
+    async.mapLimit = function (arr, limit, iterator, callback) {
+        return _mapLimit(limit)(arr, iterator, callback);
+    };
+
+    var _mapLimit = function(limit) {
+        return doParallelLimit(limit, _asyncMap);
+    };
+
+    // reduce only has a series version, as doing reduce in parallel won't
+    // work in many situations.
+    async.reduce = function (arr, memo, iterator, callback) {
+        async.eachSeries(arr, function (x, callback) {
+            iterator(memo, x, function (err, v) {
+                memo = v;
+                callback(err);
+            });
+        }, function (err) {
+            callback(err, memo);
+        });
+    };
+    // inject alias
+    async.inject = async.reduce;
+    // foldl alias
+    async.foldl = async.reduce;
+
+    async.reduceRight = function (arr, memo, iterator, callback) {
+        var reversed = _map(arr, function (x) {
+            return x;
+        }).reverse();
+        async.reduce(reversed, memo, iterator, callback);
+    };
+    // foldr alias
+    async.foldr = async.reduceRight;
+
+    var _filter = function (eachfn, arr, iterator, callback) {
+        var results = [];
+        arr = _map(arr, function (x, i) {
+            return {index: i, value: x};
+        });
+        eachfn(arr, function (x, callback) {
+            iterator(x.value, function (v) {
+                if (v) {
+                    results.push(x);
+                }
+                callback();
+            });
+        }, function (err) {
+            callback(_map(results.sort(function (a, b) {
+                return a.index - b.index;
+            }), function (x) {
+                return x.value;
+            }));
+        });
+    };
+    async.filter = doParallel(_filter);
+    async.filterSeries = doSeries(_filter);
+    // select alias
+    async.select = async.filter;
+    async.selectSeries = async.filterSeries;
+
+    var _reject = function (eachfn, arr, iterator, callback) {
+        var results = [];
+        arr = _map(arr, function (x, i) {
+            return {index: i, value: x};
+        });
+        eachfn(arr, function (x, callback) {
+            iterator(x.value, function (v) {
+                if (!v) {
+                    results.push(x);
+                }
+                callback();
+            });
+        }, function (err) {
+            callback(_map(results.sort(function (a, b) {
+                return a.index - b.index;
+            }), function (x) {
+                return x.value;
+            }));
+        });
+    };
+    async.reject = doParallel(_reject);
+    async.rejectSeries = doSeries(_reject);
+
+    var _detect = function (eachfn, arr, iterator, main_callback) {
+        eachfn(arr, function (x, callback) {
+            iterator(x, function (result) {
+                if (result) {
+                    main_callback(x);
+                    main_callback = function () {};
+                }
+                else {
+                    callback();
+                }
+            });
+        }, function (err) {
+            main_callback();
+        });
+    };
+    async.detect = doParallel(_detect);
+    async.detectSeries = doSeries(_detect);
+
+    async.some = function (arr, iterator, main_callback) {
+        async.each(arr, function (x, callback) {
+            iterator(x, function (v) {
+                if (v) {
+                    main_callback(true);
+                    main_callback = function () {};
+                }
+                callback();
+            });
+        }, function (err) {
+            main_callback(false);
+        });
+    };
+    // any alias
+    async.any = async.some;
+
+    async.every = function (arr, iterator, main_callback) {
+        async.each(arr, function (x, callback) {
+            iterator(x, function (v) {
+                if (!v) {
+                    main_callback(false);
+                    main_callback = function () {};
+                }
+                callback();
+            });
+        }, function (err) {
+            main_callback(true);
+        });
+    };
+    // all alias
+    async.all = async.every;
+
+    async.sortBy = function (arr, iterator, callback) {
+        async.map(arr, function (x, callback) {
+            iterator(x, function (err, criteria) {
+                if (err) {
+                    callback(err);
+                }
+                else {
+                    callback(null, {value: x, criteria: criteria});
+                }
+            });
+        }, function (err, results) {
+            if (err) {
+                return callback(err);
+            }
+            else {
+                var fn = function (left, right) {
+                    var a = left.criteria, b = right.criteria;
+                    return a < b ? -1 : a > b ? 1 : 0;
+                };
+                callback(null, _map(results.sort(fn), function (x) {
+                    return x.value;
+                }));
+            }
+        });
+    };
+
+    async.auto = function (tasks, callback) {
+        callback = callback || function () {};
+        var keys = _keys(tasks);
+        var remainingTasks = keys.length
+        if (!remainingTasks) {
+            return callback();
+        }
+
+        var results = {};
+
+        var listeners = [];
+        var addListener = function (fn) {
+            listeners.unshift(fn);
+        };
+        var removeListener = function (fn) {
+            for (var i = 0; i < listeners.length; i += 1) {
+                if (listeners[i] === fn) {
+                    listeners.splice(i, 1);
+                    return;
+                }
+            }
+        };
+        var taskComplete = function () {
+            remainingTasks--
+            _each(listeners.slice(0), function (fn) {
+                fn();
+            });
+        };
+
+        addListener(function () {
+            if (!remainingTasks) {
+                var theCallback = callback;
+                // prevent final callback from calling itself if it errors
+                callback = function () {};
+
+                theCallback(null, results);
+            }
+        });
+
+        _each(keys, function (k) {
+            var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
+            var taskCallback = function (err) {
+                var args = Array.prototype.slice.call(arguments, 1);
+                if (args.length <= 1) {
+                    args = args[0];
+                }
+                if (err) {
+                    var safeResults = {};
+                    _each(_keys(results), function(rkey) {
+                        safeResults[rkey] = results[rkey];
+                    });
+                    safeResults[k] = args;
+                    callback(err, safeResults);
+                    // stop subsequent errors hitting callback multiple times
+                    callback = function () {};
+                }
+                else {
+                    results[k] = args;
+                    async.setImmediate(taskComplete);
+                }
+            };
+            var requires = task.slice(0, Math.abs(task.length - 1)) || [];
+            var ready = function () {
+                return _reduce(requires, function (a, x) {
+                    return (a && results.hasOwnProperty(x));
+                }, true) && !results.hasOwnProperty(k);
+            };
+            if (ready()) {
+                task[task.length - 1](taskCallback, results);
+            }
+            else {
+                var listener = function () {
+                    if (ready()) {
+                        removeListener(listener);
+                        task[task.length - 1](taskCallback, results);
+                    }
+                };
+                addListener(listener);
+            }
+        });
+    };
+
+    async.retry = function(times, task, callback) {
+        var DEFAULT_TIMES = 5;
+        var attempts = [];
+        // Use defaults if times not passed
+        if (typeof times === 'function') {
+            callback = task;
+            task = times;
+            times = DEFAULT_TIMES;
+        }
+        // Make sure times is a number
+        times = parseInt(times, 10) || DEFAULT_TIMES;
+        var wrappedTask = function(wrappedCallback, wrappedResults) {
+            var retryAttempt = function(task, finalAttempt) {
+                return function(seriesCallback) {
+                    task(function(err, result){
+                        seriesCallback(!err || finalAttempt, {err: err, 
result: result});
+                    }, wrappedResults);
+                };
+            };
+            while (times) {
+                attempts.push(retryAttempt(task, !(times-=1)));
+            }
+            async.series(attempts, function(done, data){
+                data = data[data.length - 1];
+                (wrappedCallback || callback)(data.err, data.result);
+            });
+        }
+        // If a callback is passed, run this as a controll flow
+        return callback ? wrappedTask() : wrappedTask
+    };
+
+    async.waterfall = function (tasks, callback) {
+        callback = callback || function () {};
+        if (!_isArray(tasks)) {
+          var err = new Error('First argument to waterfall must be an array of 
functions');
+          return callback(err);
+        }
+        if (!tasks.length) {
+            return callback();
+        }
+        var wrapIterator = function (iterator) {
+            return function (err) {
+                if (err) {
+                    callback.apply(null, arguments);
+                    callback = function () {};
+                }
+                else {
+                    var args = Array.prototype.slice.call(arguments, 1);
+                    var next = iterator.next();
+                    if (next) {
+                        args.push(wrapIterator(next));
+                    }
+                    else {
+                        args.push(callback);
+                    }
+                    async.setImmediate(function () {
+                        iterator.apply(null, args);
+                    });
+                }
+            };
+        };
+        wrapIterator(async.iterator(tasks))();
+    };
+
+    var _parallel = function(eachfn, tasks, callback) {
+        callback = callback || function () {};
+        if (_isArray(tasks)) {
+            eachfn.map(tasks, function (fn, callback) {
+                if (fn) {
+                    fn(function (err) {
+                        var args = Array.prototype.slice.call(arguments, 1);
+                        if (args.length <= 1) {
+                            args = args[0];
+                        }
+                        callback.call(null, err, args);
+                    });
+                }
+            }, callback);
+        }
+        else {
+            var results = {};
+            eachfn.each(_keys(tasks), function (k, callback) {
+                tasks[k](function (err) {
+                    var args = Array.prototype.slice.call(arguments, 1);
+                    if (args.length <= 1) {
+                        args = args[0];
+                    }
+                    results[k] = args;
+                    callback(err);
+                });
+            }, function (err) {
+                callback(err, results);
+            });
+        }
+    };
+
+    async.parallel = function (tasks, callback) {
+        _parallel({ map: async.map, each: async.each }, tasks, callback);
+    };
+
+    async.parallelLimit = function(tasks, limit, callback) {
+        _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, 
callback);
+    };
+
+    async.series = function (tasks, callback) {
+        callback = callback || function () {};
+        if (_isArray(tasks)) {
+            async.mapSeries(tasks, function (fn, callback) {
+                if (fn) {
+                    fn(function (err) {
+                        var args = Array.prototype.slice.call(arguments, 1);
+                        if (args.length <= 1) {
+                            args = args[0];
+                        }
+                        callback.call(null, err, args);
+                    });
+                }
+            }, callback);
+        }
+        else {
+            var results = {};
+            async.eachSeries(_keys(tasks), function (k, callback) {
+                tasks[k](function (err) {
+                    var args = Array.prototype.slice.call(arguments, 1);
+                    if (args.length <= 1) {
+                        args = args[0];
+                    }
+                    results[k] = args;
+                    callback(err);
+                });
+            }, function (err) {
+                callback(err, results);
+            });
+        }
+    };
+
+    async.iterator = function (tasks) {
+        var makeCallback = function (index) {
+            var fn = function () {
+                if (tasks.length) {
+                    tasks[index].apply(null, arguments);
+                }
+                return fn.next();
+            };
+            fn.next = function () {
+                return (index < tasks.length - 1) ? makeCallback(index + 1): 
null;
+            };
+            return fn;
+        };
+        return makeCallback(0);
+    };
+
+    async.apply = function (fn) {
+        var args = Array.prototype.slice.call(arguments, 1);
+        return function () {
+            return fn.apply(
+                null, args.concat(Array.prototype.slice.call(arguments))
+            );
+        };
+    };
+
+    var _concat = function (eachfn, arr, fn, callback) {
+        var r = [];
+        eachfn(arr, function (x, cb) {
+            fn(x, function (err, y) {
+                r = r.concat(y || []);
+                cb(err);
+            });
+        }, function (err) {
+            callback(err, r);
+        });
+    };
+    async.concat = doParallel(_concat);
+    async.concatSeries = doSeries(_concat);
+
+    async.whilst = function (test, iterator, callback) {
+        if (test()) {
+            iterator(function (err) {
+                if (err) {
+                    return callback(err);
+                }
+                async.whilst(test, iterator, callback);
+            });
+        }
+        else {
+            callback();
+        }
+    };
+
+    async.doWhilst = function (iterator, test, callback) {
+        iterator(function (err) {
+            if (err) {
+                return callback(err);
+            }
+            var args = Array.prototype.slice.call(arguments, 1);
+            if (test.apply(null, args)) {
+                async.doWhilst(iterator, test, callback);
+            }
+            else {
+                callback();
+            }
+        });
+    };
+
+    async.until = function (test, iterator, callback) {
+        if (!test()) {
+            iterator(function (err) {
+                if (err) {
+                    return callback(err);
+                }
+                async.until(test, iterator, callback);
+            });
+        }
+        else {
+            callback();
+        }
+    };
+
+    async.doUntil = function (iterator, test, callback) {
+        iterator(function (err) {
+            if (err) {
+                return callback(err);
+            }
+            var args = Array.prototype.slice.call(arguments, 1);
+            if (!test.apply(null, args)) {
+                async.doUntil(iterator, test, callback);
+            }
+            else {
+                callback();
+            }
+        });
+    };
+
+    async.queue = function (worker, concurrency) {
+        if (concurrency === undefined) {
+            concurrency = 1;
+        }
+        function _insert(q, data, pos, callback) {
+          if (!q.started){
+            q.started = true;
+          }
+          if (!_isArray(data)) {
+              data = [data];
+          }
+          if(data.length == 0) {
+             // call drain immediately if there are no tasks
+             return async.setImmediate(function() {
+                 if (q.drain) {
+                     q.drain();
+                 }
+             });
+          }
+          _each(data, function(task) {
+              var item = {
+                  data: task,
+                  callback: typeof callback === 'function' ? callback : null
+              };
+
+              if (pos) {
+                q.tasks.unshift(item);
+              } else {
+                q.tasks.push(item);
+              }
+
+              if (q.saturated && q.tasks.length === q.concurrency) {
+                  q.saturated();
+              }
+              async.setImmediate(q.process);
+          });
+        }
+
+        var workers = 0;
+        var q = {
+            tasks: [],
+            concurrency: concurrency,
+            saturated: null,
+            empty: null,
+            drain: null,
+            started: false,
+            paused: false,
+            push: function (data, callback) {
+              _insert(q, data, false, callback);
+            },
+            kill: function () {
+              q.drain = null;
+              q.tasks = [];
+            },
+            unshift: function (data, callback) {
+              _insert(q, data, true, callback);
+            },
+            process: function () {
+                if (!q.paused && workers < q.concurrency && q.tasks.length) {
+                    var task = q.tasks.shift();
+                    if (q.empty && q.tasks.length === 0) {
+                        q.empty();
+                    }
+                    workers += 1;
+                    var next = function () {
+                        workers -= 1;
+                        if (task.callback) {
+                            task.callback.apply(task, arguments);
+                        }
+                        if (q.drain && q.tasks.length + workers === 0) {
+                            q.drain();
+                        }
+                        q.process();
+                    };
+                    var cb = only_once(next);
+                    worker(task.data, cb);
+                }
+            },
+            length: function () {
+                return q.tasks.length;
+            },
+            running: function () {
+                return workers;
+            },
+            idle: function() {
+                return q.tasks.length + workers === 0;
+            },
+            pause: function () {
+                if (q.paused === true) { return; }
+                q.paused = true;
+                q.process();
+            },
+            resume: function () {
+                if (q.paused === false) { return; }
+                q.paused = false;
+                q.process();
+            }
+        };
+        return q;
+    };
+    
+    async.priorityQueue = function (worker, concurrency) {
+        
+        function _compareTasks(a, b){
+          return a.priority - b.priority;
+        };
+        
+        function _binarySearch(sequence, item, compare) {
+          var beg = -1,
+              end = sequence.length - 1;
+          while (beg < end) {
+            var mid = beg + ((end - beg + 1) >>> 1);
+            if (compare(item, sequence[mid]) >= 0) {
+              beg = mid;
+            } else {
+              end = mid - 1;
+            }
+          }
+          return beg;
+        }
+        
+        function _insert(q, data, priority, callback) {
+          if (!q.started){
+            q.started = true;
+          }
+          if (!_isArray(data)) {
+              data = [data];
+          }
+          if(data.length == 0) {
+             // call drain immediately if there are no tasks
+             return async.setImmediate(function() {
+                 if (q.drain) {
+                     q.drain();
+                 }
+             });
+          }
+          _each(data, function(task) {
+              var item = {
+                  data: task,
+                  priority: priority,
+                  callback: typeof callback === 'function' ? callback : null
+              };
+              
+              q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 
0, item);
+
+              if (q.saturated && q.tasks.length === q.concurrency) {
+                  q.saturated();
+              }
+              async.setImmediate(q.process);
+          });
+        }
+        
+        // Start with a normal queue
+        var q = async.queue(worker, concurrency);
+        
+        // Override push to accept second parameter representing priority
+        q.push = function (data, priority, callback) {
+          _insert(q, data, priority, callback);
+        };
+        
+        // Remove unshift function
+        delete q.unshift;
+
+        return q;
+    };
+
+    async.cargo = function (worker, payload) {
+        var working     = false,
+            tasks       = [];
+
+        var cargo = {
+            tasks: tasks,
+            payload: payload,
+            saturated: null,
+            empty: null,
+            drain: null,
+            drained: true,
+            push: function (data, callback) {
+                if (!_isArray(data)) {
+                    data = [data];
+                }
+                _each(data, function(task) {
+                    tasks.push({
+                        data: task,
+                        callback: typeof callback === 'function' ? callback : 
null
+                    });
+                    cargo.drained = false;
+                    if (cargo.saturated && tasks.length === payload) {
+                        cargo.saturated();
+                    }
+                });
+                async.setImmediate(cargo.process);
+            },
+            process: function process() {
+                if (working) return;
+                if (tasks.length === 0) {
+                    if(cargo.drain && !cargo.drained) cargo.drain();
+                    cargo.drained = true;
+                    return;
+                }
+
+                var ts = typeof payload === 'number'
+                            ? tasks.splice(0, payload)
+                            : tasks.splice(0, tasks.length);
+
+                var ds = _map(ts, function (task) {
+                    return task.data;
+                });
+
+                if(cargo.empty) cargo.empty();
+                working = true;
+                worker(ds, function () {
+                    working = false;
+
+                    var args = arguments;
+                    _each(ts, function (data) {
+                        if (data.callback) {
+                            data.callback.apply(null, args);
+                        }
+                    });
+
+                    process();
+                });
+            },
+            length: function () {
+                return tasks.length;
+            },
+            running: function () {
+                return working;
+            }
+        };
+        return cargo;
+    };
+
+    var _console_fn = function (name) {
+        return function (fn) {
+            var args = Array.prototype.slice.call(arguments, 1);
+            fn.apply(null, args.concat([function (err) {
+                var args = Array.prototype.slice.call(arguments, 1);
+                if (typeof console !== 'undefined') {
+                    if (err) {
+                        if (console.error) {
+                            console.error(err);
+                        }
+                    }
+                    else if (console[name]) {
+                        _each(args, function (x) {
+                            console[name](x);
+                        });
+                    }
+                }
+            }]));
+        };
+    };
+    async.log = _console_fn('log');
+    async.dir = _console_fn('dir');
+    /*async.info = _console_fn('info');
+    async.warn = _console_fn('warn');
+    async.error = _console_fn('error');*/
+
+    async.memoize = function (fn, hasher) {
+        var memo = {};
+        var queues = {};
+        hasher = hasher || function (x) {
+            return x;
+        };
+        var memoized = function () {
+            var args = Array.prototype.slice.call(arguments);
+            var callback = args.pop();
+            var key = hasher.apply(null, args);
+            if (key in memo) {
+                async.nextTick(function () {
+                    callback.apply(null, memo[key]);
+                });
+            }
+            else if (key in queues) {
+                queues[key].push(callback);
+            }
+            else {
+                queues[key] = [callback];
+                fn.apply(null, args.concat([function () {
+                    memo[key] = arguments;
+                    var q = queues[key];
+                    delete queues[key];
+                    for (var i = 0, l = q.length; i < l; i++) {
+                      q[i].apply(null, arguments);
+                    }
+                }]));
+            }
+        };
+        memoized.memo = memo;
+        memoized.unmemoized = fn;
+        return memoized;
+    };
+
+    async.unmemoize = function (fn) {
+      return function () {
+        return (fn.unmemoized || fn).apply(null, arguments);
+      };
+    };
+
+    async.times = function (count, iterator, callback) {
+        var counter = [];
+        for (var i = 0; i < count; i++) {
+            counter.push(i);
+        }
+        return async.map(counter, iterator, callback);
+    };
+
+    async.timesSeries = function (count, iterator, callback) {
+        var counter = [];
+        for (var i = 0; i < count; i++) {
+            counter.push(i);
+        }
+        return async.mapSeries(counter, iterator, callback);
+    };
+
+    async.seq = function (/* functions... */) {
+        var fns = arguments;
+        return function () {
+            var that = this;
+            var args = Array.prototype.slice.call(arguments);
+            var callback = args.pop();
+            async.reduce(fns, args, function (newargs, fn, cb) {
+                fn.apply(that, newargs.concat([function () {
+                    var err = arguments[0];
+                    var nextargs = Array.prototype.slice.call(arguments, 1);
+                    cb(err, nextargs);
+                }]))
+            },
+            function (err, results) {
+                callback.apply(that, [err].concat(results));
+            });
+        };
+    };
+
+    async.compose = function (/* functions... */) {
+      return async.seq.apply(null, Array.prototype.reverse.call(arguments));
+    };
+
+    var _applyEach = function (eachfn, fns /*args...*/) {
+        var go = function () {
+            var that = this;
+            var args = Array.prototype.slice.call(arguments);
+            var callback = args.pop();
+            return eachfn(fns, function (fn, cb) {
+                fn.apply(that, args.concat([cb]));
+            },
+            callback);
+        };
+        if (arguments.length > 2) {
+            var args = Array.prototype.slice.call(arguments, 2);
+            return go.apply(this, args);
+        }
+        else {
+            return go;
+        }
+    };
+    async.applyEach = doParallel(_applyEach);
+    async.applyEachSeries = doSeries(_applyEach);
+
+    async.forever = function (fn, callback) {
+        function next(err) {
+            if (err) {
+                if (callback) {
+                    return callback(err);
+                }
+                throw err;
+            }
+            fn(next);
+        }
+        next();
+    };
+
+    // Node.js
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = async;
+    }
+    // AMD / RequireJS
+    else if (typeof define !== 'undefined' && define.amd) {
+        define([], function () {
+            return async;
+        });
+    }
+    // included directly via <script> tag
+    else {
+        root.async = async;
+    }
+
+}());
diff --git a/packages/context-coloring/benchmark/fixtures/jquery-2.1.1.js 
b/packages/context-coloring/benchmark/fixtures/jquery-2.1.1.js
new file mode 100644
index 0000000..9f7b3d3
--- /dev/null
+++ b/packages/context-coloring/benchmark/fixtures/jquery-2.1.1.js
@@ -0,0 +1,9190 @@
+/*!
+ * jQuery JavaScript Library v2.1.1
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-05-01T17:11Z
+ */
+
+(function( global, factory ) {
+
+       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 inherently posses a window with 
a document
+               // (such as Node.js), expose a jQuery-making 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 );
+       }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//
+
+var arr = [];
+
+var slice = arr.slice;
+
+var concat = arr.concat;
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+       // Use the correct document accordingly with window argument (sandbox)
+       document = window.document,
+
+       version = "2.1.1",
+
+       // Define a local copy of jQuery
+       jQuery = function( selector, context ) {
+               // 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 );
+       },
+
+       // Support: Android<4.1
+       // Make sure we trim BOM and NBSP
+       rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+       // Matches dashed string for camelizing
+       rmsPrefix = /^-ms-/,
+       rdashAlpha = /-([\da-z])/gi,
+
+       // Used by jQuery.camelCase as callback to replace()
+       fcamelCase = function( all, letter ) {
+               return letter.toUpperCase();
+       };
+
+jQuery.fn = jQuery.prototype = {
+       // The current version of jQuery being used
+       jquery: version,
+
+       constructor: jQuery,
+
+       // Start with an empty selector
+       selector: "",
+
+       // The default length of a jQuery object is 0
+       length: 0,
+
+       toArray: function() {
+               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 just the one element from the set
+                       ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+                       // Return all the elements in a clean array
+                       slice.call( this );
+       },
+
+       // Take an array of elements and push it onto the stack
+       // (returning the new matched element set)
+       pushStack: function( 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;
+
+               // 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 );
+       },
+
+       map: function( callback ) {
+               return this.pushStack( jQuery.map(this, function( elem, i ) {
+                       return callback.call( elem, i, elem );
+               }));
+       },
+
+       slice: function() {
+               return this.pushStack( slice.apply( this, arguments ) );
+       },
+
+       first: function() {
+               return this.eq( 0 );
+       },
+
+       last: function() {
+               return this.eq( -1 );
+       },
+
+       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);
+       },
+
+       // For internal use only.
+       // Behaves like an Array's method, not like a jQuery method.
+       push: push,
+       sort: arr.sort,
+       splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+       var options, name, src, copy, copyIsArray, clone,
+               target = arguments[0] || {},
+               i = 1,
+               length = arguments.length,
+               deep = false;
+
+       // Handle a deep copy situation
+       if ( typeof target === "boolean" ) {
+               deep = target;
+
+               // 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) ) {
+               target = {};
+       }
+
+       // extend jQuery itself if only one argument is passed
+       if ( i === length ) {
+               target = this;
+               i--;
+       }
+
+       for ( ; i < length; i++ ) {
+               // Only deal with non-null/undefined values
+               if ( (options = arguments[ i ]) != null ) {
+                       // Extend the base object
+                       for ( name in options ) {
+                               src = target[ name ];
+                               copy = options[ name ];
+
+                               // Prevent never-ending loop
+                               if ( target === copy ) {
+                                       continue;
+                               }
+
+                               // Recurse if we're merging plain objects or 
arrays
+                               if ( deep && copy && ( 
jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+                                       if ( copyIsArray ) {
+                                               copyIsArray = false;
+                                               clone = src && 
jQuery.isArray(src) ? src : [];
+
+                                       } else {
+                                               clone = src && 
jQuery.isPlainObject(src) ? src : {};
+                                       }
+
+                                       // Never move original objects, clone 
them
+                                       target[ name ] = jQuery.extend( deep, 
clone, copy );
+
+                               // Don't bring in undefined values
+                               } else if ( copy !== undefined ) {
+                                       target[ name ] = copy;
+                               }
+                       }
+               }
+       }
+
+       // Return the modified object
+       return target;
+};
+
+jQuery.extend({
+       // Unique for each copy of jQuery on the page
+       expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+       // Assume jQuery is ready without the ready module
+       isReady: true,
+
+       error: function( msg ) {
+               throw new Error( msg );
+       },
+
+       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";
+       },
+
+       isArray: Array.isArray,
+
+       isWindow: function( obj ) {
+               return obj != null && obj === obj.window;
+       },
+
+       isNumeric: function( obj ) {
+               // parseFloat NaNs numeric-cast false positives 
(null|true|false|"")
+               // ...but misinterprets leading-number strings, particularly 
hex literals ("0x...")
+               // subtraction forces infinities to NaN
+               return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
+       },
+
+       isPlainObject: function( obj ) {
+               // Not plain objects:
+               // - Any object or value whose internal [[Class]] property is 
not "[object Object]"
+               // - DOM nodes
+               // - window
+               if ( jQuery.type( obj ) !== "object" || obj.nodeType || 
jQuery.isWindow( obj ) ) {
+                       return false;
+               }
+
+               if ( obj.constructor &&
+                               !hasOwn.call( obj.constructor.prototype, 
"isPrototypeOf" ) ) {
+                       return false;
+               }
+
+               // If the function hasn't returned already, we're confident that
+               // |obj| is a plain object, created by {} or constructed with 
new Object
+               return true;
+       },
+
+       isEmptyObject: function( obj ) {
+               var name;
+               for ( name in obj ) {
+                       return false;
+               }
+               return true;
+       },
+
+       type: function( obj ) {
+               if ( obj == null ) {
+                       return obj + "";
+               }
+               // Support: Android < 4.0, iOS < 6 (functionish RegExp)
+               return typeof obj === "object" || typeof obj === "function" ?
+                       class2type[ toString.call(obj) ] || "object" :
+                       typeof obj;
+       },
+
+       // Evaluates a script in a global context
+       globalEval: function( code ) {
+               var script,
+                       indirect = eval;
+
+               code = jQuery.trim( code );
+
+               if ( code ) {
+                       // If the code includes a valid, prologue position
+                       // strict mode pragma, execute code by injecting a
+                       // script tag into the document.
+                       if ( code.indexOf("use strict") === 1 ) {
+                               script = document.createElement("script");
+                               script.text = code;
+                               document.head.appendChild( script 
).parentNode.removeChild( script );
+                       } else {
+                       // Otherwise, avoid the DOM node creation, insertion
+                       // and removal by using an indirect global eval
+                               indirect( code );
+                       }
+               }
+       },
+
+       // Convert dashed to camelCase; used by the css and data modules
+       // 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.toLowerCase() === 
name.toLowerCase();
+       },
+
+       // args is for internal usage only
+       each: function( obj, callback, args ) {
+               var value,
+                       i = 0,
+                       length = obj.length,
+                       isArray = isArraylike( obj );
+
+               if ( args ) {
+                       if ( isArray ) {
+                               for ( ; i < length; i++ ) {
+                                       value = callback.apply( obj[ i ], args 
);
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( i in obj ) {
+                                       value = callback.apply( obj[ i ], args 
);
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+
+               // A special, fast, case for the most common use of each
+               } else {
+                       if ( isArray ) {
+                               for ( ; i < length; i++ ) {
+                                       value = callback.call( obj[ i ], i, 
obj[ i ] );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( i in obj ) {
+                                       value = callback.call( obj[ i ], i, 
obj[ i ] );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               return obj;
+       },
+
+       // Support: Android<4.1
+       trim: function( text ) {
+               return text == null ?
+                       "" :
+                       ( text + "" ).replace( rtrim, "" );
+       },
+
+       // results is for internal usage only
+       makeArray: function( arr, results ) {
+               var ret = results || [];
+
+               if ( arr != null ) {
+                       if ( isArraylike( Object(arr) ) ) {
+                               jQuery.merge( ret,
+                                       typeof arr === "string" ?
+                                       [ arr ] : arr
+                               );
+                       } else {
+                               push.call( ret, arr );
+                       }
+               }
+
+               return ret;
+       },
+
+       inArray: function( elem, arr, i ) {
+               return arr == null ? -1 : indexOf.call( arr, elem, i );
+       },
+
+       merge: function( first, second ) {
+               var len = +second.length,
+                       j = 0,
+                       i = first.length;
+
+               for ( ; j < len; j++ ) {
+                       first[ i++ ] = second[ j ];
+               }
+
+               first.length = i;
+
+               return first;
+       },
+
+       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 ( ; i < length; i++ ) {
+                       callbackInverse = !callback( elems[ i ], i );
+                       if ( callbackInverse !== callbackExpect ) {
+                               matches.push( elems[ i ] );
+                       }
+               }
+
+               return matches;
+       },
+
+       // arg is for internal usage only
+       map: function( elems, callback, arg ) {
+               var value,
+                       i = 0,
+                       length = elems.length,
+                       isArray = isArraylike( elems ),
+                       ret = [];
+
+               // Go through the array, translating each of the items to their 
new values
+               if ( isArray ) {
+                       for ( ; i < length; i++ ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret.push( value );
+                               }
+                       }
+
+               // Go through every key on the object,
+               } else {
+                       for ( i in elems ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret.push( value );
+                               }
+                       }
+               }
+
+               // Flatten any nested arrays
+               return concat.apply( [], ret );
+       },
+
+       // A global GUID counter for objects
+       guid: 1,
+
+       // Bind a function to a context, optionally partially applying any
+       // arguments.
+       proxy: function( fn, context ) {
+               var tmp, args, proxy;
+
+               if ( typeof context === "string" ) {
+                       tmp = fn[ context ];
+                       context = fn;
+                       fn = tmp;
+               }
+
+               // Quick check to determine if target is callable, in the spec
+               // this throws a TypeError, but we will just return undefined.
+               if ( !jQuery.isFunction( fn ) ) {
+                       return undefined;
+               }
+
+               // Simulated bind
+               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 || jQuery.guid++;
+
+               return proxy;
+       },
+
+       now: Date.now,
+
+       // jQuery.support is not used in Core but other projects attach their
+       // properties to it so it needs to exist.
+       support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object 
Error".split(" "), function(i, name) {
+       class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+       var length = obj.length,
+               type = jQuery.type( obj );
+
+       if ( type === "function" || jQuery.isWindow( obj ) ) {
+               return false;
+       }
+
+       if ( obj.nodeType === 1 && length ) {
+               return true;
+       }
+
+       return type === "array" || length === 0 ||
+               typeof length === "number" && length > 0 && ( length - 1 ) in 
obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v1.10.19
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-04-18
+ */
+(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" + -(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;
+       },
+
+       // General-purpose constants
+       strundefined = typeof undefined,
+       MAX_NEGATIVE = 1 << 31,
+
+       // Instance methods
+       hasOwn = ({}).hasOwnProperty,
+       arr = [],
+       pop = arr.pop,
+       push_native = arr.push,
+       push = arr.push,
+       slice = arr.slice,
+       // Use a stripped-down indexOf if we can't use a native one
+       indexOf = arr.indexOf || function( elem ) {
+               var i = 0,
+                       len = this.length;
+               for ( ; i < len; i++ ) {
+                       if ( this[i] === elem ) {
+                               return i;
+                       }
+               }
+               return -1;
+       },
+
+       booleans = 
"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+       // Regular expressions
+
+       // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+       whitespace = "[\\x20\\t\\r\\n\\f]",
+       // http://www.w3.org/TR/css3-syntax/#characters
+       characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+       // Loosely modeled on CSS identifier characters
+       // An unquoted value should be a CSS identifier 
http://www.w3.org/TR/css3-selectors/#attribute-selectors
+       // Proper syntax: 
http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+       identifier = characterEncoding.replace( "w", "w#" ),
+
+       // Attribute selectors: 
http://www.w3.org/TR/selectors/#attribute-selectors
+       attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + 
whitespace +
+               // Operator (capture 2)
+               "*([*^$|!~]?=)" + whitespace +
+               // "Attribute values must be CSS identifiers [capture 5] or 
strings [capture 3 or capture 4]"
+               "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + 
identifier + "))|)" + whitespace +
+               "*\\]",
+
+       pseudos = ":(" + characterEncoding + ")(?:\\((" +
+               // 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)
+               ".*" +
+               ")\\)|)",
+
+       // Leading and non-escaped trailing whitespace, capturing some 
non-whitespace characters preceding the latter
+       rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + 
whitespace + "+$", "g" ),
+
+       rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+       rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + 
")" + whitespace + "*" ),
+
+       rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + 
whitespace + "*\\]", "g" ),
+
+       rpseudo = new RegExp( pseudos ),
+       ridentifier = new RegExp( "^" + identifier + "$" ),
+
+       matchExpr = {
+               "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+               "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+               "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" 
) + ")" ),
+               "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" )
+       },
+
+       rinputs = /^(?:input|select|textarea|button)$/i,
+       rheader = /^h\d$/i,
+
+       rnative = /^[^{]+\{\s*\[native \w/,
+
+       // Easily-parseable/retrievable ID or TAG or CLASS selectors
+       rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+       rsibling = /[+~]/,
+       rescape = /'|\\/g,
+
+       // 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 );
+       };
+
+// 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) );
+               } :
+
+               // 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;
+               }
+       };
+}
+
+function Sizzle( selector, context, results, seed ) {
+       var match, elem, m, nodeType,
+               // QSA vars
+               i, groups, old, nid, newContext, newSelector;
+
+       if ( ( context ? context.ownerDocument || context : preferredDoc ) !== 
document ) {
+               setDocument( context );
+       }
+
+       context = context || document;
+       results = results || [];
+
+       if ( !selector || typeof selector !== "string" ) {
+               return results;
+       }
+
+       if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+               return [];
+       }
+
+       if ( documentIsHTML && !seed ) {
+
+               // Shortcuts
+               if ( (match = rquickExpr.exec( selector )) ) {
+                       // Speed-up: Sizzle("#ID")
+                       if ( (m = match[1]) ) {
+                               if ( nodeType === 9 ) {
+                                       elem = context.getElementById( m );
+                                       // Check parentNode to catch when 
Blackberry 4.6 returns
+                                       // nodes that are no longer in the 
document (jQuery #6963)
+                                       if ( elem && elem.parentNode ) {
+                                               // Handle the case where IE, 
Opera, and Webkit return items
+                                               // by name instead of ID
+                                               if ( elem.id === m ) {
+                                                       results.push( elem );
+                                                       return results;
+                                               }
+                                       } else {
+                                               return results;
+                                       }
+                               } else {
+                                       // Context is not a document
+                                       if ( context.ownerDocument && (elem = 
context.ownerDocument.getElementById( m )) &&
+                                               contains( context, elem ) && 
elem.id === m ) {
+                                               results.push( elem );
+                                               return results;
+                                       }
+                               }
+
+                       // Speed-up: Sizzle("TAG")
+                       } else if ( match[2] ) {
+                               push.apply( results, 
context.getElementsByTagName( selector ) );
+                               return results;
+
+                       // Speed-up: Sizzle(".CLASS")
+                       } else if ( (m = match[3]) && 
support.getElementsByClassName && context.getElementsByClassName ) {
+                               push.apply( results, 
context.getElementsByClassName( m ) );
+                               return results;
+                       }
+               }
+
+               // QSA path
+               if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) 
) {
+                       nid = old = expando;
+                       newContext = context;
+                       newSelector = nodeType === 9 && selector;
+
+                       // qSA works strangely on Element-rooted queries
+                       // We can work around this by specifying an extra ID on 
the root
+                       // and working up from there (Thanks to Andrew Dupont 
for the technique)
+                       // IE 8 doesn't work on object elements
+                       if ( nodeType === 1 && context.nodeName.toLowerCase() 
!== "object" ) {
+                               groups = tokenize( selector );
+
+                               if ( (old = context.getAttribute("id")) ) {
+                                       nid = old.replace( rescape, "\\$&" );
+                               } else {
+                                       context.setAttribute( "id", nid );
+                               }
+                               nid = "[id='" + nid + "'] ";
+
+                               i = groups.length;
+                               while ( i-- ) {
+                                       groups[i] = nid + toSelector( groups[i] 
);
+                               }
+                               newContext = rsibling.test( selector ) && 
testContext( context.parentNode ) || context;
+                               newSelector = groups.join(",");
+                       }
+
+                       if ( newSelector ) {
+                               try {
+                                       push.apply( results,
+                                               newContext.querySelectorAll( 
newSelector )
+                                       );
+                                       return results;
+                               } catch(qsaError) {
+                               } finally {
+                                       if ( !old ) {
+                                               context.removeAttribute("id");
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // 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;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+       fn[ expando ] = true;
+       return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+       var div = document.createElement("div");
+
+       try {
+               return !!fn( div );
+       } catch (e) {
+               return false;
+       } finally {
+               // Remove from its parent by default
+               if ( div.parentNode ) {
+                       div.parentNode.removeChild( div );
+               }
+               // release memory in IE
+               div = null;
+       }
+}
+
+/**
+ * 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 = attrs.length;
+
+       while ( i-- ) {
+               Expr.attrHandle[ arr[i] ] = handler;
+       }
+}
+
+/**
+ * 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 &&
+                       ( ~b.sourceIndex || MAX_NEGATIVE ) -
+                       ( ~a.sourceIndex || MAX_NEGATIVE );
+
+       // Use IE sourceIndex if available on both nodes
+       if ( diff ) {
+               return diff;
+       }
+
+       // Check if b follows a
+       if ( cur ) {
+               while ( (cur = cur.nextSibling) ) {
+                       if ( cur === b ) {
+                               return -1;
+                       }
+               }
+       }
+
+       return a ? 1 : -1;
+}
+
+/**
+ * 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;
+       };
+}
+
+/**
+ * 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;
+       };
+}
+
+/**
+ * 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;
+
+                       // Match elements found at the specified indexes
+                       while ( i-- ) {
+                               if ( seed[ (j = matchIndexes[i]) ] ) {
+                                       seed[j] = !(matches[j] = seed[j]);
+                               }
+                       }
+               });
+       });
+}
+
+/**
+ * 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 !== strundefined 
&& context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * 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;
+};
+
+/**
+ * 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,
+               doc = node ? node.ownerDocument || node : preferredDoc,
+               parent = doc.defaultView;
+
+       // If no document and documentElement is available, return
+       if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+               return document;
+       }
+
+       // Set our document
+       document = doc;
+       docElem = doc.documentElement;
+
+       // Support tests
+       documentIsHTML = !isXML( doc );
+
+       // Support: IE>8
+       // If iframe document is assigned to "document" variable and if iframe 
has been reloaded,
+       // IE will throw "permission denied" error when accessing "document" 
variable, see jQuery #13936
+       // IE6-8 do not support the defaultView property so parent will be 
undefined
+       if ( parent && parent !== parent.top ) {
+               // IE11 does not have attachEvent, so all must suffer
+               if ( parent.addEventListener ) {
+                       parent.addEventListener( "unload", function() {
+                               setDocument();
+                       }, false );
+               } else if ( parent.attachEvent ) {
+                       parent.attachEvent( "onunload", function() {
+                               setDocument();
+                       });
+               }
+       }
+
+       /* Attributes
+       ---------------------------------------------------------------------- 
*/
+
+       // Support: IE<8
+       // Verify that getAttribute really returns attributes and not 
properties (excepting IE8 booleans)
+       support.attributes = assert(function( div ) {
+               div.className = "i";
+               return !div.getAttribute("className");
+       });
+
+       /* getElement(s)By*
+       ---------------------------------------------------------------------- 
*/
+
+       // Check if getElementsByTagName("*") returns only elements
+       support.getElementsByTagName = assert(function( div ) {
+               div.appendChild( doc.createComment("") );
+               return !div.getElementsByTagName("*").length;
+       });
+
+       // Check if getElementsByClassName can be trusted
+       support.getElementsByClassName = rnative.test( 
doc.getElementsByClassName ) && assert(function( div ) {
+               div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+               // Support: Safari<4
+               // Catch class over-caching
+               div.firstChild.className = "i";
+               // Support: Opera<10
+               // Catch gEBCN failure to find non-leading classes
+               return div.getElementsByClassName("i").length === 2;
+       });
+
+       // Support: IE<10
+       // Check if getElementById returns elements by name
+       // The broken getElementById methods don't pick up programatically-set 
names,
+       // so use a roundabout getElementsByName test
+       support.getById = assert(function( div ) {
+               docElem.appendChild( div ).id = expando;
+               return !doc.getElementsByName || !doc.getElementsByName( 
expando ).length;
+       });
+
+       // ID find and filter
+       if ( support.getById ) {
+               Expr.find["ID"] = function( id, context ) {
+                       if ( typeof context.getElementById !== strundefined && 
documentIsHTML ) {
+                               var m = context.getElementById( id );
+                               // Check parentNode to catch when Blackberry 
4.6 returns
+                               // nodes that are no longer in the document 
#6963
+                               return m && m.parentNode ? [ m ] : [];
+                       }
+               };
+               Expr.filter["ID"] = function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               return elem.getAttribute("id") === attrId;
+                       };
+               };
+       } else {
+               // Support: IE6/7
+               // getElementById is not reliable as a find shortcut
+               delete Expr.find["ID"];
+
+               Expr.filter["ID"] =  function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               var node = typeof elem.getAttributeNode !== 
strundefined && elem.getAttributeNode("id");
+                               return node && node.value === attrId;
+                       };
+               };
+       }
+
+       // Tag
+       Expr.find["TAG"] = support.getElementsByTagName ?
+               function( tag, context ) {
+                       if ( typeof context.getElementsByTagName !== 
strundefined ) {
+                               return context.getElementsByTagName( tag );
+                       }
+               } :
+               function( tag, context ) {
+                       var elem,
+                               tmp = [],
+                               i = 0,
+                               results = context.getElementsByTagName( tag );
+
+                       // Filter out possible comments
+                       if ( tag === "*" ) {
+                               while ( (elem = results[i++]) ) {
+                                       if ( elem.nodeType === 1 ) {
+                                               tmp.push( elem );
+                                       }
+                               }
+
+                               return tmp;
+                       }
+                       return results;
+               };
+
+       // Class
+       Expr.find["CLASS"] = support.getElementsByClassName && function( 
className, context ) {
+               if ( typeof context.getElementsByClassName !== strundefined && 
documentIsHTML ) {
+                       return context.getElementsByClassName( className );
+               }
+       };
+
+       /* QSA/matchesSelector
+       ---------------------------------------------------------------------- 
*/
+
+       // QSA and matchesSelector support
+
+       // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+       rbuggyMatches = [];
+
+       // 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 http://bugs.jquery.com/ticket/13378
+       rbuggyQSA = [];
+
+       if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+               // Build QSA regex
+               // Regex strategy adopted from Diego Perini
+               assert(function( div ) {
+                       // 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
+                       // http://bugs.jquery.com/ticket/12359
+                       div.innerHTML = "<select msallowclip=''><option 
selected=''></option></select>";
+
+                       // 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
+                       // 
http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+                       if ( div.querySelectorAll("[msallowclip^='']").length ) 
{
+                               rbuggyQSA.push( "[*^$]=" + whitespace + 
"*(?:''|\"\")" );
+                       }
+
+                       // Support: IE8
+                       // Boolean attributes and "value" are not treated 
correctly
+                       if ( !div.querySelectorAll("[selected]").length ) {
+                               rbuggyQSA.push( "\\[" + whitespace + 
"*(?:value|" + booleans + ")" );
+                       }
+
+                       // 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 ( !div.querySelectorAll(":checked").length ) {
+                               rbuggyQSA.push(":checked");
+                       }
+               });
+
+               assert(function( div ) {
+                       // Support: Windows 8 Native Apps
+                       // The type and name attributes are restricted during 
.innerHTML assignment
+                       var input = doc.createElement("input");
+                       input.setAttribute( "type", "hidden" );
+                       div.appendChild( input ).setAttribute( "name", "D" );
+
+                       // Support: IE8
+                       // Enforce case-sensitivity of name attribute
+                       if ( div.querySelectorAll("[name=d]").length ) {
+                               rbuggyQSA.push( "name" + whitespace + 
"*[*^$|!~]?=" );
+                       }
+
+                       // FF 3.5 - :enabled/:disabled and hidden elements 
(hidden elements are still enabled)
+                       // IE8 throws error here and will not see later tests
+                       if ( !div.querySelectorAll(":enabled").length ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
+
+                       // Opera 10-11 does not throw on post-comma invalid 
pseudos
+                       div.querySelectorAll("*,:x");
+                       rbuggyQSA.push(",.*:");
+               });
+       }
+
+       if ( (support.matchesSelector = rnative.test( (matches = 
docElem.matches ||
+               docElem.webkitMatchesSelector ||
+               docElem.mozMatchesSelector ||
+               docElem.oMatchesSelector ||
+               docElem.msMatchesSelector) )) ) {
+
+               assert(function( div ) {
+                       // Check to see if it's possible to do matchesSelector
+                       // on a disconnected node (IE 9)
+                       support.disconnectedMatch = matches.call( div, "div" );
+
+                       // This should fail with an exception
+                       // Gecko does not error, returns false instead
+                       matches.call( div, "[s!='']:x" );
+                       rbuggyMatches.push( "!=", pseudos );
+               });
+       }
+
+       rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+       rbuggyMatches = rbuggyMatches.length && new RegExp( 
rbuggyMatches.join("|") );
+
+       /* Contains
+       ---------------------------------------------------------------------- 
*/
+       hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+       // Element contains another
+       // Purposefully does not implement inclusive descendent
+       // 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;
+                                       }
+                               }
+                       }
+                       return false;
+               };
+
+       /* Sorting
+       ---------------------------------------------------------------------- 
*/
+
+       // Document order sorting
+       sortOrder = hasCompare ?
+       function( a, b ) {
+
+               // Flag for duplicate removal
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               // Sort on method existence if only one input has 
compareDocumentPosition
+               var compare = !a.compareDocumentPosition - 
!b.compareDocumentPosition;
+               if ( compare ) {
+                       return compare;
+               }
+
+               // Calculate position if both inputs belong to the same document
+               compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) 
?
+                       a.compareDocumentPosition( b ) :
+
+                       // Otherwise we know they are disconnected
+                       1;
+
+               // Disconnected nodes
+               if ( compare & 1 ||
+                       (!support.sortDetached && b.compareDocumentPosition( a 
) === compare) ) {
+
+                       // Choose the first element that is related to our 
preferred document
+                       if ( a === doc || a.ownerDocument === preferredDoc && 
contains(preferredDoc, a) ) {
+                               return -1;
+                       }
+                       if ( b === doc || b.ownerDocument === preferredDoc && 
contains(preferredDoc, b) ) {
+                               return 1;
+                       }
+
+                       // Maintain original order
+                       return sortInput ?
+                               ( indexOf.call( sortInput, a ) - indexOf.call( 
sortInput, b ) ) :
+                               0;
+               }
+
+               return compare & 4 ? -1 : 1;
+       } :
+       function( a, b ) {
+               // Exit early if the nodes are identical
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               var cur,
+                       i = 0,
+                       aup = a.parentNode,
+                       bup = b.parentNode,
+                       ap = [ a ],
+                       bp = [ b ];
+
+               // Parentless nodes are either documents or disconnected
+               if ( !aup || !bup ) {
+                       return a === doc ? -1 :
+                               b === doc ? 1 :
+                               aup ? -1 :
+                               bup ? 1 :
+                               sortInput ?
+                               ( indexOf.call( sortInput, a ) - indexOf.call( 
sortInput, b ) ) :
+                               0;
+
+               // If the nodes are siblings, we can do a quick check
+               } else if ( aup === bup ) {
+                       return siblingCheck( a, b );
+               }
+
+               // 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 );
+               }
+
+               // Walk down the tree looking for a discrepancy
+               while ( ap[i] === bp[i] ) {
+                       i++;
+               }
+
+               return i ?
+                       // Do a sibling check if the nodes have a common 
ancestor
+                       siblingCheck( ap[i], bp[i] ) :
+
+                       // Otherwise nodes in our document sort first
+                       ap[i] === preferredDoc ? -1 :
+                       bp[i] === preferredDoc ? 1 :
+                       0;
+       };
+
+       return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+       return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
+
+       // Make sure that attribute selectors are quoted
+       expr = expr.replace( rattributeQuotes, "='$1']" );
+
+       if ( support.matchesSelector && documentIsHTML &&
+               ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+               ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
+
+               try {
+                       var ret = matches.call( elem, expr );
+
+                       // 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) {}
+       }
+
+       return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+       // Set document vars if needed
+       if ( ( context.ownerDocument || context ) !== document ) {
+               setDocument( context );
+       }
+       return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
+
+       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;
+
+       return val !== undefined ?
+               val :
+               support.attributes || !documentIsHTML ?
+                       elem.getAttribute( name ) :
+                       (val = elem.getAttributeNode(name)) && val.specified ?
+                               val.value :
+                               null;
+};
+
+Sizzle.error = function( msg ) {
+       throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+       var elem,
+               duplicates = [],
+               j = 0,
+               i = 0;
+
+       // 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 );
+               }
+       }
+
+       // Clear input after sorting to release objects
+       // See https://github.com/jquery/sizzle/pull/225
+       sortInput = null;
+
+       return results;
+};
+
+/**
+ * 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 );
+               }
+       } 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 ret;
+};
+
+Expr = Sizzle.selectors = {
+
+       // Can be adjusted by the user
+       cacheLength: 50,
+
+       createPseudo: markFunction,
+
+       match: matchExpr,
+
+       attrHandle: {},
+
+       find: {},
+
+       relative: {
+               ">": { dir: "parentNode", first: true },
+               " ": { dir: "parentNode" },
+               "+": { dir: "previousSibling", first: true },
+               "~": { dir: "previousSibling" }
+       },
+
+       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] + " ";
+                       }
+
+                       return match.slice( 0, 4 );
+               },
+
+               "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 match;
+               },
+
+               "PSEUDO": function( match ) {
+                       var excess,
+                               unquoted = !match[6] && match[2];
+
+                       if ( matchExpr["CHILD"].test( match[0] ) ) {
+                               return null;
+                       }
+
+                       // 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 );
+                       }
+
+                       // Return only captures needed by the pseudo filter 
method (type and argument)
+                       return match.slice( 0, 3 );
+               }
+       },
+
+       filter: {
+
+               "TAG": function( nodeNameSelector ) {
+                       var nodeName = nodeNameSelector.replace( runescape, 
funescape ).toLowerCase();
+                       return nodeNameSelector === "*" ?
+                               function() { return true; } :
+                               function( elem ) {
+                                       return elem.nodeName && 
elem.nodeName.toLowerCase() === nodeName;
+                               };
+               },
+
+               "CLASS": function( className ) {
+                       var pattern = classCache[ className + " " ];
+
+                       return pattern ||
+                               (pattern = new RegExp( "(^|" + whitespace + ")" 
+ className + "(" + whitespace + "|$)" )) &&
+                               classCache( className, function( elem ) {
+                                       return pattern.test( typeof 
elem.className === "string" && elem.className || typeof elem.getAttribute !== 
strundefined && elem.getAttribute("class") || "" );
+                               });
+               },
+
+               "ATTR": function( name, operator, check ) {
+                       return function( elem ) {
+                               var result = Sizzle.attr( elem, name );
+
+                               if ( result == null ) {
+                                       return operator === "!=";
+                               }
+                               if ( !operator ) {
+                                       return true;
+                               }
+
+                               result += "";
+
+                               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 + " 
" ).indexOf( check ) > -1 :
+                                       operator === "|=" ? result === check || 
result.slice( 0, check.length + 1 ) === check + "-" :
+                                       false;
+                       };
+               },
+
+               "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, outerCache, node, diff, 
nodeIndex, start,
+                                               dir = simple !== forward ? 
"nextSibling" : "previousSibling",
+                                               parent = elem.parentNode,
+                                               name = ofType && 
elem.nodeName.toLowerCase(),
+                                               useCache = !xml && !ofType;
+
+                                       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 ) {
+                                                       // Seek `elem` from a 
previously-cached index
+                                                       outerCache = parent[ 
expando ] || (parent[ expando ] = {});
+                                                       cache = outerCache[ 
type ] || [];
+                                                       nodeIndex = cache[0] 
=== dirruns && cache[1];
+                                                       diff = cache[0] === 
dirruns && cache[2];
+                                                       node = nodeIndex && 
parent.childNodes[ nodeIndex ];
+
+                                                       while ( (node = 
++nodeIndex && node && node[ dir ] ||
+
+                                                               // Fallback to 
seeking `elem` from the start
+                                                               (diff = 
nodeIndex = 0) || start.pop()) ) {
+
+                                                               // When found, 
cache indexes on `parent` and break
+                                                               if ( 
node.nodeType === 1 && ++diff && node === elem ) {
+                                                                       
outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+                                                                       break;
+                                                               }
+                                                       }
+
+                                               // Use previously-cached 
element index if available
+                                               } else if ( useCache && (cache 
= (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns 
) {
+                                                       diff = cache[1];
+
+                                               // xml :nth-child(...) or 
:nth-last-child(...) or :nth(-last)?-of-type(...)
+                                               } else {
+                                                       // Use the same loop as 
above to seek `elem` from the start
+                                                       while ( (node = 
++nodeIndex && node && node[ dir ] ||
+                                                               (diff = 
nodeIndex = 0) || start.pop()) ) {
+
+                                                               if ( ( ofType ? 
node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+                                                                       // 
Cache the index of each encountered element
+                                                                       if ( 
useCache ) {
+                                                                               
(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+                                                                       }
+
+                                                                       if ( 
node === elem ) {
+                                                                               
break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+
+                                               // Incorporate the offset, then 
check against cycle size
+                                               diff -= last;
+                                               return diff === first || ( diff 
% first === 0 && diff / first >= 0 );
+                                       }
+                               };
+               },
+
+               "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.call( 
seed, matched[i] );
+                                                       seed[ idx ] = !( 
matches[ idx ] = matched[i] );
+                                               }
+                                       }) :
+                                       function( elem ) {
+                                               return fn( elem, 0, args );
+                                       };
+                       }
+
+                       return fn;
+               }
+       },
+
+       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" ) );
+
+                       return matcher[ expando ] ?
+                               markFunction(function( seed, matches, context, 
xml ) {
+                                       var elem,
+                                               unmatched = matcher( seed, 
null, xml, [] ),
+                                               i = seed.length;
+
+                                       // Match elements unmatched by `matcher`
+                                       while ( i-- ) {
+                                               if ( (elem = unmatched[i]) ) {
+                                                       seed[i] = !(matches[i] 
= elem);
+                                               }
+                                       }
+                               }) :
+                               function( elem, context, xml ) {
+                                       input[0] = elem;
+                                       matcher( input, null, xml, results );
+                                       return !results.pop();
+                               };
+               }),
+
+               "has": markFunction(function( selector ) {
+                       return function( elem ) {
+                               return Sizzle( selector, elem ).length > 0;
+                       };
+               }),
+
+               "contains": markFunction(function( text ) {
+                       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 function( elem ) {
+                               var elemLang;
+                               do {
+                                       if ( (elemLang = documentIsHTML ?
+                                               elem.lang :
+                                               elem.getAttribute("xml:lang") 
|| elem.getAttribute("lang")) ) {
+
+                                               elemLang = 
elemLang.toLowerCase();
+                                               return elemLang === lang || 
elemLang.indexOf( lang + "-" ) === 0;
+                                       }
+                               } while ( (elem = elem.parentNode) && 
elem.nodeType === 1 );
+                               return false;
+                       };
+               }),
+
+               // Miscellaneous
+               "target": function( elem ) {
+                       var hash = window.location && window.location.hash;
+                       return hash && hash.slice( 1 ) === elem.id;
+               },
+
+               "root": function( elem ) {
+                       return elem === docElem;
+               },
+
+               "focus": function( elem ) {
+                       return elem === document.activeElement && 
(!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || 
~elem.tabIndex);
+               },
+
+               // Boolean properties
+               "enabled": function( elem ) {
+                       return elem.disabled === false;
+               },
+
+               "disabled": function( elem ) {
+                       return elem.disabled === true;
+               },
+
+               "checked": function( elem ) {
+                       // In CSS3, :checked should return both checked and 
selected elements
+                       // 
http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       var nodeName = elem.nodeName.toLowerCase();
+                       return (nodeName === "input" && !!elem.checked) || 
(nodeName === "option" && !!elem.selected);
+               },
+
+               "selected": function( elem ) {
+                       // Accessing this property makes selected-by-default
+                       // options in Safari work properly
+                       if ( elem.parentNode ) {
+                               elem.parentNode.selectedIndex;
+                       }
+
+                       return elem.selected === true;
+               },
+
+               // Contents
+               "empty": function( elem ) {
+                       // http://www.w3.org/TR/selectors/#empty-pseudo
+                       // :empty is negated by element (1) or content nodes 
(text: 3; cdata: 4; entity ref: 5),
+                       //   but not by others (comment: 8; processing 
instruction: 7; etc.)
+                       // nodeType < 6 works because attributes (2) do not 
appear as children
+                       for ( elem = elem.firstChild; elem; elem = 
elem.nextSibling ) {
+                               if ( elem.nodeType < 6 ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               },
+
+               "parent": function( elem ) {
+                       return !Expr.pseudos["empty"]( elem );
+               },
+
+               // Element/input types
+               "header": function( elem ) {
+                       return rheader.test( elem.nodeName );
+               },
+
+               "input": function( elem ) {
+                       return rinputs.test( elem.nodeName );
+               },
+
+               "button": function( elem ) {
+                       var name = elem.nodeName.toLowerCase();
+                       return name === "input" && elem.type === "button" || 
name === "button";
+               },
+
+               "text": function( elem ) {
+                       var attr;
+                       return elem.nodeName.toLowerCase() === "input" &&
+                               elem.type === "text" &&
+
+                               // Support: IE<8
+                               // New HTML5 attribute values (e.g., "search") 
appear with elem.type === "text"
+                               ( (attr = elem.getAttribute("type")) == null || 
attr.toLowerCase() === "text" );
+               },
+
+               // Position-in-collection
+               "first": createPositionalPseudo(function() {
+                       return [ 0 ];
+               }),
+
+               "last": createPositionalPseudo(function( matchIndexes, length ) 
{
+                       return [ length - 1 ];
+               }),
+
+               "eq": createPositionalPseudo(function( matchIndexes, length, 
argument ) {
+                       return [ argument < 0 ? argument + length : argument ];
+               }),
+
+               "even": createPositionalPseudo(function( matchIndexes, length ) 
{
+                       var i = 0;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "odd": createPositionalPseudo(function( matchIndexes, length ) {
+                       var i = 1;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "lt": createPositionalPseudo(function( matchIndexes, length, 
argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; --i >= 0; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "gt": createPositionalPseudo(function( matchIndexes, length, 
argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; ++i < length; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               })
+       }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: 
true } ) {
+       Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+       Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+       var matched, match, tokens, type,
+               soFar, groups, preFilters,
+               cached = tokenCache[ selector + " " ];
+
+       if ( cached ) {
+               return parseOnly ? 0 : cached.slice( 0 );
+       }
+
+       soFar = selector;
+       groups = [];
+       preFilters = Expr.preFilter;
+
+       while ( soFar ) {
+
+               // Comma and first run
+               if ( !matched || (match = rcomma.exec( soFar )) ) {
+                       if ( match ) {
+                               // Don't consume trailing commas as valid
+                               soFar = soFar.slice( match[0].length ) || soFar;
+                       }
+                       groups.push( (tokens = []) );
+               }
+
+               matched = false;
+
+               // Combinators
+               if ( (match = rcombinators.exec( soFar )) ) {
+                       matched = match.shift();
+                       tokens.push({
+                               value: matched,
+                               // Cast descendant combinators to space
+                               type: match[0].replace( rtrim, " " )
+                       });
+                       soFar = soFar.slice( matched.length );
+               }
+
+               // Filters
+               for ( type in Expr.filter ) {
+                       if ( (match = matchExpr[ type ].exec( soFar )) && 
(!preFilters[ type ] ||
+                               (match = preFilters[ type ]( match ))) ) {
+                               matched = match.shift();
+                               tokens.push({
+                                       value: matched,
+                                       type: type,
+                                       matches: match
+                               });
+                               soFar = soFar.slice( matched.length );
+                       }
+               }
+
+               if ( !matched ) {
+                       break;
+               }
+       }
+
+       // Return the length of the invalid excess
+       // if we're just parsing
+       // Otherwise, throw an error or return tokens
+       return parseOnly ?
+               soFar.length :
+               soFar ?
+                       Sizzle.error( selector ) :
+                       // Cache the tokens
+                       tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+       var i = 0,
+               len = tokens.length,
+               selector = "";
+       for ( ; i < len; i++ ) {
+               selector += tokens[i].value;
+       }
+       return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+       var dir = combinator.dir,
+               checkNonElements = base && dir === "parentNode",
+               doneName = done++;
+
+       return combinator.first ?
+               // Check against closest ancestor/preceding element
+               function( elem, context, xml ) {
+                       while ( (elem = elem[ dir ]) ) {
+                               if ( elem.nodeType === 1 || checkNonElements ) {
+                                       return matcher( elem, context, xml );
+                               }
+                       }
+               } :
+
+               // Check against all ancestor/preceding elements
+               function( elem, context, xml ) {
+                       var oldCache, outerCache,
+                               newCache = [ dirruns, doneName ];
+
+                       // We can't set arbitrary data on XML nodes, so they 
don't benefit from dir caching
+                       if ( xml ) {
+                               while ( (elem = elem[ dir ]) ) {
+                                       if ( elem.nodeType === 1 || 
checkNonElements ) {
+                                               if ( matcher( elem, context, 
xml ) ) {
+                                                       return true;
+                                               }
+                                       }
+                               }
+                       } else {
+                               while ( (elem = elem[ dir ]) ) {
+                                       if ( elem.nodeType === 1 || 
checkNonElements ) {
+                                               outerCache = elem[ expando ] || 
(elem[ expando ] = {});
+                                               if ( (oldCache = outerCache[ 
dir ]) &&
+                                                       oldCache[ 0 ] === 
dirruns && oldCache[ 1 ] === doneName ) {
+
+                                                       // Assign to newCache 
so results back-propagate to previous elements
+                                                       return (newCache[ 2 ] = 
oldCache[ 2 ]);
+                                               } else {
+                                                       // Reuse newcache so 
results back-propagate to previous elements
+                                                       outerCache[ dir ] = 
newCache;
+
+                                                       // A match means we're 
done; a fail means we have to keep checking
+                                                       if ( (newCache[ 2 ] = 
matcher( elem, context, xml )) ) {
+                                                               return true;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               };
+}
+
+function elementMatcher( matchers ) {
+       return matchers.length > 1 ?
+               function( elem, context, xml ) {
+                       var i = matchers.length;
+                       while ( i-- ) {
+                               if ( !matchers[i]( elem, context, xml ) ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               } :
+               matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+       var i = 0,
+               len = contexts.length;
+       for ( ; i < len; i++ ) {
+               Sizzle( selector, contexts[i], results );
+       }
+       return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+       var elem,
+               newUnmatched = [],
+               i = 0,
+               len = unmatched.length,
+               mapped = map != null;
+
+       for ( ; i < len; i++ ) {
+               if ( (elem = unmatched[i]) ) {
+                       if ( !filter || filter( elem, context, xml ) ) {
+                               newUnmatched.push( elem );
+                               if ( mapped ) {
+                                       map.push( i );
+                               }
+                       }
+               }
+       }
+
+       return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, 
postSelector ) {
+       if ( postFilter && !postFilter[ expando ] ) {
+               postFilter = setMatcher( postFilter );
+       }
+       if ( postFinder && !postFinder[ expando ] ) {
+               postFinder = setMatcher( postFinder, postSelector );
+       }
+       return markFunction(function( seed, results, context, xml ) {
+               var temp, i, elem,
+                       preMap = [],
+                       postMap = [],
+                       preexisting = results.length,
+
+                       // Get initial elements from seed or context
+                       elems = seed || multipleContexts( selector || "*", 
context.nodeType ? [ context ] : context, [] ),
+
+                       // Prefilter to get matcher input, preserving a map for 
seed-results synchronization
+                       matcherIn = preFilter && ( seed || !selector ) ?
+                               condense( elems, preMap, preFilter, context, 
xml ) :
+                               elems,
+
+                       matcherOut = matcher ?
+                               // If we have a postFinder, or filtered seed, 
or non-seed postFilter or preexisting results,
+                               postFinder || ( seed ? preFilter : preexisting 
|| postFilter ) ?
+
+                                       // ...intermediate processing is 
necessary
+                                       [] :
+
+                                       // ...otherwise use results directly
+                                       results :
+                               matcherIn;
+
+               // Find primary matches
+               if ( matcher ) {
+                       matcher( matcherIn, matcherOut, context, xml );
+               }
+
+               // Apply postFilter
+               if ( postFilter ) {
+                       temp = condense( matcherOut, postMap );
+                       postFilter( temp, [], context, xml );
+
+                       // Un-match failing elements by moving them back to 
matcherIn
+                       i = temp.length;
+                       while ( i-- ) {
+                               if ( (elem = temp[i]) ) {
+                                       matcherOut[ postMap[i] ] = !(matcherIn[ 
postMap[i] ] = elem);
+                               }
+                       }
+               }
+
+               if ( seed ) {
+                       if ( postFinder || preFilter ) {
+                               if ( postFinder ) {
+                                       // Get the final matcherOut by 
condensing this intermediate into postFinder contexts
+                                       temp = [];
+                                       i = matcherOut.length;
+                                       while ( i-- ) {
+                                               if ( (elem = matcherOut[i]) ) {
+                                                       // Restore matcherIn 
since elem is not yet a final match
+                                                       temp.push( 
(matcherIn[i] = elem) );
+                                               }
+                                       }
+                                       postFinder( null, (matcherOut = []), 
temp, xml );
+                               }
+
+                               // Move matched elements from seed to results 
to keep them synchronized
+                               i = matcherOut.length;
+                               while ( i-- ) {
+                                       if ( (elem = matcherOut[i]) &&
+                                               (temp = postFinder ? 
indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+                                               seed[temp] = !(results[temp] = 
elem);
+                                       }
+                               }
+                       }
+
+               // Add elements to results, through postFinder if defined
+               } else {
+                       matcherOut = condense(
+                               matcherOut === results ?
+                                       matcherOut.splice( preexisting, 
matcherOut.length ) :
+                                       matcherOut
+                       );
+                       if ( postFinder ) {
+                               postFinder( null, results, matcherOut, xml );
+                       } else {
+                               push.apply( results, matcherOut );
+                       }
+               }
+       });
+}
+
+function matcherFromTokens( tokens ) {
+       var checkContext, matcher, j,
+               len = tokens.length,
+               leadingRelative = Expr.relative[ tokens[0].type ],
+               implicitRelative = leadingRelative || Expr.relative[" "],
+               i = leadingRelative ? 1 : 0,
+
+               // The foundational matcher ensures that elements are reachable 
from top-level context(s)
+               matchContext = addCombinator( function( elem ) {
+                       return elem === checkContext;
+               }, implicitRelative, true ),
+               matchAnyContext = addCombinator( function( elem ) {
+                       return indexOf.call( checkContext, elem ) > -1;
+               }, implicitRelative, true ),
+               matchers = [ function( elem, context, xml ) {
+                       return ( !leadingRelative && ( xml || context !== 
outermostContext ) ) || (
+                               (checkContext = context).nodeType ?
+                                       matchContext( elem, context, xml ) :
+                                       matchAnyContext( elem, context, xml ) );
+               } ];
+
+       for ( ; i < len; i++ ) {
+               if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+                       matchers = [ addCombinator(elementMatcher( matchers ), 
matcher) ];
+               } else {
+                       matcher = Expr.filter[ tokens[i].type ].apply( null, 
tokens[i].matches );
+
+                       // Return special upon seeing a positional matcher
+                       if ( matcher[ expando ] ) {
+                               // Find the next relative operator (if any) for 
proper handling
+                               j = ++i;
+                               for ( ; j < len; j++ ) {
+                                       if ( Expr.relative[ tokens[j].type ] ) {
+                                               break;
+                                       }
+                               }
+                               return setMatcher(
+                                       i > 1 && elementMatcher( matchers ),
+                                       i > 1 && toSelector(
+                                               // If the preceding token was a 
descendant combinator, insert an implicit any-element `*`
+                                               tokens.slice( 0, i - 1 
).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+                                       ).replace( rtrim, "$1" ),
+                                       matcher,
+                                       i < j && matcherFromTokens( 
tokens.slice( i, j ) ),
+                                       j < len && matcherFromTokens( (tokens = 
tokens.slice( j )) ),
+                                       j < len && toSelector( tokens )
+                               );
+                       }
+                       matchers.push( matcher );
+               }
+       }
+
+       return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+       var bySet = setMatchers.length > 0,
+               byElement = elementMatchers.length > 0,
+               superMatcher = function( seed, context, xml, results, outermost 
) {
+                       var elem, j, matcher,
+                               matchedCount = 0,
+                               i = "0",
+                               unmatched = seed && [],
+                               setMatched = [],
+                               contextBackup = outermostContext,
+                               // We must always have either seed elements or 
outermost context
+                               elems = seed || byElement && Expr.find["TAG"]( 
"*", outermost ),
+                               // Use integer dirruns iff this is the 
outermost matcher
+                               dirrunsUnique = (dirruns += contextBackup == 
null ? 1 : Math.random() || 0.1),
+                               len = elems.length;
+
+                       if ( outermost ) {
+                               outermostContext = context !== document && 
context;
+                       }
+
+                       // Add elements passing elementMatchers directly to 
results
+                       // Keep `i` a string if there are no elements so 
`matchedCount` will be "00" below
+                       // Support: IE<9, Safari
+                       // Tolerate NodeList properties (IE: "length"; Safari: 
<number>) matching elements by id
+                       for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+                               if ( byElement && elem ) {
+                                       j = 0;
+                                       while ( (matcher = 
elementMatchers[j++]) ) {
+                                               if ( matcher( elem, context, 
xml ) ) {
+                                                       results.push( elem );
+                                                       break;
+                                               }
+                                       }
+                                       if ( outermost ) {
+                                               dirruns = dirrunsUnique;
+                                       }
+                               }
+
+                               // Track unmatched elements for set filters
+                               if ( bySet ) {
+                                       // They will have gone through all 
possible matchers
+                                       if ( (elem = !matcher && elem) ) {
+                                               matchedCount--;
+                                       }
+
+                                       // Lengthen the array for every 
element, matched or not
+                                       if ( seed ) {
+                                               unmatched.push( elem );
+                                       }
+                               }
+                       }
+
+                       // Apply set filters to unmatched elements
+                       matchedCount += i;
+                       if ( bySet && i !== matchedCount ) {
+                               j = 0;
+                               while ( (matcher = setMatchers[j++]) ) {
+                                       matcher( unmatched, setMatched, 
context, xml );
+                               }
+
+                               if ( seed ) {
+                                       // Reintegrate element matches to 
eliminate the need for sorting
+                                       if ( matchedCount > 0 ) {
+                                               while ( i-- ) {
+                                                       if ( !(unmatched[i] || 
setMatched[i]) ) {
+                                                               setMatched[i] = 
pop.call( results );
+                                                       }
+                                               }
+                                       }
+
+                                       // Discard index placeholder values to 
get only actual matches
+                                       setMatched = condense( setMatched );
+                               }
+
+                               // Add matches to results
+                               push.apply( results, setMatched );
+
+                               // Seedless set matches succeeding multiple 
successful matchers stipulate sorting
+                               if ( outermost && !seed && setMatched.length > 
0 &&
+                                       ( matchedCount + setMatchers.length ) > 
1 ) {
+
+                                       Sizzle.uniqueSort( results );
+                               }
+                       }
+
+                       // Override manipulation of globals by nested matchers
+                       if ( outermost ) {
+                               dirruns = dirrunsUnique;
+                               outermostContext = contextBackup;
+                       }
+
+                       return unmatched;
+               };
+
+       return bySet ?
+               markFunction( superMatcher ) :
+               superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) 
{
+       var i,
+               setMatchers = [],
+               elementMatchers = [],
+               cached = compilerCache[ selector + " " ];
+
+       if ( !cached ) {
+               // Generate a function of recursive functions that can be used 
to check each element
+               if ( !match ) {
+                       match = tokenize( selector );
+               }
+               i = match.length;
+               while ( i-- ) {
+                       cached = matcherFromTokens( match[i] );
+                       if ( cached[ expando ] ) {
+                               setMatchers.push( cached );
+                       } else {
+                               elementMatchers.push( cached );
+                       }
+               }
+
+               // Cache the compiled function
+               cached = compilerCache( selector, matcherFromGroupMatchers( 
elementMatchers, setMatchers ) );
+
+               // Save selector and tokenization
+               cached.selector = selector;
+       }
+       return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ *  selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ *  selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+       var i, tokens, token, type, find,
+               compiled = typeof selector === "function" && selector,
+               match = !seed && tokenize( (selector = compiled.selector || 
selector) );
+
+       results = results || [];
+
+       // Try to minimize operations if there is no seed and only one group
+       if ( match.length === 1 ) {
+
+               // Take a shortcut and set the context if the root selector is 
an ID
+               tokens = match[0] = match[0].slice( 0 );
+               if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+                               support.getById && context.nodeType === 9 && 
documentIsHTML &&
+                               Expr.relative[ tokens[1].type ] ) {
+
+                       context = ( Expr.find["ID"]( 
token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+                       if ( !context ) {
+                               return results;
+
+                       // Precompiled matchers will still verify ancestry, so 
step up a level
+                       } else if ( compiled ) {
+                               context = context.parentNode;
+                       }
+
+                       selector = selector.slice( tokens.shift().value.length 
);
+               }
+
+               // Fetch a seed set for right-to-left matching
+               i = matchExpr["needsContext"].test( selector ) ? 0 : 
tokens.length;
+               while ( i-- ) {
+                       token = tokens[i];
+
+                       // Abort if we hit a combinator
+                       if ( Expr.relative[ (type = token.type) ] ) {
+                               break;
+                       }
+                       if ( (find = Expr.find[ type ]) ) {
+                               // Search, expanding context for leading 
sibling combinators
+                               if ( (seed = find(
+                                       token.matches[0].replace( runescape, 
funescape ),
+                                       rsibling.test( tokens[0].type ) && 
testContext( context.parentNode ) || context
+                               )) ) {
+
+                                       // If seed is empty or no tokens 
remain, we can return early
+                                       tokens.splice( i, 1 );
+                                       selector = seed.length && toSelector( 
tokens );
+                                       if ( !selector ) {
+                                               push.apply( results, seed );
+                                               return results;
+                                       }
+
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // Compile and execute a filtering function if one is not provided
+       // Provide `match` to avoid retokenization if we modified the selector 
above
+       ( compiled || compile( selector, match ) )(
+               seed,
+               context,
+               !documentIsHTML,
+               results,
+               rsibling.test( selector ) && testContext( context.parentNode ) 
|| context
+       );
+       return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+       // Should return 1, but returns 4 (following)
+       return div1.compareDocumentPosition( document.createElement("div") ) & 
1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+       div.innerHTML = "<a href='#'></a>";
+       return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+       addHandle( "type|href|height|width", function( elem, name, isXML ) {
+               if ( !isXML ) {
+                       return elem.getAttribute( name, name.toLowerCase() === 
"type" ? 1 : 2 );
+               }
+       });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+       div.innerHTML = "<input/>";
+       div.firstChild.setAttribute( "value", "" );
+       return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+       addHandle( "value", function( elem, name, isXML ) {
+               if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+                       return elem.defaultValue;
+               }
+       });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+       return div.getAttribute("disabled") == null;
+}) ) {
+       addHandle( booleans, function( elem, name, isXML ) {
+               var val;
+               if ( !isXML ) {
+                       return elem[ name ] === true ? name.toLowerCase() :
+                                       (val = elem.getAttributeNode( name )) 
&& val.specified ?
+                                       val.value :
+                               null;
+               }
+       });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+       if ( jQuery.isFunction( qualifier ) ) {
+               return jQuery.grep( elements, function( elem, i ) {
+                       /* jshint -W018 */
+                       return !!qualifier.call( elem, i, elem ) !== not;
+               });
+
+       }
+
+       if ( qualifier.nodeType ) {
+               return jQuery.grep( elements, function( elem ) {
+                       return ( elem === qualifier ) !== not;
+               });
+
+       }
+
+       if ( typeof qualifier === "string" ) {
+               if ( risSimple.test( qualifier ) ) {
+                       return jQuery.filter( qualifier, elements, not );
+               }
+
+               qualifier = jQuery.filter( qualifier, elements );
+       }
+
+       return jQuery.grep( elements, function( elem ) {
+               return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
+       });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+       var elem = elems[ 0 ];
+
+       if ( not ) {
+               expr = ":not(" + expr + ")";
+       }
+
+       return elems.length === 1 && elem.nodeType === 1 ?
+               jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+               jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) 
{
+                       return elem.nodeType === 1;
+               }));
+};
+
+jQuery.fn.extend({
+       find: function( selector ) {
+               var i,
+                       len = this.length,
+                       ret = [],
+                       self = this;
+
+               if ( typeof selector !== "string" ) {
+                       return this.pushStack( jQuery( selector 
).filter(function() {
+                               for ( i = 0; i < len; i++ ) {
+                                       if ( jQuery.contains( self[ i ], this ) 
) {
+                                               return true;
+                                       }
+                               }
+                       }) );
+               }
+
+               for ( i = 0; i < len; i++ ) {
+                       jQuery.find( selector, self[ i ], ret );
+               }
+
+               // Needed because $( selector, context ) becomes $( context 
).find( selector )
+               ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+               ret.selector = this.selector ? this.selector + " " + selector : 
selector;
+               return ret;
+       },
+       filter: function( selector ) {
+               return this.pushStack( winnow(this, selector || [], false) );
+       },
+       not: function( selector ) {
+               return this.pushStack( winnow(this, selector || [], true) );
+       },
+       is: function( selector ) {
+               return !!winnow(
+                       this,
+
+                       // If this is a positional/relative selector, check 
membership in the returned set
+                       // so $("p:first").is("p:last") won't return true for a 
doc with two "p".
+                       typeof selector === "string" && rneedsContext.test( 
selector ) ?
+                               jQuery( selector ) :
+                               selector || [],
+                       false
+               ).length;
+       }
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+       // A simple way to check for HTML strings
+       // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+       // Strict HTML recognition (#11290: must start with <)
+       rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+       init = jQuery.fn.init = function( selector, context ) {
+               var match, elem;
+
+               // HANDLE: $(""), $(null), $(undefined), $(false)
+               if ( !selector ) {
+                       return this;
+               }
+
+               // Handle HTML strings
+               if ( typeof selector === "string" ) {
+                       if ( selector[0] === "<" && selector[ 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 ];
+
+                       } else {
+                               match = rquickExpr.exec( selector );
+                       }
+
+                       // Match html or make sure no context is specified for 
#id
+                       if ( match && (match[1] || !context) ) {
+
+                               // HANDLE: $(html) -> $(array)
+                               if ( match[1] ) {
+                                       context = context instanceof jQuery ? 
context[0] : context;
+
+                                       // scripts is true for back-compat
+                                       // Intentionally let the error be 
thrown if parseHTML is not present
+                                       jQuery.merge( this, jQuery.parseHTML(
+                                               match[1],
+                                               context && context.nodeType ? 
context.ownerDocument || context : document,
+                                               true
+                                       ) );
+
+                                       // HANDLE: $(html, props)
+                                       if ( rsingleTag.test( match[1] ) && 
jQuery.isPlainObject( context ) ) {
+                                               for ( match in context ) {
+                                                       // Properties of 
context are called as methods if possible
+                                                       if ( jQuery.isFunction( 
this[ match ] ) ) {
+                                                               this[ match ]( 
context[ match ] );
+
+                                                       // ...and otherwise set 
as attributes
+                                                       } else {
+                                                               this.attr( 
match, context[ match ] );
+                                                       }
+                                               }
+                                       }
+
+                                       return this;
+
+                               // 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 ) {
+                                               // Inject the element directly 
into the jQuery object
+                                               this.length = 1;
+                                               this[0] = elem;
+                                       }
+
+                                       this.context = document;
+                                       this.selector = selector;
+                                       return this;
+                               }
+
+                       // HANDLE: $(expr, $(...))
+                       } else if ( !context || context.jquery ) {
+                               return ( context || rootjQuery ).find( selector 
);
+
+                       // HANDLE: $(expr, context)
+                       // (which is just equivalent to: $(context).find(expr)
+                       } else {
+                               return this.constructor( context ).find( 
selector );
+                       }
+
+               // HANDLE: $(DOMElement)
+               } else if ( selector.nodeType ) {
+                       this.context = this[0] = selector;
+                       this.length = 1;
+                       return this;
+
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( jQuery.isFunction( selector ) ) {
+                       return typeof rootjQuery.ready !== "undefined" ?
+                               rootjQuery.ready( selector ) :
+                               // Execute immediately if ready is not present
+                               selector( jQuery );
+               }
+
+               if ( selector.selector !== undefined ) {
+                       this.selector = selector.selector;
+                       this.context = selector.context;
+               }
+
+               return jQuery.makeArray( selector, this );
+       };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+       // methods guaranteed to produce a unique set when starting from a 
unique set
+       guaranteedUnique = {
+               children: true,
+               contents: true,
+               next: true,
+               prev: true
+       };
+
+jQuery.extend({
+       dir: function( elem, dir, until ) {
+               var matched = [],
+                       truncate = until !== undefined;
+
+               while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
+                       if ( elem.nodeType === 1 ) {
+                               if ( truncate && jQuery( elem ).is( until ) ) {
+                                       break;
+                               }
+                               matched.push( elem );
+                       }
+               }
+               return matched;
+       },
+
+       sibling: function( n, elem ) {
+               var matched = [];
+
+               for ( ; n; n = n.nextSibling ) {
+                       if ( n.nodeType === 1 && n !== elem ) {
+                               matched.push( n );
+                       }
+               }
+
+               return matched;
+       }
+});
+
+jQuery.fn.extend({
+       has: function( target ) {
+               var targets = jQuery( target, this ),
+                       l = targets.length;
+
+               return this.filter(function() {
+                       var i = 0;
+                       for ( ; i < l; i++ ) {
+                               if ( jQuery.contains( this, targets[i] ) ) {
+                                       return true;
+                               }
+                       }
+               });
+       },
+
+       closest: function( selectors, context ) {
+               var cur,
+                       i = 0,
+                       l = this.length,
+                       matched = [],
+                       pos = rneedsContext.test( selectors ) || typeof 
selectors !== "string" ?
+                               jQuery( selectors, context || this.context ) :
+                               0;
+
+               for ( ; i < l; i++ ) {
+                       for ( cur = this[i]; cur && cur !== context; cur = 
cur.parentNode ) {
+                               // Always skip document fragments
+                               if ( cur.nodeType < 11 && (pos ?
+                                       pos.index(cur) > -1 :
+
+                                       // Don't pass non-elements to Sizzle
+                                       cur.nodeType === 1 &&
+                                               
jQuery.find.matchesSelector(cur, selectors)) ) {
+
+                                       matched.push( cur );
+                                       break;
+                               }
+                       }
+               }
+
+               return this.pushStack( matched.length > 1 ? jQuery.unique( 
matched ) : matched );
+       },
+
+       // Determine the position of an element within
+       // the matched set of elements
+       index: function( elem ) {
+
+               // No argument, return index in parent
+               if ( !elem ) {
+                       return ( this[ 0 ] && this[ 0 ].parentNode ) ? 
this.first().prevAll().length : -1;
+               }
+
+               // index in selector
+               if ( typeof elem === "string" ) {
+                       return indexOf.call( jQuery( elem ), this[ 0 ] );
+               }
+
+               // Locate the position of the desired element
+               return indexOf.call( this,
+
+                       // If it receives a jQuery object, the first element is 
used
+                       elem.jquery ? elem[ 0 ] : elem
+               );
+       },
+
+       add: function( selector, context ) {
+               return this.pushStack(
+                       jQuery.unique(
+                               jQuery.merge( this.get(), jQuery( selector, 
context ) )
+                       )
+               );
+       },
+
+       addBack: function( selector ) {
+               return this.add( selector == null ?
+                       this.prevObject : this.prevObject.filter(selector)
+               );
+       }
+});
+
+function sibling( cur, dir ) {
+       while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
+       return cur;
+}
+
+jQuery.each({
+       parent: function( elem ) {
+               var parent = elem.parentNode;
+               return parent && parent.nodeType !== 11 ? parent : null;
+       },
+       parents: function( elem ) {
+               return jQuery.dir( elem, "parentNode" );
+       },
+       parentsUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "parentNode", until );
+       },
+       next: function( elem ) {
+               return sibling( elem, "nextSibling" );
+       },
+       prev: function( elem ) {
+               return sibling( elem, "previousSibling" );
+       },
+       nextAll: function( elem ) {
+               return jQuery.dir( elem, "nextSibling" );
+       },
+       prevAll: function( elem ) {
+               return jQuery.dir( elem, "previousSibling" );
+       },
+       nextUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "nextSibling", until );
+       },
+       prevUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "previousSibling", until );
+       },
+       siblings: function( elem ) {
+               return jQuery.sibling( ( elem.parentNode || {} ).firstChild, 
elem );
+       },
+       children: function( elem ) {
+               return jQuery.sibling( elem.firstChild );
+       },
+       contents: function( elem ) {
+               return elem.contentDocument || jQuery.merge( [], 
elem.childNodes );
+       }
+}, function( name, fn ) {
+       jQuery.fn[ name ] = function( until, selector ) {
+               var matched = jQuery.map( this, fn, until );
+
+               if ( name.slice( -5 ) !== "Until" ) {
+                       selector = until;
+               }
+
+               if ( selector && typeof selector === "string" ) {
+                       matched = jQuery.filter( selector, matched );
+               }
+
+               if ( this.length > 1 ) {
+                       // Remove duplicates
+                       if ( !guaranteedUnique[ name ] ) {
+                               jQuery.unique( matched );
+                       }
+
+                       // Reverse order for parents* and prev-derivatives
+                       if ( rparentsprev.test( name ) ) {
+                               matched.reverse();
+                       }
+               }
+
+               return this.pushStack( matched );
+       };
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in 
cache
+function createOptions( options ) {
+       var object = optionsCache[ options ] = {};
+       jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+               object[ flag ] = true;
+       });
+       return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *     options: an optional list of space-separated options that will change 
how
+ *                     the callback list behaves or a more traditional option 
object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *     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( options ) {
+
+       // Convert options from String-formatted to Object-formatted if needed
+       // (we check in cache first)
+       options = typeof options === "string" ?
+               ( optionsCache[ options ] || createOptions( options ) ) :
+               jQuery.extend( {}, options );
+
+       var // 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,
+               // Actual callback list
+               list = [],
+               // Stack of fire calls for repeatable lists
+               stack = !options.once && [],
+               // Fire callbacks
+               fire = function( data ) {
+                       memory = options.memory && data;
+                       fired = true;
+                       firingIndex = firingStart || 0;
+                       firingStart = 0;
+                       firingLength = list.length;
+                       firing = true;
+                       for ( ; list && firingIndex < firingLength; 
firingIndex++ ) {
+                               if ( list[ firingIndex ].apply( data[ 0 ], 
data[ 1 ] ) === false && options.stopOnFalse ) {
+                                       memory = false; // To prevent further 
calls using add
+                                       break;
+                               }
+                       }
+                       firing = false;
+                       if ( list ) {
+                               if ( stack ) {
+                                       if ( stack.length ) {
+                                               fire( stack.shift() );
+                                       }
+                               } else if ( memory ) {
+                                       list = [];
+                               } else {
+                                       self.disable();
+                               }
+                       }
+               },
+               // Actual Callbacks object
+               self = {
+                       // Add a callback or a collection of callbacks to the 
list
+                       add: function() {
+                               if ( list ) {
+                                       // First, we save the current length
+                                       var start = list.length;
+                                       (function add( args ) {
+                                               jQuery.each( args, function( _, 
arg ) {
+                                                       var type = jQuery.type( 
arg );
+                                                       if ( type === 
"function" ) {
+                                                               if ( 
!options.unique || !self.has( arg ) ) {
+                                                                       
list.push( arg );
+                                                               }
+                                                       } else if ( arg && 
arg.length && type !== "string" ) {
+                                                               // Inspect 
recursively
+                                                               add( arg );
+                                                       }
+                                               });
+                                       })( 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
+                                       } else if ( memory ) {
+                                               firingStart = start;
+                                               fire( memory );
+                                       }
+                               }
+                               return this;
+                       },
+                       // Remove a callback from the list
+                       remove: function() {
+                               if ( list ) {
+                                       jQuery.each( arguments, function( _, 
arg ) {
+                                               var index;
+                                               while ( ( index = 
jQuery.inArray( arg, list, index ) ) > -1 ) {
+                                                       list.splice( index, 1 );
+                                                       // Handle firing indexes
+                                                       if ( firing ) {
+                                                               if ( index <= 
firingLength ) {
+                                                                       
firingLength--;
+                                                               }
+                                                               if ( index <= 
firingIndex ) {
+                                                                       
firingIndex--;
+                                                               }
+                                                       }
+                                               }
+                                       });
+                               }
+                               return this;
+                       },
+                       // Check if a given callback is in the list.
+                       // If no argument is given, return whether or not list 
has callbacks attached.
+                       has: function( fn ) {
+                               return fn ? jQuery.inArray( fn, list ) > -1 : 
!!( list && list.length );
+                       },
+                       // Remove all callbacks from the list
+                       empty: function() {
+                               list = [];
+                               firingLength = 0;
+                               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 ) {
+                                       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 ( list && ( !fired || stack ) ) {
+                                       args = args || [];
+                                       args = [ context, args.slice ? 
args.slice() : args ];
+                                       if ( firing ) {
+                                               stack.push( args );
+                                       } else {
+                                               fire( 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;
+                       }
+               };
+
+       return self;
+};
+
+
+jQuery.extend({
+
+       Deferred: function( func ) {
+               var tuples = [
+                               // action, add listener, listener list, final 
state
+                               [ "resolve", "done", jQuery.Callbacks("once 
memory"), "resolved" ],
+                               [ "reject", "fail", jQuery.Callbacks("once 
memory"), "rejected" ],
+                               [ "notify", "progress", 
jQuery.Callbacks("memory") ]
+                       ],
+                       state = "pending",
+                       promise = {
+                               state: function() {
+                                       return state;
+                               },
+                               always: function() {
+                                       deferred.done( arguments ).fail( 
arguments );
+                                       return this;
+                               },
+                               then: function( /* fnDone, fnFail, fnProgress 
*/ ) {
+                                       var fns = arguments;
+                                       return jQuery.Deferred(function( 
newDefer ) {
+                                               jQuery.each( tuples, function( 
i, tuple ) {
+                                                       var fn = 
jQuery.isFunction( fns[ i ] ) && fns[ i ];
+                                                       // deferred[ done | 
fail | progress ] for forwarding actions to newDefer
+                                                       deferred[ tuple[1] 
](function() {
+                                                               var returned = 
fn && fn.apply( this, arguments );
+                                                               if ( returned 
&& jQuery.isFunction( returned.promise ) ) {
+                                                                       
returned.promise()
+                                                                               
.done( newDefer.resolve )
+                                                                               
.fail( newDefer.reject )
+                                                                               
.progress( newDefer.notify );
+                                                               } else {
+                                                                       
newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, 
fn ? [ returned ] : arguments );
+                                                               }
+                                                       });
+                                               });
+                                               fns = null;
+                                       }).promise();
+                               },
+                               // Get a promise for this deferred
+                               // If obj is provided, the promise aspect is 
added to the object
+                               promise: function( obj ) {
+                                       return obj != null ? jQuery.extend( 
obj, promise ) : promise;
+                               }
+                       },
+                       deferred = {};
+
+               // Keep pipe for back-compat
+               promise.pipe = promise.then;
+
+               // Add list-specific methods
+               jQuery.each( tuples, function( i, tuple ) {
+                       var list = tuple[ 2 ],
+                               stateString = tuple[ 3 ];
+
+                       // promise[ done | fail | progress ] = list.add
+                       promise[ tuple[1] ] = list.add;
+
+                       // Handle state
+                       if ( stateString ) {
+                               list.add(function() {
+                                       // state = [ resolved | rejected ]
+                                       state = stateString;
+
+                               // [ reject_list | resolve_list ].disable; 
progress_list.lock
+                               }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 
].lock );
+                       }
+
+                       // deferred[ resolve | reject | notify ]
+                       deferred[ tuple[0] ] = function() {
+                               deferred[ tuple[0] + "With" ]( this === 
deferred ? promise : this, arguments );
+                               return this;
+                       };
+                       deferred[ tuple[0] + "With" ] = list.fireWith;
+               });
+
+               // Make the deferred a promise
+               promise.promise( deferred );
+
+               // Call given func if any
+               if ( func ) {
+                       func.call( deferred, deferred );
+               }
+
+               // All done!
+               return deferred;
+       },
+
+       // Deferred helper
+       when: function( subordinate /* , ..., subordinateN */ ) {
+               var i = 0,
+                       resolveValues = slice.call( arguments ),
+                       length = resolveValues.length,
+
+                       // the count of uncompleted subordinates
+                       remaining = length !== 1 || ( subordinate && 
jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+                       // the master Deferred. If resolveValues consist of 
only a single Deferred, just use that.
+                       deferred = remaining === 1 ? subordinate : 
jQuery.Deferred(),
+
+                       // Update function for both resolve and progress values
+                       updateFunc = function( i, contexts, values ) {
+                               return function( value ) {
+                                       contexts[ i ] = this;
+                                       values[ i ] = arguments.length > 1 ? 
slice.call( arguments ) : value;
+                                       if ( values === progressValues ) {
+                                               deferred.notifyWith( contexts, 
values );
+                                       } else if ( !( --remaining ) ) {
+                                               deferred.resolveWith( contexts, 
values );
+                                       }
+                               };
+                       },
+
+                       progressValues, progressContexts, resolveContexts;
+
+               // add listeners to Deferred subordinates; treat others as 
resolved
+               if ( length > 1 ) {
+                       progressValues = new Array( length );
+                       progressContexts = new Array( length );
+                       resolveContexts = new Array( length );
+                       for ( ; i < length; i++ ) {
+                               if ( resolveValues[ i ] && jQuery.isFunction( 
resolveValues[ i ].promise ) ) {
+                                       resolveValues[ i ].promise()
+                                               .done( updateFunc( i, 
resolveContexts, resolveValues ) )
+                                               .fail( deferred.reject )
+                                               .progress( updateFunc( i, 
progressContexts, progressValues ) );
+                               } else {
+                                       --remaining;
+                               }
+                       }
+               }
+
+               // if we're not waiting on anything, resolve the master
+               if ( !remaining ) {
+                       deferred.resolveWith( resolveContexts, resolveValues );
+               }
+
+               return deferred.promise();
+       }
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+       // Add the callback
+       jQuery.ready.promise().done( fn );
+
+       return this;
+};
+
+jQuery.extend({
+       // 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 ) {
+
+               // Abort if there are pending holds or we're already ready
+               if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+                       return;
+               }
+
+               // Remember that the DOM is ready
+               jQuery.isReady = true;
+
+               // If a normal DOM Ready event fired, decrement, and wait if 
need be
+               if ( wait !== true && --jQuery.readyWait > 0 ) {
+                       return;
+               }
+
+               // If there are functions bound, to execute
+               readyList.resolveWith( document, [ jQuery ] );
+
+               // Trigger any bound ready events
+               if ( jQuery.fn.triggerHandler ) {
+                       jQuery( document ).triggerHandler( "ready" );
+                       jQuery( document ).off( "ready" );
+               }
+       }
+});
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+       document.removeEventListener( "DOMContentLoaded", completed, false );
+       window.removeEventListener( "load", completed, false );
+       jQuery.ready();
+}
+
+jQuery.ready.promise = function( obj ) {
+       if ( !readyList ) {
+
+               readyList = jQuery.Deferred();
+
+               // Catch cases where $(document).ready() is called after the 
browser event has already occurred.
+               // we once tried to use readyState "interactive" here, but it 
caused issues like the one
+               // discovered by ChrisS here: 
http://bugs.jquery.com/ticket/12282#comment:15
+               if ( document.readyState === "complete" ) {
+                       // Handle it asynchronously to allow scripts the 
opportunity to delay ready
+                       setTimeout( jQuery.ready );
+
+               } else {
+
+                       // Use the handy event callback
+                       document.addEventListener( "DOMContentLoaded", 
completed, false );
+
+                       // A fallback to window.onload, that will always work
+                       window.addEventListener( "load", completed, false );
+               }
+       }
+       return readyList.promise( obj );
+};
+
+// Kick off the DOM ready check even if the user does not
+jQuery.ready.promise();
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, 
emptyGet, raw ) {
+       var i = 0,
+               len = elems.length,
+               bulk = key == null;
+
+       // Sets many values
+       if ( jQuery.type( key ) === "object" ) {
+               chainable = true;
+               for ( i in key ) {
+                       jQuery.access( elems, fn, i, key[i], true, emptyGet, 
raw );
+               }
+
+       // Sets one value
+       } else if ( value !== undefined ) {
+               chainable = true;
+
+               if ( !jQuery.isFunction( value ) ) {
+                       raw = true;
+               }
+
+               if ( bulk ) {
+                       // Bulk operations run against the entire set
+                       if ( raw ) {
+                               fn.call( elems, value );
+                               fn = null;
+
+                       // ...except when executing function values
+                       } else {
+                               bulk = fn;
+                               fn = function( elem, key, value ) {
+                                       return bulk.call( jQuery( elem ), value 
);
+                               };
+                       }
+               }
+
+               if ( fn ) {
+                       for ( ; i < len; i++ ) {
+                               fn( elems[i], key, raw ? value : value.call( 
elems[i], i, fn( elems[i], key ) ) );
+                       }
+               }
+       }
+
+       return chainable ?
+               elems :
+
+               // Gets
+               bulk ?
+                       fn.call( elems ) :
+                       len ? fn( elems[0], key ) : emptyGet;
+};
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( owner ) {
+       // Accepts only:
+       //  - Node
+       //    - Node.ELEMENT_NODE
+       //    - Node.DOCUMENT_NODE
+       //  - Object
+       //    - Any
+       /* jshint -W018 */
+       return owner.nodeType === 1 || owner.nodeType === 9 || !( 
+owner.nodeType );
+};
+
+
+function Data() {
+       // Support: Android < 4,
+       // Old WebKit does not have Object.preventExtensions/freeze method,
+       // return new empty object instead with no [[set]] accessor
+       Object.defineProperty( this.cache = {}, 0, {
+               get: function() {
+                       return {};
+               }
+       });
+
+       this.expando = jQuery.expando + Math.random();
+}
+
+Data.uid = 1;
+Data.accepts = jQuery.acceptData;
+
+Data.prototype = {
+       key: function( owner ) {
+               // We can accept data for non-element nodes in modern browsers,
+               // but we should not, see #8335.
+               // Always return the key for a frozen object.
+               if ( !Data.accepts( owner ) ) {
+                       return 0;
+               }
+
+               var descriptor = {},
+                       // Check if the owner object already has a cache key
+                       unlock = owner[ this.expando ];
+
+               // If not, create one
+               if ( !unlock ) {
+                       unlock = Data.uid++;
+
+                       // Secure it in a non-enumerable, non-writable property
+                       try {
+                               descriptor[ this.expando ] = { value: unlock };
+                               Object.defineProperties( owner, descriptor );
+
+                       // Support: Android < 4
+                       // Fallback to a less secure definition
+                       } catch ( e ) {
+                               descriptor[ this.expando ] = unlock;
+                               jQuery.extend( owner, descriptor );
+                       }
+               }
+
+               // Ensure the cache object
+               if ( !this.cache[ unlock ] ) {
+                       this.cache[ unlock ] = {};
+               }
+
+               return unlock;
+       },
+       set: function( owner, data, value ) {
+               var prop,
+                       // There may be an unlock assigned to this node,
+                       // if there is no entry for this "owner", create one 
inline
+                       // and set the unlock as though an owner entry had 
always existed
+                       unlock = this.key( owner ),
+                       cache = this.cache[ unlock ];
+
+               // Handle: [ owner, key, value ] args
+               if ( typeof data === "string" ) {
+                       cache[ data ] = value;
+
+               // Handle: [ owner, { properties } ] args
+               } else {
+                       // Fresh assignments by object are shallow copied
+                       if ( jQuery.isEmptyObject( cache ) ) {
+                               jQuery.extend( this.cache[ unlock ], data );
+                       // Otherwise, copy the properties one-by-one to the 
cache object
+                       } else {
+                               for ( prop in data ) {
+                                       cache[ prop ] = data[ prop ];
+                               }
+                       }
+               }
+               return cache;
+       },
+       get: function( owner, key ) {
+               // Either a valid cache is found, or will be created.
+               // New caches will be created and the unlock returned,
+               // allowing direct access to the newly created
+               // empty data object. A valid owner object must be provided.
+               var cache = this.cache[ this.key( owner ) ];
+
+               return key === undefined ?
+                       cache : cache[ key ];
+       },
+       access: function( owner, key, value ) {
+               var stored;
+               // In cases where either:
+               //
+               //   1. No key was specified
+               //   2. A string key was specified, but no value provided
+               //
+               // Take the "read" path and allow the get method to determine
+               // which value to return, respectively either:
+               //
+               //   1. The entire cache object
+               //   2. The data stored at the key
+               //
+               if ( key === undefined ||
+                               ((key && typeof key === "string") && value === 
undefined) ) {
+
+                       stored = this.get( owner, key );
+
+                       return stored !== undefined ?
+                               stored : this.get( owner, jQuery.camelCase(key) 
);
+               }
+
+               // [*]When the key is not a string, or both a key and value
+               // are specified, set or extend (existing objects) with either:
+               //
+               //   1. An object of properties
+               //   2. A key and value
+               //
+               this.set( owner, key, value );
+
+               // Since the "set" path can have two possible entry points
+               // return the expected data based on which path was taken[*]
+               return value !== undefined ? value : key;
+       },
+       remove: function( owner, key ) {
+               var i, name, camel,
+                       unlock = this.key( owner ),
+                       cache = this.cache[ unlock ];
+
+               if ( key === undefined ) {
+                       this.cache[ unlock ] = {};
+
+               } else {
+                       // Support array or space separated string of keys
+                       if ( jQuery.isArray( key ) ) {
+                               // If "name" is an array of keys...
+                               // When data is initially created, via ("key", 
"val") signature,
+                               // keys will be converted to camelCase.
+                               // Since there is no way to tell _how_ a key 
was added, remove
+                               // both plain key and camelCase key. #12786
+                               // This will only penalize the array argument 
path.
+                               name = key.concat( key.map( jQuery.camelCase ) 
);
+                       } else {
+                               camel = jQuery.camelCase( key );
+                               // Try the string as a key before any 
manipulation
+                               if ( key in cache ) {
+                                       name = [ key, camel ];
+                               } else {
+                                       // If a key with the spaces exists, use 
it.
+                                       // Otherwise, create an array by 
matching non-whitespace
+                                       name = camel;
+                                       name = name in cache ?
+                                               [ name ] : ( name.match( 
rnotwhite ) || [] );
+                               }
+                       }
+
+                       i = name.length;
+                       while ( i-- ) {
+                               delete cache[ name[ i ] ];
+                       }
+               }
+       },
+       hasData: function( owner ) {
+               return !jQuery.isEmptyObject(
+                       this.cache[ owner[ this.expando ] ] || {}
+               );
+       },
+       discard: function( owner ) {
+               if ( owner[ this.expando ] ) {
+                       delete this.cache[ owner[ this.expando ] ];
+               }
+       }
+};
+var data_priv = new Data();
+
+var data_user = new Data();
+
+
+
+/*
+       Implementation Summary
+
+       1. Enforce API surface and semantic compatibility with 1.9.x branch
+       2. Improve the module's maintainability by reducing the storage
+               paths to a single mechanism.
+       3. Use the same single mechanism to support "private" and "user" data.
+       4. _Never_ expose "private" data to user code (TODO: Drop _data, 
_removeData)
+       5. Avoid exposing implementation details on user objects (eg. expando 
properties)
+       6. Provide a clear path for implementation upgrade to WeakMap in 2014
+*/
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+       rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+       var name;
+
+       // If nothing was found internally, try to fetch any
+       // data from the HTML5 data-* attribute
+       if ( data === undefined && elem.nodeType === 1 ) {
+               name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+               data = elem.getAttribute( name );
+
+               if ( typeof data === "string" ) {
+                       try {
+                               data = data === "true" ? true :
+                                       data === "false" ? false :
+                                       data === "null" ? null :
+                                       // Only convert to a number if it 
doesn't change the string
+                                       +data + "" === data ? +data :
+                                       rbrace.test( data ) ? jQuery.parseJSON( 
data ) :
+                                       data;
+                       } catch( e ) {}
+
+                       // Make sure we set the data so it isn't changed later
+                       data_user.set( elem, key, data );
+               } else {
+                       data = undefined;
+               }
+       }
+       return data;
+}
+
+jQuery.extend({
+       hasData: function( elem ) {
+               return data_user.hasData( elem ) || data_priv.hasData( elem );
+       },
+
+       data: function( elem, name, data ) {
+               return data_user.access( elem, name, data );
+       },
+
+       removeData: function( elem, name ) {
+               data_user.remove( elem, name );
+       },
+
+       // TODO: Now that all calls to _data and _removeData have been replaced
+       // with direct calls to data_priv methods, these can be deprecated.
+       _data: function( elem, name, data ) {
+               return data_priv.access( elem, name, data );
+       },
+
+       _removeData: function( elem, name ) {
+               data_priv.remove( elem, name );
+       }
+});
+
+jQuery.fn.extend({
+       data: function( key, value ) {
+               var i, name, data,
+                       elem = this[ 0 ],
+                       attrs = elem && elem.attributes;
+
+               // Gets all values
+               if ( key === undefined ) {
+                       if ( this.length ) {
+                               data = data_user.get( elem );
+
+                               if ( elem.nodeType === 1 && !data_priv.get( 
elem, "hasDataAttrs" ) ) {
+                                       i = attrs.length;
+                                       while ( i-- ) {
+
+                                               // Support: IE11+
+                                               // The attrs elements can be 
null (#14894)
+                                               if ( attrs[ i ] ) {
+                                                       name = attrs[ i ].name;
+                                                       if ( name.indexOf( 
"data-" ) === 0 ) {
+                                                               name = 
jQuery.camelCase( name.slice(5) );
+                                                               dataAttr( elem, 
name, data[ name ] );
+                                                       }
+                                               }
+                                       }
+                                       data_priv.set( elem, "hasDataAttrs", 
true );
+                               }
+                       }
+
+                       return data;
+               }
+
+               // Sets multiple values
+               if ( typeof key === "object" ) {
+                       return this.each(function() {
+                               data_user.set( this, key );
+                       });
+               }
+
+               return access( this, function( value ) {
+                       var data,
+                               camelKey = jQuery.camelCase( key );
+
+                       // The calling jQuery object (element matches) is not 
empty
+                       // (and therefore has an element appears at this[ 0 ]) 
and the
+                       // `value` parameter was not undefined. An empty jQuery 
object
+                       // will result in `undefined` for elem = this[ 0 ] 
which will
+                       // throw an exception if an attempt to read a data 
cache is made.
+                       if ( elem && value === undefined ) {
+                               // Attempt to get data from the cache
+                               // with the key as-is
+                               data = data_user.get( elem, key );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // Attempt to get data from the cache
+                               // with the key camelized
+                               data = data_user.get( elem, camelKey );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // Attempt to "discover" the data in
+                               // HTML5 custom data-* attrs
+                               data = dataAttr( elem, camelKey, undefined );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // We tried really hard, but the data doesn't 
exist.
+                               return;
+                       }
+
+                       // Set the data...
+                       this.each(function() {
+                               // First, attempt to store a copy or reference 
of any
+                               // data that might've been store with a 
camelCased key.
+                               var data = data_user.get( this, camelKey );
+
+                               // For HTML5 data-* attribute interop, we have 
to
+                               // store property names with dashes in a 
camelCase form.
+                               // This might not apply to all properties...*
+                               data_user.set( this, camelKey, value );
+
+                               // *... In the case of properties that might 
_actually_
+                               // have dashes, we need to also store a copy of 
that
+                               // unchanged property.
+                               if ( key.indexOf("-") !== -1 && data !== 
undefined ) {
+                                       data_user.set( this, key, value );
+                               }
+                       });
+               }, null, value, arguments.length > 1, null, true );
+       },
+
+       removeData: function( key ) {
+               return this.each(function() {
+                       data_user.remove( this, key );
+               });
+       }
+});
+
+
+jQuery.extend({
+       queue: function( elem, type, data ) {
+               var queue;
+
+               if ( elem ) {
+                       type = ( type || "fx" ) + "queue";
+                       queue = data_priv.get( elem, type );
+
+                       // Speed up dequeue by getting out quickly if this is 
just a lookup
+                       if ( data ) {
+                               if ( !queue || jQuery.isArray( data ) ) {
+                                       queue = data_priv.access( elem, type, 
jQuery.makeArray(data) );
+                               } else {
+                                       queue.push( data );
+                               }
+                       }
+                       return queue || [];
+               }
+       },
+
+       dequeue: function( elem, type ) {
+               type = type || "fx";
+
+               var queue = jQuery.queue( elem, type ),
+                       startLength = queue.length,
+                       fn = queue.shift(),
+                       hooks = jQuery._queueHooks( elem, type ),
+                       next = function() {
+                               jQuery.dequeue( elem, type );
+                       };
+
+               // If the fx queue is dequeued, always remove the progress 
sentinel
+               if ( fn === "inprogress" ) {
+                       fn = queue.shift();
+                       startLength--;
+               }
+
+               if ( fn ) {
+
+                       // Add a progress sentinel to prevent the fx queue from 
being
+                       // automatically dequeued
+                       if ( type === "fx" ) {
+                               queue.unshift( "inprogress" );
+                       }
+
+                       // clear up the last queue stop function
+                       delete hooks.stop;
+                       fn.call( elem, next, hooks );
+               }
+
+               if ( !startLength && hooks ) {
+                       hooks.empty.fire();
+               }
+       },
+
+       // not intended for public consumption - generates a queueHooks object, 
or returns the current one
+       _queueHooks: function( elem, type ) {
+               var key = type + "queueHooks";
+               return data_priv.get( elem, key ) || data_priv.access( elem, 
key, {
+                       empty: jQuery.Callbacks("once memory").add(function() {
+                               data_priv.remove( elem, [ type + "queue", key ] 
);
+                       })
+               });
+       }
+});
+
+jQuery.fn.extend({
+       queue: function( type, data ) {
+               var setter = 2;
+
+               if ( typeof type !== "string" ) {
+                       data = type;
+                       type = "fx";
+                       setter--;
+               }
+
+               if ( arguments.length < setter ) {
+                       return jQuery.queue( this[0], type );
+               }
+
+               return data === undefined ?
+                       this :
+                       this.each(function() {
+                               var queue = jQuery.queue( this, type, data );
+
+                               // ensure a hooks for this queue
+                               jQuery._queueHooks( this, type );
+
+                               if ( type === "fx" && queue[0] !== "inprogress" 
) {
+                                       jQuery.dequeue( this, type );
+                               }
+                       });
+       },
+       dequeue: function( type ) {
+               return this.each(function() {
+                       jQuery.dequeue( this, type );
+               });
+       },
+       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, obj ) {
+               var tmp,
+                       count = 1,
+                       defer = jQuery.Deferred(),
+                       elements = this,
+                       i = this.length,
+                       resolve = function() {
+                               if ( !( --count ) ) {
+                                       defer.resolveWith( elements, [ elements 
] );
+                               }
+                       };
+
+               if ( typeof type !== "string" ) {
+                       obj = type;
+                       type = undefined;
+               }
+               type = type || "fx";
+
+               while ( i-- ) {
+                       tmp = data_priv.get( elements[ i ], type + "queueHooks" 
);
+                       if ( tmp && tmp.empty ) {
+                               count++;
+                               tmp.empty.add( resolve );
+                       }
+               }
+               resolve();
+               return defer.promise( obj );
+       }
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+               // isHidden might be called from jQuery#filter function;
+               // in that case, element will be second argument
+               elem = el || elem;
+               return jQuery.css( elem, "display" ) === "none" || 
!jQuery.contains( elem.ownerDocument, elem );
+       };
+
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+       var fragment = document.createDocumentFragment(),
+               div = fragment.appendChild( document.createElement( "div" ) ),
+               input = document.createElement( "input" );
+
+       // #11217 - WebKit loses check when the name is after the checked 
attribute
+       // Support: Windows Web Apps (WWA)
+       // `name` and `type` need .setAttribute for WWA
+       input.setAttribute( "type", "radio" );
+       input.setAttribute( "checked", "checked" );
+       input.setAttribute( "name", "t" );
+
+       div.appendChild( input );
+
+       // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+       // old WebKit doesn't clone checked state correctly in fragments
+       support.checkClone = div.cloneNode( true ).cloneNode( true 
).lastChild.checked;
+
+       // Make sure textarea (and checkbox) defaultValue is properly cloned
+       // Support: IE9-IE11+
+       div.innerHTML = "<textarea>x</textarea>";
+       support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+})();
+var strundefined = typeof undefined;
+
+
+
+support.focusinBubbles = "onfocusin" in window;
+
+
+var
+       rkeyEvent = /^key/,
+       rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+       rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+       rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+       return true;
+}
+
+function returnFalse() {
+       return false;
+}
+
+function safeActiveElement() {
+       try {
+               return document.activeElement;
+       } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+       global: {},
+
+       add: function( elem, types, handler, data, selector ) {
+
+               var handleObjIn, eventHandle, tmp,
+                       events, t, handleObj,
+                       special, handlers, type, namespaces, origType,
+                       elemData = data_priv.get( elem );
+
+               // Don't attach events to noData or text/comment nodes (but 
allow plain objects)
+               if ( !elemData ) {
+                       return;
+               }
+
+               // Caller can pass in an object of custom data in lieu of the 
handler
+               if ( handler.handler ) {
+                       handleObjIn = handler;
+                       handler = handleObjIn.handler;
+                       selector = handleObjIn.selector;
+               }
+
+               // Make sure that the handler has a unique ID, used to 
find/remove it later
+               if ( !handler.guid ) {
+                       handler.guid = jQuery.guid++;
+               }
+
+               // Init the element's event structure and main handler, if this 
is the first
+               if ( !(events = elemData.events) ) {
+                       events = elemData.events = {};
+               }
+               if ( !(eventHandle = elemData.handle) ) {
+                       eventHandle = elemData.handle = function( e ) {
+                               // Discard the second event of a 
jQuery.event.trigger() and
+                               // when an event is called after a page has 
unloaded
+                               return typeof jQuery !== strundefined && 
jQuery.event.triggered !== e.type ?
+                                       jQuery.event.dispatch.apply( elem, 
arguments ) : undefined;
+                       };
+               }
+
+               // Handle multiple events separated by a space
+               types = ( types || "" ).match( rnotwhite ) || [ "" ];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[t] ) || [];
+                       type = origType = tmp[1];
+                       namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+                       // There *must* be a type, no attaching namespace-only 
handlers
+                       if ( !type ) {
+                               continue;
+                       }
+
+                       // If event changes its type, use the special event 
handlers for the changed type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // If selector defined, determine special event api 
type, otherwise given type
+                       type = ( selector ? special.delegateType : 
special.bindType ) || type;
+
+                       // Update special based on newly reset type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // handleObj is passed to all event handlers
+                       handleObj = jQuery.extend({
+                               type: type,
+                               origType: origType,
+                               data: data,
+                               handler: handler,
+                               guid: handler.guid,
+                               selector: selector,
+                               needsContext: selector && 
jQuery.expr.match.needsContext.test( selector ),
+                               namespace: namespaces.join(".")
+                       }, handleObjIn );
+
+                       // Init the event handler queue if we're the first
+                       if ( !(handlers = events[ type ]) ) {
+                               handlers = events[ type ] = [];
+                               handlers.delegateCount = 0;
+
+                               // Only use addEventListener if the special 
events handler returns false
+                               if ( !special.setup || special.setup.call( 
elem, data, namespaces, eventHandle ) === false ) {
+                                       if ( elem.addEventListener ) {
+                                               elem.addEventListener( type, 
eventHandle, false );
+                                       }
+                               }
+                       }
+
+                       if ( special.add ) {
+                               special.add.call( elem, handleObj );
+
+                               if ( !handleObj.handler.guid ) {
+                                       handleObj.handler.guid = handler.guid;
+                               }
+                       }
+
+                       // Add to the element's handler list, delegates in front
+                       if ( selector ) {
+                               handlers.splice( handlers.delegateCount++, 0, 
handleObj );
+                       } else {
+                               handlers.push( handleObj );
+                       }
+
+                       // Keep track of which events have ever been used, for 
event optimization
+                       jQuery.event.global[ type ] = true;
+               }
+
+       },
+
+       // Detach an event or set of events from an element
+       remove: function( elem, types, handler, selector, mappedTypes ) {
+
+               var j, origCount, tmp,
+                       events, t, handleObj,
+                       special, handlers, type, namespaces, origType,
+                       elemData = data_priv.hasData( elem ) && data_priv.get( 
elem );
+
+               if ( !elemData || !(events = elemData.events) ) {
+                       return;
+               }
+
+               // Once for each type.namespace in types; type may be omitted
+               types = ( types || "" ).match( rnotwhite ) || [ "" ];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[t] ) || [];
+                       type = origType = tmp[1];
+                       namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+                       // Unbind all events (on this namespace, if provided) 
for the element
+                       if ( !type ) {
+                               for ( type in events ) {
+                                       jQuery.event.remove( elem, type + 
types[ t ], handler, selector, true );
+                               }
+                               continue;
+                       }
+
+                       special = jQuery.event.special[ type ] || {};
+                       type = ( selector ? special.delegateType : 
special.bindType ) || type;
+                       handlers = events[ type ] || [];
+                       tmp = tmp[2] && new RegExp( "(^|\\.)" + 
namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+                       // Remove matching events
+                       origCount = j = handlers.length;
+                       while ( j-- ) {
+                               handleObj = handlers[ j ];
+
+                               if ( ( mappedTypes || origType === 
handleObj.origType ) &&
+                                       ( !handler || handler.guid === 
handleObj.guid ) &&
+                                       ( !tmp || tmp.test( handleObj.namespace 
) ) &&
+                                       ( !selector || selector === 
handleObj.selector || selector === "**" && handleObj.selector ) ) {
+                                       handlers.splice( j, 1 );
+
+                                       if ( handleObj.selector ) {
+                                               handlers.delegateCount--;
+                                       }
+                                       if ( special.remove ) {
+                                               special.remove.call( elem, 
handleObj );
+                                       }
+                               }
+                       }
+
+                       // Remove generic event handler if we removed something 
and no more handlers exist
+                       // (avoids potential for endless recursion during 
removal of special event handlers)
+                       if ( origCount && !handlers.length ) {
+                               if ( !special.teardown || 
special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+                                       jQuery.removeEvent( elem, type, 
elemData.handle );
+                               }
+
+                               delete events[ type ];
+                       }
+               }
+
+               // Remove the expando if it's no longer used
+               if ( jQuery.isEmptyObject( events ) ) {
+                       delete elemData.handle;
+                       data_priv.remove( elem, "events" );
+               }
+       },
+
+       trigger: function( event, data, elem, onlyHandlers ) {
+
+               var i, cur, tmp, bubbleType, ontype, handle, special,
+                       eventPath = [ elem || document ],
+                       type = hasOwn.call( event, "type" ) ? event.type : 
event,
+                       namespaces = hasOwn.call( event, "namespace" ) ? 
event.namespace.split(".") : [];
+
+               cur = tmp = elem = elem || document;
+
+               // Don't do events on text and comment nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               // focus/blur morphs to focusin/out; ensure we're not firing 
them right now
+               if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+                       return;
+               }
+
+               if ( type.indexOf(".") >= 0 ) {
+                       // Namespaced trigger; create a regexp to match event 
type in handle()
+                       namespaces = type.split(".");
+                       type = namespaces.shift();
+                       namespaces.sort();
+               }
+               ontype = type.indexOf(":") < 0 && "on" + type;
+
+               // Caller can pass in a jQuery.Event object, Object, or just an 
event type string
+               event = event[ jQuery.expando ] ?
+                       event :
+                       new jQuery.Event( type, typeof event === "object" && 
event );
+
+               // Trigger bitmask: & 1 for native handlers; & 2 for jQuery 
(always true)
+               event.isTrigger = onlyHandlers ? 2 : 3;
+               event.namespace = namespaces.join(".");
+               event.namespace_re = event.namespace ?
+                       new RegExp( "(^|\\.)" + 
namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+                       null;
+
+               // Clean up the event in case it is being reused
+               event.result = undefined;
+               if ( !event.target ) {
+                       event.target = elem;
+               }
+
+               // Clone any incoming data and prepend the event, creating the 
handler arg list
+               data = data == null ?
+                       [ event ] :
+                       jQuery.makeArray( data, [ event ] );
+
+               // Allow special events to draw outside the lines
+               special = jQuery.event.special[ type ] || {};
+               if ( !onlyHandlers && special.trigger && special.trigger.apply( 
elem, data ) === false ) {
+                       return;
+               }
+
+               // Determine event propagation path in advance, per W3C events 
spec (#9951)
+               // Bubble up to document, then to window; watch for a global 
ownerDocument var (#9724)
+               if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( 
elem ) ) {
+
+                       bubbleType = special.delegateType || type;
+                       if ( !rfocusMorph.test( bubbleType + type ) ) {
+                               cur = cur.parentNode;
+                       }
+                       for ( ; cur; cur = cur.parentNode ) {
+                               eventPath.push( cur );
+                               tmp = cur;
+                       }
+
+                       // Only add window if we got to document (e.g., not 
plain obj or detached DOM)
+                       if ( tmp === (elem.ownerDocument || document) ) {
+                               eventPath.push( tmp.defaultView || 
tmp.parentWindow || window );
+                       }
+               }
+
+               // Fire handlers on the event path
+               i = 0;
+               while ( (cur = eventPath[i++]) && !event.isPropagationStopped() 
) {
+
+                       event.type = i > 1 ?
+                               bubbleType :
+                               special.bindType || type;
+
+                       // jQuery handler
+                       handle = ( data_priv.get( cur, "events" ) || {} )[ 
event.type ] && data_priv.get( cur, "handle" );
+                       if ( handle ) {
+                               handle.apply( cur, data );
+                       }
+
+                       // Native handler
+                       handle = ontype && cur[ ontype ];
+                       if ( handle && handle.apply && jQuery.acceptData( cur ) 
) {
+                               event.result = handle.apply( cur, data );
+                               if ( event.result === false ) {
+                                       event.preventDefault();
+                               }
+                       }
+               }
+               event.type = type;
+
+               // If nobody prevented the default action, do it now
+               if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+                       if ( (!special._default || special._default.apply( 
eventPath.pop(), data ) === false) &&
+                               jQuery.acceptData( elem ) ) {
+
+                               // Call a native DOM method on the target with 
the same name name as the event.
+                               // Don't do default actions on window, that's 
where global variables be (#6170)
+                               if ( ontype && jQuery.isFunction( elem[ type ] 
) && !jQuery.isWindow( elem ) ) {
+
+                                       // Don't re-trigger an onFOO event when 
we call its FOO() method
+                                       tmp = elem[ ontype ];
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = null;
+                                       }
+
+                                       // Prevent re-triggering of the same 
event, since we already bubbled it above
+                                       jQuery.event.triggered = type;
+                                       elem[ type ]();
+                                       jQuery.event.triggered = undefined;
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = tmp;
+                                       }
+                               }
+                       }
+               }
+
+               return event.result;
+       },
+
+       dispatch: function( event ) {
+
+               // Make a writable jQuery.Event from the native event object
+               event = jQuery.event.fix( event );
+
+               var i, j, ret, matched, handleObj,
+                       handlerQueue = [],
+                       args = slice.call( arguments ),
+                       handlers = ( data_priv.get( this, "events" ) || {} )[ 
event.type ] || [],
+                       special = jQuery.event.special[ event.type ] || {};
+
+               // Use the fix-ed jQuery.Event rather than the (read-only) 
native event
+               args[0] = event;
+               event.delegateTarget = this;
+
+               // Call the preDispatch hook for the mapped type, and let it 
bail if desired
+               if ( special.preDispatch && special.preDispatch.call( this, 
event ) === false ) {
+                       return;
+               }
+
+               // Determine handlers
+               handlerQueue = jQuery.event.handlers.call( this, event, 
handlers );
+
+               // Run delegates first; they may want to stop propagation 
beneath us
+               i = 0;
+               while ( (matched = handlerQueue[ i++ ]) && 
!event.isPropagationStopped() ) {
+                       event.currentTarget = matched.elem;
+
+                       j = 0;
+                       while ( (handleObj = matched.handlers[ j++ ]) && 
!event.isImmediatePropagationStopped() ) {
+
+                               // Triggered event must either 1) have no 
namespace, or
+                               // 2) have namespace(s) a subset or equal to 
those in the bound event (both can have no namespace).
+                               if ( !event.namespace_re || 
event.namespace_re.test( handleObj.namespace ) ) {
+
+                                       event.handleObj = handleObj;
+                                       event.data = handleObj.data;
+
+                                       ret = ( (jQuery.event.special[ 
handleObj.origType ] || {}).handle || handleObj.handler )
+                                                       .apply( matched.elem, 
args );
+
+                                       if ( ret !== undefined ) {
+                                               if ( (event.result = ret) === 
false ) {
+                                                       event.preventDefault();
+                                                       event.stopPropagation();
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // Call the postDispatch hook for the mapped type
+               if ( special.postDispatch ) {
+                       special.postDispatch.call( this, event );
+               }
+
+               return event.result;
+       },
+
+       handlers: function( event, handlers ) {
+               var i, matches, sel, handleObj,
+                       handlerQueue = [],
+                       delegateCount = handlers.delegateCount,
+                       cur = event.target;
+
+               // Find delegate handlers
+               // Black-hole SVG <use> instance trees (#13180)
+               // Avoid non-left-click bubbling in Firefox (#3861)
+               if ( delegateCount && cur.nodeType && (!event.button || 
event.type !== "click") ) {
+
+                       for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+                               // Don't process clicks on disabled elements 
(#6911, #8165, #11382, #11764)
+                               if ( cur.disabled !== true || event.type !== 
"click" ) {
+                                       matches = [];
+                                       for ( i = 0; i < delegateCount; i++ ) {
+                                               handleObj = handlers[ i ];
+
+                                               // Don't conflict with 
Object.prototype properties (#13203)
+                                               sel = handleObj.selector + " ";
+
+                                               if ( matches[ sel ] === 
undefined ) {
+                                                       matches[ sel ] = 
handleObj.needsContext ?
+                                                               jQuery( sel, 
this ).index( cur ) >= 0 :
+                                                               jQuery.find( 
sel, this, null, [ cur ] ).length;
+                                               }
+                                               if ( matches[ sel ] ) {
+                                                       matches.push( handleObj 
);
+                                               }
+                                       }
+                                       if ( matches.length ) {
+                                               handlerQueue.push({ elem: cur, 
handlers: matches });
+                                       }
+                               }
+                       }
+               }
+
+               // Add the remaining (directly-bound) handlers
+               if ( delegateCount < handlers.length ) {
+                       handlerQueue.push({ elem: this, handlers: 
handlers.slice( delegateCount ) });
+               }
+
+               return handlerQueue;
+       },
+
+       // Includes some event props shared by KeyEvent and MouseEvent
+       props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase 
metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+       fixHooks: {},
+
+       keyHooks: {
+               props: "char charCode key keyCode".split(" "),
+               filter: function( event, original ) {
+
+                       // Add which for key events
+                       if ( event.which == null ) {
+                               event.which = original.charCode != null ? 
original.charCode : original.keyCode;
+                       }
+
+                       return event;
+               }
+       },
+
+       mouseHooks: {
+               props: "button buttons clientX clientY offsetX offsetY pageX 
pageY screenX screenY toElement".split(" "),
+               filter: function( event, original ) {
+                       var eventDoc, doc, body,
+                               button = original.button;
+
+                       // Calculate pageX/Y if missing and clientX/Y available
+                       if ( event.pageX == null && original.clientX != null ) {
+                               eventDoc = event.target.ownerDocument || 
document;
+                               doc = eventDoc.documentElement;
+                               body = eventDoc.body;
+
+                               event.pageX = original.clientX + ( doc && 
doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || 
body && body.clientLeft || 0 );
+                               event.pageY = original.clientY + ( doc && 
doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || 
body && body.clientTop  || 0 );
+                       }
+
+                       // Add which for click: 1 === left; 2 === middle; 3 === 
right
+                       // Note: button is not normalized, so don't use it
+                       if ( !event.which && button !== undefined ) {
+                               event.which = ( button & 1 ? 1 : ( button & 2 ? 
3 : ( button & 4 ? 2 : 0 ) ) );
+                       }
+
+                       return event;
+               }
+       },
+
+       fix: function( event ) {
+               if ( event[ jQuery.expando ] ) {
+                       return event;
+               }
+
+               // Create a writable copy of the event object and normalize 
some properties
+               var i, prop, copy,
+                       type = event.type,
+                       originalEvent = event,
+                       fixHook = this.fixHooks[ type ];
+
+               if ( !fixHook ) {
+                       this.fixHooks[ type ] = fixHook =
+                               rmouseEvent.test( type ) ? this.mouseHooks :
+                               rkeyEvent.test( type ) ? this.keyHooks :
+                               {};
+               }
+               copy = fixHook.props ? this.props.concat( fixHook.props ) : 
this.props;
+
+               event = new jQuery.Event( originalEvent );
+
+               i = copy.length;
+               while ( i-- ) {
+                       prop = copy[ i ];
+                       event[ prop ] = originalEvent[ prop ];
+               }
+
+               // Support: Cordova 2.5 (WebKit) (#13255)
+               // All events should have a target; Cordova deviceready doesn't
+               if ( !event.target ) {
+                       event.target = document;
+               }
+
+               // Support: Safari 6.0+, Chrome < 28
+               // Target should not be a text node (#504, #13143)
+               if ( event.target.nodeType === 3 ) {
+                       event.target = event.target.parentNode;
+               }
+
+               return fixHook.filter ? fixHook.filter( event, originalEvent ) 
: event;
+       },
+
+       special: {
+               load: {
+                       // Prevent triggered image.load events from bubbling to 
window.load
+                       noBubble: true
+               },
+               focus: {
+                       // Fire native event if possible so blur/focus sequence 
is correct
+                       trigger: function() {
+                               if ( this !== safeActiveElement() && this.focus 
) {
+                                       this.focus();
+                                       return false;
+                               }
+                       },
+                       delegateType: "focusin"
+               },
+               blur: {
+                       trigger: function() {
+                               if ( this === safeActiveElement() && this.blur 
) {
+                                       this.blur();
+                                       return false;
+                               }
+                       },
+                       delegateType: "focusout"
+               },
+               click: {
+                       // For checkbox, fire native event so checked state 
will be right
+                       trigger: function() {
+                               if ( this.type === "checkbox" && this.click && 
jQuery.nodeName( this, "input" ) ) {
+                                       this.click();
+                                       return false;
+                               }
+                       },
+
+                       // For cross-browser consistency, don't fire native 
.click() on links
+                       _default: function( event ) {
+                               return jQuery.nodeName( event.target, "a" );
+                       }
+               },
+
+               beforeunload: {
+                       postDispatch: function( event ) {
+
+                               // Support: Firefox 20+
+                               // Firefox doesn't alert if the returnValue 
field is not set.
+                               if ( event.result !== undefined && 
event.originalEvent ) {
+                                       event.originalEvent.returnValue = 
event.result;
+                               }
+                       }
+               }
+       },
+
+       simulate: function( type, elem, event, bubble ) {
+               // Piggyback on a donor event to simulate a different one.
+               // Fake originalEvent to avoid donor's stopPropagation, but if 
the
+               // simulated event prevents default then we do the same on the 
donor.
+               var e = jQuery.extend(
+                       new jQuery.Event(),
+                       event,
+                       {
+                               type: type,
+                               isSimulated: true,
+                               originalEvent: {}
+                       }
+               );
+               if ( bubble ) {
+                       jQuery.event.trigger( e, null, elem );
+               } else {
+                       jQuery.event.dispatch.call( elem, e );
+               }
+               if ( e.isDefaultPrevented() ) {
+                       event.preventDefault();
+               }
+       }
+};
+
+jQuery.removeEvent = function( elem, type, handle ) {
+       if ( elem.removeEventListener ) {
+               elem.removeEventListener( type, handle, false );
+       }
+};
+
+jQuery.Event = function( src, props ) {
+       // Allow instantiation without the 'new' keyword
+       if ( !(this instanceof jQuery.Event) ) {
+               return new jQuery.Event( src, props );
+       }
+
+       // Event object
+       if ( src && src.type ) {
+               this.originalEvent = src;
+               this.type = src.type;
+
+               // Events bubbling up the document may have been marked as 
prevented
+               // by a handler lower down the tree; reflect the correct value.
+               this.isDefaultPrevented = src.defaultPrevented ||
+                               src.defaultPrevented === undefined &&
+                               // Support: Android < 4.0
+                               src.returnValue === false ?
+                       returnTrue :
+                       returnFalse;
+
+       // Event type
+       } else {
+               this.type = src;
+       }
+
+       // Put explicitly provided properties onto the event object
+       if ( props ) {
+               jQuery.extend( this, props );
+       }
+
+       // Create a timestamp if incoming event doesn't have one
+       this.timeStamp = src && src.timeStamp || jQuery.now();
+
+       // Mark it as fixed
+       this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript 
Language Binding
+// 
http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+       isDefaultPrevented: returnFalse,
+       isPropagationStopped: returnFalse,
+       isImmediatePropagationStopped: returnFalse,
+
+       preventDefault: function() {
+               var e = this.originalEvent;
+
+               this.isDefaultPrevented = returnTrue;
+
+               if ( e && e.preventDefault ) {
+                       e.preventDefault();
+               }
+       },
+       stopPropagation: function() {
+               var e = this.originalEvent;
+
+               this.isPropagationStopped = returnTrue;
+
+               if ( e && e.stopPropagation ) {
+                       e.stopPropagation();
+               }
+       },
+       stopImmediatePropagation: function() {
+               var e = this.originalEvent;
+
+               this.isImmediatePropagationStopped = returnTrue;
+
+               if ( e && e.stopImmediatePropagation ) {
+                       e.stopImmediatePropagation();
+               }
+
+               this.stopPropagation();
+       }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// Support: Chrome 15+
+jQuery.each({
+       mouseenter: "mouseover",
+       mouseleave: "mouseout",
+       pointerenter: "pointerover",
+       pointerleave: "pointerout"
+}, function( orig, fix ) {
+       jQuery.event.special[ orig ] = {
+               delegateType: fix,
+               bindType: fix,
+
+               handle: function( event ) {
+                       var ret,
+                               target = this,
+                               related = event.relatedTarget,
+                               handleObj = event.handleObj;
+
+                       // For mousenter/leave call the handler if related is 
outside the target.
+                       // NB: No relatedTarget if the mouse left/entered the 
browser window
+                       if ( !related || (related !== target && 
!jQuery.contains( target, related )) ) {
+                               event.type = handleObj.origType;
+                               ret = handleObj.handler.apply( this, arguments 
);
+                               event.type = fix;
+                       }
+                       return ret;
+               }
+       };
+});
+
+// Create "bubbling" focus and blur events
+// Support: Firefox, Chrome, Safari
+if ( !support.focusinBubbles ) {
+       jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix 
) {
+
+               // Attach a single capturing handler on the document while 
someone wants focusin/focusout
+               var handler = function( event ) {
+                               jQuery.event.simulate( fix, event.target, 
jQuery.event.fix( event ), true );
+                       };
+
+               jQuery.event.special[ fix ] = {
+                       setup: function() {
+                               var doc = this.ownerDocument || this,
+                                       attaches = data_priv.access( doc, fix );
+
+                               if ( !attaches ) {
+                                       doc.addEventListener( orig, handler, 
true );
+                               }
+                               data_priv.access( doc, fix, ( attaches || 0 ) + 
1 );
+                       },
+                       teardown: function() {
+                               var doc = this.ownerDocument || this,
+                                       attaches = data_priv.access( doc, fix ) 
- 1;
+
+                               if ( !attaches ) {
+                                       doc.removeEventListener( orig, handler, 
true );
+                                       data_priv.remove( doc, fix );
+
+                               } else {
+                                       data_priv.access( doc, fix, attaches );
+                               }
+                       }
+               };
+       });
+}
+
+jQuery.fn.extend({
+
+       on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+               var origFn, type;
+
+               // Types can be a map of types/handlers
+               if ( typeof types === "object" ) {
+                       // ( types-Object, selector, data )
+                       if ( typeof selector !== "string" ) {
+                               // ( types-Object, data )
+                               data = data || selector;
+                               selector = undefined;
+                       }
+                       for ( type in types ) {
+                               this.on( type, selector, data, types[ type ], 
one );
+                       }
+                       return this;
+               }
+
+               if ( data == null && fn == null ) {
+                       // ( types, fn )
+                       fn = selector;
+                       data = selector = undefined;
+               } else if ( fn == null ) {
+                       if ( typeof selector === "string" ) {
+                               // ( types, selector, fn )
+                               fn = data;
+                               data = undefined;
+                       } else {
+                               // ( types, data, fn )
+                               fn = data;
+                               data = selector;
+                               selector = undefined;
+                       }
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               } else if ( !fn ) {
+                       return this;
+               }
+
+               if ( one === 1 ) {
+                       origFn = fn;
+                       fn = function( event ) {
+                               // Can use an empty set, since event contains 
the info
+                               jQuery().off( event );
+                               return origFn.apply( this, arguments );
+                       };
+                       // Use same guid so caller can remove using origFn
+                       fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ 
);
+               }
+               return this.each( function() {
+                       jQuery.event.add( this, types, fn, data, selector );
+               });
+       },
+       one: function( types, selector, data, fn ) {
+               return this.on( types, selector, data, fn, 1 );
+       },
+       off: function( types, selector, fn ) {
+               var handleObj, type;
+               if ( types && types.preventDefault && types.handleObj ) {
+                       // ( event )  dispatched jQuery.Event
+                       handleObj = types.handleObj;
+                       jQuery( types.delegateTarget ).off(
+                               handleObj.namespace ? handleObj.origType + "." 
+ handleObj.namespace : handleObj.origType,
+                               handleObj.selector,
+                               handleObj.handler
+                       );
+                       return this;
+               }
+               if ( typeof types === "object" ) {
+                       // ( types-object [, selector] )
+                       for ( type in types ) {
+                               this.off( type, selector, types[ type ] );
+                       }
+                       return this;
+               }
+               if ( selector === false || typeof selector === "function" ) {
+                       // ( types [, fn] )
+                       fn = selector;
+                       selector = undefined;
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               }
+               return this.each(function() {
+                       jQuery.event.remove( this, types, fn, selector );
+               });
+       },
+
+       trigger: function( type, data ) {
+               return this.each(function() {
+                       jQuery.event.trigger( type, data, this );
+               });
+       },
+       triggerHandler: function( type, data ) {
+               var elem = this[0];
+               if ( elem ) {
+                       return jQuery.event.trigger( type, data, elem, true );
+               }
+       }
+});
+
+
+var
+       rxhtmlTag = 
/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+       rtagName = /<([\w:]+)/,
+       rhtml = /<|&#?\w+;/,
+       rnoInnerhtml = /<(?:script|style|link)/i,
+       // checked="checked" or checked
+       rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+       rscriptType = /^$|\/(?:java|ecma)script/i,
+       rscriptTypeMasked = /^true\/(.*)/,
+       rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+       // We have to close these tags to support XHTML (#13200)
+       wrapMap = {
+
+               // Support: IE 9
+               option: [ 1, "<select multiple='multiple'>", "</select>" ],
+
+               thead: [ 1, "<table>", "</table>" ],
+               col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+               tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+               td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+               _default: [ 0, "", "" ]
+       };
+
+// Support: IE 9
+wrapMap.optgroup = wrapMap.option;
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = 
wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: 1.x compatibility
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+       return jQuery.nodeName( elem, "table" ) &&
+               jQuery.nodeName( content.nodeType !== 11 ? content : 
content.firstChild, "tr" ) ?
+
+               elem.getElementsByTagName("tbody")[0] ||
+                       elem.appendChild( 
elem.ownerDocument.createElement("tbody") ) :
+               elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM 
manipulation
+function disableScript( elem ) {
+       elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
+       return elem;
+}
+function restoreScript( elem ) {
+       var match = rscriptTypeMasked.exec( elem.type );
+
+       if ( match ) {
+               elem.type = match[ 1 ];
+       } else {
+               elem.removeAttribute("type");
+       }
+
+       return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+       var i = 0,
+               l = elems.length;
+
+       for ( ; i < l; i++ ) {
+               data_priv.set(
+                       elems[ i ], "globalEval", !refElements || 
data_priv.get( refElements[ i ], "globalEval" )
+               );
+       }
+}
+
+function cloneCopyEvent( src, dest ) {
+       var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
+
+       if ( dest.nodeType !== 1 ) {
+               return;
+       }
+
+       // 1. Copy private data: events, handlers, etc.
+       if ( data_priv.hasData( src ) ) {
+               pdataOld = data_priv.access( src );
+               pdataCur = data_priv.set( dest, pdataOld );
+               events = pdataOld.events;
+
+               if ( events ) {
+                       delete pdataCur.handle;
+                       pdataCur.events = {};
+
+                       for ( type in events ) {
+                               for ( i = 0, l = events[ type ].length; i < l; 
i++ ) {
+                                       jQuery.event.add( dest, type, events[ 
type ][ i ] );
+                               }
+                       }
+               }
+       }
+
+       // 2. Copy user data
+       if ( data_user.hasData( src ) ) {
+               udataOld = data_user.access( src );
+               udataCur = jQuery.extend( {}, udataOld );
+
+               data_user.set( dest, udataCur );
+       }
+}
+
+function getAll( context, tag ) {
+       var ret = context.getElementsByTagName ? context.getElementsByTagName( 
tag || "*" ) :
+                       context.querySelectorAll ? context.querySelectorAll( 
tag || "*" ) :
+                       [];
+
+       return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+               jQuery.merge( [ context ], ret ) :
+               ret;
+}
+
+// Support: IE >= 9
+function fixInput( src, dest ) {
+       var nodeName = dest.nodeName.toLowerCase();
+
+       // Fails to persist the checked state of a cloned checkbox or radio 
button.
+       if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+               dest.checked = src.checked;
+
+       // Fails to return the selected option to the default selected state 
when cloning options
+       } else if ( nodeName === "input" || nodeName === "textarea" ) {
+               dest.defaultValue = src.defaultValue;
+       }
+}
+
+jQuery.extend({
+       clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+               var i, l, srcElements, destElements,
+                       clone = elem.cloneNode( true ),
+                       inPage = jQuery.contains( elem.ownerDocument, elem );
+
+               // Support: IE >= 9
+               // Fix Cloning issues
+               if ( !support.noCloneChecked && ( elem.nodeType === 1 || 
elem.nodeType === 11 ) &&
+                               !jQuery.isXMLDoc( elem ) ) {
+
+                       // We eschew Sizzle here for performance reasons: 
http://jsperf.com/getall-vs-sizzle/2
+                       destElements = getAll( clone );
+                       srcElements = getAll( elem );
+
+                       for ( i = 0, l = srcElements.length; i < l; i++ ) {
+                               fixInput( srcElements[ i ], destElements[ i ] );
+                       }
+               }
+
+               // Copy the events from the original to the clone
+               if ( dataAndEvents ) {
+                       if ( deepDataAndEvents ) {
+                               srcElements = srcElements || getAll( elem );
+                               destElements = destElements || getAll( clone );
+
+                               for ( i = 0, l = srcElements.length; i < l; i++ 
) {
+                                       cloneCopyEvent( srcElements[ i ], 
destElements[ i ] );
+                               }
+                       } else {
+                               cloneCopyEvent( elem, clone );
+                       }
+               }
+
+               // Preserve script evaluation history
+               destElements = getAll( clone, "script" );
+               if ( destElements.length > 0 ) {
+                       setGlobalEval( destElements, !inPage && getAll( elem, 
"script" ) );
+               }
+
+               // Return the cloned set
+               return clone;
+       },
+
+       buildFragment: function( elems, context, scripts, selection ) {
+               var elem, tmp, tag, wrap, contains, j,
+                       fragment = context.createDocumentFragment(),
+                       nodes = [],
+                       i = 0,
+                       l = elems.length;
+
+               for ( ; i < l; i++ ) {
+                       elem = elems[ i ];
+
+                       if ( elem || elem === 0 ) {
+
+                               // Add nodes directly
+                               if ( jQuery.type( elem ) === "object" ) {
+                                       // Support: QtWebKit
+                                       // jQuery.merge because push.apply(_, 
arraylike) throws
+                                       jQuery.merge( nodes, elem.nodeType ? [ 
elem ] : elem );
+
+                               // Convert non-html into a text node
+                               } else if ( !rhtml.test( elem ) ) {
+                                       nodes.push( context.createTextNode( 
elem ) );
+
+                               // Convert html into DOM nodes
+                               } else {
+                                       tmp = tmp || fragment.appendChild( 
context.createElement("div") );
+
+                                       // Deserialize a standard representation
+                                       tag = ( rtagName.exec( elem ) || [ "", 
"" ] )[ 1 ].toLowerCase();
+                                       wrap = wrapMap[ tag ] || 
wrapMap._default;
+                                       tmp.innerHTML = wrap[ 1 ] + 
elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
+
+                                       // Descend through wrappers to the 
right content
+                                       j = wrap[ 0 ];
+                                       while ( j-- ) {
+                                               tmp = tmp.lastChild;
+                                       }
+
+                                       // Support: QtWebKit
+                                       // jQuery.merge because push.apply(_, 
arraylike) throws
+                                       jQuery.merge( nodes, tmp.childNodes );
+
+                                       // Remember the top-level container
+                                       tmp = fragment.firstChild;
+
+                                       // Fixes #12346
+                                       // Support: Webkit, IE
+                                       tmp.textContent = "";
+                               }
+                       }
+               }
+
+               // Remove wrapper from fragment
+               fragment.textContent = "";
+
+               i = 0;
+               while ( (elem = nodes[ i++ ]) ) {
+
+                       // #4087 - If origin and destination elements are the 
same, and this is
+                       // that element, do not do anything
+                       if ( selection && jQuery.inArray( elem, selection ) !== 
-1 ) {
+                               continue;
+                       }
+
+                       contains = jQuery.contains( elem.ownerDocument, elem );
+
+                       // Append to fragment
+                       tmp = getAll( fragment.appendChild( elem ), "script" );
+
+                       // Preserve script evaluation history
+                       if ( contains ) {
+                               setGlobalEval( tmp );
+                       }
+
+                       // Capture executables
+                       if ( scripts ) {
+                               j = 0;
+                               while ( (elem = tmp[ j++ ]) ) {
+                                       if ( rscriptType.test( elem.type || "" 
) ) {
+                                               scripts.push( elem );
+                                       }
+                               }
+                       }
+               }
+
+               return fragment;
+       },
+
+       cleanData: function( elems ) {
+               var data, elem, type, key,
+                       special = jQuery.event.special,
+                       i = 0;
+
+               for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
+                       if ( jQuery.acceptData( elem ) ) {
+                               key = elem[ data_priv.expando ];
+
+                               if ( key && (data = data_priv.cache[ key ]) ) {
+                                       if ( data.events ) {
+                                               for ( type in data.events ) {
+                                                       if ( special[ type ] ) {
+                                                               
jQuery.event.remove( elem, type );
+
+                                                       // This is a shortcut 
to avoid jQuery.event.remove's overhead
+                                                       } else {
+                                                               
jQuery.removeEvent( elem, type, data.handle );
+                                                       }
+                                               }
+                                       }
+                                       if ( data_priv.cache[ key ] ) {
+                                               // Discard any remaining 
`private` data
+                                               delete data_priv.cache[ key ];
+                                       }
+                               }
+                       }
+                       // Discard any remaining `user` data
+                       delete data_user.cache[ elem[ data_user.expando ] ];
+               }
+       }
+});
+
+jQuery.fn.extend({
+       text: function( value ) {
+               return access( this, function( value ) {
+                       return value === undefined ?
+                               jQuery.text( this ) :
+                               this.empty().each(function() {
+                                       if ( this.nodeType === 1 || 
this.nodeType === 11 || this.nodeType === 9 ) {
+                                               this.textContent = value;
+                                       }
+                               });
+               }, null, value, arguments.length );
+       },
+
+       append: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || 
this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.appendChild( elem );
+                       }
+               });
+       },
+
+       prepend: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || 
this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.insertBefore( elem, target.firstChild );
+                       }
+               });
+       },
+
+       before: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this );
+                       }
+               });
+       },
+
+       after: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, 
this.nextSibling );
+                       }
+               });
+       },
+
+       remove: function( selector, keepData /* Internal Use Only */ ) {
+               var elem,
+                       elems = selector ? jQuery.filter( selector, this ) : 
this,
+                       i = 0;
+
+               for ( ; (elem = elems[i]) != null; i++ ) {
+                       if ( !keepData && elem.nodeType === 1 ) {
+                               jQuery.cleanData( getAll( elem ) );
+                       }
+
+                       if ( elem.parentNode ) {
+                               if ( keepData && jQuery.contains( 
elem.ownerDocument, elem ) ) {
+                                       setGlobalEval( getAll( elem, "script" ) 
);
+                               }
+                               elem.parentNode.removeChild( elem );
+                       }
+               }
+
+               return this;
+       },
+
+       empty: function() {
+               var elem,
+                       i = 0;
+
+               for ( ; (elem = this[i]) != null; i++ ) {
+                       if ( elem.nodeType === 1 ) {
+
+                               // Prevent memory leaks
+                               jQuery.cleanData( getAll( elem, false ) );
+
+                               // Remove any remaining nodes
+                               elem.textContent = "";
+                       }
+               }
+
+               return this;
+       },
+
+       clone: function( dataAndEvents, deepDataAndEvents ) {
+               dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+               deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : 
deepDataAndEvents;
+
+               return this.map(function() {
+                       return jQuery.clone( this, dataAndEvents, 
deepDataAndEvents );
+               });
+       },
+
+       html: function( value ) {
+               return access( this, function( value ) {
+                       var elem = this[ 0 ] || {},
+                               i = 0,
+                               l = this.length;
+
+                       if ( value === undefined && elem.nodeType === 1 ) {
+                               return elem.innerHTML;
+                       }
+
+                       // See if we can take a shortcut and just use innerHTML
+                       if ( typeof value === "string" && !rnoInnerhtml.test( 
value ) &&
+                               !wrapMap[ ( rtagName.exec( value ) || [ "", "" 
] )[ 1 ].toLowerCase() ] ) {
+
+                               value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+                               try {
+                                       for ( ; i < l; i++ ) {
+                                               elem = this[ i ] || {};
+
+                                               // Remove element nodes and 
prevent memory leaks
+                                               if ( elem.nodeType === 1 ) {
+                                                       jQuery.cleanData( 
getAll( elem, false ) );
+                                                       elem.innerHTML = value;
+                                               }
+                                       }
+
+                                       elem = 0;
+
+                               // If using innerHTML throws an exception, use 
the fallback method
+                               } catch( e ) {}
+                       }
+
+                       if ( elem ) {
+                               this.empty().append( value );
+                       }
+               }, null, value, arguments.length );
+       },
+
+       replaceWith: function() {
+               var arg = arguments[ 0 ];
+
+               // Make the changes, replacing each context element with the 
new content
+               this.domManip( arguments, function( elem ) {
+                       arg = this.parentNode;
+
+                       jQuery.cleanData( getAll( this ) );
+
+                       if ( arg ) {
+                               arg.replaceChild( elem, this );
+                       }
+               });
+
+               // Force removal if there was no new content (e.g., from empty 
arguments)
+               return arg && (arg.length || arg.nodeType) ? this : 
this.remove();
+       },
+
+       detach: function( selector ) {
+               return this.remove( selector, true );
+       },
+
+       domManip: function( args, callback ) {
+
+               // Flatten any nested arrays
+               args = concat.apply( [], args );
+
+               var fragment, first, scripts, hasScripts, node, doc,
+                       i = 0,
+                       l = this.length,
+                       set = this,
+                       iNoClone = l - 1,
+                       value = args[ 0 ],
+                       isFunction = jQuery.isFunction( value );
+
+               // We can't cloneNode fragments that contain checked, in WebKit
+               if ( isFunction ||
+                               ( l > 1 && typeof value === "string" &&
+                                       !support.checkClone && rchecked.test( 
value ) ) ) {
+                       return this.each(function( index ) {
+                               var self = set.eq( index );
+                               if ( isFunction ) {
+                                       args[ 0 ] = value.call( this, index, 
self.html() );
+                               }
+                               self.domManip( args, callback );
+                       });
+               }
+
+               if ( l ) {
+                       fragment = jQuery.buildFragment( args, this[ 0 
].ownerDocument, false, this );
+                       first = fragment.firstChild;
+
+                       if ( fragment.childNodes.length === 1 ) {
+                               fragment = first;
+                       }
+
+                       if ( first ) {
+                               scripts = jQuery.map( getAll( fragment, 
"script" ), disableScript );
+                               hasScripts = scripts.length;
+
+                               // Use the original fragment for the last item 
instead of the first because it can end up
+                               // being emptied incorrectly in certain 
situations (#8070).
+                               for ( ; i < l; i++ ) {
+                                       node = fragment;
+
+                                       if ( i !== iNoClone ) {
+                                               node = jQuery.clone( node, 
true, true );
+
+                                               // Keep references to cloned 
scripts for later restoration
+                                               if ( hasScripts ) {
+                                                       // Support: QtWebKit
+                                                       // jQuery.merge because 
push.apply(_, arraylike) throws
+                                                       jQuery.merge( scripts, 
getAll( node, "script" ) );
+                                               }
+                                       }
+
+                                       callback.call( this[ i ], node, i );
+                               }
+
+                               if ( hasScripts ) {
+                                       doc = scripts[ scripts.length - 1 
].ownerDocument;
+
+                                       // Reenable scripts
+                                       jQuery.map( scripts, restoreScript );
+
+                                       // Evaluate executable scripts on first 
document insertion
+                                       for ( i = 0; i < hasScripts; i++ ) {
+                                               node = scripts[ i ];
+                                               if ( rscriptType.test( 
node.type || "" ) &&
+                                                       !data_priv.access( 
node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+                                                       if ( node.src ) {
+                                                               // Optional 
AJAX dependency, but won't run scripts if not present
+                                                               if ( 
jQuery._evalUrl ) {
+                                                                       
jQuery._evalUrl( node.src );
+                                                               }
+                                                       } else {
+                                                               
jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       }
+});
+
+jQuery.each({
+       appendTo: "append",
+       prependTo: "prepend",
+       insertBefore: "before",
+       insertAfter: "after",
+       replaceAll: "replaceWith"
+}, function( name, original ) {
+       jQuery.fn[ name ] = function( selector ) {
+               var elems,
+                       ret = [],
+                       insert = jQuery( selector ),
+                       last = insert.length - 1,
+                       i = 0;
+
+               for ( ; i <= last; i++ ) {
+                       elems = i === last ? this : this.clone( true );
+                       jQuery( insert[ i ] )[ original ]( elems );
+
+                       // Support: QtWebKit
+                       // .get() because push.apply(_, arraylike) throws
+                       push.apply( ret, elems.get() );
+               }
+
+               return this.pushStack( ret );
+       };
+});
+
+
+var iframe,
+       elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+       var style,
+               elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+               // getDefaultComputedStyle might be reliably used only on 
attached element
+               display = window.getDefaultComputedStyle && ( style = 
window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+                       // Use of this method is a temporary fix (more like 
optmization) until something better comes along,
+                       // since it was removed from specification and 
supported only in FF
+                       style.display : jQuery.css( elem[ 0 ], "display" );
+
+       // We don't have any data stored on the element,
+       // so use "detach" method as fast way to get rid of the element
+       elem.detach();
+
+       return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+       var doc = document,
+               display = elemdisplay[ nodeName ];
+
+       if ( !display ) {
+               display = actualDisplay( nodeName, doc );
+
+               // If the simple way fails, read from inside an iframe
+               if ( display === "none" || !display ) {
+
+                       // Use the already-created iframe if possible
+                       iframe = (iframe || jQuery( "<iframe frameborder='0' 
width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+                       // Always write a new HTML skeleton so Webkit and 
Firefox don't choke on reuse
+                       doc = iframe[ 0 ].contentDocument;
+
+                       // Support: IE
+                       doc.write();
+                       doc.close();
+
+                       display = actualDisplay( nodeName, doc );
+                       iframe.detach();
+               }
+
+               // Store the correct default display
+               elemdisplay[ nodeName ] = display;
+       }
+
+       return display;
+}
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+               return elem.ownerDocument.defaultView.getComputedStyle( elem, 
null );
+       };
+
+
+
+function curCSS( elem, name, computed ) {
+       var width, minWidth, maxWidth, ret,
+               style = elem.style;
+
+       computed = computed || getStyles( elem );
+
+       // Support: IE9
+       // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+       if ( computed ) {
+               ret = computed.getPropertyValue( name ) || computed[ name ];
+       }
+
+       if ( computed ) {
+
+               if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) 
) {
+                       ret = jQuery.style( elem, name );
+               }
+
+               // Support: iOS < 6
+               // A tribute to the "awesome hack by Dean Edwards"
+               // iOS < 6 (at least) returns percentage for a larger set of 
values, but width seems to be reliably pixels
+               // this is against the CSSOM draft spec: 
http://dev.w3.org/csswg/cssom/#resolved-values
+               if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+                       // Remember the original values
+                       width = style.width;
+                       minWidth = style.minWidth;
+                       maxWidth = style.maxWidth;
+
+                       // Put in the new values to get a computed value out
+                       style.minWidth = style.maxWidth = style.width = ret;
+                       ret = computed.width;
+
+                       // Revert the changed values
+                       style.width = width;
+                       style.minWidth = minWidth;
+                       style.maxWidth = maxWidth;
+               }
+       }
+
+       return ret !== undefined ?
+               // Support: IE
+               // IE returns zIndex value as an integer.
+               ret + "" :
+               ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+       // Define the hook, we'll check on the first run if it's really needed.
+       return {
+               get: function() {
+                       if ( conditionFn() ) {
+                               // Hook not needed (or it's not possible to use 
it due to missing dependency),
+                               // remove it.
+                               // Since there are no other hooks for 
marginRight, remove the whole object.
+                               delete this.get;
+                               return;
+                       }
+
+                       // Hook needed; redefine it so that the support test is 
not executed again.
+
+                       return (this.get = hookFn).apply( this, arguments );
+               }
+       };
+}
+
+
+(function() {
+       var pixelPositionVal, boxSizingReliableVal,
+               docElem = document.documentElement,
+               container = document.createElement( "div" ),
+               div = document.createElement( "div" );
+
+       if ( !div.style ) {
+               return;
+       }
+
+       div.style.backgroundClip = "content-box";
+       div.cloneNode( true ).style.backgroundClip = "";
+       support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+       container.style.cssText = 
"border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
+               "position:absolute";
+       container.appendChild( div );
+
+       // Executing both pixelPosition & boxSizingReliable tests require only 
one layout
+       // so they're executed at the same time to save the second computation.
+       function computePixelPositionAndBoxSizingReliable() {
+               div.style.cssText =
+                       // Support: Firefox<29, Android 2.3
+                       // Vendor-prefix box-sizing
+                       
"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+                       
"box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+                       "border:1px;padding:1px;width:4px;position:absolute";
+               div.innerHTML = "";
+               docElem.appendChild( container );
+
+               var divStyle = window.getComputedStyle( div, null );
+               pixelPositionVal = divStyle.top !== "1%";
+               boxSizingReliableVal = divStyle.width === "4px";
+
+               docElem.removeChild( container );
+       }
+
+       // Support: node.js jsdom
+       // Don't assume that getComputedStyle is a property of the global object
+       if ( window.getComputedStyle ) {
+               jQuery.extend( support, {
+                       pixelPosition: function() {
+                               // This test is executed only once but we still 
do memoizing
+                               // since we can use the boxSizingReliable 
pre-computing.
+                               // No need to check if the test was already 
performed, though.
+                               computePixelPositionAndBoxSizingReliable();
+                               return pixelPositionVal;
+                       },
+                       boxSizingReliable: function() {
+                               if ( boxSizingReliableVal == null ) {
+                                       
computePixelPositionAndBoxSizingReliable();
+                               }
+                               return boxSizingReliableVal;
+                       },
+                       reliableMarginRight: function() {
+                               // Support: Android 2.3
+                               // Check if div with explicit width and no 
margin-right incorrectly
+                               // gets computed margin-right based on width of 
container. (#3333)
+                               // WebKit Bug 13343 - getComputedStyle returns 
wrong value for margin-right
+                               // This support function is only executed once 
so no memoizing is needed.
+                               var ret,
+                                       marginDiv = div.appendChild( 
document.createElement( "div" ) );
+
+                               // Reset CSS: box-sizing; display; margin; 
border; padding
+                               marginDiv.style.cssText = div.style.cssText =
+                                       // Support: Firefox<29, Android 2.3
+                                       // Vendor-prefix box-sizing
+                                       
"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+                                       
"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+                               marginDiv.style.marginRight = 
marginDiv.style.width = "0";
+                               div.style.width = "1px";
+                               docElem.appendChild( container );
+
+                               ret = !parseFloat( window.getComputedStyle( 
marginDiv, null ).marginRight );
+
+                               docElem.removeChild( container );
+
+                               return ret;
+                       }
+               });
+       }
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct 
calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+       var ret, name,
+               old = {};
+
+       // Remember the old values, and insert the new ones
+       for ( name in options ) {
+               old[ name ] = elem.style[ name ];
+               elem.style[ name ] = options[ name ];
+       }
+
+       ret = callback.apply( elem, args || [] );
+
+       // Revert the old values
+       for ( name in options ) {
+               elem.style[ name ] = old[ name ];
+       }
+
+       return ret;
+};
+
+
+var
+       // swappable if display is none or starts with table except "table", 
"table-cell", or "table-caption"
+       // see here for display values: 
https://developer.mozilla.org/en-US/docs/CSS/display
+       rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+       rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+       rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+       cssShow = { position: "absolute", visibility: "hidden", display: 
"block" },
+       cssNormalTransform = {
+               letterSpacing: "0",
+               fontWeight: "400"
+       },
+
+       cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+       // shortcut for names that are not vendor prefixed
+       if ( name in style ) {
+               return name;
+       }
+
+       // check for vendor prefixed names
+       var capName = name[0].toUpperCase() + name.slice(1),
+               origName = name,
+               i = cssPrefixes.length;
+
+       while ( i-- ) {
+               name = cssPrefixes[ i ] + capName;
+               if ( name in style ) {
+                       return name;
+               }
+       }
+
+       return origName;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+       var matches = rnumsplit.exec( value );
+       return matches ?
+               // Guard against undefined "subtract", e.g., when used as in 
cssHooks
+               Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 
] || "px" ) :
+               value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+       var i = extra === ( isBorderBox ? "border" : "content" ) ?
+               // If we already have the right measurement, avoid augmentation
+               4 :
+               // Otherwise initialize for horizontal or vertical properties
+               name === "width" ? 1 : 0,
+
+               val = 0;
+
+       for ( ; i < 4; i += 2 ) {
+               // both box models exclude margin, so add it if we want it
+               if ( extra === "margin" ) {
+                       val += jQuery.css( elem, extra + cssExpand[ i ], true, 
styles );
+               }
+
+               if ( isBorderBox ) {
+                       // border-box includes padding, so remove it if we want 
content
+                       if ( extra === "content" ) {
+                               val -= jQuery.css( elem, "padding" + cssExpand[ 
i ], true, styles );
+                       }
+
+                       // at this point, extra isn't border nor margin, so 
remove border
+                       if ( extra !== "margin" ) {
+                               val -= jQuery.css( elem, "border" + cssExpand[ 
i ] + "Width", true, styles );
+                       }
+               } else {
+                       // at this point, extra isn't content, so add padding
+                       val += jQuery.css( elem, "padding" + cssExpand[ i ], 
true, styles );
+
+                       // at this point, extra isn't content nor padding, so 
add border
+                       if ( extra !== "padding" ) {
+                               val += jQuery.css( elem, "border" + cssExpand[ 
i ] + "Width", true, styles );
+                       }
+               }
+       }
+
+       return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+       // Start with offset property, which is equivalent to the border-box 
value
+       var valueIsBorderBox = true,
+               val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+               styles = getStyles( elem ),
+               isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) 
=== "border-box";
+
+       // some non-html elements return undefined for offsetWidth, so check 
for null/undefined
+       // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+       // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+       if ( val <= 0 || val == null ) {
+               // Fall back to computed then uncomputed css if necessary
+               val = curCSS( elem, name, styles );
+               if ( val < 0 || val == null ) {
+                       val = elem.style[ name ];
+               }
+
+               // Computed unit is not pixels. Stop here and return.
+               if ( rnumnonpx.test(val) ) {
+                       return val;
+               }
+
+               // we need the check for style in case a browser which returns 
unreliable values
+               // for getComputedStyle silently falls back to the reliable 
elem.style
+               valueIsBorderBox = isBorderBox &&
+                       ( support.boxSizingReliable() || val === elem.style[ 
name ] );
+
+               // Normalize "", auto, and prepare for extra
+               val = parseFloat( val ) || 0;
+       }
+
+       // use the active box-sizing model to add/subtract irrelevant styles
+       return ( val +
+               augmentWidthOrHeight(
+                       elem,
+                       name,
+                       extra || ( isBorderBox ? "border" : "content" ),
+                       valueIsBorderBox,
+                       styles
+               )
+       ) + "px";
+}
+
+function showHide( elements, show ) {
+       var display, elem, hidden,
+               values = [],
+               index = 0,
+               length = elements.length;
+
+       for ( ; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+
+               values[ index ] = data_priv.get( elem, "olddisplay" );
+               display = elem.style.display;
+               if ( show ) {
+                       // Reset the inline display of this element to learn if 
it is
+                       // being hidden by cascaded rules or not
+                       if ( !values[ index ] && display === "none" ) {
+                               elem.style.display = "";
+                       }
+
+                       // Set elements which have been overridden with 
display: none
+                       // in a stylesheet to whatever the default browser 
style is
+                       // for such an element
+                       if ( elem.style.display === "" && isHidden( elem ) ) {
+                               values[ index ] = data_priv.access( elem, 
"olddisplay", defaultDisplay(elem.nodeName) );
+                       }
+               } else {
+                       hidden = isHidden( elem );
+
+                       if ( display !== "none" || !hidden ) {
+                               data_priv.set( elem, "olddisplay", hidden ? 
display : jQuery.css( elem, "display" ) );
+                       }
+               }
+       }
+
+       // Set the display of most of the elements in a second loop
+       // to avoid the constant reflow
+       for ( index = 0; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+               if ( !show || elem.style.display === "none" || 
elem.style.display === "" ) {
+                       elem.style.display = show ? values[ index ] || "" : 
"none";
+               }
+       }
+
+       return elements;
+}
+
+jQuery.extend({
+       // Add in style property hooks for overriding the default
+       // behavior of getting and setting a style property
+       cssHooks: {
+               opacity: {
+                       get: function( elem, computed ) {
+                               if ( computed ) {
+                                       // We should always get a number back 
from opacity
+                                       var ret = curCSS( elem, "opacity" );
+                                       return ret === "" ? "1" : ret;
+                               }
+                       }
+               }
+       },
+
+       // Don't automatically add "px" to these possibly-unitless properties
+       cssNumber: {
+               "columnCount": true,
+               "fillOpacity": true,
+               "flexGrow": true,
+               "flexShrink": true,
+               "fontWeight": true,
+               "lineHeight": true,
+               "opacity": true,
+               "order": true,
+               "orphans": true,
+               "widows": true,
+               "zIndex": true,
+               "zoom": true
+       },
+
+       // Add in properties whose names you wish to fix before
+       // setting or getting the value
+       cssProps: {
+               // normalize float css property
+               "float": "cssFloat"
+       },
+
+       // Get and set the style property on a DOM Node
+       style: function( elem, name, value, extra ) {
+               // Don't set styles on text and comment nodes
+               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || 
!elem.style ) {
+                       return;
+               }
+
+               // Make sure that we're working with the right name
+               var ret, type, hooks,
+                       origName = jQuery.camelCase( name ),
+                       style = elem.style;
+
+               name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ 
origName ] = vendorPropName( style, origName ) );
+
+               // gets hook for the prefixed version
+               // followed by the unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // Check if we're setting a value
+               if ( value !== undefined ) {
+                       type = typeof value;
+
+                       // convert relative number strings (+= or -=) to 
relative numbers. #7345
+                       if ( type === "string" && (ret = rrelNum.exec( value )) 
) {
+                               value = ( ret[1] + 1 ) * ret[2] + parseFloat( 
jQuery.css( elem, name ) );
+                               // Fixes bug #9237
+                               type = "number";
+                       }
+
+                       // Make sure that null and NaN values aren't set. See: 
#7116
+                       if ( value == null || value !== value ) {
+                               return;
+                       }
+
+                       // If a number was passed in, add 'px' to the (except 
for certain CSS properties)
+                       if ( type === "number" && !jQuery.cssNumber[ origName ] 
) {
+                               value += "px";
+                       }
+
+                       // Fixes #8908, it can be done more correctly by 
specifying setters in cssHooks,
+                       // but it would mean to define eight (for every 
problematic property) identical functions
+                       if ( !support.clearCloneStyle && value === "" && 
name.indexOf( "background" ) === 0 ) {
+                               style[ name ] = "inherit";
+                       }
+
+                       // If a hook was provided, use that value, otherwise 
just set the specified value
+                       if ( !hooks || !("set" in hooks) || (value = hooks.set( 
elem, value, extra )) !== undefined ) {
+                               style[ name ] = value;
+                       }
+
+               } else {
+                       // If a hook was provided get the non-computed value 
from there
+                       if ( hooks && "get" in hooks && (ret = hooks.get( elem, 
false, extra )) !== undefined ) {
+                               return ret;
+                       }
+
+                       // Otherwise just get the value from the style object
+                       return style[ name ];
+               }
+       },
+
+       css: function( elem, name, extra, styles ) {
+               var val, num, hooks,
+                       origName = jQuery.camelCase( name );
+
+               // Make sure that we're working with the right name
+               name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ 
origName ] = vendorPropName( elem.style, origName ) );
+
+               // gets hook for the prefixed version
+               // followed by the unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // If a hook was provided get the computed value from there
+               if ( hooks && "get" in hooks ) {
+                       val = hooks.get( elem, true, extra );
+               }
+
+               // Otherwise, if a way to get the computed value exists, use 
that
+               if ( val === undefined ) {
+                       val = curCSS( elem, name, styles );
+               }
+
+               //convert "normal" to computed value
+               if ( val === "normal" && name in cssNormalTransform ) {
+                       val = cssNormalTransform[ name ];
+               }
+
+               // Return, converting to number if forced or a qualifier was 
provided and val looks numeric
+               if ( extra === "" || extra ) {
+                       num = parseFloat( val );
+                       return extra === true || jQuery.isNumeric( num ) ? num 
|| 0 : val;
+               }
+               return val;
+       }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+       jQuery.cssHooks[ name ] = {
+               get: function( elem, computed, extra ) {
+                       if ( computed ) {
+                               // certain elements can have dimension info if 
we invisibly show them
+                               // however, it must have a current display 
style that would benefit from this
+                               return rdisplayswap.test( jQuery.css( elem, 
"display" ) ) && elem.offsetWidth === 0 ?
+                                       jQuery.swap( elem, cssShow, function() {
+                                               return getWidthOrHeight( elem, 
name, extra );
+                                       }) :
+                                       getWidthOrHeight( elem, name, extra );
+                       }
+               },
+
+               set: function( elem, value, extra ) {
+                       var styles = extra && getStyles( elem );
+                       return setPositiveNumber( elem, value, extra ?
+                               augmentWidthOrHeight(
+                                       elem,
+                                       name,
+                                       extra,
+                                       jQuery.css( elem, "boxSizing", false, 
styles ) === "border-box",
+                                       styles
+                               ) : 0
+                       );
+               }
+       };
+});
+
+// Support: Android 2.3
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+       function( elem, computed ) {
+               if ( computed ) {
+                       // WebKit Bug 13343 - getComputedStyle returns wrong 
value for margin-right
+                       // Work around by temporarily setting element display 
to inline-block
+                       return jQuery.swap( elem, { "display": "inline-block" },
+                               curCSS, [ elem, "marginRight" ] );
+               }
+       }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+       margin: "",
+       padding: "",
+       border: "Width"
+}, function( prefix, suffix ) {
+       jQuery.cssHooks[ prefix + suffix ] = {
+               expand: function( value ) {
+                       var i = 0,
+                               expanded = {},
+
+                               // assumes a single number if not a string
+                               parts = typeof value === "string" ? 
value.split(" ") : [ value ];
+
+                       for ( ; i < 4; i++ ) {
+                               expanded[ prefix + cssExpand[ i ] + suffix ] =
+                                       parts[ i ] || parts[ i - 2 ] || parts[ 
0 ];
+                       }
+
+                       return expanded;
+               }
+       };
+
+       if ( !rmargin.test( prefix ) ) {
+               jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+       }
+});
+
+jQuery.fn.extend({
+       css: function( name, value ) {
+               return access( this, function( elem, name, value ) {
+                       var styles, len,
+                               map = {},
+                               i = 0;
+
+                       if ( jQuery.isArray( name ) ) {
+                               styles = getStyles( elem );
+                               len = name.length;
+
+                               for ( ; i < len; i++ ) {
+                                       map[ name[ i ] ] = jQuery.css( elem, 
name[ i ], false, styles );
+                               }
+
+                               return map;
+                       }
+
+                       return value !== undefined ?
+                               jQuery.style( elem, name, value ) :
+                               jQuery.css( elem, name );
+               }, name, value, arguments.length > 1 );
+       },
+       show: function() {
+               return showHide( this, true );
+       },
+       hide: function() {
+               return showHide( this );
+       },
+       toggle: function( state ) {
+               if ( typeof state === "boolean" ) {
+                       return state ? this.show() : this.hide();
+               }
+
+               return this.each(function() {
+                       if ( isHidden( this ) ) {
+                               jQuery( this ).show();
+                       } else {
+                               jQuery( this ).hide();
+                       }
+               });
+       }
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+       return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+       constructor: Tween,
+       init: function( elem, options, prop, end, easing, unit ) {
+               this.elem = elem;
+               this.prop = prop;
+               this.easing = easing || "swing";
+               this.options = options;
+               this.start = this.now = this.cur();
+               this.end = end;
+               this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+       },
+       cur: function() {
+               var hooks = Tween.propHooks[ this.prop ];
+
+               return hooks && hooks.get ?
+                       hooks.get( this ) :
+                       Tween.propHooks._default.get( this );
+       },
+       run: function( percent ) {
+               var eased,
+                       hooks = Tween.propHooks[ this.prop ];
+
+               if ( this.options.duration ) {
+                       this.pos = eased = jQuery.easing[ this.easing ](
+                               percent, this.options.duration * percent, 0, 1, 
this.options.duration
+                       );
+               } else {
+                       this.pos = eased = percent;
+               }
+               this.now = ( this.end - this.start ) * eased + this.start;
+
+               if ( this.options.step ) {
+                       this.options.step.call( this.elem, this.now, this );
+               }
+
+               if ( hooks && hooks.set ) {
+                       hooks.set( this );
+               } else {
+                       Tween.propHooks._default.set( this );
+               }
+               return this;
+       }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+       _default: {
+               get: function( tween ) {
+                       var result;
+
+                       if ( tween.elem[ tween.prop ] != null &&
+                               (!tween.elem.style || tween.elem.style[ 
tween.prop ] == null) ) {
+                               return tween.elem[ tween.prop ];
+                       }
+
+                       // passing an empty string as a 3rd parameter to .css 
will automatically
+                       // attempt a parseFloat and fallback to a string if the 
parse fails
+                       // so, simple values such as "10px" are parsed to Float.
+                       // complex values such as "rotate(1rad)" are returned 
as is.
+                       result = jQuery.css( tween.elem, tween.prop, "" );
+                       // Empty strings, null, undefined and "auto" are 
converted to 0.
+                       return !result || result === "auto" ? 0 : result;
+               },
+               set: function( tween ) {
+                       // use step hook for back compat - use cssHook if its 
there - use .style if its
+                       // available and use plain properties where available
+                       if ( jQuery.fx.step[ tween.prop ] ) {
+                               jQuery.fx.step[ tween.prop ]( tween );
+                       } else if ( tween.elem.style && ( tween.elem.style[ 
jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+                               jQuery.style( tween.elem, tween.prop, tween.now 
+ tween.unit );
+                       } else {
+                               tween.elem[ tween.prop ] = tween.now;
+                       }
+               }
+       }
+};
+
+// Support: IE9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+       set: function( tween ) {
+               if ( tween.elem.nodeType && tween.elem.parentNode ) {
+                       tween.elem[ tween.prop ] = tween.now;
+               }
+       }
+};
+
+jQuery.easing = {
+       linear: function( p ) {
+               return p;
+       },
+       swing: function( p ) {
+               return 0.5 - Math.cos( p * Math.PI ) / 2;
+       }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+       fxNow, timerId,
+       rfxtypes = /^(?:toggle|show|hide)$/,
+       rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+       rrun = /queueHooks$/,
+       animationPrefilters = [ defaultPrefilter ],
+       tweeners = {
+               "*": [ function( prop, value ) {
+                       var tween = this.createTween( prop, value ),
+                               target = tween.cur(),
+                               parts = rfxnum.exec( value ),
+                               unit = parts && parts[ 3 ] || ( 
jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+                               // Starting value computation is required for 
potential unit mismatches
+                               start = ( jQuery.cssNumber[ prop ] || unit !== 
"px" && +target ) &&
+                                       rfxnum.exec( jQuery.css( tween.elem, 
prop ) ),
+                               scale = 1,
+                               maxIterations = 20;
+
+                       if ( start && start[ 3 ] !== unit ) {
+                               // Trust units reported by jQuery.css
+                               unit = unit || start[ 3 ];
+
+                               // Make sure we update the tween properties 
later on
+                               parts = parts || [];
+
+                               // Iteratively approximate from a nonzero 
starting point
+                               start = +target || 1;
+
+                               do {
+                                       // If previous iteration zeroed out, 
double until we get *something*
+                                       // Use a string for doubling factor so 
we don't accidentally see scale as unchanged below
+                                       scale = scale || ".5";
+
+                                       // Adjust and apply
+                                       start = start / scale;
+                                       jQuery.style( tween.elem, prop, start + 
unit );
+
+                               // Update scale, tolerating zero or NaN from 
tween.cur()
+                               // And breaking the loop if scale is unchanged 
or perfect, or if we've just had enough
+                               } while ( scale !== (scale = tween.cur() / 
target) && scale !== 1 && --maxIterations );
+                       }
+
+                       // Update tween properties
+                       if ( parts ) {
+                               start = tween.start = +start || +target || 0;
+                               tween.unit = unit;
+                               // If a +=/-= token was provided, we're doing a 
relative animation
+                               tween.end = parts[ 1 ] ?
+                                       start + ( parts[ 1 ] + 1 ) * parts[ 2 ] 
:
+                                       +parts[ 2 ];
+                       }
+
+                       return tween;
+               } ]
+       };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+       setTimeout(function() {
+               fxNow = undefined;
+       });
+       return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+       var which,
+               i = 0,
+               attrs = { height: type };
+
+       // if we include width, step value is 1 to do all cssExpand values,
+       // if we don't include width, step value is 2 to skip over Left and 
Right
+       includeWidth = includeWidth ? 1 : 0;
+       for ( ; i < 4 ; i += 2 - includeWidth ) {
+               which = cssExpand[ i ];
+               attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+       }
+
+       if ( includeWidth ) {
+               attrs.opacity = attrs.width = type;
+       }
+
+       return attrs;
+}
+
+function createTween( value, prop, animation ) {
+       var tween,
+               collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] 
),
+               index = 0,
+               length = collection.length;
+       for ( ; index < length; index++ ) {
+               if ( (tween = collection[ index ].call( animation, prop, value 
)) ) {
+
+                       // we're done with this property
+                       return tween;
+               }
+       }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+       /* jshint validthis: true */
+       var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+               anim = this,
+               orig = {},
+               style = elem.style,
+               hidden = elem.nodeType && isHidden( elem ),
+               dataShow = data_priv.get( elem, "fxshow" );
+
+       // handle queue: false promises
+       if ( !opts.queue ) {
+               hooks = jQuery._queueHooks( elem, "fx" );
+               if ( hooks.unqueued == null ) {
+                       hooks.unqueued = 0;
+                       oldfire = hooks.empty.fire;
+                       hooks.empty.fire = function() {
+                               if ( !hooks.unqueued ) {
+                                       oldfire();
+                               }
+                       };
+               }
+               hooks.unqueued++;
+
+               anim.always(function() {
+                       // doing this makes sure that the complete handler will 
be called
+                       // before this completes
+                       anim.always(function() {
+                               hooks.unqueued--;
+                               if ( !jQuery.queue( elem, "fx" ).length ) {
+                                       hooks.empty.fire();
+                               }
+                       });
+               });
+       }
+
+       // height/width overflow pass
+       if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) 
{
+               // Make sure that nothing sneaks out
+               // Record all 3 overflow attributes because IE9-10 do not
+               // change the overflow attribute when overflowX and
+               // overflowY are set to the same value
+               opts.overflow = [ style.overflow, style.overflowX, 
style.overflowY ];
+
+               // Set display property to inline-block for height/width
+               // animations on inline elements that are having width/height 
animated
+               display = jQuery.css( elem, "display" );
+
+               // Test default display if display is currently "none"
+               checkDisplay = display === "none" ?
+                       data_priv.get( elem, "olddisplay" ) || defaultDisplay( 
elem.nodeName ) : display;
+
+               if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) 
=== "none" ) {
+                       style.display = "inline-block";
+               }
+       }
+
+       if ( opts.overflow ) {
+               style.overflow = "hidden";
+               anim.always(function() {
+                       style.overflow = opts.overflow[ 0 ];
+                       style.overflowX = opts.overflow[ 1 ];
+                       style.overflowY = opts.overflow[ 2 ];
+               });
+       }
+
+       // show/hide pass
+       for ( prop in props ) {
+               value = props[ prop ];
+               if ( rfxtypes.exec( value ) ) {
+                       delete props[ prop ];
+                       toggle = toggle || value === "toggle";
+                       if ( value === ( hidden ? "hide" : "show" ) ) {
+
+                               // If there is dataShow left over from a 
stopped hide or show and we are going to proceed with show, we should pretend 
to be hidden
+                               if ( value === "show" && dataShow && dataShow[ 
prop ] !== undefined ) {
+                                       hidden = true;
+                               } else {
+                                       continue;
+                               }
+                       }
+                       orig[ prop ] = dataShow && dataShow[ prop ] || 
jQuery.style( elem, prop );
+
+               // Any non-fx value stops us from restoring the original 
display value
+               } else {
+                       display = undefined;
+               }
+       }
+
+       if ( !jQuery.isEmptyObject( orig ) ) {
+               if ( dataShow ) {
+                       if ( "hidden" in dataShow ) {
+                               hidden = dataShow.hidden;
+                       }
+               } else {
+                       dataShow = data_priv.access( elem, "fxshow", {} );
+               }
+
+               // store state if its toggle - enables .stop().toggle() to 
"reverse"
+               if ( toggle ) {
+                       dataShow.hidden = !hidden;
+               }
+               if ( hidden ) {
+                       jQuery( elem ).show();
+               } else {
+                       anim.done(function() {
+                               jQuery( elem ).hide();
+                       });
+               }
+               anim.done(function() {
+                       var prop;
+
+                       data_priv.remove( elem, "fxshow" );
+                       for ( prop in orig ) {
+                               jQuery.style( elem, prop, orig[ prop ] );
+                       }
+               });
+               for ( prop in orig ) {
+                       tween = createTween( hidden ? dataShow[ prop ] : 0, 
prop, anim );
+
+                       if ( !( prop in dataShow ) ) {
+                               dataShow[ prop ] = tween.start;
+                               if ( hidden ) {
+                                       tween.end = tween.start;
+                                       tween.start = prop === "width" || prop 
=== "height" ? 1 : 0;
+                               }
+                       }
+               }
+
+       // If this is a noop like .hide().hide(), restore an overwritten 
display value
+       } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : 
display) === "inline" ) {
+               style.display = display;
+       }
+}
+
+function propFilter( props, specialEasing ) {
+       var index, name, easing, value, hooks;
+
+       // camelCase, specialEasing and expand cssHook pass
+       for ( index in props ) {
+               name = jQuery.camelCase( index );
+               easing = specialEasing[ name ];
+               value = props[ index ];
+               if ( jQuery.isArray( value ) ) {
+                       easing = value[ 1 ];
+                       value = props[ index ] = value[ 0 ];
+               }
+
+               if ( index !== name ) {
+                       props[ name ] = value;
+                       delete props[ index ];
+               }
+
+               hooks = jQuery.cssHooks[ name ];
+               if ( hooks && "expand" in hooks ) {
+                       value = hooks.expand( value );
+                       delete props[ name ];
+
+                       // not quite $.extend, this wont overwrite keys already 
present.
+                       // also - reusing 'index' from above because we have 
the correct "name"
+                       for ( index in value ) {
+                               if ( !( index in props ) ) {
+                                       props[ index ] = value[ index ];
+                                       specialEasing[ index ] = easing;
+                               }
+                       }
+               } else {
+                       specialEasing[ name ] = easing;
+               }
+       }
+}
+
+function Animation( elem, properties, options ) {
+       var result,
+               stopped,
+               index = 0,
+               length = animationPrefilters.length,
+               deferred = jQuery.Deferred().always( function() {
+                       // don't match elem in the :animated selector
+                       delete tick.elem;
+               }),
+               tick = function() {
+                       if ( stopped ) {
+                               return false;
+                       }
+                       var currentTime = fxNow || createFxNow(),
+                               remaining = Math.max( 0, animation.startTime + 
animation.duration - currentTime ),
+                               // archaic crash bug won't allow us to use 1 - 
( 0.5 || 0 ) (#12497)
+                               temp = remaining / animation.duration || 0,
+                               percent = 1 - temp,
+                               index = 0,
+                               length = animation.tweens.length;
+
+                       for ( ; index < length ; index++ ) {
+                               animation.tweens[ index ].run( percent );
+                       }
+
+                       deferred.notifyWith( elem, [ animation, percent, 
remaining ]);
+
+                       if ( percent < 1 && length ) {
+                               return remaining;
+                       } else {
+                               deferred.resolveWith( elem, [ animation ] );
+                               return false;
+                       }
+               },
+               animation = deferred.promise({
+                       elem: elem,
+                       props: jQuery.extend( {}, properties ),
+                       opts: jQuery.extend( true, { specialEasing: {} }, 
options ),
+                       originalProperties: properties,
+                       originalOptions: options,
+                       startTime: fxNow || createFxNow(),
+                       duration: options.duration,
+                       tweens: [],
+                       createTween: function( prop, end ) {
+                               var tween = jQuery.Tween( elem, animation.opts, 
prop, end,
+                                               animation.opts.specialEasing[ 
prop ] || animation.opts.easing );
+                               animation.tweens.push( tween );
+                               return tween;
+                       },
+                       stop: function( gotoEnd ) {
+                               var index = 0,
+                                       // if we are going to the end, we want 
to run all the tweens
+                                       // otherwise we skip this part
+                                       length = gotoEnd ? 
animation.tweens.length : 0;
+                               if ( stopped ) {
+                                       return this;
+                               }
+                               stopped = true;
+                               for ( ; index < length ; index++ ) {
+                                       animation.tweens[ index ].run( 1 );
+                               }
+
+                               // resolve when we played the last frame
+                               // otherwise, reject
+                               if ( gotoEnd ) {
+                                       deferred.resolveWith( elem, [ 
animation, gotoEnd ] );
+                               } else {
+                                       deferred.rejectWith( elem, [ animation, 
gotoEnd ] );
+                               }
+                               return this;
+                       }
+               }),
+               props = animation.props;
+
+       propFilter( props, animation.opts.specialEasing );
+
+       for ( ; index < length ; index++ ) {
+               result = animationPrefilters[ index ].call( animation, elem, 
props, animation.opts );
+               if ( result ) {
+                       return result;
+               }
+       }
+
+       jQuery.map( props, createTween, animation );
+
+       if ( jQuery.isFunction( animation.opts.start ) ) {
+               animation.opts.start.call( elem, animation );
+       }
+
+       jQuery.fx.timer(
+               jQuery.extend( tick, {
+                       elem: elem,
+                       anim: animation,
+                       queue: animation.opts.queue
+               })
+       );
+
+       // attach callbacks from options
+       return animation.progress( animation.opts.progress )
+               .done( animation.opts.done, animation.opts.complete )
+               .fail( animation.opts.fail )
+               .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+       tweener: function( props, callback ) {
+               if ( jQuery.isFunction( props ) ) {
+                       callback = props;
+                       props = [ "*" ];
+               } else {
+                       props = props.split(" ");
+               }
+
+               var prop,
+                       index = 0,
+                       length = props.length;
+
+               for ( ; index < length ; index++ ) {
+                       prop = props[ index ];
+                       tweeners[ prop ] = tweeners[ prop ] || [];
+                       tweeners[ prop ].unshift( callback );
+               }
+       },
+
+       prefilter: function( callback, prepend ) {
+               if ( prepend ) {
+                       animationPrefilters.unshift( callback );
+               } else {
+                       animationPrefilters.push( callback );
+               }
+       }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+       var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed 
) : {
+               complete: fn || !fn && easing ||
+                       jQuery.isFunction( speed ) && speed,
+               duration: speed,
+               easing: fn && easing || easing && !jQuery.isFunction( easing ) 
&& easing
+       };
+
+       opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? 
opt.duration :
+               opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ 
opt.duration ] : jQuery.fx.speeds._default;
+
+       // normalize opt.queue - true/undefined/null -> "fx"
+       if ( opt.queue == null || opt.queue === true ) {
+               opt.queue = "fx";
+       }
+
+       // Queueing
+       opt.old = opt.complete;
+
+       opt.complete = function() {
+               if ( jQuery.isFunction( opt.old ) ) {
+                       opt.old.call( this );
+               }
+
+               if ( opt.queue ) {
+                       jQuery.dequeue( this, opt.queue );
+               }
+       };
+
+       return opt;
+};
+
+jQuery.fn.extend({
+       fadeTo: function( speed, to, easing, callback ) {
+
+               // show any hidden elements after setting opacity to 0
+               return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+                       // animate to the value specified
+                       .end().animate({ opacity: to }, speed, easing, callback 
);
+       },
+       animate: function( prop, speed, easing, callback ) {
+               var empty = jQuery.isEmptyObject( prop ),
+                       optall = jQuery.speed( speed, easing, callback ),
+                       doAnimation = function() {
+                               // Operate on a copy of prop so per-property 
easing won't be lost
+                               var anim = Animation( this, jQuery.extend( {}, 
prop ), optall );
+
+                               // Empty animations, or finishing resolves 
immediately
+                               if ( empty || data_priv.get( this, "finish" ) ) 
{
+                                       anim.stop( true );
+                               }
+                       };
+                       doAnimation.finish = doAnimation;
+
+               return empty || optall.queue === false ?
+                       this.each( doAnimation ) :
+                       this.queue( optall.queue, doAnimation );
+       },
+       stop: function( type, clearQueue, gotoEnd ) {
+               var stopQueue = function( hooks ) {
+                       var stop = hooks.stop;
+                       delete hooks.stop;
+                       stop( gotoEnd );
+               };
+
+               if ( typeof type !== "string" ) {
+                       gotoEnd = clearQueue;
+                       clearQueue = type;
+                       type = undefined;
+               }
+               if ( clearQueue && type !== false ) {
+                       this.queue( type || "fx", [] );
+               }
+
+               return this.each(function() {
+                       var dequeue = true,
+                               index = type != null && type + "queueHooks",
+                               timers = jQuery.timers,
+                               data = data_priv.get( this );
+
+                       if ( index ) {
+                               if ( data[ index ] && data[ index ].stop ) {
+                                       stopQueue( data[ index ] );
+                               }
+                       } else {
+                               for ( index in data ) {
+                                       if ( data[ index ] && data[ index 
].stop && rrun.test( index ) ) {
+                                               stopQueue( data[ index ] );
+                                       }
+                               }
+                       }
+
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && (type == 
null || timers[ index ].queue === type) ) {
+                                       timers[ index ].anim.stop( gotoEnd );
+                                       dequeue = false;
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // start the next in the queue if the last step wasn't 
forced
+                       // timers currently will call their complete callbacks, 
which will dequeue
+                       // but only if they were gotoEnd
+                       if ( dequeue || !gotoEnd ) {
+                               jQuery.dequeue( this, type );
+                       }
+               });
+       },
+       finish: function( type ) {
+               if ( type !== false ) {
+                       type = type || "fx";
+               }
+               return this.each(function() {
+                       var index,
+                               data = data_priv.get( this ),
+                               queue = data[ type + "queue" ],
+                               hooks = data[ type + "queueHooks" ],
+                               timers = jQuery.timers,
+                               length = queue ? queue.length : 0;
+
+                       // enable finishing flag on private data
+                       data.finish = true;
+
+                       // empty the queue first
+                       jQuery.queue( this, type, [] );
+
+                       if ( hooks && hooks.stop ) {
+                               hooks.stop.call( this, true );
+                       }
+
+                       // look for any active animations, and finish them
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && timers[ 
index ].queue === type ) {
+                                       timers[ index ].anim.stop( true );
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // look for any animations in the old queue and finish 
them
+                       for ( index = 0; index < length; index++ ) {
+                               if ( queue[ index ] && queue[ index ].finish ) {
+                                       queue[ index ].finish.call( this );
+                               }
+                       }
+
+                       // turn off finishing flag
+                       delete data.finish;
+               });
+       }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+       var cssFn = jQuery.fn[ name ];
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return speed == null || typeof speed === "boolean" ?
+                       cssFn.apply( this, arguments ) :
+                       this.animate( genFx( name, true ), speed, easing, 
callback );
+       };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+       slideDown: genFx("show"),
+       slideUp: genFx("hide"),
+       slideToggle: genFx("toggle"),
+       fadeIn: { opacity: "show" },
+       fadeOut: { opacity: "hide" },
+       fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return this.animate( props, speed, easing, callback );
+       };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+       var timer,
+               i = 0,
+               timers = jQuery.timers;
+
+       fxNow = jQuery.now();
+
+       for ( ; i < timers.length; i++ ) {
+               timer = timers[ i ];
+               // Checks the timer has not already been removed
+               if ( !timer() && timers[ i ] === timer ) {
+                       timers.splice( i--, 1 );
+               }
+       }
+
+       if ( !timers.length ) {
+               jQuery.fx.stop();
+       }
+       fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+       jQuery.timers.push( timer );
+       if ( timer() ) {
+               jQuery.fx.start();
+       } else {
+               jQuery.timers.pop();
+       }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+       if ( !timerId ) {
+               timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+       }
+};
+
+jQuery.fx.stop = function() {
+       clearInterval( timerId );
+       timerId = null;
+};
+
+jQuery.fx.speeds = {
+       slow: 600,
+       fast: 200,
+       // Default speed
+       _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+       time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+       type = type || "fx";
+
+       return this.queue( type, function( next, hooks ) {
+               var timeout = setTimeout( next, time );
+               hooks.stop = function() {
+                       clearTimeout( timeout );
+               };
+       });
+};
+
+
+(function() {
+       var input = document.createElement( "input" ),
+               select = document.createElement( "select" ),
+               opt = select.appendChild( document.createElement( "option" ) );
+
+       input.type = "checkbox";
+
+       // Support: iOS 5.1, Android 4.x, Android 2.3
+       // Check the default checkbox/radio value ("" on old WebKit; "on" 
elsewhere)
+       support.checkOn = input.value !== "";
+
+       // Must access the parent to make an option select properly
+       // Support: IE9, IE10
+       support.optSelected = opt.selected;
+
+       // 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;
+
+       // Check if an input maintains its value after becoming a radio
+       // Support: IE9, IE10
+       input = document.createElement( "input" );
+       input.value = "t";
+       input.type = "radio";
+       support.radioValue = input.value === "t";
+})();
+
+
+var nodeHook, boolHook,
+       attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend({
+       attr: function( name, value ) {
+               return access( this, jQuery.attr, name, value, arguments.length 
> 1 );
+       },
+
+       removeAttr: function( name ) {
+               return this.each(function() {
+                       jQuery.removeAttr( this, name );
+               });
+       }
+});
+
+jQuery.extend({
+       attr: function( elem, name, value ) {
+               var hooks, ret,
+                       nType = elem.nodeType;
+
+               // don't get/set attributes on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               // Fallback to prop when attributes are not supported
+               if ( typeof elem.getAttribute === strundefined ) {
+                       return jQuery.prop( elem, name, value );
+               }
+
+               // All attributes are lowercase
+               // Grab necessary hook if one is defined
+               if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+                       name = name.toLowerCase();
+                       hooks = jQuery.attrHooks[ name ] ||
+                               ( jQuery.expr.match.bool.test( name ) ? 
boolHook : nodeHook );
+               }
+
+               if ( value !== undefined ) {
+
+                       if ( value === null ) {
+                               jQuery.removeAttr( elem, name );
+
+                       } else if ( hooks && "set" in hooks && (ret = 
hooks.set( elem, value, name )) !== undefined ) {
+                               return ret;
+
+                       } else {
+                               elem.setAttribute( name, value + "" );
+                               return value;
+                       }
+
+               } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, 
name )) !== null ) {
+                       return ret;
+
+               } else {
+                       ret = jQuery.find.attr( elem, name );
+
+                       // Non-existent attributes return null, we normalize to 
undefined
+                       return ret == null ?
+                               undefined :
+                               ret;
+               }
+       },
+
+       removeAttr: function( elem, value ) {
+               var name, propName,
+                       i = 0,
+                       attrNames = value && value.match( rnotwhite );
+
+               if ( attrNames && elem.nodeType === 1 ) {
+                       while ( (name = attrNames[i++]) ) {
+                               propName = jQuery.propFix[ name ] || name;
+
+                               // Boolean attributes get special treatment 
(#10870)
+                               if ( jQuery.expr.match.bool.test( name ) ) {
+                                       // Set corresponding property to false
+                                       elem[ propName ] = false;
+                               }
+
+                               elem.removeAttribute( name );
+                       }
+               }
+       },
+
+       attrHooks: {
+               type: {
+                       set: function( elem, value ) {
+                               if ( !support.radioValue && value === "radio" &&
+                                       jQuery.nodeName( elem, "input" ) ) {
+                                       // Setting the type on a radio button 
after the value resets the value in IE6-9
+                                       // Reset value to default in case type 
is set after value during creation
+                                       var val = elem.value;
+                                       elem.setAttribute( "type", value );
+                                       if ( val ) {
+                                               elem.value = val;
+                                       }
+                                       return value;
+                               }
+                       }
+               }
+       }
+});
+
+// Hooks for boolean attributes
+boolHook = {
+       set: function( elem, value, name ) {
+               if ( value === false ) {
+                       // Remove boolean attributes when set to false
+                       jQuery.removeAttr( elem, name );
+               } else {
+                       elem.setAttribute( name, name );
+               }
+               return name;
+       }
+};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name 
) {
+       var getter = attrHandle[ name ] || jQuery.find.attr;
+
+       attrHandle[ name ] = function( elem, name, isXML ) {
+               var ret, handle;
+               if ( !isXML ) {
+                       // Avoid an infinite loop by temporarily removing this 
function from the getter
+                       handle = attrHandle[ name ];
+                       attrHandle[ name ] = ret;
+                       ret = getter( elem, name, isXML ) != null ?
+                               name.toLowerCase() :
+                               null;
+                       attrHandle[ name ] = handle;
+               }
+               return ret;
+       };
+});
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i;
+
+jQuery.fn.extend({
+       prop: function( name, value ) {
+               return access( this, jQuery.prop, name, value, arguments.length 
> 1 );
+       },
+
+       removeProp: function( name ) {
+               return this.each(function() {
+                       delete this[ jQuery.propFix[ name ] || name ];
+               });
+       }
+});
+
+jQuery.extend({
+       propFix: {
+               "for": "htmlFor",
+               "class": "className"
+       },
+
+       prop: function( elem, name, value ) {
+               var ret, hooks, notxml,
+                       nType = elem.nodeType;
+
+               // don't get/set properties on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+               if ( notxml ) {
+                       // Fix name and attach hooks
+                       name = jQuery.propFix[ name ] || name;
+                       hooks = jQuery.propHooks[ name ];
+               }
+
+               if ( value !== undefined ) {
+                       return hooks && "set" in hooks && (ret = hooks.set( 
elem, value, name )) !== undefined ?
+                               ret :
+                               ( elem[ name ] = value );
+
+               } else {
+                       return hooks && "get" in hooks && (ret = hooks.get( 
elem, name )) !== null ?
+                               ret :
+                               elem[ name ];
+               }
+       },
+
+       propHooks: {
+               tabIndex: {
+                       get: function( elem ) {
+                               return elem.hasAttribute( "tabindex" ) || 
rfocusable.test( elem.nodeName ) || elem.href ?
+                                       elem.tabIndex :
+                                       -1;
+                       }
+               }
+       }
+});
+
+// Support: IE9+
+// Selectedness for an option in an optgroup can be inaccurate
+if ( !support.optSelected ) {
+       jQuery.propHooks.selected = {
+               get: function( elem ) {
+                       var parent = elem.parentNode;
+                       if ( parent && parent.parentNode ) {
+                               parent.parentNode.selectedIndex;
+                       }
+                       return null;
+               }
+       };
+}
+
+jQuery.each([
+       "tabIndex",
+       "readOnly",
+       "maxLength",
+       "cellSpacing",
+       "cellPadding",
+       "rowSpan",
+       "colSpan",
+       "useMap",
+       "frameBorder",
+       "contentEditable"
+], function() {
+       jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+       addClass: function( value ) {
+               var classes, elem, cur, clazz, j, finalValue,
+                       proceed = typeof value === "string" && value,
+                       i = 0,
+                       len = this.length;
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( j ) {
+                               jQuery( this ).addClass( value.call( this, j, 
this.className ) );
+                       });
+               }
+
+               if ( proceed ) {
+                       // The disjunction here is for better compressibility 
(see removeClass)
+                       classes = ( value || "" ).match( rnotwhite ) || [];
+
+                       for ( ; i < len; i++ ) {
+                               elem = this[ i ];
+                               cur = elem.nodeType === 1 && ( elem.className ?
+                                       ( " " + elem.className + " " ).replace( 
rclass, " " ) :
+                                       " "
+                               );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( (clazz = classes[j++]) ) {
+                                               if ( cur.indexOf( " " + clazz + 
" " ) < 0 ) {
+                                                       cur += clazz + " ";
+                                               }
+                                       }
+
+                                       // only assign if different to avoid 
unneeded rendering.
+                                       finalValue = jQuery.trim( cur );
+                                       if ( elem.className !== finalValue ) {
+                                               elem.className = finalValue;
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       removeClass: function( value ) {
+               var classes, elem, cur, clazz, j, finalValue,
+                       proceed = arguments.length === 0 || typeof value === 
"string" && value,
+                       i = 0,
+                       len = this.length;
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( j ) {
+                               jQuery( this ).removeClass( value.call( this, 
j, this.className ) );
+                       });
+               }
+               if ( proceed ) {
+                       classes = ( value || "" ).match( rnotwhite ) || [];
+
+                       for ( ; i < len; i++ ) {
+                               elem = this[ i ];
+                               // This expression is here for better 
compressibility (see addClass)
+                               cur = elem.nodeType === 1 && ( elem.className ?
+                                       ( " " + elem.className + " " ).replace( 
rclass, " " ) :
+                                       ""
+                               );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( (clazz = classes[j++]) ) {
+                                               // Remove *all* instances
+                                               while ( cur.indexOf( " " + 
clazz + " " ) >= 0 ) {
+                                                       cur = cur.replace( " " 
+ clazz + " ", " " );
+                                               }
+                                       }
+
+                                       // only assign if different to avoid 
unneeded rendering.
+                                       finalValue = value ? jQuery.trim( cur ) 
: "";
+                                       if ( elem.className !== finalValue ) {
+                                               elem.className = finalValue;
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       toggleClass: function( value, stateVal ) {
+               var type = typeof value;
+
+               if ( typeof stateVal === "boolean" && type === "string" ) {
+                       return stateVal ? this.addClass( value ) : 
this.removeClass( value );
+               }
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).toggleClass( value.call(this, i, 
this.className, stateVal), stateVal );
+                       });
+               }
+
+               return this.each(function() {
+                       if ( type === "string" ) {
+                               // toggle individual class names
+                               var className,
+                                       i = 0,
+                                       self = jQuery( this ),
+                                       classNames = value.match( rnotwhite ) 
|| [];
+
+                               while ( (className = classNames[ i++ ]) ) {
+                                       // check each className given, space 
separated list
+                                       if ( self.hasClass( className ) ) {
+                                               self.removeClass( className );
+                                       } else {
+                                               self.addClass( className );
+                                       }
+                               }
+
+                       // Toggle whole class name
+                       } else if ( type === strundefined || type === "boolean" 
) {
+                               if ( this.className ) {
+                                       // store className if set
+                                       data_priv.set( this, "__className__", 
this.className );
+                               }
+
+                               // If the element has a class name or if we're 
passed "false",
+                               // then remove the whole classname (if there 
was one, the above saved it).
+                               // Otherwise bring back whatever was previously 
saved (if anything),
+                               // falling back to the empty string if nothing 
was stored.
+                               this.className = this.className || value === 
false ? "" : data_priv.get( this, "__className__" ) || "";
+                       }
+               });
+       },
+
+       hasClass: function( selector ) {
+               var className = " " + selector + " ",
+                       i = 0,
+                       l = this.length;
+               for ( ; i < l; i++ ) {
+                       if ( this[i].nodeType === 1 && (" " + this[i].className 
+ " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+});
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+       val: function( value ) {
+               var hooks, ret, isFunction,
+                       elem = this[0];
+
+               if ( !arguments.length ) {
+                       if ( elem ) {
+                               hooks = jQuery.valHooks[ elem.type ] || 
jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+                               if ( hooks && "get" in hooks && (ret = 
hooks.get( elem, "value" )) !== undefined ) {
+                                       return ret;
+                               }
+
+                               ret = elem.value;
+
+                               return typeof ret === "string" ?
+                                       // handle most common string cases
+                                       ret.replace(rreturn, "") :
+                                       // handle cases where value is 
null/undef or number
+                                       ret == null ? "" : ret;
+                       }
+
+                       return;
+               }
+
+               isFunction = jQuery.isFunction( value );
+
+               return this.each(function( i ) {
+                       var val;
+
+                       if ( this.nodeType !== 1 ) {
+                               return;
+                       }
+
+                       if ( isFunction ) {
+                               val = value.call( this, i, jQuery( this ).val() 
);
+                       } else {
+                               val = value;
+                       }
+
+                       // Treat null/undefined as ""; convert numbers to string
+                       if ( val == null ) {
+                               val = "";
+
+                       } else if ( typeof val === "number" ) {
+                               val += "";
+
+                       } else if ( jQuery.isArray( val ) ) {
+                               val = jQuery.map( val, function( value ) {
+                                       return value == null ? "" : value + "";
+                               });
+                       }
+
+                       hooks = jQuery.valHooks[ this.type ] || 
jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+                       // If set returns undefined, fall back to normal setting
+                       if ( !hooks || !("set" in hooks) || hooks.set( this, 
val, "value" ) === undefined ) {
+                               this.value = val;
+                       }
+               });
+       }
+});
+
+jQuery.extend({
+       valHooks: {
+               option: {
+                       get: function( elem ) {
+                               var val = jQuery.find.attr( elem, "value" );
+                               return val != null ?
+                                       val :
+                                       // Support: IE10-11+
+                                       // option.text throws exceptions 
(#14686, #14858)
+                                       jQuery.trim( jQuery.text( elem ) );
+                       }
+               },
+               select: {
+                       get: function( elem ) {
+                               var value, option,
+                                       options = elem.options,
+                                       index = elem.selectedIndex,
+                                       one = elem.type === "select-one" || 
index < 0,
+                                       values = one ? null : [],
+                                       max = one ? index + 1 : options.length,
+                                       i = index < 0 ?
+                                               max :
+                                               one ? index : 0;
+
+                               // Loop through all the selected options
+                               for ( ; i < max; i++ ) {
+                                       option = options[ i ];
+
+                                       // IE6-9 doesn't update selected after 
form reset (#2551)
+                                       if ( ( option.selected || i === index ) 
&&
+                                                       // Don't return options 
that are disabled or in a disabled optgroup
+                                                       ( support.optDisabled ? 
!option.disabled : option.getAttribute( "disabled" ) === null ) &&
+                                                       ( 
!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" 
) ) ) {
+
+                                               // Get the specific value for 
the option
+                                               value = jQuery( option ).val();
+
+                                               // We don't need an array for 
one selects
+                                               if ( one ) {
+                                                       return value;
+                                               }
+
+                                               // Multi-Selects return an array
+                                               values.push( value );
+                                       }
+                               }
+
+                               return values;
+                       },
+
+                       set: function( elem, value ) {
+                               var optionSet, option,
+                                       options = elem.options,
+                                       values = jQuery.makeArray( value ),
+                                       i = options.length;
+
+                               while ( i-- ) {
+                                       option = options[ i ];
+                                       if ( (option.selected = jQuery.inArray( 
option.value, values ) >= 0) ) {
+                                               optionSet = true;
+                                       }
+                               }
+
+                               // force browsers to behave consistently when 
non-matching value is set
+                               if ( !optionSet ) {
+                                       elem.selectedIndex = -1;
+                               }
+                               return values;
+                       }
+               }
+       }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+       jQuery.valHooks[ this ] = {
+               set: function( elem, value ) {
+                       if ( jQuery.isArray( value ) ) {
+                               return ( elem.checked = jQuery.inArray( 
jQuery(elem).val(), value ) >= 0 );
+                       }
+               }
+       };
+       if ( !support.checkOn ) {
+               jQuery.valHooks[ this ].get = function( elem ) {
+                       // Support: Webkit
+                       // "" is returned instead of "on" if a value isn't 
specified
+                       return elem.getAttribute("value") === null ? "on" : 
elem.value;
+               };
+       }
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click 
dblclick " +
+       "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " 
+
+       "change select submit keydown keypress keyup error 
contextmenu").split(" "), function( i, name ) {
+
+       // Handle event binding
+       jQuery.fn[ name ] = function( data, fn ) {
+               return arguments.length > 0 ?
+                       this.on( name, null, data, fn ) :
+                       this.trigger( name );
+       };
+});
+
+jQuery.fn.extend({
+       hover: function( fnOver, fnOut ) {
+               return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+       },
+
+       bind: function( types, data, fn ) {
+               return this.on( types, null, data, fn );
+       },
+       unbind: function( types, fn ) {
+               return this.off( types, null, fn );
+       },
+
+       delegate: function( selector, types, data, fn ) {
+               return this.on( types, selector, data, fn );
+       },
+       undelegate: function( selector, types, fn ) {
+               // ( namespace ) or ( selector, types [, fn] )
+               return arguments.length === 1 ? this.off( selector, "**" ) : 
this.off( types, selector || "**", fn );
+       }
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+// Support: Android 2.3
+// Workaround failure to string-cast null input
+jQuery.parseJSON = function( data ) {
+       return JSON.parse( data + "" );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+       var xml, tmp;
+       if ( !data || typeof data !== "string" ) {
+               return null;
+       }
+
+       // Support: IE9
+       try {
+               tmp = new DOMParser();
+               xml = tmp.parseFromString( data, "text/xml" );
+       } catch ( e ) {
+               xml = undefined;
+       }
+
+       if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+               jQuery.error( "Invalid XML: " + data );
+       }
+       return xml;
+};
+
+
+var
+       // Document location
+       ajaxLocParts,
+       ajaxLocation,
+
+       rhash = /#.*$/,
+       rts = /([?&])_=[^&]*/,
+       rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+       // #7653, #8125, #8152: local protocol detection
+       rlocalProtocol = 
/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+       rnoContent = /^(?:GET|HEAD)$/,
+       rprotocol = /^\/\//,
+       rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+       /* Prefilters
+        * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js 
for an example)
+        * 2) These are called:
+        *    - BEFORE asking for a transport
+        *    - AFTER param serialization (s.data is a string if s.processData 
is true)
+        * 3) key is the dataType
+        * 4) the catchall symbol "*" can be used
+        * 5) execution will start with transport dataType and THEN continue 
down to "*" if needed
+        */
+       prefilters = {},
+
+       /* Transports bindings
+        * 1) key is the dataType
+        * 2) the catchall symbol "*" can be used
+        * 3) selection will start with transport dataType and THEN go to "*" 
if needed
+        */
+       transports = {},
+
+       // Avoid comment-prolog char sequence (#10098); must appease lint and 
evade compression
+       allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+       ajaxLocation = location.href;
+} catch( e ) {
+       // Use the href attribute of an A element
+       // since IE will modify it given document.location
+       ajaxLocation = document.createElement( "a" );
+       ajaxLocation.href = "";
+       ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+       // dataTypeExpression is optional and defaults to "*"
+       return function( dataTypeExpression, func ) {
+
+               if ( typeof dataTypeExpression !== "string" ) {
+                       func = dataTypeExpression;
+                       dataTypeExpression = "*";
+               }
+
+               var dataType,
+                       i = 0,
+                       dataTypes = dataTypeExpression.toLowerCase().match( 
rnotwhite ) || [];
+
+               if ( jQuery.isFunction( func ) ) {
+                       // For each dataType in the dataTypeExpression
+                       while ( (dataType = dataTypes[i++]) ) {
+                               // Prepend if requested
+                               if ( dataType[0] === "+" ) {
+                                       dataType = dataType.slice( 1 ) || "*";
+                                       (structure[ dataType ] = structure[ 
dataType ] || []).unshift( func );
+
+                               // Otherwise append
+                               } else {
+                                       (structure[ dataType ] = structure[ 
dataType ] || []).push( func );
+                               }
+                       }
+               }
+       };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, 
jqXHR ) {
+
+       var inspected = {},
+               seekingTransport = ( structure === transports );
+
+       function inspect( dataType ) {
+               var selected;
+               inspected[ dataType ] = true;
+               jQuery.each( structure[ dataType ] || [], function( _, 
prefilterOrFactory ) {
+                       var dataTypeOrTransport = prefilterOrFactory( options, 
originalOptions, jqXHR );
+                       if ( typeof dataTypeOrTransport === "string" && 
!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+                               options.dataTypes.unshift( dataTypeOrTransport 
);
+                               inspect( dataTypeOrTransport );
+                               return false;
+                       } else if ( seekingTransport ) {
+                               return !( selected = dataTypeOrTransport );
+                       }
+               });
+               return selected;
+       }
+
+       return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && 
inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+       var key, deep,
+               flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+       for ( key in src ) {
+               if ( src[ key ] !== undefined ) {
+                       ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) 
)[ key ] = src[ key ];
+               }
+       }
+       if ( deep ) {
+               jQuery.extend( true, target, deep );
+       }
+
+       return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected 
dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+       var ct, type, finalDataType, firstDataType,
+               contents = s.contents,
+               dataTypes = s.dataTypes;
+
+       // Remove auto dataType and get content-type in the process
+       while ( dataTypes[ 0 ] === "*" ) {
+               dataTypes.shift();
+               if ( ct === undefined ) {
+                       ct = s.mimeType || 
jqXHR.getResponseHeader("Content-Type");
+               }
+       }
+
+       // Check if we're dealing with a known content-type
+       if ( ct ) {
+               for ( type in contents ) {
+                       if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                               dataTypes.unshift( type );
+                               break;
+                       }
+               }
+       }
+
+       // Check to see if we have a response for the expected dataType
+       if ( dataTypes[ 0 ] in responses ) {
+               finalDataType = dataTypes[ 0 ];
+       } else {
+               // Try convertible dataTypes
+               for ( type in responses ) {
+                       if ( !dataTypes[ 0 ] || s.converters[ type + " " + 
dataTypes[0] ] ) {
+                               finalDataType = type;
+                               break;
+                       }
+                       if ( !firstDataType ) {
+                               firstDataType = type;
+                       }
+               }
+               // Or just use first one
+               finalDataType = finalDataType || firstDataType;
+       }
+
+       // If we found a dataType
+       // We add the dataType to the list if needed
+       // and return the corresponding response
+       if ( finalDataType ) {
+               if ( finalDataType !== dataTypes[ 0 ] ) {
+                       dataTypes.unshift( finalDataType );
+               }
+               return responses[ finalDataType ];
+       }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+       var conv2, current, conv, tmp, prev,
+               converters = {},
+               // Work with a copy of dataTypes in case we need to modify it 
for conversion
+               dataTypes = s.dataTypes.slice();
+
+       // Create converters map with lowercased keys
+       if ( dataTypes[ 1 ] ) {
+               for ( conv in s.converters ) {
+                       converters[ conv.toLowerCase() ] = s.converters[ conv ];
+               }
+       }
+
+       current = dataTypes.shift();
+
+       // Convert to each sequential dataType
+       while ( current ) {
+
+               if ( s.responseFields[ current ] ) {
+                       jqXHR[ s.responseFields[ current ] ] = response;
+               }
+
+               // Apply the dataFilter if provided
+               if ( !prev && isSuccess && s.dataFilter ) {
+                       response = s.dataFilter( response, s.dataType );
+               }
+
+               prev = current;
+               current = dataTypes.shift();
+
+               if ( current ) {
+
+               // There's only work to do if current dataType is non-auto
+                       if ( current === "*" ) {
+
+                               current = prev;
+
+                       // Convert response if prev dataType is non-auto and 
differs from current
+                       } else if ( prev !== "*" && prev !== current ) {
+
+                               // Seek a direct converter
+                               conv = converters[ prev + " " + current ] || 
converters[ "* " + current ];
+
+                               // If none found, seek a pair
+                               if ( !conv ) {
+                                       for ( conv2 in converters ) {
+
+                                               // If conv2 outputs current
+                                               tmp = conv2.split( " " );
+                                               if ( tmp[ 1 ] === current ) {
+
+                                                       // If prev can be 
converted to accepted input
+                                                       conv = converters[ prev 
+ " " + tmp[ 0 ] ] ||
+                                                               converters[ "* 
" + tmp[ 0 ] ];
+                                                       if ( conv ) {
+                                                               // Condense 
equivalence converters
+                                                               if ( conv === 
true ) {
+                                                                       conv = 
converters[ conv2 ];
+
+                                                               // Otherwise, 
insert the intermediate dataType
+                                                               } else if ( 
converters[ conv2 ] !== true ) {
+                                                                       current 
= tmp[ 0 ];
+                                                                       
dataTypes.unshift( tmp[ 1 ] );
+                                                               }
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Apply converter (if not an equivalence)
+                               if ( conv !== true ) {
+
+                                       // Unless errors are allowed to bubble, 
catch and return them
+                                       if ( conv && s[ "throws" ] ) {
+                                               response = conv( response );
+                                       } else {
+                                               try {
+                                                       response = conv( 
response );
+                                               } catch ( e ) {
+                                                       return { state: 
"parsererror", error: conv ? e : "No conversion from " + prev + " to " + 
current };
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+       // Counter for holding the number of active queries
+       active: 0,
+
+       // Last-Modified header cache for next request
+       lastModified: {},
+       etag: {},
+
+       ajaxSettings: {
+               url: ajaxLocation,
+               type: "GET",
+               isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+               global: true,
+               processData: true,
+               async: true,
+               contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+               /*
+               timeout: 0,
+               data: null,
+               dataType: null,
+               username: null,
+               password: null,
+               cache: null,
+               throws: false,
+               traditional: false,
+               headers: {},
+               */
+
+               accepts: {
+                       "*": allTypes,
+                       text: "text/plain",
+                       html: "text/html",
+                       xml: "application/xml, text/xml",
+                       json: "application/json, text/javascript"
+               },
+
+               contents: {
+                       xml: /xml/,
+                       html: /html/,
+                       json: /json/
+               },
+
+               responseFields: {
+                       xml: "responseXML",
+                       text: "responseText",
+                       json: "responseJSON"
+               },
+
+               // Data converters
+               // Keys separate source (or catchall "*") and destination types 
with a single space
+               converters: {
+
+                       // Convert anything to text
+                       "* text": String,
+
+                       // Text to html (true = no transformation)
+                       "text html": true,
+
+                       // Evaluate text as a json expression
+                       "text json": jQuery.parseJSON,
+
+                       // Parse text as xml
+                       "text xml": jQuery.parseXML
+               },
+
+               // For options that shouldn't be deep extended:
+               // you can add your own custom options here if
+               // and when you create one that shouldn't be
+               // deep extended (see ajaxExtend)
+               flatOptions: {
+                       url: true,
+                       context: true
+               }
+       },
+
+       // Creates a full fledged settings object into target
+       // with both ajaxSettings and settings fields.
+       // If target is omitted, writes into ajaxSettings.
+       ajaxSetup: function( target, settings ) {
+               return settings ?
+
+                       // Building a settings object
+                       ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), 
settings ) :
+
+                       // Extending ajaxSettings
+                       ajaxExtend( jQuery.ajaxSettings, target );
+       },
+
+       ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+       ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+       // Main method
+       ajax: function( url, options ) {
+
+               // If url is an object, simulate pre-1.5 signature
+               if ( typeof url === "object" ) {
+                       options = url;
+                       url = undefined;
+               }
+
+               // Force options to be an object
+               options = options || {};
+
+               var transport,
+                       // URL without anti-cache param
+                       cacheURL,
+                       // Response headers
+                       responseHeadersString,
+                       responseHeaders,
+                       // timeout handle
+                       timeoutTimer,
+                       // Cross-domain detection vars
+                       parts,
+                       // To know if global events are to be dispatched
+                       fireGlobals,
+                       // Loop variable
+                       i,
+                       // Create the final options object
+                       s = jQuery.ajaxSetup( {}, options ),
+                       // Callbacks context
+                       callbackContext = s.context || s,
+                       // Context for global events is callbackContext if it 
is a DOM node or jQuery collection
+                       globalEventContext = s.context && ( 
callbackContext.nodeType || callbackContext.jquery ) ?
+                               jQuery( callbackContext ) :
+                               jQuery.event,
+                       // Deferreds
+                       deferred = jQuery.Deferred(),
+                       completeDeferred = jQuery.Callbacks("once memory"),
+                       // Status-dependent callbacks
+                       statusCode = s.statusCode || {},
+                       // Headers (they are sent all at once)
+                       requestHeaders = {},
+                       requestHeadersNames = {},
+                       // The jqXHR state
+                       state = 0,
+                       // Default abort message
+                       strAbort = "canceled",
+                       // Fake xhr
+                       jqXHR = {
+                               readyState: 0,
+
+                               // Builds headers hashtable if needed
+                               getResponseHeader: function( key ) {
+                                       var match;
+                                       if ( state === 2 ) {
+                                               if ( !responseHeaders ) {
+                                                       responseHeaders = {};
+                                                       while ( (match = 
rheaders.exec( responseHeadersString )) ) {
+                                                               
responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+                                                       }
+                                               }
+                                               match = responseHeaders[ 
key.toLowerCase() ];
+                                       }
+                                       return match == null ? null : match;
+                               },
+
+                               // Raw string
+                               getAllResponseHeaders: function() {
+                                       return state === 2 ? 
responseHeadersString : null;
+                               },
+
+                               // Caches the header
+                               setRequestHeader: function( name, value ) {
+                                       var lname = name.toLowerCase();
+                                       if ( !state ) {
+                                               name = requestHeadersNames[ 
lname ] = requestHeadersNames[ lname ] || name;
+                                               requestHeaders[ name ] = value;
+                                       }
+                                       return this;
+                               },
+
+                               // Overrides response content-type header
+                               overrideMimeType: function( type ) {
+                                       if ( !state ) {
+                                               s.mimeType = type;
+                                       }
+                                       return this;
+                               },
+
+                               // Status-dependent callbacks
+                               statusCode: function( map ) {
+                                       var code;
+                                       if ( map ) {
+                                               if ( state < 2 ) {
+                                                       for ( code in map ) {
+                                                               // Lazy-add the 
new callback in a way that preserves old ones
+                                                               statusCode[ 
code ] = [ statusCode[ code ], map[ code ] ];
+                                                       }
+                                               } else {
+                                                       // Execute the 
appropriate callbacks
+                                                       jqXHR.always( map[ 
jqXHR.status ] );
+                                               }
+                                       }
+                                       return this;
+                               },
+
+                               // Cancel the request
+                               abort: function( statusText ) {
+                                       var finalText = statusText || strAbort;
+                                       if ( transport ) {
+                                               transport.abort( finalText );
+                                       }
+                                       done( 0, finalText );
+                                       return this;
+                               }
+                       };
+
+               // Attach deferreds
+               deferred.promise( jqXHR ).complete = completeDeferred.add;
+               jqXHR.success = jqXHR.done;
+               jqXHR.error = jqXHR.fail;
+
+               // Remove hash character (#7531: and string promotion)
+               // Add protocol if not provided (prefilters might expect it)
+               // Handle falsy url in the settings object (#10093: consistency 
with old signature)
+               // We also use the url parameter if available
+               s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( 
rhash, "" )
+                       .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+               // Alias method option to type as per ticket #12004
+               s.type = options.method || options.type || s.method || s.type;
+
+               // Extract dataTypes list
+               s.dataTypes = jQuery.trim( s.dataType || "*" 
).toLowerCase().match( rnotwhite ) || [ "" ];
+
+               // A cross-domain request is in order when we have a 
protocol:host:port mismatch
+               if ( s.crossDomain == null ) {
+                       parts = rurl.exec( s.url.toLowerCase() );
+                       s.crossDomain = !!( parts &&
+                               ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 
] !== ajaxLocParts[ 2 ] ||
+                                       ( parts[ 3 ] || ( parts[ 1 ] === 
"http:" ? "80" : "443" ) ) !==
+                                               ( ajaxLocParts[ 3 ] || ( 
ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+                       );
+               }
+
+               // Convert data if not already a string
+               if ( s.data && s.processData && typeof s.data !== "string" ) {
+                       s.data = jQuery.param( s.data, s.traditional );
+               }
+
+               // Apply prefilters
+               inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+               // If request was aborted inside a prefilter, stop there
+               if ( state === 2 ) {
+                       return jqXHR;
+               }
+
+               // We can fire global events as of now if asked to
+               fireGlobals = s.global;
+
+               // Watch for a new set of requests
+               if ( fireGlobals && jQuery.active++ === 0 ) {
+                       jQuery.event.trigger("ajaxStart");
+               }
+
+               // Uppercase the type
+               s.type = s.type.toUpperCase();
+
+               // Determine if request has content
+               s.hasContent = !rnoContent.test( s.type );
+
+               // Save the URL in case we're toying with the If-Modified-Since
+               // and/or If-None-Match header later on
+               cacheURL = s.url;
+
+               // More options handling for requests with no content
+               if ( !s.hasContent ) {
+
+                       // If data is available, append data to url
+                       if ( s.data ) {
+                               cacheURL = ( s.url += ( rquery.test( cacheURL ) 
? "&" : "?" ) + s.data );
+                               // #9682: remove data so that it's not used in 
an eventual retry
+                               delete s.data;
+                       }
+
+                       // Add anti-cache in url if needed
+                       if ( s.cache === false ) {
+                               s.url = rts.test( cacheURL ) ?
+
+                                       // If there is already a '_' parameter, 
set its value
+                                       cacheURL.replace( rts, "$1_=" + nonce++ 
) :
+
+                                       // Otherwise add one to the end
+                                       cacheURL + ( rquery.test( cacheURL ) ? 
"&" : "?" ) + "_=" + nonce++;
+                       }
+               }
+
+               // Set the If-Modified-Since and/or If-None-Match header, if in 
ifModified mode.
+               if ( s.ifModified ) {
+                       if ( jQuery.lastModified[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-Modified-Since", 
jQuery.lastModified[ cacheURL ] );
+                       }
+                       if ( jQuery.etag[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-None-Match", 
jQuery.etag[ cacheURL ] );
+                       }
+               }
+
+               // Set the correct header, if data is being sent
+               if ( s.data && s.hasContent && s.contentType !== false || 
options.contentType ) {
+                       jqXHR.setRequestHeader( "Content-Type", s.contentType );
+               }
+
+               // Set the Accepts header for the server, depending on the 
dataType
+               jqXHR.setRequestHeader(
+                       "Accept",
+                       s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+                               s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 
] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+                               s.accepts[ "*" ]
+               );
+
+               // Check for headers option
+               for ( i in s.headers ) {
+                       jqXHR.setRequestHeader( i, s.headers[ i ] );
+               }
+
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend && ( s.beforeSend.call( callbackContext, 
jqXHR, s ) === false || state === 2 ) ) {
+                       // Abort if not done already and return
+                       return jqXHR.abort();
+               }
+
+               // aborting is no longer a cancellation
+               strAbort = "abort";
+
+               // Install callbacks on deferreds
+               for ( i in { success: 1, error: 1, complete: 1 } ) {
+                       jqXHR[ i ]( s[ i ] );
+               }
+
+               // Get transport
+               transport = inspectPrefiltersOrTransports( transports, s, 
options, jqXHR );
+
+               // If no transport, we auto-abort
+               if ( !transport ) {
+                       done( -1, "No Transport" );
+               } else {
+                       jqXHR.readyState = 1;
+
+                       // Send global event
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxSend", [ 
jqXHR, s ] );
+                       }
+                       // Timeout
+                       if ( s.async && s.timeout > 0 ) {
+                               timeoutTimer = setTimeout(function() {
+                                       jqXHR.abort("timeout");
+                               }, s.timeout );
+                       }
+
+                       try {
+                               state = 1;
+                               transport.send( requestHeaders, done );
+                       } catch ( e ) {
+                               // Propagate exception as error if not done
+                               if ( state < 2 ) {
+                                       done( -1, e );
+                               // Simply rethrow otherwise
+                               } else {
+                                       throw e;
+                               }
+                       }
+               }
+
+               // Callback for when everything is done
+               function done( status, nativeStatusText, responses, headers ) {
+                       var isSuccess, success, error, response, modified,
+                               statusText = nativeStatusText;
+
+                       // Called once
+                       if ( state === 2 ) {
+                               return;
+                       }
+
+                       // State is "done" now
+                       state = 2;
+
+                       // Clear timeout if it exists
+                       if ( timeoutTimer ) {
+                               clearTimeout( timeoutTimer );
+                       }
+
+                       // Dereference transport for early garbage collection
+                       // (no matter how long the jqXHR object will be used)
+                       transport = undefined;
+
+                       // Cache response headers
+                       responseHeadersString = headers || "";
+
+                       // Set readyState
+                       jqXHR.readyState = status > 0 ? 4 : 0;
+
+                       // Determine if successful
+                       isSuccess = status >= 200 && status < 300 || status === 
304;
+
+                       // Get response data
+                       if ( responses ) {
+                               response = ajaxHandleResponses( s, jqXHR, 
responses );
+                       }
+
+                       // Convert no matter what (that way responseXXX fields 
are always set)
+                       response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+                       // If successful, handle type chaining
+                       if ( isSuccess ) {
+
+                               // Set the If-Modified-Since and/or 
If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+                                       modified = 
jqXHR.getResponseHeader("Last-Modified");
+                                       if ( modified ) {
+                                               jQuery.lastModified[ cacheURL ] 
= modified;
+                                       }
+                                       modified = 
jqXHR.getResponseHeader("etag");
+                                       if ( modified ) {
+                                               jQuery.etag[ cacheURL ] = 
modified;
+                                       }
+                               }
+
+                               // if no content
+                               if ( status === 204 || s.type === "HEAD" ) {
+                                       statusText = "nocontent";
+
+                               // if not modified
+                               } else if ( status === 304 ) {
+                                       statusText = "notmodified";
+
+                               // If we have data, let's convert it
+                               } else {
+                                       statusText = response.state;
+                                       success = response.data;
+                                       error = response.error;
+                                       isSuccess = !error;
+                               }
+                       } else {
+                               // We extract error from statusText
+                               // then normalize statusText and status for 
non-aborts
+                               error = statusText;
+                               if ( status || !statusText ) {
+                                       statusText = "error";
+                                       if ( status < 0 ) {
+                                               status = 0;
+                                       }
+                               }
+                       }
+
+                       // Set data for the fake xhr object
+                       jqXHR.status = status;
+                       jqXHR.statusText = ( nativeStatusText || statusText ) + 
"";
+
+                       // Success/Error
+                       if ( isSuccess ) {
+                               deferred.resolveWith( callbackContext, [ 
success, statusText, jqXHR ] );
+                       } else {
+                               deferred.rejectWith( callbackContext, [ jqXHR, 
statusText, error ] );
+                       }
+
+                       // Status-dependent callbacks
+                       jqXHR.statusCode( statusCode );
+                       statusCode = undefined;
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( isSuccess ? 
"ajaxSuccess" : "ajaxError",
+                                       [ jqXHR, s, isSuccess ? success : error 
] );
+                       }
+
+                       // Complete
+                       completeDeferred.fireWith( callbackContext, [ jqXHR, 
statusText ] );
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxComplete", [ 
jqXHR, s ] );
+                               // Handle the global AJAX counter
+                               if ( !( --jQuery.active ) ) {
+                                       jQuery.event.trigger("ajaxStop");
+                               }
+                       }
+               }
+
+               return jqXHR;
+       },
+
+       getJSON: function( url, data, callback ) {
+               return jQuery.get( url, data, callback, "json" );
+       },
+
+       getScript: function( url, callback ) {
+               return jQuery.get( url, undefined, callback, "script" );
+       }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+       jQuery[ method ] = function( url, data, callback, type ) {
+               // shift arguments if data argument was omitted
+               if ( jQuery.isFunction( data ) ) {
+                       type = type || callback;
+                       callback = data;
+                       data = undefined;
+               }
+
+               return jQuery.ajax({
+                       url: url,
+                       type: method,
+                       dataType: type,
+                       data: data,
+                       success: callback
+               });
+       };
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", 
"ajaxSuccess", "ajaxSend" ], function( i, type ) {
+       jQuery.fn[ type ] = function( fn ) {
+               return this.on( type, fn );
+       };
+});
+
+
+jQuery._evalUrl = function( url ) {
+       return jQuery.ajax({
+               url: url,
+               type: "GET",
+               dataType: "script",
+               async: false,
+               global: false,
+               "throws": true
+       });
+};
+
+
+jQuery.fn.extend({
+       wrapAll: function( html ) {
+               var wrap;
+
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).wrapAll( html.call(this, i) );
+                       });
+               }
+
+               if ( this[ 0 ] ) {
+
+                       // The elements to wrap the target around
+                       wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 
).clone( true );
+
+                       if ( this[ 0 ].parentNode ) {
+                               wrap.insertBefore( this[ 0 ] );
+                       }
+
+                       wrap.map(function() {
+                               var elem = this;
+
+                               while ( elem.firstElementChild ) {
+                                       elem = elem.firstElementChild;
+                               }
+
+                               return elem;
+                       }).append( this );
+               }
+
+               return this;
+       },
+
+       wrapInner: function( html ) {
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).wrapInner( html.call(this, i) );
+                       });
+               }
+
+               return this.each(function() {
+                       var self = jQuery( this ),
+                               contents = self.contents();
+
+                       if ( contents.length ) {
+                               contents.wrapAll( html );
+
+                       } else {
+                               self.append( html );
+                       }
+               });
+       },
+
+       wrap: function( html ) {
+               var isFunction = jQuery.isFunction( html );
+
+               return this.each(function( i ) {
+                       jQuery( this ).wrapAll( isFunction ? html.call(this, i) 
: html );
+               });
+       },
+
+       unwrap: function() {
+               return this.parent().each(function() {
+                       if ( !jQuery.nodeName( this, "body" ) ) {
+                               jQuery( this ).replaceWith( this.childNodes );
+                       }
+               }).end();
+       }
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+       // Support: Opera <= 12.12
+       // Opera reports offsetWidths and offsetHeights less than zero on some 
elements
+       return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
+};
+jQuery.expr.filters.visible = function( elem ) {
+       return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+       rbracket = /\[\]$/,
+       rCRLF = /\r?\n/g,
+       rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+       rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+       var name;
+
+       if ( jQuery.isArray( obj ) ) {
+               // Serialize array item.
+               jQuery.each( obj, function( i, v ) {
+                       if ( traditional || rbracket.test( prefix ) ) {
+                               // Treat each array item as a scalar.
+                               add( prefix, v );
+
+                       } else {
+                               // Item is non-scalar (array or object), encode 
its numeric index.
+                               buildParams( prefix + "[" + ( typeof v === 
"object" ? i : "" ) + "]", v, traditional, add );
+                       }
+               });
+
+       } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+               // Serialize object item.
+               for ( name in obj ) {
+                       buildParams( prefix + "[" + name + "]", obj[ name ], 
traditional, add );
+               }
+
+       } else {
+               // Serialize scalar item.
+               add( prefix, obj );
+       }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+       var prefix,
+               s = [],
+               add = function( key, value ) {
+                       // If value is a function, invoke it and return its 
value
+                       value = jQuery.isFunction( value ) ? value() : ( value 
== null ? "" : value );
+                       s[ s.length ] = encodeURIComponent( key ) + "=" + 
encodeURIComponent( value );
+               };
+
+       // Set traditional to true for jQuery <= 1.3.2 behavior.
+       if ( traditional === undefined ) {
+               traditional = jQuery.ajaxSettings && 
jQuery.ajaxSettings.traditional;
+       }
+
+       // If an array was passed in, assume that it is an array of form 
elements.
+       if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) 
) {
+               // Serialize the form elements
+               jQuery.each( a, function() {
+                       add( this.name, this.value );
+               });
+
+       } else {
+               // If traditional, encode the "old" way (the way 1.3.2 or older
+               // did it), otherwise encode params recursively.
+               for ( prefix in a ) {
+                       buildParams( prefix, a[ prefix ], traditional, add );
+               }
+       }
+
+       // Return the resulting serialization
+       return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+       serialize: function() {
+               return jQuery.param( this.serializeArray() );
+       },
+       serializeArray: function() {
+               return this.map(function() {
+                       // Can add propHook for "elements" to filter or add 
form elements
+                       var elements = jQuery.prop( this, "elements" );
+                       return elements ? jQuery.makeArray( elements ) : this;
+               })
+               .filter(function() {
+                       var type = this.type;
+
+                       // Use .is( ":disabled" ) so that fieldset[disabled] 
works
+                       return this.name && !jQuery( this ).is( ":disabled" ) &&
+                               rsubmittable.test( this.nodeName ) && 
!rsubmitterTypes.test( type ) &&
+                               ( this.checked || !rcheckableType.test( type ) 
);
+               })
+               .map(function( i, elem ) {
+                       var val = jQuery( this ).val();
+
+                       return val == null ?
+                               null :
+                               jQuery.isArray( val ) ?
+                                       jQuery.map( val, function( val ) {
+                                               return { name: elem.name, 
value: val.replace( rCRLF, "\r\n" ) };
+                                       }) :
+                                       { name: elem.name, value: val.replace( 
rCRLF, "\r\n" ) };
+               }).get();
+       }
+});
+
+
+jQuery.ajaxSettings.xhr = function() {
+       try {
+               return new XMLHttpRequest();
+       } catch( e ) {}
+};
+
+var xhrId = 0,
+       xhrCallbacks = {},
+       xhrSuccessStatus = {
+               // file protocol always yields status code 0, assume 200
+               0: 200,
+               // Support: IE9
+               // #1450: sometimes IE returns 1223 when it should be 204
+               1223: 204
+       },
+       xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE9
+// Open requests must be manually aborted on unload (#5280)
+if ( window.ActiveXObject ) {
+       jQuery( window ).on( "unload", function() {
+               for ( var key in xhrCallbacks ) {
+                       xhrCallbacks[ key ]();
+               }
+       });
+}
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport(function( options ) {
+       var callback;
+
+       // Cross domain only allowed if supported through XMLHttpRequest
+       if ( support.cors || xhrSupported && !options.crossDomain ) {
+               return {
+                       send: function( headers, complete ) {
+                               var i,
+                                       xhr = options.xhr(),
+                                       id = ++xhrId;
+
+                               xhr.open( options.type, options.url, 
options.async, options.username, options.password );
+
+                               // Apply custom fields if provided
+                               if ( options.xhrFields ) {
+                                       for ( i in options.xhrFields ) {
+                                               xhr[ i ] = options.xhrFields[ i 
];
+                                       }
+                               }
+
+                               // Override mime type if needed
+                               if ( options.mimeType && xhr.overrideMimeType ) 
{
+                                       xhr.overrideMimeType( options.mimeType 
);
+                               }
+
+                               // X-Requested-With header
+                               // For cross-domain requests, seeing as 
conditions for a preflight are
+                               // akin to a jigsaw puzzle, we simply never set 
it to be sure.
+                               // (it can always be set on a per-request basis 
or even using ajaxSetup)
+                               // For same-domain requests, won't change 
header if already provided.
+                               if ( !options.crossDomain && 
!headers["X-Requested-With"] ) {
+                                       headers["X-Requested-With"] = 
"XMLHttpRequest";
+                               }
+
+                               // Set headers
+                               for ( i in headers ) {
+                                       xhr.setRequestHeader( i, headers[ i ] );
+                               }
+
+                               // Callback
+                               callback = function( type ) {
+                                       return function() {
+                                               if ( callback ) {
+                                                       delete xhrCallbacks[ id 
];
+                                                       callback = xhr.onload = 
xhr.onerror = null;
+
+                                                       if ( type === "abort" ) 
{
+                                                               xhr.abort();
+                                                       } else if ( type === 
"error" ) {
+                                                               complete(
+                                                                       // 
file: protocol always yields status 0; see #8605, #14207
+                                                                       
xhr.status,
+                                                                       
xhr.statusText
+                                                               );
+                                                       } else {
+                                                               complete(
+                                                                       
xhrSuccessStatus[ xhr.status ] || xhr.status,
+                                                                       
xhr.statusText,
+                                                                       // 
Support: IE9
+                                                                       // 
Accessing binary-data responseText throws an exception
+                                                                       // 
(#11426)
+                                                                       typeof 
xhr.responseText === "string" ? {
+                                                                               
text: xhr.responseText
+                                                                       } : 
undefined,
+                                                                       
xhr.getAllResponseHeaders()
+                                                               );
+                                                       }
+                                               }
+                                       };
+                               };
+
+                               // Listen to events
+                               xhr.onload = callback();
+                               xhr.onerror = callback("error");
+
+                               // Create the abort callback
+                               callback = xhrCallbacks[ id ] = 
callback("abort");
+
+                               try {
+                                       // Do send the request (this may raise 
an exception)
+                                       xhr.send( options.hasContent && 
options.data || null );
+                               } catch ( e ) {
+                                       // #14683: Only rethrow if this hasn't 
been notified as an error yet
+                                       if ( callback ) {
+                                               throw e;
+                                       }
+                               }
+                       },
+
+                       abort: function() {
+                               if ( callback ) {
+                                       callback();
+                               }
+                       }
+               };
+       }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+       accepts: {
+               script: "text/javascript, application/javascript, 
application/ecmascript, application/x-ecmascript"
+       },
+       contents: {
+               script: /(?:java|ecma)script/
+       },
+       converters: {
+               "text script": function( text ) {
+                       jQuery.globalEval( text );
+                       return text;
+               }
+       }
+});
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+       if ( s.cache === undefined ) {
+               s.cache = false;
+       }
+       if ( s.crossDomain ) {
+               s.type = "GET";
+       }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+       // This transport only deals with cross domain requests
+       if ( s.crossDomain ) {
+               var script, callback;
+               return {
+                       send: function( _, complete ) {
+                               script = jQuery("<script>").prop({
+                                       async: true,
+                                       charset: s.scriptCharset,
+                                       src: s.url
+                               }).on(
+                                       "load error",
+                                       callback = function( evt ) {
+                                               script.remove();
+                                               callback = null;
+                                               if ( evt ) {
+                                                       complete( evt.type === 
"error" ? 404 : 200, evt.type );
+                                               }
+                                       }
+                               );
+                               document.head.appendChild( script[ 0 ] );
+                       },
+                       abort: function() {
+                               if ( callback ) {
+                                       callback();
+                               }
+                       }
+               };
+       }
+});
+
+
+
+
+var oldCallbacks = [],
+       rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+       jsonp: "callback",
+       jsonpCallback: function() {
+               var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( 
nonce++ ) );
+               this[ callback ] = true;
+               return callback;
+       }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+       var callbackName, overwritten, responseContainer,
+               jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+                       "url" :
+                       typeof s.data === "string" && !( s.contentType || "" 
).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && 
"data"
+               );
+
+       // Handle iff the expected data type is "jsonp" or we have a parameter 
to set
+       if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+               // Get callback name, remembering preexisting value associated 
with it
+               callbackName = s.jsonpCallback = jQuery.isFunction( 
s.jsonpCallback ) ?
+                       s.jsonpCallback() :
+                       s.jsonpCallback;
+
+               // Insert callback into url or form data
+               if ( jsonProp ) {
+                       s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + 
callbackName );
+               } else if ( s.jsonp !== false ) {
+                       s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp 
+ "=" + callbackName;
+               }
+
+               // Use data converter to retrieve json after script execution
+               s.converters["script json"] = function() {
+                       if ( !responseContainer ) {
+                               jQuery.error( callbackName + " was not called" 
);
+                       }
+                       return responseContainer[ 0 ];
+               };
+
+               // force json dataType
+               s.dataTypes[ 0 ] = "json";
+
+               // Install callback
+               overwritten = window[ callbackName ];
+               window[ callbackName ] = function() {
+                       responseContainer = arguments;
+               };
+
+               // Clean-up function (fires after converters)
+               jqXHR.always(function() {
+                       // Restore preexisting value
+                       window[ callbackName ] = overwritten;
+
+                       // Save back as free
+                       if ( s[ callbackName ] ) {
+                               // make sure that re-using the options doesn't 
screw things around
+                               s.jsonpCallback = 
originalSettings.jsonpCallback;
+
+                               // save the callback name for future use
+                               oldCallbacks.push( callbackName );
+                       }
+
+                       // Call if it was a function and we have a response
+                       if ( responseContainer && jQuery.isFunction( 
overwritten ) ) {
+                               overwritten( responseContainer[ 0 ] );
+                       }
+
+                       responseContainer = overwritten = undefined;
+               });
+
+               // Delegate to script
+               return "script";
+       }
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this 
context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html 
string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+       if ( !data || typeof data !== "string" ) {
+               return null;
+       }
+       if ( typeof context === "boolean" ) {
+               keepScripts = context;
+               context = false;
+       }
+       context = context || document;
+
+       var parsed = rsingleTag.exec( data ),
+               scripts = !keepScripts && [];
+
+       // Single tag
+       if ( parsed ) {
+               return [ context.createElement( parsed[1] ) ];
+       }
+
+       parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+       if ( scripts && scripts.length ) {
+               jQuery( scripts ).remove();
+       }
+
+       return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+       if ( typeof url !== "string" && _load ) {
+               return _load.apply( this, arguments );
+       }
+
+       var selector, type, response,
+               self = this,
+               off = url.indexOf(" ");
+
+       if ( off >= 0 ) {
+               selector = jQuery.trim( url.slice( off ) );
+               url = url.slice( 0, off );
+       }
+
+       // If it's a function
+       if ( jQuery.isFunction( params ) ) {
+
+               // We assume that it's the callback
+               callback = params;
+               params = undefined;
+
+       // Otherwise, build a param string
+       } else if ( params && typeof params === "object" ) {
+               type = "POST";
+       }
+
+       // If we have elements to modify, make the request
+       if ( self.length > 0 ) {
+               jQuery.ajax({
+                       url: url,
+
+                       // if "type" variable is undefined, then "GET" method 
will be used
+                       type: type,
+                       dataType: "html",
+                       data: params
+               }).done(function( responseText ) {
+
+                       // Save response for use in complete callback
+                       response = arguments;
+
+                       self.html( selector ?
+
+                               // If a selector was specified, locate the 
right elements in a dummy div
+                               // Exclude scripts to avoid IE 'Permission 
Denied' errors
+                               jQuery("<div>").append( jQuery.parseHTML( 
responseText ) ).find( selector ) :
+
+                               // Otherwise use the full result
+                               responseText );
+
+               }).complete( callback && function( jqXHR, status ) {
+                       self.each( callback, response || [ jqXHR.responseText, 
status, jqXHR ] );
+               });
+       }
+
+       return this;
+};
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+       return jQuery.grep(jQuery.timers, function( fn ) {
+               return elem === fn.elem;
+       }).length;
+};
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+       return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && 
elem.defaultView;
+}
+
+jQuery.offset = {
+       setOffset: function( elem, options, i ) {
+               var curPosition, curLeft, curCSSTop, curTop, curOffset, 
curCSSLeft, calculatePosition,
+                       position = jQuery.css( elem, "position" ),
+                       curElem = jQuery( elem ),
+                       props = {};
+
+               // Set position first, in-case top/left are set even on static 
elem
+               if ( position === "static" ) {
+                       elem.style.position = "relative";
+               }
+
+               curOffset = curElem.offset();
+               curCSSTop = jQuery.css( elem, "top" );
+               curCSSLeft = jQuery.css( elem, "left" );
+               calculatePosition = ( position === "absolute" || position === 
"fixed" ) &&
+                       ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
+
+               // Need to be able to calculate position if either top or left 
is auto and position is either absolute or fixed
+               if ( calculatePosition ) {
+                       curPosition = curElem.position();
+                       curTop = curPosition.top;
+                       curLeft = curPosition.left;
+
+               } else {
+                       curTop = parseFloat( curCSSTop ) || 0;
+                       curLeft = parseFloat( curCSSLeft ) || 0;
+               }
+
+               if ( jQuery.isFunction( options ) ) {
+                       options = options.call( elem, i, curOffset );
+               }
+
+               if ( options.top != null ) {
+                       props.top = ( options.top - curOffset.top ) + curTop;
+               }
+               if ( options.left != null ) {
+                       props.left = ( options.left - curOffset.left ) + 
curLeft;
+               }
+
+               if ( "using" in options ) {
+                       options.using.call( elem, props );
+
+               } else {
+                       curElem.css( props );
+               }
+       }
+};
+
+jQuery.fn.extend({
+       offset: function( options ) {
+               if ( arguments.length ) {
+                       return options === undefined ?
+                               this :
+                               this.each(function( i ) {
+                                       jQuery.offset.setOffset( this, options, 
i );
+                               });
+               }
+
+               var docElem, win,
+                       elem = this[ 0 ],
+                       box = { top: 0, left: 0 },
+                       doc = elem && elem.ownerDocument;
+
+               if ( !doc ) {
+                       return;
+               }
+
+               docElem = doc.documentElement;
+
+               // Make sure it's not a disconnected DOM node
+               if ( !jQuery.contains( docElem, elem ) ) {
+                       return box;
+               }
+
+               // If we don't have gBCR, just use 0,0 rather than error
+               // BlackBerry 5, iOS 3 (original iPhone)
+               if ( typeof elem.getBoundingClientRect !== strundefined ) {
+                       box = elem.getBoundingClientRect();
+               }
+               win = getWindow( doc );
+               return {
+                       top: box.top + win.pageYOffset - docElem.clientTop,
+                       left: box.left + win.pageXOffset - docElem.clientLeft
+               };
+       },
+
+       position: function() {
+               if ( !this[ 0 ] ) {
+                       return;
+               }
+
+               var offsetParent, offset,
+                       elem = this[ 0 ],
+                       parentOffset = { top: 0, left: 0 };
+
+               // Fixed elements are offset from window (parentOffset = 
{top:0, left: 0}, because it is its only offset parent
+               if ( jQuery.css( elem, "position" ) === "fixed" ) {
+                       // We assume that getBoundingClientRect is available 
when computed position is fixed
+                       offset = elem.getBoundingClientRect();
+
+               } else {
+                       // Get *real* offsetParent
+                       offsetParent = this.offsetParent();
+
+                       // Get correct offsets
+                       offset = this.offset();
+                       if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+                               parentOffset = offsetParent.offset();
+                       }
+
+                       // Add offsetParent borders
+                       parentOffset.top += jQuery.css( offsetParent[ 0 ], 
"borderTopWidth", true );
+                       parentOffset.left += jQuery.css( offsetParent[ 0 ], 
"borderLeftWidth", true );
+               }
+
+               // Subtract parent offsets and element margins
+               return {
+                       top: offset.top - parentOffset.top - jQuery.css( elem, 
"marginTop", true ),
+                       left: offset.left - parentOffset.left - jQuery.css( 
elem, "marginLeft", true )
+               };
+       },
+
+       offsetParent: function() {
+               return this.map(function() {
+                       var offsetParent = this.offsetParent || docElem;
+
+                       while ( offsetParent && ( !jQuery.nodeName( 
offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) 
) {
+                               offsetParent = offsetParent.offsetParent;
+                       }
+
+                       return offsetParent || docElem;
+               });
+       }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, 
function( method, prop ) {
+       var top = "pageYOffset" === prop;
+
+       jQuery.fn[ method ] = function( val ) {
+               return access( this, function( elem, method, val ) {
+                       var win = getWindow( elem );
+
+                       if ( val === undefined ) {
+                               return win ? win[ prop ] : elem[ method ];
+                       }
+
+                       if ( win ) {
+                               win.scrollTo(
+                                       !top ? val : window.pageXOffset,
+                                       top ? val : window.pageYOffset
+                               );
+
+                       } else {
+                               elem[ method ] = val;
+                       }
+               }, method, val, arguments.length, null );
+       };
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check 
for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+       jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+               function( elem, computed ) {
+                       if ( computed ) {
+                               computed = curCSS( elem, prop );
+                               // if curCSS returns percentage, fallback to 
offset
+                               return rnumnonpx.test( computed ) ?
+                                       jQuery( elem ).position()[ prop ] + 
"px" :
+                                       computed;
+                       }
+               }
+       );
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth 
methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+       jQuery.each( { padding: "inner" + name, content: type, "": "outer" + 
name }, function( defaultExtra, funcName ) {
+               // margin is only for outerHeight, outerWidth
+               jQuery.fn[ funcName ] = function( margin, value ) {
+                       var chainable = arguments.length && ( defaultExtra || 
typeof margin !== "boolean" ),
+                               extra = defaultExtra || ( margin === true || 
value === true ? "margin" : "border" );
+
+                       return access( this, function( elem, type, value ) {
+                               var doc;
+
+                               if ( jQuery.isWindow( elem ) ) {
+                                       // As of 5/8/2012 this will yield 
incorrect results for Mobile Safari, but there
+                                       // isn't a whole lot we can do. See 
pull request at this URL for discussion:
+                                       // 
https://github.com/jquery/jquery/pull/764
+                                       return elem.document.documentElement[ 
"client" + name ];
+                               }
+
+                               // Get document width or height
+                               if ( elem.nodeType === 9 ) {
+                                       doc = elem.documentElement;
+
+                                       // Either scroll[Width/Height] or 
offset[Width/Height] or client[Width/Height],
+                                       // whichever is greatest
+                                       return Math.max(
+                                               elem.body[ "scroll" + name ], 
doc[ "scroll" + name ],
+                                               elem.body[ "offset" + name ], 
doc[ "offset" + name ],
+                                               doc[ "client" + name ]
+                                       );
+                               }
+
+                               return value === undefined ?
+                                       // Get width or height on the element, 
requesting but not forcing parseFloat
+                                       jQuery.css( elem, type, extra ) :
+
+                                       // Set width or height on the element
+                                       jQuery.style( elem, type, value, extra 
);
+                       }, type, chainable ? margin : undefined, chainable, 
null );
+               };
+       });
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+       return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// 
https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+       define( "jquery", [], function() {
+               return jQuery;
+       });
+}
+
+
+
+
+var
+       // Map over jQuery in case of overwrite
+       _jQuery = window.jQuery,
+
+       // Map over the $ in case of overwrite
+       _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+       if ( window.$ === jQuery ) {
+               window.$ = _$;
+       }
+
+       if ( deep && window.jQuery === jQuery ) {
+               window.jQuery = _jQuery;
+       }
+
+       return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+       window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/packages/context-coloring/benchmark/fixtures/lodash-2.4.1.js 
b/packages/context-coloring/benchmark/fixtures/lodash-2.4.1.js
new file mode 100644
index 0000000..d653e5a
--- /dev/null
+++ b/packages/context-coloring/benchmark/fixtures/lodash-2.4.1.js
@@ -0,0 +1,6785 @@
+/**
+ * @license
+ * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
+ * Build: `lodash modern -o ./dist/lodash.js`
+ * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative 
Reporters & Editors
+ * Available under MIT license <http://lodash.com/license>
+ */
+;(function() {
+
+  /** Used as a safe reference for `undefined` in pre ES5 environments */
+  var undefined;
+
+  /** Used to pool arrays and objects used internally */
+  var arrayPool = [],
+      objectPool = [];
+
+  /** Used to generate unique IDs */
+  var idCounter = 0;
+
+  /** Used to prefix keys to avoid issues with `__proto__` and properties on 
`Object.prototype` */
+  var keyPrefix = +new Date + '';
+
+  /** Used as the size when optimizations are enabled for large arrays */
+  var largeArraySize = 75;
+
+  /** Used as the max size of the `arrayPool` and `objectPool` */
+  var maxPoolSize = 40;
+
+  /** Used to detect and test whitespace */
+  var whitespace = (
+    // whitespace
+    ' \t\x0B\f\xA0\ufeff' +
+
+    // line terminators
+    '\n\r\u2028\u2029' +
+
+    // unicode category "Zs" space separators
+    
'\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
+  );
+
+  /** Used to match empty string literals in compiled template source */
+  var reEmptyStringLeading = /\b__p \+= '';/g,
+      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+  /**
+   * Used to match ES6 template delimiters
+   * 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
+   */
+  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+  /** Used to match regexp flags from their coerced string values */
+  var reFlags = /\w*$/;
+
+  /** Used to detected named functions */
+  var reFuncName = /^\s*function[ \n\r\t]+\w/;
+
+  /** Used to match "interpolate" template delimiters */
+  var reInterpolate = /<%=([\s\S]+?)%>/g;
+
+  /** Used to match leading whitespace and zeros to be removed */
+  var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
+
+  /** Used to ensure capturing order of template delimiters */
+  var reNoMatch = /($^)/;
+
+  /** Used to detect functions containing a `this` reference */
+  var reThis = /\bthis\b/;
+
+  /** Used to match unescaped characters in compiled string literals */
+  var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
+
+  /** Used to assign default `context` object properties */
+  var contextProps = [
+    'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
+    'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 
'isNaN',
+    'parseInt', 'setTimeout'
+  ];
+
+  /** Used to make template sourceURLs easier to identify */
+  var templateCounter = 0;
+
+  /** `Object#toString` result shortcuts */
+  var argsClass = '[object Arguments]',
+      arrayClass = '[object Array]',
+      boolClass = '[object Boolean]',
+      dateClass = '[object Date]',
+      funcClass = '[object Function]',
+      numberClass = '[object Number]',
+      objectClass = '[object Object]',
+      regexpClass = '[object RegExp]',
+      stringClass = '[object String]';
+
+  /** Used to identify object classifications that `_.clone` supports */
+  var cloneableClasses = {};
+  cloneableClasses[funcClass] = false;
+  cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
+  cloneableClasses[boolClass] = cloneableClasses[dateClass] =
+  cloneableClasses[numberClass] = cloneableClasses[objectClass] =
+  cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
+
+  /** Used as an internal `_.debounce` options object */
+  var debounceOptions = {
+    'leading': false,
+    'maxWait': 0,
+    'trailing': false
+  };
+
+  /** Used as the property descriptor for `__bindData__` */
+  var descriptor = {
+    'configurable': false,
+    'enumerable': false,
+    'value': null,
+    'writable': false
+  };
+
+  /** Used to determine if values are of the language type Object */
+  var objectTypes = {
+    'boolean': false,
+    'function': true,
+    'object': true,
+    'number': false,
+    'string': false,
+    'undefined': false
+  };
+
+  /** Used to escape characters for inclusion in compiled string literals */
+  var stringEscapes = {
+    '\\': '\\',
+    "'": "'",
+    '\n': 'n',
+    '\r': 'r',
+    '\t': 't',
+    '\u2028': 'u2028',
+    '\u2029': 'u2029'
+  };
+
+  /** Used as a reference to the global object */
+  var root = (objectTypes[typeof window] && window) || this;
+
+  /** Detect free variable `exports` */
+  var freeExports = objectTypes[typeof exports] && exports && 
!exports.nodeType && exports;
+
+  /** Detect free variable `module` */
+  var freeModule = objectTypes[typeof module] && module && !module.nodeType && 
module;
+
+  /** Detect the popular CommonJS extension `module.exports` */
+  var moduleExports = freeModule && freeModule.exports === freeExports && 
freeExports;
+
+  /** Detect free variable `global` from Node.js or Browserified code and use 
it as `root` */
+  var freeGlobal = objectTypes[typeof global] && global;
+  if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === 
freeGlobal)) {
+    root = freeGlobal;
+  }
+
+  
/*--------------------------------------------------------------------------*/
+
+  /**
+   * The base implementation of `_.indexOf` without support for binary searches
+   * or `fromIndex` constraints.
+   *
+   * @private
+   * @param {Array} array The array to search.
+   * @param {*} value The value to search for.
+   * @param {number} [fromIndex=0] The index to search from.
+   * @returns {number} Returns the index of the matched value or `-1`.
+   */
+  function baseIndexOf(array, value, fromIndex) {
+    var index = (fromIndex || 0) - 1,
+        length = array ? array.length : 0;
+
+    while (++index < length) {
+      if (array[index] === value) {
+        return index;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * An implementation of `_.contains` for cache objects that mimics the return
+   * signature of `_.indexOf` by returning `0` if the value is found, else 
`-1`.
+   *
+   * @private
+   * @param {Object} cache The cache object to inspect.
+   * @param {*} value The value to search for.
+   * @returns {number} Returns `0` if `value` is found, else `-1`.
+   */
+  function cacheIndexOf(cache, value) {
+    var type = typeof value;
+    cache = cache.cache;
+
+    if (type == 'boolean' || value == null) {
+      return cache[value] ? 0 : -1;
+    }
+    if (type != 'number' && type != 'string') {
+      type = 'object';
+    }
+    var key = type == 'number' ? value : keyPrefix + value;
+    cache = (cache = cache[type]) && cache[key];
+
+    return type == 'object'
+      ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
+      : (cache ? 0 : -1);
+  }
+
+  /**
+   * Adds a given value to the corresponding cache object.
+   *
+   * @private
+   * @param {*} value The value to add to the cache.
+   */
+  function cachePush(value) {
+    var cache = this.cache,
+        type = typeof value;
+
+    if (type == 'boolean' || value == null) {
+      cache[value] = true;
+    } else {
+      if (type != 'number' && type != 'string') {
+        type = 'object';
+      }
+      var key = type == 'number' ? value : keyPrefix + value,
+          typeCache = cache[type] || (cache[type] = {});
+
+      if (type == 'object') {
+        (typeCache[key] || (typeCache[key] = [])).push(value);
+      } else {
+        typeCache[key] = true;
+      }
+    }
+  }
+
+  /**
+   * Used by `_.max` and `_.min` as the default callback when a given
+   * collection is a string value.
+   *
+   * @private
+   * @param {string} value The character to inspect.
+   * @returns {number} Returns the code unit of given character.
+   */
+  function charAtCallback(value) {
+    return value.charCodeAt(0);
+  }
+
+  /**
+   * Used by `sortBy` to compare transformed `collection` elements, stable 
sorting
+   * them in ascending order.
+   *
+   * @private
+   * @param {Object} a The object to compare to `b`.
+   * @param {Object} b The object to compare to `a`.
+   * @returns {number} Returns the sort order indicator of `1` or `-1`.
+   */
+  function compareAscending(a, b) {
+    var ac = a.criteria,
+        bc = b.criteria,
+        index = -1,
+        length = ac.length;
+
+    while (++index < length) {
+      var value = ac[index],
+          other = bc[index];
+
+      if (value !== other) {
+        if (value > other || typeof value == 'undefined') {
+          return 1;
+        }
+        if (value < other || typeof other == 'undefined') {
+          return -1;
+        }
+      }
+    }
+    // Fixes an `Array#sort` bug in the JS engine embedded in Adobe 
applications
+    // that causes it, under certain circumstances, to return the same value 
for
+    // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
+    //
+    // This also ensures a stable sort in V8 and other engines.
+    // See http://code.google.com/p/v8/issues/detail?id=90
+    return a.index - b.index;
+  }
+
+  /**
+   * Creates a cache object to optimize linear searches of large arrays.
+   *
+   * @private
+   * @param {Array} [array=[]] The array to search.
+   * @returns {null|Object} Returns the cache object or `null` if caching 
should not be used.
+   */
+  function createCache(array) {
+    var index = -1,
+        length = array.length,
+        first = array[0],
+        mid = array[(length / 2) | 0],
+        last = array[length - 1];
+
+    if (first && typeof first == 'object' &&
+        mid && typeof mid == 'object' && last && typeof last == 'object') {
+      return false;
+    }
+    var cache = getObject();
+    cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = 
false;
+
+    var result = getObject();
+    result.array = array;
+    result.cache = cache;
+    result.push = cachePush;
+
+    while (++index < length) {
+      result.push(array[index]);
+    }
+    return result;
+  }
+
+  /**
+   * Used by `template` to escape characters for inclusion in compiled
+   * string literals.
+   *
+   * @private
+   * @param {string} match The matched character to escape.
+   * @returns {string} Returns the escaped character.
+   */
+  function escapeStringChar(match) {
+    return '\\' + stringEscapes[match];
+  }
+
+  /**
+   * Gets an array from the array pool or creates a new one if the pool is 
empty.
+   *
+   * @private
+   * @returns {Array} The array from the pool.
+   */
+  function getArray() {
+    return arrayPool.pop() || [];
+  }
+
+  /**
+   * Gets an object from the object pool or creates a new one if the pool is 
empty.
+   *
+   * @private
+   * @returns {Object} The object from the pool.
+   */
+  function getObject() {
+    return objectPool.pop() || {
+      'array': null,
+      'cache': null,
+      'criteria': null,
+      'false': false,
+      'index': 0,
+      'null': false,
+      'number': null,
+      'object': null,
+      'push': null,
+      'string': null,
+      'true': false,
+      'undefined': false,
+      'value': null
+    };
+  }
+
+  /**
+   * Releases the given array back to the array pool.
+   *
+   * @private
+   * @param {Array} [array] The array to release.
+   */
+  function releaseArray(array) {
+    array.length = 0;
+    if (arrayPool.length < maxPoolSize) {
+      arrayPool.push(array);
+    }
+  }
+
+  /**
+   * Releases the given object back to the object pool.
+   *
+   * @private
+   * @param {Object} [object] The object to release.
+   */
+  function releaseObject(object) {
+    var cache = object.cache;
+    if (cache) {
+      releaseObject(cache);
+    }
+    object.array = object.cache = object.criteria = object.object = 
object.number = object.string = object.value = null;
+    if (objectPool.length < maxPoolSize) {
+      objectPool.push(object);
+    }
+  }
+
+  /**
+   * Slices the `collection` from the `start` index up to, but not including,
+   * the `end` index.
+   *
+   * Note: This function is used instead of `Array#slice` to support node lists
+   * in IE < 9 and to ensure dense arrays are returned.
+   *
+   * @private
+   * @param {Array|Object|string} collection The collection to slice.
+   * @param {number} start The start index.
+   * @param {number} end The end index.
+   * @returns {Array} Returns the new array.
+   */
+  function slice(array, start, end) {
+    start || (start = 0);
+    if (typeof end == 'undefined') {
+      end = array ? array.length : 0;
+    }
+    var index = -1,
+        length = end - start || 0,
+        result = Array(length < 0 ? 0 : length);
+
+    while (++index < length) {
+      result[index] = array[start + index];
+    }
+    return result;
+  }
+
+  
/*--------------------------------------------------------------------------*/
+
+  /**
+   * Create a new `lodash` function using the given context object.
+   *
+   * @static
+   * @memberOf _
+   * @category Utilities
+   * @param {Object} [context=root] The context object.
+   * @returns {Function} Returns the `lodash` function.
+   */
+  function runInContext(context) {
+    // Avoid issues with some ES3 environments that attempt to use values, 
named
+    // after built-in constructors like `Object`, for the creation of literals.
+    // ES5 clears this up by stating that literals must use built-in 
constructors.
+    // See http://es5.github.io/#x11.1.5.
+    context = context ? _.defaults(root.Object(), context, _.pick(root, 
contextProps)) : root;
+
+    /** Native constructor references */
+    var Array = context.Array,
+        Boolean = context.Boolean,
+        Date = context.Date,
+        Function = context.Function,
+        Math = context.Math,
+        Number = context.Number,
+        Object = context.Object,
+        RegExp = context.RegExp,
+        String = context.String,
+        TypeError = context.TypeError;
+
+    /**
+     * Used for `Array` method references.
+     *
+     * Normally `Array.prototype` would suffice, however, using an array 
literal
+     * avoids issues in Narwhal.
+     */
+    var arrayRef = [];
+
+    /** Used for native method references */
+    var objectProto = Object.prototype;
+
+    /** Used to restore the original `_` reference in `noConflict` */
+    var oldDash = context._;
+
+    /** Used to resolve the internal [[Class]] of values */
+    var toString = objectProto.toString;
+
+    /** Used to detect if a method is native */
+    var reNative = RegExp('^' +
+      String(toString)
+        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+        .replace(/toString| for [^\]]+/g, '.*?') + '$'
+    );
+
+    /** Native method shortcuts */
+    var ceil = Math.ceil,
+        clearTimeout = context.clearTimeout,
+        floor = Math.floor,
+        fnToString = Function.prototype.toString,
+        getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && 
getPrototypeOf,
+        hasOwnProperty = objectProto.hasOwnProperty,
+        push = arrayRef.push,
+        setTimeout = context.setTimeout,
+        splice = arrayRef.splice,
+        unshift = arrayRef.unshift;
+
+    /** Used to set meta data on functions */
+    var defineProperty = (function() {
+      // IE 8 only accepts DOM elements
+      try {
+        var o = {},
+            func = isNative(func = Object.defineProperty) && func,
+            result = func(o, o, o) && func;
+      } catch(e) { }
+      return result;
+    }());
+
+    /* Native method shortcuts for methods with the same name as other 
`lodash` methods */
+    var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
+        nativeIsArray = isNative(nativeIsArray = Array.isArray) && 
nativeIsArray,
+        nativeIsFinite = context.isFinite,
+        nativeIsNaN = context.isNaN,
+        nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
+        nativeMax = Math.max,
+        nativeMin = Math.min,
+        nativeParseInt = context.parseInt,
+        nativeRandom = Math.random;
+
+    /** Used to lookup a built-in constructor by [[Class]] */
+    var ctorByClass = {};
+    ctorByClass[arrayClass] = Array;
+    ctorByClass[boolClass] = Boolean;
+    ctorByClass[dateClass] = Date;
+    ctorByClass[funcClass] = Function;
+    ctorByClass[objectClass] = Object;
+    ctorByClass[numberClass] = Number;
+    ctorByClass[regexpClass] = RegExp;
+    ctorByClass[stringClass] = String;
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Creates a `lodash` object which wraps the given value to enable 
intuitive
+     * method chaining.
+     *
+     * In addition to Lo-Dash methods, wrappers also have the following 
`Array` methods:
+     * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, 
`splice`,
+     * and `unshift`
+     *
+     * Chaining is supported in custom builds as long as the `value` method is
+     * implicitly or explicitly included in the build.
+     *
+     * The chainable wrapper functions are:
+     * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
+     * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
+     * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, 
`flatten`,
+     * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, 
`forOwnRight`,
+     * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
+     * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, 
`omit`,
+     * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, 
`push`,
+     * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, 
`sort`,
+     * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
+     * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, 
`wrap`,
+     * and `zip`
+     *
+     * The non-chainable wrapper functions are:
+     * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, 
`findIndex`,
+     * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, 
`identity`,
+     * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
+     * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, 
`isNumber`,
+     * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, 
`join`,
+     * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, 
`reduce`,
+     * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, 
`runInContext`,
+     * `template`, `unescape`, `uniqueId`, and `value`
+     *
+     * The wrapper functions `first` and `last` return wrapped values when `n` 
is
+     * provided, otherwise they return unwrapped values.
+     *
+     * Explicit chaining can be enabled by using the `_.chain` method.
+     *
+     * @name _
+     * @constructor
+     * @category Chaining
+     * @param {*} value The value to wrap in a `lodash` instance.
+     * @returns {Object} Returns a `lodash` instance.
+     * @example
+     *
+     * var wrapped = _([1, 2, 3]);
+     *
+     * // returns an unwrapped value
+     * wrapped.reduce(function(sum, num) {
+     *   return sum + num;
+     * });
+     * // => 6
+     *
+     * // returns a wrapped value
+     * var squares = wrapped.map(function(num) {
+     *   return num * num;
+     * });
+     *
+     * _.isArray(squares);
+     * // => false
+     *
+     * _.isArray(squares.value());
+     * // => true
+     */
+    function lodash(value) {
+      // don't wrap if already wrapped, even if wrapped by a different 
`lodash` constructor
+      return (value && typeof value == 'object' && !isArray(value) && 
hasOwnProperty.call(value, '__wrapped__'))
+       ? value
+       : new lodashWrapper(value);
+    }
+
+    /**
+     * A fast path for creating `lodash` wrapper objects.
+     *
+     * @private
+     * @param {*} value The value to wrap in a `lodash` instance.
+     * @param {boolean} chainAll A flag to enable chaining for all methods
+     * @returns {Object} Returns a `lodash` instance.
+     */
+    function lodashWrapper(value, chainAll) {
+      this.__chain__ = !!chainAll;
+      this.__wrapped__ = value;
+    }
+    // ensure `new lodashWrapper` is an instance of `lodash`
+    lodashWrapper.prototype = lodash.prototype;
+
+    /**
+     * An object used to flag environments features.
+     *
+     * @static
+     * @memberOf _
+     * @type Object
+     */
+    var support = lodash.support = {};
+
+    /**
+     * Detect if functions can be decompiled by `Function#toString`
+     * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 
apps).
+     *
+     * @memberOf _.support
+     * @type boolean
+     */
+    support.funcDecomp = !isNative(context.WinRTError) && 
reThis.test(runInContext);
+
+    /**
+     * Detect if `Function#name` is supported (all but IE).
+     *
+     * @memberOf _.support
+     * @type boolean
+     */
+    support.funcNames = typeof Function.name == 'string';
+
+    /**
+     * By default, the template delimiters used by Lo-Dash are similar to 
those in
+     * embedded Ruby (ERB). Change the following template settings to use 
alternative
+     * delimiters.
+     *
+     * @static
+     * @memberOf _
+     * @type Object
+     */
+    lodash.templateSettings = {
+
+      /**
+       * Used to detect `data` property values to be HTML-escaped.
+       *
+       * @memberOf _.templateSettings
+       * @type RegExp
+       */
+      'escape': /<%-([\s\S]+?)%>/g,
+
+      /**
+       * Used to detect code to be evaluated.
+       *
+       * @memberOf _.templateSettings
+       * @type RegExp
+       */
+      'evaluate': /<%([\s\S]+?)%>/g,
+
+      /**
+       * Used to detect `data` property values to inject.
+       *
+       * @memberOf _.templateSettings
+       * @type RegExp
+       */
+      'interpolate': reInterpolate,
+
+      /**
+       * Used to reference the data object in the template text.
+       *
+       * @memberOf _.templateSettings
+       * @type string
+       */
+      'variable': '',
+
+      /**
+       * Used to import variables into the compiled template.
+       *
+       * @memberOf _.templateSettings
+       * @type Object
+       */
+      'imports': {
+
+        /**
+         * A reference to the `lodash` function.
+         *
+         * @memberOf _.templateSettings.imports
+         * @type Function
+         */
+        '_': lodash
+      }
+    };
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * The base implementation of `_.bind` that creates the bound function and
+     * sets its meta data.
+     *
+     * @private
+     * @param {Array} bindData The bind data array.
+     * @returns {Function} Returns the new bound function.
+     */
+    function baseBind(bindData) {
+      var func = bindData[0],
+          partialArgs = bindData[2],
+          thisArg = bindData[4];
+
+      function bound() {
+        // `Function#bind` spec
+        // http://es5.github.io/#x15.3.4.5
+        if (partialArgs) {
+          // avoid `arguments` object deoptimizations by using `slice` instead
+          // of `Array.prototype.slice.call` and not assigning `arguments` to a
+          // variable as a ternary expression
+          var args = slice(partialArgs);
+          push.apply(args, arguments);
+        }
+        // mimic the constructor's `return` behavior
+        // http://es5.github.io/#x13.2.2
+        if (this instanceof bound) {
+          // ensure `new bound` is an instance of `func`
+          var thisBinding = baseCreate(func.prototype),
+              result = func.apply(thisBinding, args || arguments);
+          return isObject(result) ? result : thisBinding;
+        }
+        return func.apply(thisArg, args || arguments);
+      }
+      setBindData(bound, bindData);
+      return bound;
+    }
+
+    /**
+     * The base implementation of `_.clone` without argument juggling or 
support
+     * for `thisArg` binding.
+     *
+     * @private
+     * @param {*} value The value to clone.
+     * @param {boolean} [isDeep=false] Specify a deep clone.
+     * @param {Function} [callback] The function to customize cloning values.
+     * @param {Array} [stackA=[]] Tracks traversed source objects.
+     * @param {Array} [stackB=[]] Associates clones with source counterparts.
+     * @returns {*} Returns the cloned value.
+     */
+    function baseClone(value, isDeep, callback, stackA, stackB) {
+      if (callback) {
+        var result = callback(value);
+        if (typeof result != 'undefined') {
+          return result;
+        }
+      }
+      // inspect [[Class]]
+      var isObj = isObject(value);
+      if (isObj) {
+        var className = toString.call(value);
+        if (!cloneableClasses[className]) {
+          return value;
+        }
+        var ctor = ctorByClass[className];
+        switch (className) {
+          case boolClass:
+          case dateClass:
+            return new ctor(+value);
+
+          case numberClass:
+          case stringClass:
+            return new ctor(value);
+
+          case regexpClass:
+            result = ctor(value.source, reFlags.exec(value));
+            result.lastIndex = value.lastIndex;
+            return result;
+        }
+      } else {
+        return value;
+      }
+      var isArr = isArray(value);
+      if (isDeep) {
+        // check for circular references and return corresponding clone
+        var initedStack = !stackA;
+        stackA || (stackA = getArray());
+        stackB || (stackB = getArray());
+
+        var length = stackA.length;
+        while (length--) {
+          if (stackA[length] == value) {
+            return stackB[length];
+          }
+        }
+        result = isArr ? ctor(value.length) : {};
+      }
+      else {
+        result = isArr ? slice(value) : assign({}, value);
+      }
+      // add array properties assigned by `RegExp#exec`
+      if (isArr) {
+        if (hasOwnProperty.call(value, 'index')) {
+          result.index = value.index;
+        }
+        if (hasOwnProperty.call(value, 'input')) {
+          result.input = value.input;
+        }
+      }
+      // exit for shallow clone
+      if (!isDeep) {
+        return result;
+      }
+      // add the source value to the stack of traversed objects
+      // and associate it with its clone
+      stackA.push(value);
+      stackB.push(result);
+
+      // recursively populate clone (susceptible to call stack limits)
+      (isArr ? forEach : forOwn)(value, function(objValue, key) {
+        result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
+      });
+
+      if (initedStack) {
+        releaseArray(stackA);
+        releaseArray(stackB);
+      }
+      return result;
+    }
+
+    /**
+     * The base implementation of `_.create` without support for assigning
+     * properties to the created object.
+     *
+     * @private
+     * @param {Object} prototype The object to inherit from.
+     * @returns {Object} Returns the new object.
+     */
+    function baseCreate(prototype, properties) {
+      return isObject(prototype) ? nativeCreate(prototype) : {};
+    }
+    // fallback for browsers without `Object.create`
+    if (!nativeCreate) {
+      baseCreate = (function() {
+        function Object() {}
+        return function(prototype) {
+          if (isObject(prototype)) {
+            Object.prototype = prototype;
+            var result = new Object;
+            Object.prototype = null;
+          }
+          return result || context.Object();
+        };
+      }());
+    }
+
+    /**
+     * The base implementation of `_.createCallback` without support for 
creating
+     * "_.pluck" or "_.where" style callbacks.
+     *
+     * @private
+     * @param {*} [func=identity] The value to convert to a callback.
+     * @param {*} [thisArg] The `this` binding of the created callback.
+     * @param {number} [argCount] The number of arguments the callback accepts.
+     * @returns {Function} Returns a callback function.
+     */
+    function baseCreateCallback(func, thisArg, argCount) {
+      if (typeof func != 'function') {
+        return identity;
+      }
+      // exit early for no `thisArg` or already bound by `Function#bind`
+      if (typeof thisArg == 'undefined' || !('prototype' in func)) {
+        return func;
+      }
+      var bindData = func.__bindData__;
+      if (typeof bindData == 'undefined') {
+        if (support.funcNames) {
+          bindData = !func.name;
+        }
+        bindData = bindData || !support.funcDecomp;
+        if (!bindData) {
+          var source = fnToString.call(func);
+          if (!support.funcNames) {
+            bindData = !reFuncName.test(source);
+          }
+          if (!bindData) {
+            // checks if `func` references the `this` keyword and stores the 
result
+            bindData = reThis.test(source);
+            setBindData(func, bindData);
+          }
+        }
+      }
+      // exit early if there are no `this` references or `func` is bound
+      if (bindData === false || (bindData !== true && bindData[1] & 1)) {
+        return func;
+      }
+      switch (argCount) {
+        case 1: return function(value) {
+          return func.call(thisArg, value);
+        };
+        case 2: return function(a, b) {
+          return func.call(thisArg, a, b);
+        };
+        case 3: return function(value, index, collection) {
+          return func.call(thisArg, value, index, collection);
+        };
+        case 4: return function(accumulator, value, index, collection) {
+          return func.call(thisArg, accumulator, value, index, collection);
+        };
+      }
+      return bind(func, thisArg);
+    }
+
+    /**
+     * The base implementation of `createWrapper` that creates the wrapper and
+     * sets its meta data.
+     *
+     * @private
+     * @param {Array} bindData The bind data array.
+     * @returns {Function} Returns the new function.
+     */
+    function baseCreateWrapper(bindData) {
+      var func = bindData[0],
+          bitmask = bindData[1],
+          partialArgs = bindData[2],
+          partialRightArgs = bindData[3],
+          thisArg = bindData[4],
+          arity = bindData[5];
+
+      var isBind = bitmask & 1,
+          isBindKey = bitmask & 2,
+          isCurry = bitmask & 4,
+          isCurryBound = bitmask & 8,
+          key = func;
+
+      function bound() {
+        var thisBinding = isBind ? thisArg : this;
+        if (partialArgs) {
+          var args = slice(partialArgs);
+          push.apply(args, arguments);
+        }
+        if (partialRightArgs || isCurry) {
+          args || (args = slice(arguments));
+          if (partialRightArgs) {
+            push.apply(args, partialRightArgs);
+          }
+          if (isCurry && args.length < arity) {
+            bitmask |= 16 & ~32;
+            return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask 
& ~3), args, null, thisArg, arity]);
+          }
+        }
+        args || (args = arguments);
+        if (isBindKey) {
+          func = thisBinding[key];
+        }
+        if (this instanceof bound) {
+          thisBinding = baseCreate(func.prototype);
+          var result = func.apply(thisBinding, args);
+          return isObject(result) ? result : thisBinding;
+        }
+        return func.apply(thisBinding, args);
+      }
+      setBindData(bound, bindData);
+      return bound;
+    }
+
+    /**
+     * The base implementation of `_.difference` that accepts a single array
+     * of values to exclude.
+     *
+     * @private
+     * @param {Array} array The array to process.
+     * @param {Array} [values] The array of values to exclude.
+     * @returns {Array} Returns a new array of filtered values.
+     */
+    function baseDifference(array, values) {
+      var index = -1,
+          indexOf = getIndexOf(),
+          length = array ? array.length : 0,
+          isLarge = length >= largeArraySize && indexOf === baseIndexOf,
+          result = [];
+
+      if (isLarge) {
+        var cache = createCache(values);
+        if (cache) {
+          indexOf = cacheIndexOf;
+          values = cache;
+        } else {
+          isLarge = false;
+        }
+      }
+      while (++index < length) {
+        var value = array[index];
+        if (indexOf(values, value) < 0) {
+          result.push(value);
+        }
+      }
+      if (isLarge) {
+        releaseObject(values);
+      }
+      return result;
+    }
+
+    /**
+     * The base implementation of `_.flatten` without support for callback
+     * shorthands or `thisArg` binding.
+     *
+     * @private
+     * @param {Array} array The array to flatten.
+     * @param {boolean} [isShallow=false] A flag to restrict flattening to a 
single level.
+     * @param {boolean} [isStrict=false] A flag to restrict flattening to 
arrays and `arguments` objects.
+     * @param {number} [fromIndex=0] The index to start from.
+     * @returns {Array} Returns a new flattened array.
+     */
+    function baseFlatten(array, isShallow, isStrict, fromIndex) {
+      var index = (fromIndex || 0) - 1,
+          length = array ? array.length : 0,
+          result = [];
+
+      while (++index < length) {
+        var value = array[index];
+
+        if (value && typeof value == 'object' && typeof value.length == 
'number'
+            && (isArray(value) || isArguments(value))) {
+          // recursively flatten arrays (susceptible to call stack limits)
+          if (!isShallow) {
+            value = baseFlatten(value, isShallow, isStrict);
+          }
+          var valIndex = -1,
+              valLength = value.length,
+              resIndex = result.length;
+
+          result.length += valLength;
+          while (++valIndex < valLength) {
+            result[resIndex++] = value[valIndex];
+          }
+        } else if (!isStrict) {
+          result.push(value);
+        }
+      }
+      return result;
+    }
+
+    /**
+     * The base implementation of `_.isEqual`, without support for `thisArg` 
binding,
+     * that allows partial "_.where" style comparisons.
+     *
+     * @private
+     * @param {*} a The value to compare.
+     * @param {*} b The other value to compare.
+     * @param {Function} [callback] The function to customize comparing values.
+     * @param {Function} [isWhere=false] A flag to indicate performing partial 
comparisons.
+     * @param {Array} [stackA=[]] Tracks traversed `a` objects.
+     * @param {Array} [stackB=[]] Tracks traversed `b` objects.
+     * @returns {boolean} Returns `true` if the values are equivalent, else 
`false`.
+     */
+    function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
+      // used to indicate that when comparing objects, `a` has at least the 
properties of `b`
+      if (callback) {
+        var result = callback(a, b);
+        if (typeof result != 'undefined') {
+          return !!result;
+        }
+      }
+      // exit early for identical values
+      if (a === b) {
+        // treat `+0` vs. `-0` as not equal
+        return a !== 0 || (1 / a == 1 / b);
+      }
+      var type = typeof a,
+          otherType = typeof b;
+
+      // exit early for unlike primitive values
+      if (a === a &&
+          !(a && objectTypes[type]) &&
+          !(b && objectTypes[otherType])) {
+        return false;
+      }
+      // exit early for `null` and `undefined` avoiding ES3's Function#call 
behavior
+      // http://es5.github.io/#x15.3.4.4
+      if (a == null || b == null) {
+        return a === b;
+      }
+      // compare [[Class]] names
+      var className = toString.call(a),
+          otherClass = toString.call(b);
+
+      if (className == argsClass) {
+        className = objectClass;
+      }
+      if (otherClass == argsClass) {
+        otherClass = objectClass;
+      }
+      if (className != otherClass) {
+        return false;
+      }
+      switch (className) {
+        case boolClass:
+        case dateClass:
+          // coerce dates and booleans to numbers, dates to milliseconds and 
booleans
+          // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
+          return +a == +b;
+
+        case numberClass:
+          // treat `NaN` vs. `NaN` as equal
+          return (a != +a)
+            ? b != +b
+            // but treat `+0` vs. `-0` as not equal
+            : (a == 0 ? (1 / a == 1 / b) : a == +b);
+
+        case regexpClass:
+        case stringClass:
+          // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
+          // treat string primitives and their corresponding object instances 
as equal
+          return a == String(b);
+      }
+      var isArr = className == arrayClass;
+      if (!isArr) {
+        // unwrap any `lodash` wrapped values
+        var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
+            bWrapped = hasOwnProperty.call(b, '__wrapped__');
+
+        if (aWrapped || bWrapped) {
+          return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? 
b.__wrapped__ : b, callback, isWhere, stackA, stackB);
+        }
+        // exit for functions and DOM nodes
+        if (className != objectClass) {
+          return false;
+        }
+        // in older versions of Opera, `arguments` objects have `Array` 
constructors
+        var ctorA = a.constructor,
+            ctorB = b.constructor;
+
+        // non `Object` object instances with different constructors are not 
equal
+        if (ctorA != ctorB &&
+              !(isFunction(ctorA) && ctorA instanceof ctorA && 
isFunction(ctorB) && ctorB instanceof ctorB) &&
+              ('constructor' in a && 'constructor' in b)
+            ) {
+          return false;
+        }
+      }
+      // assume cyclic structures are equal
+      // the algorithm for detecting cyclic structures is adapted from ES 5.1
+      // section 15.12.3, abstract operation `JO` 
(http://es5.github.io/#x15.12.3)
+      var initedStack = !stackA;
+      stackA || (stackA = getArray());
+      stackB || (stackB = getArray());
+
+      var length = stackA.length;
+      while (length--) {
+        if (stackA[length] == a) {
+          return stackB[length] == b;
+        }
+      }
+      var size = 0;
+      result = true;
+
+      // add `a` and `b` to the stack of traversed objects
+      stackA.push(a);
+      stackB.push(b);
+
+      // recursively compare objects and arrays (susceptible to call stack 
limits)
+      if (isArr) {
+        // compare lengths to determine if a deep comparison is necessary
+        length = a.length;
+        size = b.length;
+        result = size == length;
+
+        if (result || isWhere) {
+          // deep compare the contents, ignoring non-numeric properties
+          while (size--) {
+            var index = length,
+                value = b[size];
+
+            if (isWhere) {
+              while (index--) {
+                if ((result = baseIsEqual(a[index], value, callback, isWhere, 
stackA, stackB))) {
+                  break;
+                }
+              }
+            } else if (!(result = baseIsEqual(a[size], value, callback, 
isWhere, stackA, stackB))) {
+              break;
+            }
+          }
+        }
+      }
+      else {
+        // deep compare objects using `forIn`, instead of `forOwn`, to avoid 
`Object.keys`
+        // which, in this case, is more costly
+        forIn(b, function(value, key, b) {
+          if (hasOwnProperty.call(b, key)) {
+            // count the number of properties.
+            size++;
+            // deep compare each property value.
+            return (result = hasOwnProperty.call(a, key) && 
baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
+          }
+        });
+
+        if (result && !isWhere) {
+          // ensure both objects have the same number of properties
+          forIn(a, function(value, key, a) {
+            if (hasOwnProperty.call(a, key)) {
+              // `size` will be `-1` if `a` has more properties than `b`
+              return (result = --size > -1);
+            }
+          });
+        }
+      }
+      stackA.pop();
+      stackB.pop();
+
+      if (initedStack) {
+        releaseArray(stackA);
+        releaseArray(stackB);
+      }
+      return result;
+    }
+
+    /**
+     * The base implementation of `_.merge` without argument juggling or 
support
+     * for `thisArg` binding.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @param {Function} [callback] The function to customize merging 
properties.
+     * @param {Array} [stackA=[]] Tracks traversed source objects.
+     * @param {Array} [stackB=[]] Associates values with source counterparts.
+     */
+    function baseMerge(object, source, callback, stackA, stackB) {
+      (isArray(source) ? forEach : forOwn)(source, function(source, key) {
+        var found,
+            isArr,
+            result = source,
+            value = object[key];
+
+        if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
+          // avoid merging previously merged cyclic sources
+          var stackLength = stackA.length;
+          while (stackLength--) {
+            if ((found = stackA[stackLength] == source)) {
+              value = stackB[stackLength];
+              break;
+            }
+          }
+          if (!found) {
+            var isShallow;
+            if (callback) {
+              result = callback(value, source);
+              if ((isShallow = typeof result != 'undefined')) {
+                value = result;
+              }
+            }
+            if (!isShallow) {
+              value = isArr
+                ? (isArray(value) ? value : [])
+                : (isPlainObject(value) ? value : {});
+            }
+            // add `source` and associated `value` to the stack of traversed 
objects
+            stackA.push(source);
+            stackB.push(value);
+
+            // recursively merge objects and arrays (susceptible to call stack 
limits)
+            if (!isShallow) {
+              baseMerge(value, source, callback, stackA, stackB);
+            }
+          }
+        }
+        else {
+          if (callback) {
+            result = callback(value, source);
+            if (typeof result == 'undefined') {
+              result = source;
+            }
+          }
+          if (typeof result != 'undefined') {
+            value = result;
+          }
+        }
+        object[key] = value;
+      });
+    }
+
+    /**
+     * The base implementation of `_.random` without argument juggling or 
support
+     * for returning floating-point numbers.
+     *
+     * @private
+     * @param {number} min The minimum possible value.
+     * @param {number} max The maximum possible value.
+     * @returns {number} Returns a random number.
+     */
+    function baseRandom(min, max) {
+      return min + floor(nativeRandom() * (max - min + 1));
+    }
+
+    /**
+     * The base implementation of `_.uniq` without support for callback 
shorthands
+     * or `thisArg` binding.
+     *
+     * @private
+     * @param {Array} array The array to process.
+     * @param {boolean} [isSorted=false] A flag to indicate that `array` is 
sorted.
+     * @param {Function} [callback] The function called per iteration.
+     * @returns {Array} Returns a duplicate-value-free array.
+     */
+    function baseUniq(array, isSorted, callback) {
+      var index = -1,
+          indexOf = getIndexOf(),
+          length = array ? array.length : 0,
+          result = [];
+
+      var isLarge = !isSorted && length >= largeArraySize && indexOf === 
baseIndexOf,
+          seen = (callback || isLarge) ? getArray() : result;
+
+      if (isLarge) {
+        var cache = createCache(seen);
+        indexOf = cacheIndexOf;
+        seen = cache;
+      }
+      while (++index < length) {
+        var value = array[index],
+            computed = callback ? callback(value, index, array) : value;
+
+        if (isSorted
+              ? !index || seen[seen.length - 1] !== computed
+              : indexOf(seen, computed) < 0
+            ) {
+          if (callback || isLarge) {
+            seen.push(computed);
+          }
+          result.push(value);
+        }
+      }
+      if (isLarge) {
+        releaseArray(seen.array);
+        releaseObject(seen);
+      } else if (callback) {
+        releaseArray(seen);
+      }
+      return result;
+    }
+
+    /**
+     * Creates a function that aggregates a collection, creating an object 
composed
+     * of keys generated from the results of running each element of the 
collection
+     * through a callback. The given `setter` function sets the keys and values
+     * of the composed object.
+     *
+     * @private
+     * @param {Function} setter The setter function.
+     * @returns {Function} Returns the new aggregator function.
+     */
+    function createAggregator(setter) {
+      return function(collection, callback, thisArg) {
+        var result = {};
+        callback = lodash.createCallback(callback, thisArg, 3);
+
+        var index = -1,
+            length = collection ? collection.length : 0;
+
+        if (typeof length == 'number') {
+          while (++index < length) {
+            var value = collection[index];
+            setter(result, value, callback(value, index, collection), 
collection);
+          }
+        } else {
+          forOwn(collection, function(value, key, collection) {
+            setter(result, value, callback(value, key, collection), 
collection);
+          });
+        }
+        return result;
+      };
+    }
+
+    /**
+     * Creates a function that, when called, either curries or invokes `func`
+     * with an optional `this` binding and partially applied arguments.
+     *
+     * @private
+     * @param {Function|string} func The function or method name to reference.
+     * @param {number} bitmask The bitmask of method flags to compose.
+     *  The bitmask may be composed of the following flags:
+     *  1 - `_.bind`
+     *  2 - `_.bindKey`
+     *  4 - `_.curry`
+     *  8 - `_.curry` (bound)
+     *  16 - `_.partial`
+     *  32 - `_.partialRight`
+     * @param {Array} [partialArgs] An array of arguments to prepend to those
+     *  provided to the new function.
+     * @param {Array} [partialRightArgs] An array of arguments to append to 
those
+     *  provided to the new function.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @param {number} [arity] The arity of `func`.
+     * @returns {Function} Returns the new function.
+     */
+    function createWrapper(func, bitmask, partialArgs, partialRightArgs, 
thisArg, arity) {
+      var isBind = bitmask & 1,
+          isBindKey = bitmask & 2,
+          isCurry = bitmask & 4,
+          isCurryBound = bitmask & 8,
+          isPartial = bitmask & 16,
+          isPartialRight = bitmask & 32;
+
+      if (!isBindKey && !isFunction(func)) {
+        throw new TypeError;
+      }
+      if (isPartial && !partialArgs.length) {
+        bitmask &= ~16;
+        isPartial = partialArgs = false;
+      }
+      if (isPartialRight && !partialRightArgs.length) {
+        bitmask &= ~32;
+        isPartialRight = partialRightArgs = false;
+      }
+      var bindData = func && func.__bindData__;
+      if (bindData && bindData !== true) {
+        // clone `bindData`
+        bindData = slice(bindData);
+        if (bindData[2]) {
+          bindData[2] = slice(bindData[2]);
+        }
+        if (bindData[3]) {
+          bindData[3] = slice(bindData[3]);
+        }
+        // set `thisBinding` is not previously bound
+        if (isBind && !(bindData[1] & 1)) {
+          bindData[4] = thisArg;
+        }
+        // set if previously bound but not currently (subsequent curried 
functions)
+        if (!isBind && bindData[1] & 1) {
+          bitmask |= 8;
+        }
+        // set curried arity if not yet set
+        if (isCurry && !(bindData[1] & 4)) {
+          bindData[5] = arity;
+        }
+        // append partial left arguments
+        if (isPartial) {
+          push.apply(bindData[2] || (bindData[2] = []), partialArgs);
+        }
+        // append partial right arguments
+        if (isPartialRight) {
+          unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
+        }
+        // merge flags
+        bindData[1] |= bitmask;
+        return createWrapper.apply(null, bindData);
+      }
+      // fast path for `_.bind`
+      var creater = (bitmask == 1 || bitmask === 17) ? baseBind : 
baseCreateWrapper;
+      return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, 
arity]);
+    }
+
+    /**
+     * Used by `escape` to convert characters to HTML entities.
+     *
+     * @private
+     * @param {string} match The matched character to escape.
+     * @returns {string} Returns the escaped character.
+     */
+    function escapeHtmlChar(match) {
+      return htmlEscapes[match];
+    }
+
+    /**
+     * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+     * customized, this method returns the custom method, otherwise it returns
+     * the `baseIndexOf` function.
+     *
+     * @private
+     * @returns {Function} Returns the "indexOf" function.
+     */
+    function getIndexOf() {
+      var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : 
result;
+      return result;
+    }
+
+    /**
+     * Checks if `value` is a native function.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a native function, 
else `false`.
+     */
+    function isNative(value) {
+      return typeof value == 'function' && reNative.test(value);
+    }
+
+    /**
+     * Sets `this` binding data on a given function.
+     *
+     * @private
+     * @param {Function} func The function to set data on.
+     * @param {Array} value The data array to set.
+     */
+    var setBindData = !defineProperty ? noop : function(func, value) {
+      descriptor.value = value;
+      defineProperty(func, '__bindData__', descriptor);
+    };
+
+    /**
+     * A fallback implementation of `isPlainObject` which checks if a given 
value
+     * is an object created by the `Object` constructor, assuming objects 
created
+     * by the `Object` constructor have no inherited enumerable properties and 
that
+     * there are no `Object.prototype` extensions.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a plain object, else 
`false`.
+     */
+    function shimIsPlainObject(value) {
+      var ctor,
+          result;
+
+      // avoid non Object objects, `arguments` objects, and DOM elements
+      if (!(value && toString.call(value) == objectClass) ||
+          (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof 
ctor))) {
+        return false;
+      }
+      // In most environments an object's own properties are iterated before
+      // its inherited properties. If the last iterated property is an object's
+      // own property then there are no inherited enumerable properties.
+      forIn(value, function(value, key) {
+        result = key;
+      });
+      return typeof result == 'undefined' || hasOwnProperty.call(value, 
result);
+    }
+
+    /**
+     * Used by `unescape` to convert HTML entities to characters.
+     *
+     * @private
+     * @param {string} match The matched character to unescape.
+     * @returns {string} Returns the unescaped character.
+     */
+    function unescapeHtmlChar(match) {
+      return htmlUnescapes[match];
+    }
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Checks if `value` is an `arguments` object.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is an `arguments` 
object, else `false`.
+     * @example
+     *
+     * (function() { return _.isArguments(arguments); })(1, 2, 3);
+     * // => true
+     *
+     * _.isArguments([1, 2, 3]);
+     * // => false
+     */
+    function isArguments(value) {
+      return value && typeof value == 'object' && typeof value.length == 
'number' &&
+        toString.call(value) == argsClass || false;
+    }
+
+    /**
+     * Checks if `value` is an array.
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is an array, else 
`false`.
+     * @example
+     *
+     * (function() { return _.isArray(arguments); })();
+     * // => false
+     *
+     * _.isArray([1, 2, 3]);
+     * // => true
+     */
+    var isArray = nativeIsArray || function(value) {
+      return value && typeof value == 'object' && typeof value.length == 
'number' &&
+        toString.call(value) == arrayClass || false;
+    };
+
+    /**
+     * A fallback implementation of `Object.keys` which produces an array of 
the
+     * given object's own enumerable property names.
+     *
+     * @private
+     * @type Function
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns an array of property names.
+     */
+    var shimKeys = function(object) {
+      var index, iterable = object, result = [];
+      if (!iterable) return result;
+      if (!(objectTypes[typeof object])) return result;
+        for (index in iterable) {
+          if (hasOwnProperty.call(iterable, index)) {
+            result.push(index);
+          }
+        }
+      return result
+    };
+
+    /**
+     * Creates an array composed of the own enumerable property names of an 
object.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns an array of property names.
+     * @example
+     *
+     * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
+     * // => ['one', 'two', 'three'] (property order is not guaranteed across 
environments)
+     */
+    var keys = !nativeKeys ? shimKeys : function(object) {
+      if (!isObject(object)) {
+        return [];
+      }
+      return nativeKeys(object);
+    };
+
+    /**
+     * Used to convert characters to HTML entities:
+     *
+     * Though the `>` character is escaped for symmetry, characters like `>` 
and `/`
+     * don't require escaping in HTML and have no special meaning unless 
they're part
+     * of a tag or an unquoted attribute value.
+     * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related 
fun fact")
+     */
+    var htmlEscapes = {
+      '&': '&amp;',
+      '<': '&lt;',
+      '>': '&gt;',
+      '"': '&quot;',
+      "'": '&#39;'
+    };
+
+    /** Used to convert HTML entities to characters */
+    var htmlUnescapes = invert(htmlEscapes);
+
+    /** Used to match HTML entities and HTML characters */
+    var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
+        reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Assigns own enumerable properties of source object(s) to the destination
+     * object. Subsequent sources will overwrite property assignments of 
previous
+     * sources. If a callback is provided it will be executed to produce the
+     * assigned values. The callback is bound to `thisArg` and invoked with two
+     * arguments; (objectValue, sourceValue).
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @alias extend
+     * @category Objects
+     * @param {Object} object The destination object.
+     * @param {...Object} [source] The source objects.
+     * @param {Function} [callback] The function to customize assigning values.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns the destination object.
+     * @example
+     *
+     * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
+     * // => { 'name': 'fred', 'employer': 'slate' }
+     *
+     * var defaults = _.partialRight(_.assign, function(a, b) {
+     *   return typeof a == 'undefined' ? b : a;
+     * });
+     *
+     * var object = { 'name': 'barney' };
+     * defaults(object, { 'name': 'fred', 'employer': 'slate' });
+     * // => { 'name': 'barney', 'employer': 'slate' }
+     */
+    var assign = function(object, source, guard) {
+      var index, iterable = object, result = iterable;
+      if (!iterable) return result;
+      var args = arguments,
+          argsIndex = 0,
+          argsLength = typeof guard == 'number' ? 2 : args.length;
+      if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
+        var callback = baseCreateCallback(args[--argsLength - 1], 
args[argsLength--], 2);
+      } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
+        callback = args[--argsLength];
+      }
+      while (++argsIndex < argsLength) {
+        iterable = args[argsIndex];
+        if (iterable && objectTypes[typeof iterable]) {
+        var ownIndex = -1,
+            ownProps = objectTypes[typeof iterable] && keys(iterable),
+            length = ownProps ? ownProps.length : 0;
+
+        while (++ownIndex < length) {
+          index = ownProps[ownIndex];
+          result[index] = callback ? callback(result[index], iterable[index]) 
: iterable[index];
+        }
+        }
+      }
+      return result
+    };
+
+    /**
+     * Creates a clone of `value`. If `isDeep` is `true` nested objects will 
also
+     * be cloned, otherwise they will be assigned by reference. If a callback
+     * is provided it will be executed to produce the cloned values. If the
+     * callback returns `undefined` cloning will be handled by the method 
instead.
+     * The callback is bound to `thisArg` and invoked with one argument; 
(value).
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to clone.
+     * @param {boolean} [isDeep=false] Specify a deep clone.
+     * @param {Function} [callback] The function to customize cloning values.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the cloned value.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * var shallow = _.clone(characters);
+     * shallow[0] === characters[0];
+     * // => true
+     *
+     * var deep = _.clone(characters, true);
+     * deep[0] === characters[0];
+     * // => false
+     *
+     * _.mixin({
+     *   'clone': _.partialRight(_.clone, function(value) {
+     *     return _.isElement(value) ? value.cloneNode(false) : undefined;
+     *   })
+     * });
+     *
+     * var clone = _.clone(document.body);
+     * clone.childNodes.length;
+     * // => 0
+     */
+    function clone(value, isDeep, callback, thisArg) {
+      // allows working with "Collections" methods without using their `index`
+      // and `collection` arguments for `isDeep` and `callback`
+      if (typeof isDeep != 'boolean' && isDeep != null) {
+        thisArg = callback;
+        callback = isDeep;
+        isDeep = false;
+      }
+      return baseClone(value, isDeep, typeof callback == 'function' && 
baseCreateCallback(callback, thisArg, 1));
+    }
+
+    /**
+     * Creates a deep clone of `value`. If a callback is provided it will be
+     * executed to produce the cloned values. If the callback returns 
`undefined`
+     * cloning will be handled by the method instead. The callback is bound to
+     * `thisArg` and invoked with one argument; (value).
+     *
+     * Note: This method is loosely based on the structured clone algorithm. 
Functions
+     * and DOM nodes are **not** cloned. The enumerable properties of 
`arguments` objects and
+     * objects created by constructors other than `Object` are cloned to plain 
`Object` objects.
+     * See 
http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to deep clone.
+     * @param {Function} [callback] The function to customize cloning values.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the deep cloned value.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * var deep = _.cloneDeep(characters);
+     * deep[0] === characters[0];
+     * // => false
+     *
+     * var view = {
+     *   'label': 'docs',
+     *   'node': element
+     * };
+     *
+     * var clone = _.cloneDeep(view, function(value) {
+     *   return _.isElement(value) ? value.cloneNode(true) : undefined;
+     * });
+     *
+     * clone.node == view.node;
+     * // => false
+     */
+    function cloneDeep(value, callback, thisArg) {
+      return baseClone(value, true, typeof callback == 'function' && 
baseCreateCallback(callback, thisArg, 1));
+    }
+
+    /**
+     * Creates an object that inherits from the given `prototype` object. If a
+     * `properties` object is provided its own enumerable properties are 
assigned
+     * to the created object.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} prototype The object to inherit from.
+     * @param {Object} [properties] The properties to assign to the object.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * function Shape() {
+     *   this.x = 0;
+     *   this.y = 0;
+     * }
+     *
+     * function Circle() {
+     *   Shape.call(this);
+     * }
+     *
+     * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
+     *
+     * var circle = new Circle;
+     * circle instanceof Circle;
+     * // => true
+     *
+     * circle instanceof Shape;
+     * // => true
+     */
+    function create(prototype, properties) {
+      var result = baseCreate(prototype);
+      return properties ? assign(result, properties) : result;
+    }
+
+    /**
+     * Assigns own enumerable properties of source object(s) to the destination
+     * object for all destination properties that resolve to `undefined`. Once 
a
+     * property is set, additional defaults of the same property will be 
ignored.
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @category Objects
+     * @param {Object} object The destination object.
+     * @param {...Object} [source] The source objects.
+     * @param- {Object} [guard] Allows working with `_.reduce` without using 
its
+     *  `key` and `object` arguments as sources.
+     * @returns {Object} Returns the destination object.
+     * @example
+     *
+     * var object = { 'name': 'barney' };
+     * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
+     * // => { 'name': 'barney', 'employer': 'slate' }
+     */
+    var defaults = function(object, source, guard) {
+      var index, iterable = object, result = iterable;
+      if (!iterable) return result;
+      var args = arguments,
+          argsIndex = 0,
+          argsLength = typeof guard == 'number' ? 2 : args.length;
+      while (++argsIndex < argsLength) {
+        iterable = args[argsIndex];
+        if (iterable && objectTypes[typeof iterable]) {
+        var ownIndex = -1,
+            ownProps = objectTypes[typeof iterable] && keys(iterable),
+            length = ownProps ? ownProps.length : 0;
+
+        while (++ownIndex < length) {
+          index = ownProps[ownIndex];
+          if (typeof result[index] == 'undefined') result[index] = 
iterable[index];
+        }
+        }
+      }
+      return result
+    };
+
+    /**
+     * This method is like `_.findIndex` except that it returns the key of the
+     * first element that passes the callback check, instead of the element 
itself.
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to search.
+     * @param {Function|Object|string} [callback=identity] The function called 
per
+     *  iteration. If a property name or object is provided it will be used to
+     *  create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {string|undefined} Returns the key of the found element, else 
`undefined`.
+     * @example
+     *
+     * var characters = {
+     *   'barney': {  'age': 36, 'blocked': false },
+     *   'fred': {    'age': 40, 'blocked': true },
+     *   'pebbles': { 'age': 1,  'blocked': false }
+     * };
+     *
+     * _.findKey(characters, function(chr) {
+     *   return chr.age < 40;
+     * });
+     * // => 'barney' (property order is not guaranteed across environments)
+     *
+     * // using "_.where" callback shorthand
+     * _.findKey(characters, { 'age': 1 });
+     * // => 'pebbles'
+     *
+     * // using "_.pluck" callback shorthand
+     * _.findKey(characters, 'blocked');
+     * // => 'fred'
+     */
+    function findKey(object, callback, thisArg) {
+      var result;
+      callback = lodash.createCallback(callback, thisArg, 3);
+      forOwn(object, function(value, key, object) {
+        if (callback(value, key, object)) {
+          result = key;
+          return false;
+        }
+      });
+      return result;
+    }
+
+    /**
+     * This method is like `_.findKey` except that it iterates over elements
+     * of a `collection` in the opposite order.
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to search.
+     * @param {Function|Object|string} [callback=identity] The function called 
per
+     *  iteration. If a property name or object is provided it will be used to
+     *  create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {string|undefined} Returns the key of the found element, else 
`undefined`.
+     * @example
+     *
+     * var characters = {
+     *   'barney': {  'age': 36, 'blocked': true },
+     *   'fred': {    'age': 40, 'blocked': false },
+     *   'pebbles': { 'age': 1,  'blocked': true }
+     * };
+     *
+     * _.findLastKey(characters, function(chr) {
+     *   return chr.age < 40;
+     * });
+     * // => returns `pebbles`, assuming `_.findKey` returns `barney`
+     *
+     * // using "_.where" callback shorthand
+     * _.findLastKey(characters, { 'age': 40 });
+     * // => 'fred'
+     *
+     * // using "_.pluck" callback shorthand
+     * _.findLastKey(characters, 'blocked');
+     * // => 'pebbles'
+     */
+    function findLastKey(object, callback, thisArg) {
+      var result;
+      callback = lodash.createCallback(callback, thisArg, 3);
+      forOwnRight(object, function(value, key, object) {
+        if (callback(value, key, object)) {
+          result = key;
+          return false;
+        }
+      });
+      return result;
+    }
+
+    /**
+     * Iterates over own and inherited enumerable properties of an object,
+     * executing the callback for each property. The callback is bound to 
`thisArg`
+     * and invoked with three arguments; (value, key, object). Callbacks may 
exit
+     * iteration early by explicitly returning `false`.
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @category Objects
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * function Shape() {
+     *   this.x = 0;
+     *   this.y = 0;
+     * }
+     *
+     * Shape.prototype.move = function(x, y) {
+     *   this.x += x;
+     *   this.y += y;
+     * };
+     *
+     * _.forIn(new Shape, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => logs 'x', 'y', and 'move' (property order is not guaranteed 
across environments)
+     */
+    var forIn = function(collection, callback, thisArg) {
+      var index, iterable = collection, result = iterable;
+      if (!iterable) return result;
+      if (!objectTypes[typeof iterable]) return result;
+      callback = callback && typeof thisArg == 'undefined' ? callback : 
baseCreateCallback(callback, thisArg, 3);
+        for (index in iterable) {
+          if (callback(iterable[index], index, collection) === false) return 
result;
+        }
+      return result
+    };
+
+    /**
+     * This method is like `_.forIn` except that it iterates over elements
+     * of a `collection` in the opposite order.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * function Shape() {
+     *   this.x = 0;
+     *   this.y = 0;
+     * }
+     *
+     * Shape.prototype.move = function(x, y) {
+     *   this.x += x;
+     *   this.y += y;
+     * };
+     *
+     * _.forInRight(new Shape, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 
'move'
+     */
+    function forInRight(object, callback, thisArg) {
+      var pairs = [];
+
+      forIn(object, function(value, key) {
+        pairs.push(key, value);
+      });
+
+      var length = pairs.length;
+      callback = baseCreateCallback(callback, thisArg, 3);
+      while (length--) {
+        if (callback(pairs[length--], pairs[length], object) === false) {
+          break;
+        }
+      }
+      return object;
+    }
+
+    /**
+     * Iterates over own enumerable properties of an object, executing the 
callback
+     * for each property. The callback is bound to `thisArg` and invoked with 
three
+     * arguments; (value, key, object). Callbacks may exit iteration early by
+     * explicitly returning `false`.
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @category Objects
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+     *   console.log(key);
+     * });
+     * // => logs '0', '1', and 'length' (property order is not guaranteed 
across environments)
+     */
+    var forOwn = function(collection, callback, thisArg) {
+      var index, iterable = collection, result = iterable;
+      if (!iterable) return result;
+      if (!objectTypes[typeof iterable]) return result;
+      callback = callback && typeof thisArg == 'undefined' ? callback : 
baseCreateCallback(callback, thisArg, 3);
+        var ownIndex = -1,
+            ownProps = objectTypes[typeof iterable] && keys(iterable),
+            length = ownProps ? ownProps.length : 0;
+
+        while (++ownIndex < length) {
+          index = ownProps[ownIndex];
+          if (callback(iterable[index], index, collection) === false) return 
result;
+        }
+      return result
+    };
+
+    /**
+     * This method is like `_.forOwn` except that it iterates over elements
+     * of a `collection` in the opposite order.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, 
key) {
+     *   console.log(key);
+     * });
+     * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', 
and 'length'
+     */
+    function forOwnRight(object, callback, thisArg) {
+      var props = keys(object),
+          length = props.length;
+
+      callback = baseCreateCallback(callback, thisArg, 3);
+      while (length--) {
+        var key = props[length];
+        if (callback(object[key], key, object) === false) {
+          break;
+        }
+      }
+      return object;
+    }
+
+    /**
+     * Creates a sorted array of property names of all enumerable properties,
+     * own and inherited, of `object` that have function values.
+     *
+     * @static
+     * @memberOf _
+     * @alias methods
+     * @category Objects
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns an array of property names that have function 
values.
+     * @example
+     *
+     * _.functions(_);
+     * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', 
...]
+     */
+    function functions(object) {
+      var result = [];
+      forIn(object, function(value, key) {
+        if (isFunction(value)) {
+          result.push(key);
+        }
+      });
+      return result.sort();
+    }
+
+    /**
+     * Checks if the specified property name exists as a direct property of 
`object`,
+     * instead of an inherited property.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to inspect.
+     * @param {string} key The name of the property to check.
+     * @returns {boolean} Returns `true` if key is a direct property, else 
`false`.
+     * @example
+     *
+     * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+     * // => true
+     */
+    function has(object, key) {
+      return object ? hasOwnProperty.call(object, key) : false;
+    }
+
+    /**
+     * Creates an object composed of the inverted keys and values of the given 
object.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to invert.
+     * @returns {Object} Returns the created inverted object.
+     * @example
+     *
+     * _.invert({ 'first': 'fred', 'second': 'barney' });
+     * // => { 'fred': 'first', 'barney': 'second' }
+     */
+    function invert(object) {
+      var index = -1,
+          props = keys(object),
+          length = props.length,
+          result = {};
+
+      while (++index < length) {
+        var key = props[index];
+        result[object[key]] = key;
+      }
+      return result;
+    }
+
+    /**
+     * Checks if `value` is a boolean value.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a boolean value, 
else `false`.
+     * @example
+     *
+     * _.isBoolean(null);
+     * // => false
+     */
+    function isBoolean(value) {
+      return value === true || value === false ||
+        value && typeof value == 'object' && toString.call(value) == boolClass 
|| false;
+    }
+
+    /**
+     * Checks if `value` is a date.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a date, else 
`false`.
+     * @example
+     *
+     * _.isDate(new Date);
+     * // => true
+     */
+    function isDate(value) {
+      return value && typeof value == 'object' && toString.call(value) == 
dateClass || false;
+    }
+
+    /**
+     * Checks if `value` is a DOM element.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a DOM element, else 
`false`.
+     * @example
+     *
+     * _.isElement(document.body);
+     * // => true
+     */
+    function isElement(value) {
+      return value && value.nodeType === 1 || false;
+    }
+
+    /**
+     * Checks if `value` is empty. Arrays, strings, or `arguments` objects 
with a
+     * length of `0` and objects with no own enumerable properties are 
considered
+     * "empty".
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Array|Object|string} value The value to inspect.
+     * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
+     * @example
+     *
+     * _.isEmpty([1, 2, 3]);
+     * // => false
+     *
+     * _.isEmpty({});
+     * // => true
+     *
+     * _.isEmpty('');
+     * // => true
+     */
+    function isEmpty(value) {
+      var result = true;
+      if (!value) {
+        return result;
+      }
+      var className = toString.call(value),
+          length = value.length;
+
+      if ((className == arrayClass || className == stringClass || className == 
argsClass ) ||
+          (className == objectClass && typeof length == 'number' && 
isFunction(value.splice))) {
+        return !length;
+      }
+      forOwn(value, function() {
+        return (result = false);
+      });
+      return result;
+    }
+
+    /**
+     * Performs a deep comparison between two values to determine if they are
+     * equivalent to each other. If a callback is provided it will be executed
+     * to compare values. If the callback returns `undefined` comparisons will
+     * be handled by the method instead. The callback is bound to `thisArg` and
+     * invoked with two arguments; (a, b).
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} a The value to compare.
+     * @param {*} b The other value to compare.
+     * @param {Function} [callback] The function to customize comparing values.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {boolean} Returns `true` if the values are equivalent, else 
`false`.
+     * @example
+     *
+     * var object = { 'name': 'fred' };
+     * var copy = { 'name': 'fred' };
+     *
+     * object == copy;
+     * // => false
+     *
+     * _.isEqual(object, copy);
+     * // => true
+     *
+     * var words = ['hello', 'goodbye'];
+     * var otherWords = ['hi', 'goodbye'];
+     *
+     * _.isEqual(words, otherWords, function(a, b) {
+     *   var reGreet = /^(?:hello|hi)$/i,
+     *       aGreet = _.isString(a) && reGreet.test(a),
+     *       bGreet = _.isString(b) && reGreet.test(b);
+     *
+     *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
+     * });
+     * // => true
+     */
+    function isEqual(a, b, callback, thisArg) {
+      return baseIsEqual(a, b, typeof callback == 'function' && 
baseCreateCallback(callback, thisArg, 2));
+    }
+
+    /**
+     * Checks if `value` is, or can be coerced to, a finite number.
+     *
+     * Note: This is not the same as native `isFinite` which will return true 
for
+     * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is finite, else 
`false`.
+     * @example
+     *
+     * _.isFinite(-101);
+     * // => true
+     *
+     * _.isFinite('10');
+     * // => true
+     *
+     * _.isFinite(true);
+     * // => false
+     *
+     * _.isFinite('');
+     * // => false
+     *
+     * _.isFinite(Infinity);
+     * // => false
+     */
+    function isFinite(value) {
+      return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
+    }
+
+    /**
+     * Checks if `value` is a function.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a function, else 
`false`.
+     * @example
+     *
+     * _.isFunction(_);
+     * // => true
+     */
+    function isFunction(value) {
+      return typeof value == 'function';
+    }
+
+    /**
+     * Checks if `value` is the language type of Object.
+     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new 
String('')`)
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is an object, else 
`false`.
+     * @example
+     *
+     * _.isObject({});
+     * // => true
+     *
+     * _.isObject([1, 2, 3]);
+     * // => true
+     *
+     * _.isObject(1);
+     * // => false
+     */
+    function isObject(value) {
+      // check if the value is the ECMAScript language type of Object
+      // http://es5.github.io/#x8
+      // and avoid a V8 bug
+      // http://code.google.com/p/v8/issues/detail?id=2291
+      return !!(value && objectTypes[typeof value]);
+    }
+
+    /**
+     * Checks if `value` is `NaN`.
+     *
+     * Note: This is not the same as native `isNaN` which will return `true` 
for
+     * `undefined` and other non-numeric values. See 
http://es5.github.io/#x15.1.2.4.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
+     * @example
+     *
+     * _.isNaN(NaN);
+     * // => true
+     *
+     * _.isNaN(new Number(NaN));
+     * // => true
+     *
+     * isNaN(undefined);
+     * // => true
+     *
+     * _.isNaN(undefined);
+     * // => false
+     */
+    function isNaN(value) {
+      // `NaN` as a primitive is the only value that is not equal to itself
+      // (perform the [[Class]] check first to avoid errors with some host 
objects in IE)
+      return isNumber(value) && value != +value;
+    }
+
+    /**
+     * Checks if `value` is `null`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is `null`, else 
`false`.
+     * @example
+     *
+     * _.isNull(null);
+     * // => true
+     *
+     * _.isNull(undefined);
+     * // => false
+     */
+    function isNull(value) {
+      return value === null;
+    }
+
+    /**
+     * Checks if `value` is a number.
+     *
+     * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a number, else 
`false`.
+     * @example
+     *
+     * _.isNumber(8.4 * 5);
+     * // => true
+     */
+    function isNumber(value) {
+      return typeof value == 'number' ||
+        value && typeof value == 'object' && toString.call(value) == 
numberClass || false;
+    }
+
+    /**
+     * Checks if `value` is an object created by the `Object` constructor.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a plain object, else 
`false`.
+     * @example
+     *
+     * function Shape() {
+     *   this.x = 0;
+     *   this.y = 0;
+     * }
+     *
+     * _.isPlainObject(new Shape);
+     * // => false
+     *
+     * _.isPlainObject([1, 2, 3]);
+     * // => false
+     *
+     * _.isPlainObject({ 'x': 0, 'y': 0 });
+     * // => true
+     */
+    var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+      if (!(value && toString.call(value) == objectClass)) {
+        return false;
+      }
+      var valueOf = value.valueOf,
+          objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) 
&& getPrototypeOf(objProto);
+
+      return objProto
+        ? (value == objProto || getPrototypeOf(value) == objProto)
+        : shimIsPlainObject(value);
+    };
+
+    /**
+     * Checks if `value` is a regular expression.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a regular 
expression, else `false`.
+     * @example
+     *
+     * _.isRegExp(/fred/);
+     * // => true
+     */
+    function isRegExp(value) {
+      return value && typeof value == 'object' && toString.call(value) == 
regexpClass || false;
+    }
+
+    /**
+     * Checks if `value` is a string.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is a string, else 
`false`.
+     * @example
+     *
+     * _.isString('fred');
+     * // => true
+     */
+    function isString(value) {
+      return typeof value == 'string' ||
+        value && typeof value == 'object' && toString.call(value) == 
stringClass || false;
+    }
+
+    /**
+     * Checks if `value` is `undefined`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if the `value` is `undefined`, else 
`false`.
+     * @example
+     *
+     * _.isUndefined(void 0);
+     * // => true
+     */
+    function isUndefined(value) {
+      return typeof value == 'undefined';
+    }
+
+    /**
+     * Creates an object with the same keys as `object` and values generated by
+     * running each own enumerable property of `object` through the callback.
+     * The callback is bound to `thisArg` and invoked with three arguments;
+     * (value, key, object).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new object with values of the results of 
each `callback` execution.
+     * @example
+     *
+     * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; 
});
+     * // => { 'a': 3, 'b': 6, 'c': 9 }
+     *
+     * var characters = {
+     *   'fred': { 'name': 'fred', 'age': 40 },
+     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
+     * };
+     *
+     * // using "_.pluck" callback shorthand
+     * _.mapValues(characters, 'age');
+     * // => { 'fred': 40, 'pebbles': 1 }
+     */
+    function mapValues(object, callback, thisArg) {
+      var result = {};
+      callback = lodash.createCallback(callback, thisArg, 3);
+
+      forOwn(object, function(value, key, object) {
+        result[key] = callback(value, key, object);
+      });
+      return result;
+    }
+
+    /**
+     * Recursively merges own enumerable properties of the source object(s), 
that
+     * don't resolve to `undefined` into the destination object. Subsequent 
sources
+     * will overwrite property assignments of previous sources. If a callback 
is
+     * provided it will be executed to produce the merged values of the 
destination
+     * and source properties. If the callback returns `undefined` merging will
+     * be handled by the method instead. The callback is bound to `thisArg` and
+     * invoked with two arguments; (objectValue, sourceValue).
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The destination object.
+     * @param {...Object} [source] The source objects.
+     * @param {Function} [callback] The function to customize merging 
properties.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns the destination object.
+     * @example
+     *
+     * var names = {
+     *   'characters': [
+     *     { 'name': 'barney' },
+     *     { 'name': 'fred' }
+     *   ]
+     * };
+     *
+     * var ages = {
+     *   'characters': [
+     *     { 'age': 36 },
+     *     { 'age': 40 }
+     *   ]
+     * };
+     *
+     * _.merge(names, ages);
+     * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 
'fred', 'age': 40 }] }
+     *
+     * var food = {
+     *   'fruits': ['apple'],
+     *   'vegetables': ['beet']
+     * };
+     *
+     * var otherFood = {
+     *   'fruits': ['banana'],
+     *   'vegetables': ['carrot']
+     * };
+     *
+     * _.merge(food, otherFood, function(a, b) {
+     *   return _.isArray(a) ? a.concat(b) : undefined;
+     * });
+     * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
+     */
+    function merge(object) {
+      var args = arguments,
+          length = 2;
+
+      if (!isObject(object)) {
+        return object;
+      }
+      // allows working with `_.reduce` and `_.reduceRight` without using
+      // their `index` and `collection` arguments
+      if (typeof args[2] != 'number') {
+        length = args.length;
+      }
+      if (length > 3 && typeof args[length - 2] == 'function') {
+        var callback = baseCreateCallback(args[--length - 1], args[length--], 
2);
+      } else if (length > 2 && typeof args[length - 1] == 'function') {
+        callback = args[--length];
+      }
+      var sources = slice(arguments, 1, length),
+          index = -1,
+          stackA = getArray(),
+          stackB = getArray();
+
+      while (++index < length) {
+        baseMerge(object, sources[index], callback, stackA, stackB);
+      }
+      releaseArray(stackA);
+      releaseArray(stackB);
+      return object;
+    }
+
+    /**
+     * Creates a shallow clone of `object` excluding the specified properties.
+     * Property names may be specified as individual arguments or as arrays of
+     * property names. If a callback is provided it will be executed for each
+     * property of `object` omitting the properties the callback returns truey
+     * for. The callback is bound to `thisArg` and invoked with three 
arguments;
+     * (value, key, object).
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The source object.
+     * @param {Function|...string|string[]} [callback] The properties to omit 
or the
+     *  function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns an object without the omitted properties.
+     * @example
+     *
+     * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
+     * // => { 'name': 'fred' }
+     *
+     * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
+     *   return typeof value == 'number';
+     * });
+     * // => { 'name': 'fred' }
+     */
+    function omit(object, callback, thisArg) {
+      var result = {};
+      if (typeof callback != 'function') {
+        var props = [];
+        forIn(object, function(value, key) {
+          props.push(key);
+        });
+        props = baseDifference(props, baseFlatten(arguments, true, false, 1));
+
+        var index = -1,
+            length = props.length;
+
+        while (++index < length) {
+          var key = props[index];
+          result[key] = object[key];
+        }
+      } else {
+        callback = lodash.createCallback(callback, thisArg, 3);
+        forIn(object, function(value, key, object) {
+          if (!callback(value, key, object)) {
+            result[key] = value;
+          }
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Creates a two dimensional array of an object's key-value pairs,
+     * i.e. `[[key1, value1], [key2, value2]]`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns new array of key-value pairs.
+     * @example
+     *
+     * _.pairs({ 'barney': 36, 'fred': 40 });
+     * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed 
across environments)
+     */
+    function pairs(object) {
+      var index = -1,
+          props = keys(object),
+          length = props.length,
+          result = Array(length);
+
+      while (++index < length) {
+        var key = props[index];
+        result[index] = [key, object[key]];
+      }
+      return result;
+    }
+
+    /**
+     * Creates a shallow clone of `object` composed of the specified 
properties.
+     * Property names may be specified as individual arguments or as arrays of
+     * property names. If a callback is provided it will be executed for each
+     * property of `object` picking the properties the callback returns truey
+     * for. The callback is bound to `thisArg` and invoked with three 
arguments;
+     * (value, key, object).
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The source object.
+     * @param {Function|...string|string[]} [callback] The function called per
+     *  iteration or property names to pick, specified as individual property
+     *  names or arrays of property names.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns an object composed of the picked properties.
+     * @example
+     *
+     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
+     * // => { 'name': 'fred' }
+     *
+     * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
+     *   return key.charAt(0) != '_';
+     * });
+     * // => { 'name': 'fred' }
+     */
+    function pick(object, callback, thisArg) {
+      var result = {};
+      if (typeof callback != 'function') {
+        var index = -1,
+            props = baseFlatten(arguments, true, false, 1),
+            length = isObject(object) ? props.length : 0;
+
+        while (++index < length) {
+          var key = props[index];
+          if (key in object) {
+            result[key] = object[key];
+          }
+        }
+      } else {
+        callback = lodash.createCallback(callback, thisArg, 3);
+        forIn(object, function(value, key, object) {
+          if (callback(value, key, object)) {
+            result[key] = value;
+          }
+        });
+      }
+      return result;
+    }
+
+    /**
+     * An alternative to `_.reduce` this method transforms `object` to a new
+     * `accumulator` object which is the result of running each of its own
+     * enumerable properties through a callback, with each callback execution
+     * potentially mutating the `accumulator` object. The callback is bound to
+     * `thisArg` and invoked with four arguments; (accumulator, value, key, 
object).
+     * Callbacks may exit iteration early by explicitly returning `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Array|Object} object The object to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [accumulator] The custom accumulator value.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the accumulated value.
+     * @example
+     *
+     * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 
function(result, num) {
+     *   num *= num;
+     *   if (num % 2) {
+     *     return result.push(num) < 3;
+     *   }
+     * });
+     * // => [1, 9, 25]
+     *
+     * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, 
num, key) {
+     *   result[key] = num * 3;
+     * });
+     * // => { 'a': 3, 'b': 6, 'c': 9 }
+     */
+    function transform(object, callback, accumulator, thisArg) {
+      var isArr = isArray(object);
+      if (accumulator == null) {
+        if (isArr) {
+          accumulator = [];
+        } else {
+          var ctor = object && object.constructor,
+              proto = ctor && ctor.prototype;
+
+          accumulator = baseCreate(proto);
+        }
+      }
+      if (callback) {
+        callback = lodash.createCallback(callback, thisArg, 4);
+        (isArr ? forEach : forOwn)(object, function(value, index, object) {
+          return callback(accumulator, value, index, object);
+        });
+      }
+      return accumulator;
+    }
+
+    /**
+     * Creates an array composed of the own enumerable property values of 
`object`.
+     *
+     * @static
+     * @memberOf _
+     * @category Objects
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns an array of property values.
+     * @example
+     *
+     * _.values({ 'one': 1, 'two': 2, 'three': 3 });
+     * // => [1, 2, 3] (property order is not guaranteed across environments)
+     */
+    function values(object) {
+      var index = -1,
+          props = keys(object),
+          length = props.length,
+          result = Array(length);
+
+      while (++index < length) {
+        result[index] = object[props[index]];
+      }
+      return result;
+    }
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Creates an array of elements from the specified indexes, or keys, of the
+     * `collection`. Indexes may be specified as individual arguments or as 
arrays
+     * of indexes.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {...(number|number[]|string|string[])} [index] The indexes of 
`collection`
+     *   to retrieve, specified as individual indexes or arrays of indexes.
+     * @returns {Array} Returns a new array of elements corresponding to the
+     *  provided indexes.
+     * @example
+     *
+     * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
+     * // => ['a', 'c', 'e']
+     *
+     * _.at(['fred', 'barney', 'pebbles'], 0, 2);
+     * // => ['fred', 'pebbles']
+     */
+    function at(collection) {
+      var args = arguments,
+          index = -1,
+          props = baseFlatten(args, true, false, 1),
+          length = (args[2] && args[2][args[1]] === collection) ? 1 : 
props.length,
+          result = Array(length);
+
+      while(++index < length) {
+        result[index] = collection[props[index]];
+      }
+      return result;
+    }
+
+    /**
+     * Checks if a given value is present in a collection using strict equality
+     * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as 
the
+     * offset from the end of the collection.
+     *
+     * @static
+     * @memberOf _
+     * @alias include
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {*} target The value to check for.
+     * @param {number} [fromIndex=0] The index to search from.
+     * @returns {boolean} Returns `true` if the `target` element is found, 
else `false`.
+     * @example
+     *
+     * _.contains([1, 2, 3], 1);
+     * // => true
+     *
+     * _.contains([1, 2, 3], 1, 2);
+     * // => false
+     *
+     * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
+     * // => true
+     *
+     * _.contains('pebbles', 'eb');
+     * // => true
+     */
+    function contains(collection, target, fromIndex) {
+      var index = -1,
+          indexOf = getIndexOf(),
+          length = collection ? collection.length : 0,
+          result = false;
+
+      fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : 
fromIndex) || 0;
+      if (isArray(collection)) {
+        result = indexOf(collection, target, fromIndex) > -1;
+      } else if (typeof length == 'number') {
+        result = (isString(collection) ? collection.indexOf(target, fromIndex) 
: indexOf(collection, target, fromIndex)) > -1;
+      } else {
+        forOwn(collection, function(value) {
+          if (++index >= fromIndex) {
+            return !(result = value === target);
+          }
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Creates an object composed of keys generated from the results of running
+     * each element of `collection` through the callback. The corresponding 
value
+     * of each key is the number of times the key was returned by the callback.
+     * The callback is bound to `thisArg` and invoked with three arguments;
+     * (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns the composed aggregate object.
+     * @example
+     *
+     * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
+     * // => { '4': 1, '6': 2 }
+     *
+     * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, 
Math);
+     * // => { '4': 1, '6': 2 }
+     *
+     * _.countBy(['one', 'two', 'three'], 'length');
+     * // => { '3': 2, '5': 1 }
+     */
+    var countBy = createAggregator(function(result, value, key) {
+      (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
+    });
+
+    /**
+     * Checks if the given callback returns truey value for **all** elements of
+     * a collection. The callback is bound to `thisArg` and invoked with three
+     * arguments; (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias all
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {boolean} Returns `true` if all elements passed the callback 
check,
+     *  else `false`.
+     * @example
+     *
+     * _.every([true, 1, null, 'yes']);
+     * // => false
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.every(characters, 'age');
+     * // => true
+     *
+     * // using "_.where" callback shorthand
+     * _.every(characters, { 'age': 36 });
+     * // => false
+     */
+    function every(collection, callback, thisArg) {
+      var result = true;
+      callback = lodash.createCallback(callback, thisArg, 3);
+
+      var index = -1,
+          length = collection ? collection.length : 0;
+
+      if (typeof length == 'number') {
+        while (++index < length) {
+          if (!(result = !!callback(collection[index], index, collection))) {
+            break;
+          }
+        }
+      } else {
+        forOwn(collection, function(value, index, collection) {
+          return (result = !!callback(value, index, collection));
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Iterates over elements of a collection, returning an array of all 
elements
+     * the callback returns truey for. The callback is bound to `thisArg` and
+     * invoked with three arguments; (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias select
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new array of elements that passed the 
callback check.
+     * @example
+     *
+     * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 
== 0; });
+     * // => [2, 4, 6]
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36, 'blocked': false },
+     *   { 'name': 'fred',   'age': 40, 'blocked': true }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.filter(characters, 'blocked');
+     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+     *
+     * // using "_.where" callback shorthand
+     * _.filter(characters, { 'age': 36 });
+     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+     */
+    function filter(collection, callback, thisArg) {
+      var result = [];
+      callback = lodash.createCallback(callback, thisArg, 3);
+
+      var index = -1,
+          length = collection ? collection.length : 0;
+
+      if (typeof length == 'number') {
+        while (++index < length) {
+          var value = collection[index];
+          if (callback(value, index, collection)) {
+            result.push(value);
+          }
+        }
+      } else {
+        forOwn(collection, function(value, index, collection) {
+          if (callback(value, index, collection)) {
+            result.push(value);
+          }
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Iterates over elements of a collection, returning the first element that
+     * the callback returns truey for. The callback is bound to `thisArg` and
+     * invoked with three arguments; (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias detect, findWhere
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the found element, else `undefined`.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'age': 36, 'blocked': false },
+     *   { 'name': 'fred',    'age': 40, 'blocked': true },
+     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
+     * ];
+     *
+     * _.find(characters, function(chr) {
+     *   return chr.age < 40;
+     * });
+     * // => { 'name': 'barney', 'age': 36, 'blocked': false }
+     *
+     * // using "_.where" callback shorthand
+     * _.find(characters, { 'age': 1 });
+     * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
+     *
+     * // using "_.pluck" callback shorthand
+     * _.find(characters, 'blocked');
+     * // => { 'name': 'fred', 'age': 40, 'blocked': true }
+     */
+    function find(collection, callback, thisArg) {
+      callback = lodash.createCallback(callback, thisArg, 3);
+
+      var index = -1,
+          length = collection ? collection.length : 0;
+
+      if (typeof length == 'number') {
+        while (++index < length) {
+          var value = collection[index];
+          if (callback(value, index, collection)) {
+            return value;
+          }
+        }
+      } else {
+        var result;
+        forOwn(collection, function(value, index, collection) {
+          if (callback(value, index, collection)) {
+            result = value;
+            return false;
+          }
+        });
+        return result;
+      }
+    }
+
+    /**
+     * This method is like `_.find` except that it iterates over elements
+     * of a `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the found element, else `undefined`.
+     * @example
+     *
+     * _.findLast([1, 2, 3, 4], function(num) {
+     *   return num % 2 == 1;
+     * });
+     * // => 3
+     */
+    function findLast(collection, callback, thisArg) {
+      var result;
+      callback = lodash.createCallback(callback, thisArg, 3);
+      forEachRight(collection, function(value, index, collection) {
+        if (callback(value, index, collection)) {
+          result = value;
+          return false;
+        }
+      });
+      return result;
+    }
+
+    /**
+     * Iterates over elements of a collection, executing the callback for each
+     * element. The callback is bound to `thisArg` and invoked with three 
arguments;
+     * (value, index|key, collection). Callbacks may exit iteration early by
+     * explicitly returning `false`.
+     *
+     * Note: As with other "Collections" methods, objects with a `length` 
property
+     * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
+     * may be used for object iteration.
+     *
+     * @static
+     * @memberOf _
+     * @alias each
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array|Object|string} Returns `collection`.
+     * @example
+     *
+     * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
+     * // => logs each number and returns '1,2,3'
+     *
+     * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { 
console.log(num); });
+     * // => logs each number and returns the object (property order is not 
guaranteed across environments)
+     */
+    function forEach(collection, callback, thisArg) {
+      var index = -1,
+          length = collection ? collection.length : 0;
+
+      callback = callback && typeof thisArg == 'undefined' ? callback : 
baseCreateCallback(callback, thisArg, 3);
+      if (typeof length == 'number') {
+        while (++index < length) {
+          if (callback(collection[index], index, collection) === false) {
+            break;
+          }
+        }
+      } else {
+        forOwn(collection, callback);
+      }
+      return collection;
+    }
+
+    /**
+     * This method is like `_.forEach` except that it iterates over elements
+     * of a `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @alias eachRight
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array|Object|string} Returns `collection`.
+     * @example
+     *
+     * _([1, 2, 3]).forEachRight(function(num) { console.log(num); 
}).join(',');
+     * // => logs each number from right to left and returns '3,2,1'
+     */
+    function forEachRight(collection, callback, thisArg) {
+      var length = collection ? collection.length : 0;
+      callback = callback && typeof thisArg == 'undefined' ? callback : 
baseCreateCallback(callback, thisArg, 3);
+      if (typeof length == 'number') {
+        while (length--) {
+          if (callback(collection[length], length, collection) === false) {
+            break;
+          }
+        }
+      } else {
+        var props = keys(collection);
+        length = props.length;
+        forOwn(collection, function(value, key, collection) {
+          key = props ? props[--length] : --length;
+          return callback(collection[key], key, collection);
+        });
+      }
+      return collection;
+    }
+
+    /**
+     * Creates an object composed of keys generated from the results of running
+     * each element of a collection through the callback. The corresponding 
value
+     * of each key is an array of the elements responsible for generating the 
key.
+     * The callback is bound to `thisArg` and invoked with three arguments;
+     * (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns the composed aggregate object.
+     * @example
+     *
+     * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
+     * // => { '4': [4.2], '6': [6.1, 6.4] }
+     *
+     * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, 
Math);
+     * // => { '4': [4.2], '6': [6.1, 6.4] }
+     *
+     * // using "_.pluck" callback shorthand
+     * _.groupBy(['one', 'two', 'three'], 'length');
+     * // => { '3': ['one', 'two'], '5': ['three'] }
+     */
+    var groupBy = createAggregator(function(result, value, key) {
+      (hasOwnProperty.call(result, key) ? result[key] : result[key] = 
[]).push(value);
+    });
+
+    /**
+     * Creates an object composed of keys generated from the results of running
+     * each element of the collection through the given callback. The 
corresponding
+     * value of each key is the last element responsible for generating the 
key.
+     * The callback is bound to `thisArg` and invoked with three arguments;
+     * (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Object} Returns the composed aggregate object.
+     * @example
+     *
+     * var keys = [
+     *   { 'dir': 'left', 'code': 97 },
+     *   { 'dir': 'right', 'code': 100 }
+     * ];
+     *
+     * _.indexBy(keys, 'dir');
+     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 
'right', 'code': 100 } }
+     *
+     * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); 
});
+     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 
'code': 100 } }
+     *
+     * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, 
String);
+     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 
'code': 100 } }
+     */
+    var indexBy = createAggregator(function(result, value, key) {
+      result[key] = value;
+    });
+
+    /**
+     * Invokes the method named by `methodName` on each element in the 
`collection`
+     * returning an array of the results of each invoked method. Additional 
arguments
+     * will be provided to each invoked method. If `methodName` is a function 
it
+     * will be invoked for, and `this` bound to, each element in the 
`collection`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|string} methodName The name of the method to invoke or
+     *  the function invoked per iteration.
+     * @param {...*} [arg] Arguments to invoke the method with.
+     * @returns {Array} Returns a new array of the results of each invoked 
method.
+     * @example
+     *
+     * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
+     * // => [[1, 5, 7], [1, 2, 3]]
+     *
+     * _.invoke([123, 456], String.prototype.split, '');
+     * // => [['1', '2', '3'], ['4', '5', '6']]
+     */
+    function invoke(collection, methodName) {
+      var args = slice(arguments, 2),
+          index = -1,
+          isFunc = typeof methodName == 'function',
+          length = collection ? collection.length : 0,
+          result = Array(typeof length == 'number' ? length : 0);
+
+      forEach(collection, function(value) {
+        result[++index] = (isFunc ? methodName : 
value[methodName]).apply(value, args);
+      });
+      return result;
+    }
+
+    /**
+     * Creates an array of values by running each element in the collection
+     * through the callback. The callback is bound to `thisArg` and invoked 
with
+     * three arguments; (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias collect
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new array of the results of each `callback` 
execution.
+     * @example
+     *
+     * _.map([1, 2, 3], function(num) { return num * 3; });
+     * // => [3, 6, 9]
+     *
+     * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 
3; });
+     * // => [3, 6, 9] (property order is not guaranteed across environments)
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.map(characters, 'name');
+     * // => ['barney', 'fred']
+     */
+    function map(collection, callback, thisArg) {
+      var index = -1,
+          length = collection ? collection.length : 0;
+
+      callback = lodash.createCallback(callback, thisArg, 3);
+      if (typeof length == 'number') {
+        var result = Array(length);
+        while (++index < length) {
+          result[index] = callback(collection[index], index, collection);
+        }
+      } else {
+        result = [];
+        forOwn(collection, function(value, key, collection) {
+          result[++index] = callback(value, key, collection);
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Retrieves the maximum value of a collection. If the collection is empty 
or
+     * falsey `-Infinity` is returned. If a callback is provided it will be 
executed
+     * for each value in the collection to generate the criterion by which the 
value
+     * is ranked. The callback is bound to `thisArg` and invoked with three
+     * arguments; (value, index, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the maximum value.
+     * @example
+     *
+     * _.max([4, 2, 8, 6]);
+     * // => 8
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * _.max(characters, function(chr) { return chr.age; });
+     * // => { 'name': 'fred', 'age': 40 };
+     *
+     * // using "_.pluck" callback shorthand
+     * _.max(characters, 'age');
+     * // => { 'name': 'fred', 'age': 40 };
+     */
+    function max(collection, callback, thisArg) {
+      var computed = -Infinity,
+          result = computed;
+
+      // allows working with functions like `_.map` without using
+      // their `index` argument as a callback
+      if (typeof callback != 'function' && thisArg && thisArg[callback] === 
collection) {
+        callback = null;
+      }
+      if (callback == null && isArray(collection)) {
+        var index = -1,
+            length = collection.length;
+
+        while (++index < length) {
+          var value = collection[index];
+          if (value > result) {
+            result = value;
+          }
+        }
+      } else {
+        callback = (callback == null && isString(collection))
+          ? charAtCallback
+          : lodash.createCallback(callback, thisArg, 3);
+
+        forEach(collection, function(value, index, collection) {
+          var current = callback(value, index, collection);
+          if (current > computed) {
+            computed = current;
+            result = value;
+          }
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Retrieves the minimum value of a collection. If the collection is empty 
or
+     * falsey `Infinity` is returned. If a callback is provided it will be 
executed
+     * for each value in the collection to generate the criterion by which the 
value
+     * is ranked. The callback is bound to `thisArg` and invoked with three
+     * arguments; (value, index, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the minimum value.
+     * @example
+     *
+     * _.min([4, 2, 8, 6]);
+     * // => 2
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * _.min(characters, function(chr) { return chr.age; });
+     * // => { 'name': 'barney', 'age': 36 };
+     *
+     * // using "_.pluck" callback shorthand
+     * _.min(characters, 'age');
+     * // => { 'name': 'barney', 'age': 36 };
+     */
+    function min(collection, callback, thisArg) {
+      var computed = Infinity,
+          result = computed;
+
+      // allows working with functions like `_.map` without using
+      // their `index` argument as a callback
+      if (typeof callback != 'function' && thisArg && thisArg[callback] === 
collection) {
+        callback = null;
+      }
+      if (callback == null && isArray(collection)) {
+        var index = -1,
+            length = collection.length;
+
+        while (++index < length) {
+          var value = collection[index];
+          if (value < result) {
+            result = value;
+          }
+        }
+      } else {
+        callback = (callback == null && isString(collection))
+          ? charAtCallback
+          : lodash.createCallback(callback, thisArg, 3);
+
+        forEach(collection, function(value, index, collection) {
+          var current = callback(value, index, collection);
+          if (current < computed) {
+            computed = current;
+            result = value;
+          }
+        });
+      }
+      return result;
+    }
+
+    /**
+     * Retrieves the value of a specified property from all elements in the 
collection.
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {string} property The name of the property to pluck.
+     * @returns {Array} Returns a new array of property values.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * _.pluck(characters, 'name');
+     * // => ['barney', 'fred']
+     */
+    var pluck = map;
+
+    /**
+     * Reduces a collection to a value which is the accumulated result of 
running
+     * each element in the collection through the callback, where each 
successive
+     * callback execution consumes the return value of the previous execution. 
If
+     * `accumulator` is not provided the first element of the collection will 
be
+     * used as the initial `accumulator` value. The callback is bound to 
`thisArg`
+     * and invoked with four arguments; (accumulator, value, index|key, 
collection).
+     *
+     * @static
+     * @memberOf _
+     * @alias foldl, inject
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [accumulator] Initial value of the accumulator.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the accumulated value.
+     * @example
+     *
+     * var sum = _.reduce([1, 2, 3], function(sum, num) {
+     *   return sum + num;
+     * });
+     * // => 6
+     *
+     * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, 
key) {
+     *   result[key] = num * 3;
+     *   return result;
+     * }, {});
+     * // => { 'a': 3, 'b': 6, 'c': 9 }
+     */
+    function reduce(collection, callback, accumulator, thisArg) {
+      if (!collection) return accumulator;
+      var noaccum = arguments.length < 3;
+      callback = lodash.createCallback(callback, thisArg, 4);
+
+      var index = -1,
+          length = collection.length;
+
+      if (typeof length == 'number') {
+        if (noaccum) {
+          accumulator = collection[++index];
+        }
+        while (++index < length) {
+          accumulator = callback(accumulator, collection[index], index, 
collection);
+        }
+      } else {
+        forOwn(collection, function(value, index, collection) {
+          accumulator = noaccum
+            ? (noaccum = false, value)
+            : callback(accumulator, value, index, collection)
+        });
+      }
+      return accumulator;
+    }
+
+    /**
+     * This method is like `_.reduce` except that it iterates over elements
+     * of a `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @alias foldr
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function} [callback=identity] The function called per iteration.
+     * @param {*} [accumulator] Initial value of the accumulator.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the accumulated value.
+     * @example
+     *
+     * var list = [[0, 1], [2, 3], [4, 5]];
+     * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, 
[]);
+     * // => [4, 5, 2, 3, 0, 1]
+     */
+    function reduceRight(collection, callback, accumulator, thisArg) {
+      var noaccum = arguments.length < 3;
+      callback = lodash.createCallback(callback, thisArg, 4);
+      forEachRight(collection, function(value, index, collection) {
+        accumulator = noaccum
+          ? (noaccum = false, value)
+          : callback(accumulator, value, index, collection);
+      });
+      return accumulator;
+    }
+
+    /**
+     * The opposite of `_.filter` this method returns the elements of a
+     * collection that the callback does **not** return truey for.
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new array of elements that failed the 
callback check.
+     * @example
+     *
+     * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 
== 0; });
+     * // => [1, 3, 5]
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36, 'blocked': false },
+     *   { 'name': 'fred',   'age': 40, 'blocked': true }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.reject(characters, 'blocked');
+     * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
+     *
+     * // using "_.where" callback shorthand
+     * _.reject(characters, { 'age': 36 });
+     * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
+     */
+    function reject(collection, callback, thisArg) {
+      callback = lodash.createCallback(callback, thisArg, 3);
+      return filter(collection, function(value, index, collection) {
+        return !callback(value, index, collection);
+      });
+    }
+
+    /**
+     * Retrieves a random element or `n` random elements from a collection.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to sample.
+     * @param {number} [n] The number of elements to sample.
+     * @param- {Object} [guard] Allows working with functions like `_.map`
+     *  without using their `index` arguments as `n`.
+     * @returns {Array} Returns the random sample(s) of `collection`.
+     * @example
+     *
+     * _.sample([1, 2, 3, 4]);
+     * // => 2
+     *
+     * _.sample([1, 2, 3, 4], 2);
+     * // => [3, 1]
+     */
+    function sample(collection, n, guard) {
+      if (collection && typeof collection.length != 'number') {
+        collection = values(collection);
+      }
+      if (n == null || guard) {
+        return collection ? collection[baseRandom(0, collection.length - 1)] : 
undefined;
+      }
+      var result = shuffle(collection);
+      result.length = nativeMin(nativeMax(0, n), result.length);
+      return result;
+    }
+
+    /**
+     * Creates an array of shuffled values, using a version of the Fisher-Yates
+     * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to shuffle.
+     * @returns {Array} Returns a new shuffled collection.
+     * @example
+     *
+     * _.shuffle([1, 2, 3, 4, 5, 6]);
+     * // => [4, 1, 6, 3, 5, 2]
+     */
+    function shuffle(collection) {
+      var index = -1,
+          length = collection ? collection.length : 0,
+          result = Array(typeof length == 'number' ? length : 0);
+
+      forEach(collection, function(value) {
+        var rand = baseRandom(0, ++index);
+        result[index] = result[rand];
+        result[rand] = value;
+      });
+      return result;
+    }
+
+    /**
+     * Gets the size of the `collection` by returning `collection.length` for 
arrays
+     * and array-like objects or the number of own enumerable properties for 
objects.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to inspect.
+     * @returns {number} Returns `collection.length` or number of own 
enumerable properties.
+     * @example
+     *
+     * _.size([1, 2]);
+     * // => 2
+     *
+     * _.size({ 'one': 1, 'two': 2, 'three': 3 });
+     * // => 3
+     *
+     * _.size('pebbles');
+     * // => 7
+     */
+    function size(collection) {
+      var length = collection ? collection.length : 0;
+      return typeof length == 'number' ? length : keys(collection).length;
+    }
+
+    /**
+     * Checks if the callback returns a truey value for **any** element of a
+     * collection. The function returns as soon as it finds a passing value and
+     * does not iterate over the entire collection. The callback is bound to
+     * `thisArg` and invoked with three arguments; (value, index|key, 
collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias any
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {boolean} Returns `true` if any element passed the callback 
check,
+     *  else `false`.
+     * @example
+     *
+     * _.some([null, 0, 'yes', false], Boolean);
+     * // => true
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36, 'blocked': false },
+     *   { 'name': 'fred',   'age': 40, 'blocked': true }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.some(characters, 'blocked');
+     * // => true
+     *
+     * // using "_.where" callback shorthand
+     * _.some(characters, { 'age': 1 });
+     * // => false
+     */
+    function some(collection, callback, thisArg) {
+      var result;
+      callback = lodash.createCallback(callback, thisArg, 3);
+
+      var index = -1,
+          length = collection ? collection.length : 0;
+
+      if (typeof length == 'number') {
+        while (++index < length) {
+          if ((result = callback(collection[index], index, collection))) {
+            break;
+          }
+        }
+      } else {
+        forOwn(collection, function(value, index, collection) {
+          return !(result = callback(value, index, collection));
+        });
+      }
+      return !!result;
+    }
+
+    /**
+     * Creates an array of elements, sorted in ascending order by the results 
of
+     * running each element in a collection through the callback. This method
+     * performs a stable sort, that is, it will preserve the original sort 
order
+     * of equal elements. The callback is bound to `thisArg` and invoked with
+     * three arguments; (value, index|key, collection).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an array of property names is provided for `callback` the collection
+     * will be sorted by each property value.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Array|Function|Object|string} [callback=identity] The function 
called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new array of sorted elements.
+     * @example
+     *
+     * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
+     * // => [3, 1, 2]
+     *
+     * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
+     * // => [3, 1, 2]
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'age': 36 },
+     *   { 'name': 'fred',    'age': 40 },
+     *   { 'name': 'barney',  'age': 26 },
+     *   { 'name': 'fred',    'age': 30 }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.map(_.sortBy(characters, 'age'), _.values);
+     * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
+     *
+     * // sorting by multiple properties
+     * _.map(_.sortBy(characters, ['name', 'age']), _.values);
+     * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
+     */
+    function sortBy(collection, callback, thisArg) {
+      var index = -1,
+          isArr = isArray(callback),
+          length = collection ? collection.length : 0,
+          result = Array(typeof length == 'number' ? length : 0);
+
+      if (!isArr) {
+        callback = lodash.createCallback(callback, thisArg, 3);
+      }
+      forEach(collection, function(value, key, collection) {
+        var object = result[++index] = getObject();
+        if (isArr) {
+          object.criteria = map(callback, function(key) { return value[key]; 
});
+        } else {
+          (object.criteria = getArray())[0] = callback(value, key, collection);
+        }
+        object.index = index;
+        object.value = value;
+      });
+
+      length = result.length;
+      result.sort(compareAscending);
+      while (length--) {
+        var object = result[length];
+        result[length] = object.value;
+        if (!isArr) {
+          releaseArray(object.criteria);
+        }
+        releaseObject(object);
+      }
+      return result;
+    }
+
+    /**
+     * Converts the `collection` to an array.
+     *
+     * @static
+     * @memberOf _
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to convert.
+     * @returns {Array} Returns the new converted array.
+     * @example
+     *
+     * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
+     * // => [2, 3, 4]
+     */
+    function toArray(collection) {
+      if (collection && typeof collection.length == 'number') {
+        return slice(collection);
+      }
+      return values(collection);
+    }
+
+    /**
+     * Performs a deep comparison of each element in a `collection` to the 
given
+     * `properties` object, returning an array of all elements that have 
equivalent
+     * property values.
+     *
+     * @static
+     * @memberOf _
+     * @type Function
+     * @category Collections
+     * @param {Array|Object|string} collection The collection to iterate over.
+     * @param {Object} props The object of property values to filter by.
+     * @returns {Array} Returns a new array of elements that have the given 
properties.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
+     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
+     * ];
+     *
+     * _.where(characters, { 'age': 36 });
+     * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
+     *
+     * _.where(characters, { 'pets': ['dino'] });
+     * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
+     */
+    var where = filter;
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Creates an array with all falsey values removed. The values `false`, 
`null`,
+     * `0`, `""`, `undefined`, and `NaN` are all falsey.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to compact.
+     * @returns {Array} Returns a new array of filtered values.
+     * @example
+     *
+     * _.compact([0, 1, false, 2, '', 3]);
+     * // => [1, 2, 3]
+     */
+    function compact(array) {
+      var index = -1,
+          length = array ? array.length : 0,
+          result = [];
+
+      while (++index < length) {
+        var value = array[index];
+        if (value) {
+          result.push(value);
+        }
+      }
+      return result;
+    }
+
+    /**
+     * Creates an array excluding all values of the provided arrays using 
strict
+     * equality for comparisons, i.e. `===`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to process.
+     * @param {...Array} [values] The arrays of values to exclude.
+     * @returns {Array} Returns a new array of filtered values.
+     * @example
+     *
+     * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
+     * // => [1, 3, 4]
+     */
+    function difference(array) {
+      return baseDifference(array, baseFlatten(arguments, true, true, 1));
+    }
+
+    /**
+     * This method is like `_.find` except that it returns the index of the 
first
+     * element that passes the callback check, instead of the element itself.
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to search.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {number} Returns the index of the found element, else `-1`.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'age': 36, 'blocked': false },
+     *   { 'name': 'fred',    'age': 40, 'blocked': true },
+     *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
+     * ];
+     *
+     * _.findIndex(characters, function(chr) {
+     *   return chr.age < 20;
+     * });
+     * // => 2
+     *
+     * // using "_.where" callback shorthand
+     * _.findIndex(characters, { 'age': 36 });
+     * // => 0
+     *
+     * // using "_.pluck" callback shorthand
+     * _.findIndex(characters, 'blocked');
+     * // => 1
+     */
+    function findIndex(array, callback, thisArg) {
+      var index = -1,
+          length = array ? array.length : 0;
+
+      callback = lodash.createCallback(callback, thisArg, 3);
+      while (++index < length) {
+        if (callback(array[index], index, array)) {
+          return index;
+        }
+      }
+      return -1;
+    }
+
+    /**
+     * This method is like `_.findIndex` except that it iterates over elements
+     * of a `collection` from right to left.
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to search.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {number} Returns the index of the found element, else `-1`.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'age': 36, 'blocked': true },
+     *   { 'name': 'fred',    'age': 40, 'blocked': false },
+     *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
+     * ];
+     *
+     * _.findLastIndex(characters, function(chr) {
+     *   return chr.age > 30;
+     * });
+     * // => 1
+     *
+     * // using "_.where" callback shorthand
+     * _.findLastIndex(characters, { 'age': 36 });
+     * // => 0
+     *
+     * // using "_.pluck" callback shorthand
+     * _.findLastIndex(characters, 'blocked');
+     * // => 2
+     */
+    function findLastIndex(array, callback, thisArg) {
+      var length = array ? array.length : 0;
+      callback = lodash.createCallback(callback, thisArg, 3);
+      while (length--) {
+        if (callback(array[length], length, array)) {
+          return length;
+        }
+      }
+      return -1;
+    }
+
+    /**
+     * Gets the first element or first `n` elements of an array. If a callback
+     * is provided elements at the beginning of the array are returned as long
+     * as the callback returns truey. The callback is bound to `thisArg` and
+     * invoked with three arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias head, take
+     * @category Arrays
+     * @param {Array} array The array to query.
+     * @param {Function|Object|number|string} [callback] The function called
+     *  per element or the number of elements to return. If a property name or
+     *  object is provided it will be used to create a "_.pluck" or "_.where"
+     *  style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the first element(s) of `array`.
+     * @example
+     *
+     * _.first([1, 2, 3]);
+     * // => 1
+     *
+     * _.first([1, 2, 3], 2);
+     * // => [1, 2]
+     *
+     * _.first([1, 2, 3], function(num) {
+     *   return num < 3;
+     * });
+     * // => [1, 2]
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
+     *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
+     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.first(characters, 'blocked');
+     * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
+     *
+     * // using "_.where" callback shorthand
+     * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
+     * // => ['barney', 'fred']
+     */
+    function first(array, callback, thisArg) {
+      var n = 0,
+          length = array ? array.length : 0;
+
+      if (typeof callback != 'number' && callback != null) {
+        var index = -1;
+        callback = lodash.createCallback(callback, thisArg, 3);
+        while (++index < length && callback(array[index], index, array)) {
+          n++;
+        }
+      } else {
+        n = callback;
+        if (n == null || thisArg) {
+          return array ? array[0] : undefined;
+        }
+      }
+      return slice(array, 0, nativeMin(nativeMax(0, n), length));
+    }
+
+    /**
+     * Flattens a nested array (the nesting can be to any depth). If 
`isShallow`
+     * is truey, the array will only be flattened a single level. If a callback
+     * is provided each element of the array is passed through the callback 
before
+     * flattening. The callback is bound to `thisArg` and invoked with three
+     * arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to flatten.
+     * @param {boolean} [isShallow=false] A flag to restrict flattening to a 
single level.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new flattened array.
+     * @example
+     *
+     * _.flatten([1, [2], [3, [[4]]]]);
+     * // => [1, 2, 3, 4];
+     *
+     * _.flatten([1, [2], [3, [[4]]]], true);
+     * // => [1, 2, 3, [[4]]];
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
+     *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.flatten(characters, 'pets');
+     * // => ['hoppy', 'baby puss', 'dino']
+     */
+    function flatten(array, isShallow, callback, thisArg) {
+      // juggle arguments
+      if (typeof isShallow != 'boolean' && isShallow != null) {
+        thisArg = callback;
+        callback = (typeof isShallow != 'function' && thisArg && 
thisArg[isShallow] === array) ? null : isShallow;
+        isShallow = false;
+      }
+      if (callback != null) {
+        array = map(array, callback, thisArg);
+      }
+      return baseFlatten(array, isShallow);
+    }
+
+    /**
+     * Gets the index at which the first occurrence of `value` is found using
+     * strict equality for comparisons, i.e. `===`. If the array is already 
sorted
+     * providing `true` for `fromIndex` will run a faster binary search.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to search.
+     * @param {*} value The value to search for.
+     * @param {boolean|number} [fromIndex=0] The index to search from or `true`
+     *  to perform a binary search on a sorted array.
+     * @returns {number} Returns the index of the matched value or `-1`.
+     * @example
+     *
+     * _.indexOf([1, 2, 3, 1, 2, 3], 2);
+     * // => 1
+     *
+     * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+     * // => 4
+     *
+     * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
+     * // => 2
+     */
+    function indexOf(array, value, fromIndex) {
+      if (typeof fromIndex == 'number') {
+        var length = array ? array.length : 0;
+        fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : 
fromIndex || 0);
+      } else if (fromIndex) {
+        var index = sortedIndex(array, value);
+        return array[index] === value ? index : -1;
+      }
+      return baseIndexOf(array, value, fromIndex);
+    }
+
+    /**
+     * Gets all but the last element or last `n` elements of an array. If a
+     * callback is provided elements at the end of the array are excluded from
+     * the result as long as the callback returns truey. The callback is bound
+     * to `thisArg` and invoked with three arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to query.
+     * @param {Function|Object|number|string} [callback=1] The function called
+     *  per element or the number of elements to exclude. If a property name or
+     *  object is provided it will be used to create a "_.pluck" or "_.where"
+     *  style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a slice of `array`.
+     * @example
+     *
+     * _.initial([1, 2, 3]);
+     * // => [1, 2]
+     *
+     * _.initial([1, 2, 3], 2);
+     * // => [1]
+     *
+     * _.initial([1, 2, 3], function(num) {
+     *   return num > 1;
+     * });
+     * // => [1]
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
+     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
+     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.initial(characters, 'blocked');
+     * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
+     *
+     * // using "_.where" callback shorthand
+     * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
+     * // => ['barney', 'fred']
+     */
+    function initial(array, callback, thisArg) {
+      var n = 0,
+          length = array ? array.length : 0;
+
+      if (typeof callback != 'number' && callback != null) {
+        var index = length;
+        callback = lodash.createCallback(callback, thisArg, 3);
+        while (index-- && callback(array[index], index, array)) {
+          n++;
+        }
+      } else {
+        n = (callback == null || thisArg) ? 1 : callback || n;
+      }
+      return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
+    }
+
+    /**
+     * Creates an array of unique values present in all provided arrays using
+     * strict equality for comparisons, i.e. `===`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {...Array} [array] The arrays to inspect.
+     * @returns {Array} Returns an array of shared values.
+     * @example
+     *
+     * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+     * // => [1, 2]
+     */
+    function intersection() {
+      var args = [],
+          argsIndex = -1,
+          argsLength = arguments.length,
+          caches = getArray(),
+          indexOf = getIndexOf(),
+          trustIndexOf = indexOf === baseIndexOf,
+          seen = getArray();
+
+      while (++argsIndex < argsLength) {
+        var value = arguments[argsIndex];
+        if (isArray(value) || isArguments(value)) {
+          args.push(value);
+          caches.push(trustIndexOf && value.length >= largeArraySize &&
+            createCache(argsIndex ? args[argsIndex] : seen));
+        }
+      }
+      var array = args[0],
+          index = -1,
+          length = array ? array.length : 0,
+          result = [];
+
+      outer:
+      while (++index < length) {
+        var cache = caches[0];
+        value = array[index];
+
+        if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
+          argsIndex = argsLength;
+          (cache || seen).push(value);
+          while (--argsIndex) {
+            cache = caches[argsIndex];
+            if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], 
value)) < 0) {
+              continue outer;
+            }
+          }
+          result.push(value);
+        }
+      }
+      while (argsLength--) {
+        cache = caches[argsLength];
+        if (cache) {
+          releaseObject(cache);
+        }
+      }
+      releaseArray(caches);
+      releaseArray(seen);
+      return result;
+    }
+
+    /**
+     * Gets the last element or last `n` elements of an array. If a callback is
+     * provided elements at the end of the array are returned as long as the
+     * callback returns truey. The callback is bound to `thisArg` and invoked
+     * with three arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to query.
+     * @param {Function|Object|number|string} [callback] The function called
+     *  per element or the number of elements to return. If a property name or
+     *  object is provided it will be used to create a "_.pluck" or "_.where"
+     *  style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {*} Returns the last element(s) of `array`.
+     * @example
+     *
+     * _.last([1, 2, 3]);
+     * // => 3
+     *
+     * _.last([1, 2, 3], 2);
+     * // => [2, 3]
+     *
+     * _.last([1, 2, 3], function(num) {
+     *   return num > 1;
+     * });
+     * // => [2, 3]
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
+     *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
+     *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.pluck(_.last(characters, 'blocked'), 'name');
+     * // => ['fred', 'pebbles']
+     *
+     * // using "_.where" callback shorthand
+     * _.last(characters, { 'employer': 'na' });
+     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+     */
+    function last(array, callback, thisArg) {
+      var n = 0,
+          length = array ? array.length : 0;
+
+      if (typeof callback != 'number' && callback != null) {
+        var index = length;
+        callback = lodash.createCallback(callback, thisArg, 3);
+        while (index-- && callback(array[index], index, array)) {
+          n++;
+        }
+      } else {
+        n = callback;
+        if (n == null || thisArg) {
+          return array ? array[length - 1] : undefined;
+        }
+      }
+      return slice(array, nativeMax(0, length - n));
+    }
+
+    /**
+     * Gets the index at which the last occurrence of `value` is found using 
strict
+     * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is 
used
+     * as the offset from the end of the collection.
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to search.
+     * @param {*} value The value to search for.
+     * @param {number} [fromIndex=array.length-1] The index to search from.
+     * @returns {number} Returns the index of the matched value or `-1`.
+     * @example
+     *
+     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
+     * // => 4
+     *
+     * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+     * // => 1
+     */
+    function lastIndexOf(array, value, fromIndex) {
+      var index = array ? array.length : 0;
+      if (typeof fromIndex == 'number') {
+        index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : 
nativeMin(fromIndex, index - 1)) + 1;
+      }
+      while (index--) {
+        if (array[index] === value) {
+          return index;
+        }
+      }
+      return -1;
+    }
+
+    /**
+     * Removes all provided values from the given array using strict equality 
for
+     * comparisons, i.e. `===`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to modify.
+     * @param {...*} [value] The values to remove.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = [1, 2, 3, 1, 2, 3];
+     * _.pull(array, 2, 3);
+     * console.log(array);
+     * // => [1, 1]
+     */
+    function pull(array) {
+      var args = arguments,
+          argsIndex = 0,
+          argsLength = args.length,
+          length = array ? array.length : 0;
+
+      while (++argsIndex < argsLength) {
+        var index = -1,
+            value = args[argsIndex];
+        while (++index < length) {
+          if (array[index] === value) {
+            splice.call(array, index--, 1);
+            length--;
+          }
+        }
+      }
+      return array;
+    }
+
+    /**
+     * Creates an array of numbers (positive and/or negative) progressing from
+     * `start` up to but not including `end`. If `start` is less than `stop` a
+     * zero-length range is created unless a negative `step` is specified.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {number} [start=0] The start of the range.
+     * @param {number} end The end of the range.
+     * @param {number} [step=1] The value to increment or decrement by.
+     * @returns {Array} Returns a new range array.
+     * @example
+     *
+     * _.range(4);
+     * // => [0, 1, 2, 3]
+     *
+     * _.range(1, 5);
+     * // => [1, 2, 3, 4]
+     *
+     * _.range(0, 20, 5);
+     * // => [0, 5, 10, 15]
+     *
+     * _.range(0, -4, -1);
+     * // => [0, -1, -2, -3]
+     *
+     * _.range(1, 4, 0);
+     * // => [1, 1, 1]
+     *
+     * _.range(0);
+     * // => []
+     */
+    function range(start, end, step) {
+      start = +start || 0;
+      step = typeof step == 'number' ? step : (+step || 1);
+
+      if (end == null) {
+        end = start;
+        start = 0;
+      }
+      // use `Array(length)` so engines like Chakra and V8 avoid slower modes
+      // http://youtu.be/XAqIpGU8ZZk#t=17m25s
+      var index = -1,
+          length = nativeMax(0, ceil((end - start) / (step || 1))),
+          result = Array(length);
+
+      while (++index < length) {
+        result[index] = start;
+        start += step;
+      }
+      return result;
+    }
+
+    /**
+     * Removes all elements from an array that the callback returns truey for
+     * and returns an array of removed elements. The callback is bound to 
`thisArg`
+     * and invoked with three arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to modify.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a new array of removed elements.
+     * @example
+     *
+     * var array = [1, 2, 3, 4, 5, 6];
+     * var evens = _.remove(array, function(num) { return num % 2 == 0; });
+     *
+     * console.log(array);
+     * // => [1, 3, 5]
+     *
+     * console.log(evens);
+     * // => [2, 4, 6]
+     */
+    function remove(array, callback, thisArg) {
+      var index = -1,
+          length = array ? array.length : 0,
+          result = [];
+
+      callback = lodash.createCallback(callback, thisArg, 3);
+      while (++index < length) {
+        var value = array[index];
+        if (callback(value, index, array)) {
+          result.push(value);
+          splice.call(array, index--, 1);
+          length--;
+        }
+      }
+      return result;
+    }
+
+    /**
+     * The opposite of `_.initial` this method gets all but the first element 
or
+     * first `n` elements of an array. If a callback function is provided 
elements
+     * at the beginning of the array are excluded from the result as long as 
the
+     * callback returns truey. The callback is bound to `thisArg` and invoked
+     * with three arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias drop, tail
+     * @category Arrays
+     * @param {Array} array The array to query.
+     * @param {Function|Object|number|string} [callback=1] The function called
+     *  per element or the number of elements to exclude. If a property name or
+     *  object is provided it will be used to create a "_.pluck" or "_.where"
+     *  style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a slice of `array`.
+     * @example
+     *
+     * _.rest([1, 2, 3]);
+     * // => [2, 3]
+     *
+     * _.rest([1, 2, 3], 2);
+     * // => [3]
+     *
+     * _.rest([1, 2, 3], function(num) {
+     *   return num < 3;
+     * });
+     * // => [3]
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
+     *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
+     *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
+     * ];
+     *
+     * // using "_.pluck" callback shorthand
+     * _.pluck(_.rest(characters, 'blocked'), 'name');
+     * // => ['fred', 'pebbles']
+     *
+     * // using "_.where" callback shorthand
+     * _.rest(characters, { 'employer': 'slate' });
+     * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
+     */
+    function rest(array, callback, thisArg) {
+      if (typeof callback != 'number' && callback != null) {
+        var n = 0,
+            index = -1,
+            length = array ? array.length : 0;
+
+        callback = lodash.createCallback(callback, thisArg, 3);
+        while (++index < length && callback(array[index], index, array)) {
+          n++;
+        }
+      } else {
+        n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
+      }
+      return slice(array, n);
+    }
+
+    /**
+     * Uses a binary search to determine the smallest index at which a value
+     * should be inserted into a given sorted array in order to maintain the 
sort
+     * order of the array. If a callback is provided it will be executed for
+     * `value` and each element of `array` to compute their sort ranking. The
+     * callback is bound to `thisArg` and invoked with one argument; (value).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     * @example
+     *
+     * _.sortedIndex([20, 30, 50], 40);
+     * // => 2
+     *
+     * // using "_.pluck" callback shorthand
+     * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 
'x');
+     * // => 2
+     *
+     * var dict = {
+     *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 
50 }
+     * };
+     *
+     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
+     *   return dict.wordToNumber[word];
+     * });
+     * // => 2
+     *
+     * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
+     *   return this.wordToNumber[word];
+     * }, dict);
+     * // => 2
+     */
+    function sortedIndex(array, value, callback, thisArg) {
+      var low = 0,
+          high = array ? array.length : low;
+
+      // explicitly reference `identity` for better inlining in Firefox
+      callback = callback ? lodash.createCallback(callback, thisArg, 1) : 
identity;
+      value = callback(value);
+
+      while (low < high) {
+        var mid = (low + high) >>> 1;
+        (callback(array[mid]) < value)
+          ? low = mid + 1
+          : high = mid;
+      }
+      return low;
+    }
+
+    /**
+     * Creates an array of unique values, in order, of the provided arrays 
using
+     * strict equality for comparisons, i.e. `===`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {...Array} [array] The arrays to inspect.
+     * @returns {Array} Returns an array of combined values.
+     * @example
+     *
+     * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
+     * // => [1, 2, 3, 5, 4]
+     */
+    function union() {
+      return baseUniq(baseFlatten(arguments, true, true));
+    }
+
+    /**
+     * Creates a duplicate-value-free version of an array using strict equality
+     * for comparisons, i.e. `===`. If the array is sorted, providing
+     * `true` for `isSorted` will use a faster algorithm. If a callback is 
provided
+     * each element of `array` is passed through the callback before uniqueness
+     * is computed. The callback is bound to `thisArg` and invoked with three
+     * arguments; (value, index, array).
+     *
+     * If a property name is provided for `callback` the created "_.pluck" 
style
+     * callback will return the property value of the given element.
+     *
+     * If an object is provided for `callback` the created "_.where" style 
callback
+     * will return `true` for elements that have the properties of the given 
object,
+     * else `false`.
+     *
+     * @static
+     * @memberOf _
+     * @alias unique
+     * @category Arrays
+     * @param {Array} array The array to process.
+     * @param {boolean} [isSorted=false] A flag to indicate that `array` is 
sorted.
+     * @param {Function|Object|string} [callback=identity] The function called
+     *  per iteration. If a property name or object is provided it will be used
+     *  to create a "_.pluck" or "_.where" style callback, respectively.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns a duplicate-value-free array.
+     * @example
+     *
+     * _.uniq([1, 2, 1, 3, 1]);
+     * // => [1, 2, 3]
+     *
+     * _.uniq([1, 1, 2, 2, 3], true);
+     * // => [1, 2, 3]
+     *
+     * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return 
letter.toLowerCase(); });
+     * // => ['A', 'b', 'C']
+     *
+     * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return 
this.floor(num); }, Math);
+     * // => [1, 2.5, 3]
+     *
+     * // using "_.pluck" callback shorthand
+     * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+     * // => [{ 'x': 1 }, { 'x': 2 }]
+     */
+    function uniq(array, isSorted, callback, thisArg) {
+      // juggle arguments
+      if (typeof isSorted != 'boolean' && isSorted != null) {
+        thisArg = callback;
+        callback = (typeof isSorted != 'function' && thisArg && 
thisArg[isSorted] === array) ? null : isSorted;
+        isSorted = false;
+      }
+      if (callback != null) {
+        callback = lodash.createCallback(callback, thisArg, 3);
+      }
+      return baseUniq(array, isSorted, callback);
+    }
+
+    /**
+     * Creates an array excluding all provided values using strict equality for
+     * comparisons, i.e. `===`.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {Array} array The array to filter.
+     * @param {...*} [value] The values to exclude.
+     * @returns {Array} Returns a new array of filtered values.
+     * @example
+     *
+     * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
+     * // => [2, 3, 4]
+     */
+    function without(array) {
+      return baseDifference(array, slice(arguments, 1));
+    }
+
+    /**
+     * Creates an array that is the symmetric difference of the provided 
arrays.
+     * See http://en.wikipedia.org/wiki/Symmetric_difference.
+     *
+     * @static
+     * @memberOf _
+     * @category Arrays
+     * @param {...Array} [array] The arrays to inspect.
+     * @returns {Array} Returns an array of values.
+     * @example
+     *
+     * _.xor([1, 2, 3], [5, 2, 1, 4]);
+     * // => [3, 5, 4]
+     *
+     * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
+     * // => [1, 4, 5]
+     */
+    function xor() {
+      var index = -1,
+          length = arguments.length;
+
+      while (++index < length) {
+        var array = arguments[index];
+        if (isArray(array) || isArguments(array)) {
+          var result = result
+            ? baseUniq(baseDifference(result, 
array).concat(baseDifference(array, result)))
+            : array;
+        }
+      }
+      return result || [];
+    }
+
+    /**
+     * Creates an array of grouped elements, the first of which contains the 
first
+     * elements of the given arrays, the second of which contains the second
+     * elements of the given arrays, and so on.
+     *
+     * @static
+     * @memberOf _
+     * @alias unzip
+     * @category Arrays
+     * @param {...Array} [array] Arrays to process.
+     * @returns {Array} Returns a new array of grouped elements.
+     * @example
+     *
+     * _.zip(['fred', 'barney'], [30, 40], [true, false]);
+     * // => [['fred', 30, true], ['barney', 40, false]]
+     */
+    function zip() {
+      var array = arguments.length > 1 ? arguments : arguments[0],
+          index = -1,
+          length = array ? max(pluck(array, 'length')) : 0,
+          result = Array(length < 0 ? 0 : length);
+
+      while (++index < length) {
+        result[index] = pluck(array, index);
+      }
+      return result;
+    }
+
+    /**
+     * Creates an object composed from arrays of `keys` and `values`. Provide
+     * either a single two dimensional array, i.e. `[[key1, value1], [key2, 
value2]]`
+     * or two arrays, one of `keys` and one of corresponding `values`.
+     *
+     * @static
+     * @memberOf _
+     * @alias object
+     * @category Arrays
+     * @param {Array} keys The array of keys.
+     * @param {Array} [values=[]] The array of values.
+     * @returns {Object} Returns an object composed of the given keys and
+     *  corresponding values.
+     * @example
+     *
+     * _.zipObject(['fred', 'barney'], [30, 40]);
+     * // => { 'fred': 30, 'barney': 40 }
+     */
+    function zipObject(keys, values) {
+      var index = -1,
+          length = keys ? keys.length : 0,
+          result = {};
+
+      if (!values && length && !isArray(keys[0])) {
+        values = [];
+      }
+      while (++index < length) {
+        var key = keys[index];
+        if (values) {
+          result[key] = values[index];
+        } else if (key) {
+          result[key[0]] = key[1];
+        }
+      }
+      return result;
+    }
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Creates a function that executes `func`, with  the `this` binding and
+     * arguments of the created function, only after being called `n` times.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {number} n The number of times the function must be called before
+     *  `func` is executed.
+     * @param {Function} func The function to restrict.
+     * @returns {Function} Returns the new restricted function.
+     * @example
+     *
+     * var saves = ['profile', 'settings'];
+     *
+     * var done = _.after(saves.length, function() {
+     *   console.log('Done saving!');
+     * });
+     *
+     * _.forEach(saves, function(type) {
+     *   asyncSave({ 'type': type, 'complete': done });
+     * });
+     * // => logs 'Done saving!', after all saves have completed
+     */
+    function after(n, func) {
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      return function() {
+        if (--n < 1) {
+          return func.apply(this, arguments);
+        }
+      };
+    }
+
+    /**
+     * Creates a function that, when called, invokes `func` with the `this`
+     * binding of `thisArg` and prepends any additional `bind` arguments to 
those
+     * provided to the bound function.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to bind.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @param {...*} [arg] Arguments to be partially applied.
+     * @returns {Function} Returns the new bound function.
+     * @example
+     *
+     * var func = function(greeting) {
+     *   return greeting + ' ' + this.name;
+     * };
+     *
+     * func = _.bind(func, { 'name': 'fred' }, 'hi');
+     * func();
+     * // => 'hi fred'
+     */
+    function bind(func, thisArg) {
+      return arguments.length > 2
+        ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
+        : createWrapper(func, 1, null, null, thisArg);
+    }
+
+    /**
+     * Binds methods of an object to the object itself, overwriting the 
existing
+     * method. Method names may be specified as individual arguments or as 
arrays
+     * of method names. If no method names are provided all the function 
properties
+     * of `object` will be bound.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Object} object The object to bind and assign the bound methods 
to.
+     * @param {...string} [methodName] The object method names to
+     *  bind, specified as individual method names or arrays of method names.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var view = {
+     *   'label': 'docs',
+     *   'onClick': function() { console.log('clicked ' + this.label); }
+     * };
+     *
+     * _.bindAll(view);
+     * jQuery('#docs').on('click', view.onClick);
+     * // => logs 'clicked docs', when the button is clicked
+     */
+    function bindAll(object) {
+      var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 
1) : functions(object),
+          index = -1,
+          length = funcs.length;
+
+      while (++index < length) {
+        var key = funcs[index];
+        object[key] = createWrapper(object[key], 1, null, null, object);
+      }
+      return object;
+    }
+
+    /**
+     * Creates a function that, when called, invokes the method at 
`object[key]`
+     * and prepends any additional `bindKey` arguments to those provided to 
the bound
+     * function. This method differs from `_.bind` by allowing bound functions 
to
+     * reference methods that will be redefined or don't yet exist.
+     * See http://michaux.ca/articles/lazy-function-definition-pattern.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Object} object The object the method belongs to.
+     * @param {string} key The key of the method.
+     * @param {...*} [arg] Arguments to be partially applied.
+     * @returns {Function} Returns the new bound function.
+     * @example
+     *
+     * var object = {
+     *   'name': 'fred',
+     *   'greet': function(greeting) {
+     *     return greeting + ' ' + this.name;
+     *   }
+     * };
+     *
+     * var func = _.bindKey(object, 'greet', 'hi');
+     * func();
+     * // => 'hi fred'
+     *
+     * object.greet = function(greeting) {
+     *   return greeting + 'ya ' + this.name + '!';
+     * };
+     *
+     * func();
+     * // => 'hiya fred!'
+     */
+    function bindKey(object, key) {
+      return arguments.length > 2
+        ? createWrapper(key, 19, slice(arguments, 2), null, object)
+        : createWrapper(key, 3, null, null, object);
+    }
+
+    /**
+     * Creates a function that is the composition of the provided functions,
+     * where each function consumes the return value of the function that 
follows.
+     * For example, composing the functions `f()`, `g()`, and `h()` produces 
`f(g(h()))`.
+     * Each function is executed with the `this` binding of the composed 
function.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {...Function} [func] Functions to compose.
+     * @returns {Function} Returns the new composed function.
+     * @example
+     *
+     * var realNameMap = {
+     *   'pebbles': 'penelope'
+     * };
+     *
+     * var format = function(name) {
+     *   name = realNameMap[name.toLowerCase()] || name;
+     *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
+     * };
+     *
+     * var greet = function(formatted) {
+     *   return 'Hiya ' + formatted + '!';
+     * };
+     *
+     * var welcome = _.compose(greet, format);
+     * welcome('pebbles');
+     * // => 'Hiya Penelope!'
+     */
+    function compose() {
+      var funcs = arguments,
+          length = funcs.length;
+
+      while (length--) {
+        if (!isFunction(funcs[length])) {
+          throw new TypeError;
+        }
+      }
+      return function() {
+        var args = arguments,
+            length = funcs.length;
+
+        while (length--) {
+          args = [funcs[length].apply(this, args)];
+        }
+        return args[0];
+      };
+    }
+
+    /**
+     * Creates a function which accepts one or more arguments of `func` that 
when
+     * invoked either executes `func` returning its result, if all `func` 
arguments
+     * have been provided, or returns a function that accepts one or more of 
the
+     * remaining `func` arguments, and so on. The arity of `func` can be 
specified
+     * if `func.length` is not sufficient.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to curry.
+     * @param {number} [arity=func.length] The arity of `func`.
+     * @returns {Function} Returns the new curried function.
+     * @example
+     *
+     * var curried = _.curry(function(a, b, c) {
+     *   console.log(a + b + c);
+     * });
+     *
+     * curried(1)(2)(3);
+     * // => 6
+     *
+     * curried(1, 2)(3);
+     * // => 6
+     *
+     * curried(1, 2, 3);
+     * // => 6
+     */
+    function curry(func, arity) {
+      arity = typeof arity == 'number' ? arity : (+arity || func.length);
+      return createWrapper(func, 4, null, null, null, arity);
+    }
+
+    /**
+     * Creates a function that will delay the execution of `func` until after
+     * `wait` milliseconds have elapsed since the last time it was invoked.
+     * Provide an options object to indicate that `func` should be invoked on
+     * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
+     * to the debounced function will return the result of the last `func` 
call.
+     *
+     * Note: If `leading` and `trailing` options are `true` `func` will be 
called
+     * on the trailing edge of the timeout only if the the debounced function 
is
+     * invoked more than once during the `wait` timeout.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to debounce.
+     * @param {number} wait The number of milliseconds to delay.
+     * @param {Object} [options] The options object.
+     * @param {boolean} [options.leading=false] Specify execution on the 
leading edge of the timeout.
+     * @param {number} [options.maxWait] The maximum time `func` is allowed to 
be delayed before it's called.
+     * @param {boolean} [options.trailing=true] Specify execution on the 
trailing edge of the timeout.
+     * @returns {Function} Returns the new debounced function.
+     * @example
+     *
+     * // avoid costly calculations while the window size is in flux
+     * var lazyLayout = _.debounce(calculateLayout, 150);
+     * jQuery(window).on('resize', lazyLayout);
+     *
+     * // execute `sendMail` when the click event is fired, debouncing 
subsequent calls
+     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
+     *   'leading': true,
+     *   'trailing': false
+     * });
+     *
+     * // ensure `batchLog` is executed once after 1 second of debounced calls
+     * var source = new EventSource('/stream');
+     * source.addEventListener('message', _.debounce(batchLog, 250, {
+     *   'maxWait': 1000
+     * }, false);
+     */
+    function debounce(func, wait, options) {
+      var args,
+          maxTimeoutId,
+          result,
+          stamp,
+          thisArg,
+          timeoutId,
+          trailingCall,
+          lastCalled = 0,
+          maxWait = false,
+          trailing = true;
+
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      wait = nativeMax(0, wait) || 0;
+      if (options === true) {
+        var leading = true;
+        trailing = false;
+      } else if (isObject(options)) {
+        leading = options.leading;
+        maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 
0);
+        trailing = 'trailing' in options ? options.trailing : trailing;
+      }
+      var delayed = function() {
+        var remaining = wait - (now() - stamp);
+        if (remaining <= 0) {
+          if (maxTimeoutId) {
+            clearTimeout(maxTimeoutId);
+          }
+          var isCalled = trailingCall;
+          maxTimeoutId = timeoutId = trailingCall = undefined;
+          if (isCalled) {
+            lastCalled = now();
+            result = func.apply(thisArg, args);
+            if (!timeoutId && !maxTimeoutId) {
+              args = thisArg = null;
+            }
+          }
+        } else {
+          timeoutId = setTimeout(delayed, remaining);
+        }
+      };
+
+      var maxDelayed = function() {
+        if (timeoutId) {
+          clearTimeout(timeoutId);
+        }
+        maxTimeoutId = timeoutId = trailingCall = undefined;
+        if (trailing || (maxWait !== wait)) {
+          lastCalled = now();
+          result = func.apply(thisArg, args);
+          if (!timeoutId && !maxTimeoutId) {
+            args = thisArg = null;
+          }
+        }
+      };
+
+      return function() {
+        args = arguments;
+        stamp = now();
+        thisArg = this;
+        trailingCall = trailing && (timeoutId || !leading);
+
+        if (maxWait === false) {
+          var leadingCall = leading && !timeoutId;
+        } else {
+          if (!maxTimeoutId && !leading) {
+            lastCalled = stamp;
+          }
+          var remaining = maxWait - (stamp - lastCalled),
+              isCalled = remaining <= 0;
+
+          if (isCalled) {
+            if (maxTimeoutId) {
+              maxTimeoutId = clearTimeout(maxTimeoutId);
+            }
+            lastCalled = stamp;
+            result = func.apply(thisArg, args);
+          }
+          else if (!maxTimeoutId) {
+            maxTimeoutId = setTimeout(maxDelayed, remaining);
+          }
+        }
+        if (isCalled && timeoutId) {
+          timeoutId = clearTimeout(timeoutId);
+        }
+        else if (!timeoutId && wait !== maxWait) {
+          timeoutId = setTimeout(delayed, wait);
+        }
+        if (leadingCall) {
+          isCalled = true;
+          result = func.apply(thisArg, args);
+        }
+        if (isCalled && !timeoutId && !maxTimeoutId) {
+          args = thisArg = null;
+        }
+        return result;
+      };
+    }
+
+    /**
+     * Defers executing the `func` function until the current call stack has 
cleared.
+     * Additional arguments will be provided to `func` when it is invoked.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to defer.
+     * @param {...*} [arg] Arguments to invoke the function with.
+     * @returns {number} Returns the timer id.
+     * @example
+     *
+     * _.defer(function(text) { console.log(text); }, 'deferred');
+     * // logs 'deferred' after one or more milliseconds
+     */
+    function defer(func) {
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      var args = slice(arguments, 1);
+      return setTimeout(function() { func.apply(undefined, args); }, 1);
+    }
+
+    /**
+     * Executes the `func` function after `wait` milliseconds. Additional 
arguments
+     * will be provided to `func` when it is invoked.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to delay.
+     * @param {number} wait The number of milliseconds to delay execution.
+     * @param {...*} [arg] Arguments to invoke the function with.
+     * @returns {number} Returns the timer id.
+     * @example
+     *
+     * _.delay(function(text) { console.log(text); }, 1000, 'later');
+     * // => logs 'later' after one second
+     */
+    function delay(func, wait) {
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      var args = slice(arguments, 2);
+      return setTimeout(function() { func.apply(undefined, args); }, wait);
+    }
+
+    /**
+     * Creates a function that memoizes the result of `func`. If `resolver` is
+     * provided it will be used to determine the cache key for storing the 
result
+     * based on the arguments provided to the memoized function. By default, 
the
+     * first argument provided to the memoized function is used as the cache 
key.
+     * The `func` is executed with the `this` binding of the memoized function.
+     * The result cache is exposed as the `cache` property on the memoized 
function.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to have its output memoized.
+     * @param {Function} [resolver] A function used to resolve the cache key.
+     * @returns {Function} Returns the new memoizing function.
+     * @example
+     *
+     * var fibonacci = _.memoize(function(n) {
+     *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
+     * });
+     *
+     * fibonacci(9)
+     * // => 34
+     *
+     * var data = {
+     *   'fred': { 'name': 'fred', 'age': 40 },
+     *   'pebbles': { 'name': 'pebbles', 'age': 1 }
+     * };
+     *
+     * // modifying the result cache
+     * var get = _.memoize(function(name) { return data[name]; }, _.identity);
+     * get('pebbles');
+     * // => { 'name': 'pebbles', 'age': 1 }
+     *
+     * get.cache.pebbles.name = 'penelope';
+     * get('pebbles');
+     * // => { 'name': 'penelope', 'age': 1 }
+     */
+    function memoize(func, resolver) {
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      var memoized = function() {
+        var cache = memoized.cache,
+            key = resolver ? resolver.apply(this, arguments) : keyPrefix + 
arguments[0];
+
+        return hasOwnProperty.call(cache, key)
+          ? cache[key]
+          : (cache[key] = func.apply(this, arguments));
+      }
+      memoized.cache = {};
+      return memoized;
+    }
+
+    /**
+     * Creates a function that is restricted to execute `func` once. Repeat 
calls to
+     * the function will return the value of the first call. The `func` is 
executed
+     * with the `this` binding of the created function.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to restrict.
+     * @returns {Function} Returns the new restricted function.
+     * @example
+     *
+     * var initialize = _.once(createApplication);
+     * initialize();
+     * initialize();
+     * // `initialize` executes `createApplication` once
+     */
+    function once(func) {
+      var ran,
+          result;
+
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      return function() {
+        if (ran) {
+          return result;
+        }
+        ran = true;
+        result = func.apply(this, arguments);
+
+        // clear the `func` variable so the function may be garbage collected
+        func = null;
+        return result;
+      };
+    }
+
+    /**
+     * Creates a function that, when called, invokes `func` with any additional
+     * `partial` arguments prepended to those provided to the new function. 
This
+     * method is similar to `_.bind` except it does **not** alter the `this` 
binding.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to partially apply arguments to.
+     * @param {...*} [arg] Arguments to be partially applied.
+     * @returns {Function} Returns the new partially applied function.
+     * @example
+     *
+     * var greet = function(greeting, name) { return greeting + ' ' + name; };
+     * var hi = _.partial(greet, 'hi');
+     * hi('fred');
+     * // => 'hi fred'
+     */
+    function partial(func) {
+      return createWrapper(func, 16, slice(arguments, 1));
+    }
+
+    /**
+     * This method is like `_.partial` except that `partial` arguments are
+     * appended to those provided to the new function.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to partially apply arguments to.
+     * @param {...*} [arg] Arguments to be partially applied.
+     * @returns {Function} Returns the new partially applied function.
+     * @example
+     *
+     * var defaultsDeep = _.partialRight(_.merge, _.defaults);
+     *
+     * var options = {
+     *   'variable': 'data',
+     *   'imports': { 'jq': $ }
+     * };
+     *
+     * defaultsDeep(options, _.templateSettings);
+     *
+     * options.variable
+     * // => 'data'
+     *
+     * options.imports
+     * // => { '_': _, 'jq': $ }
+     */
+    function partialRight(func) {
+      return createWrapper(func, 32, null, slice(arguments, 1));
+    }
+
+    /**
+     * Creates a function that, when executed, will only call the `func` 
function
+     * at most once per every `wait` milliseconds. Provide an options object to
+     * indicate that `func` should be invoked on the leading and/or trailing 
edge
+     * of the `wait` timeout. Subsequent calls to the throttled function will
+     * return the result of the last `func` call.
+     *
+     * Note: If `leading` and `trailing` options are `true` `func` will be 
called
+     * on the trailing edge of the timeout only if the the throttled function 
is
+     * invoked more than once during the `wait` timeout.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {Function} func The function to throttle.
+     * @param {number} wait The number of milliseconds to throttle executions 
to.
+     * @param {Object} [options] The options object.
+     * @param {boolean} [options.leading=true] Specify execution on the 
leading edge of the timeout.
+     * @param {boolean} [options.trailing=true] Specify execution on the 
trailing edge of the timeout.
+     * @returns {Function} Returns the new throttled function.
+     * @example
+     *
+     * // avoid excessively updating the position while scrolling
+     * var throttled = _.throttle(updatePosition, 100);
+     * jQuery(window).on('scroll', throttled);
+     *
+     * // execute `renewToken` when the click event is fired, but not more 
than once every 5 minutes
+     * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
+     *   'trailing': false
+     * }));
+     */
+    function throttle(func, wait, options) {
+      var leading = true,
+          trailing = true;
+
+      if (!isFunction(func)) {
+        throw new TypeError;
+      }
+      if (options === false) {
+        leading = false;
+      } else if (isObject(options)) {
+        leading = 'leading' in options ? options.leading : leading;
+        trailing = 'trailing' in options ? options.trailing : trailing;
+      }
+      debounceOptions.leading = leading;
+      debounceOptions.maxWait = wait;
+      debounceOptions.trailing = trailing;
+
+      return debounce(func, wait, debounceOptions);
+    }
+
+    /**
+     * Creates a function that provides `value` to the wrapper function as its
+     * first argument. Additional arguments provided to the function are 
appended
+     * to those provided to the wrapper function. The wrapper is executed with
+     * the `this` binding of the created function.
+     *
+     * @static
+     * @memberOf _
+     * @category Functions
+     * @param {*} value The value to wrap.
+     * @param {Function} wrapper The wrapper function.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var p = _.wrap(_.escape, function(func, text) {
+     *   return '<p>' + func(text) + '</p>';
+     * });
+     *
+     * p('Fred, Wilma, & Pebbles');
+     * // => '<p>Fred, Wilma, &amp; Pebbles</p>'
+     */
+    function wrap(value, wrapper) {
+      return createWrapper(wrapper, 16, [value]);
+    }
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Creates a function that returns `value`.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {*} value The value to return from the new function.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var object = { 'name': 'fred' };
+     * var getter = _.constant(object);
+     * getter() === object;
+     * // => true
+     */
+    function constant(value) {
+      return function() {
+        return value;
+      };
+    }
+
+    /**
+     * Produces a callback bound to an optional `thisArg`. If `func` is a 
property
+     * name the created callback will return the property value for a given 
element.
+     * If `func` is an object the created callback will return `true` for 
elements
+     * that contain the equivalent object properties, otherwise it will return 
`false`.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {*} [func=identity] The value to convert to a callback.
+     * @param {*} [thisArg] The `this` binding of the created callback.
+     * @param {number} [argCount] The number of arguments the callback accepts.
+     * @returns {Function} Returns a callback function.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * // wrap to create custom callback shorthands
+     * _.createCallback = _.wrap(_.createCallback, function(func, callback, 
thisArg) {
+     *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
+     *   return !match ? func(callback, thisArg) : function(object) {
+     *     return match[2] == 'gt' ? object[match[1]] > match[3] : 
object[match[1]] < match[3];
+     *   };
+     * });
+     *
+     * _.filter(characters, 'age__gt38');
+     * // => [{ 'name': 'fred', 'age': 40 }]
+     */
+    function createCallback(func, thisArg, argCount) {
+      var type = typeof func;
+      if (func == null || type == 'function') {
+        return baseCreateCallback(func, thisArg, argCount);
+      }
+      // handle "_.pluck" style callback shorthands
+      if (type != 'object') {
+        return property(func);
+      }
+      var props = keys(func),
+          key = props[0],
+          a = func[key];
+
+      // handle "_.where" style callback shorthands
+      if (props.length == 1 && a === a && !isObject(a)) {
+        // fast path the common case of providing an object with a single
+        // property containing a primitive value
+        return function(object) {
+          var b = object[key];
+          return a === b && (a !== 0 || (1 / a == 1 / b));
+        };
+      }
+      return function(object) {
+        var length = props.length,
+            result = false;
+
+        while (length--) {
+          if (!(result = baseIsEqual(object[props[length]], 
func[props[length]], null, true))) {
+            break;
+          }
+        }
+        return result;
+      };
+    }
+
+    /**
+     * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
+     * corresponding HTML entities.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {string} string The string to escape.
+     * @returns {string} Returns the escaped string.
+     * @example
+     *
+     * _.escape('Fred, Wilma, & Pebbles');
+     * // => 'Fred, Wilma, &amp; Pebbles'
+     */
+    function escape(string) {
+      return string == null ? '' : String(string).replace(reUnescapedHtml, 
escapeHtmlChar);
+    }
+
+    /**
+     * This method returns the first argument provided to it.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {*} value Any value.
+     * @returns {*} Returns `value`.
+     * @example
+     *
+     * var object = { 'name': 'fred' };
+     * _.identity(object) === object;
+     * // => true
+     */
+    function identity(value) {
+      return value;
+    }
+
+    /**
+     * Adds function properties of a source object to the destination object.
+     * If `object` is a function methods will be added to its prototype as 
well.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {Function|Object} [object=lodash] object The destination object.
+     * @param {Object} source The object of functions to add.
+     * @param {Object} [options] The options object.
+     * @param {boolean} [options.chain=true] Specify whether the functions 
added are chainable.
+     * @example
+     *
+     * function capitalize(string) {
+     *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
+     * }
+     *
+     * _.mixin({ 'capitalize': capitalize });
+     * _.capitalize('fred');
+     * // => 'Fred'
+     *
+     * _('fred').capitalize().value();
+     * // => 'Fred'
+     *
+     * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
+     * _('fred').capitalize();
+     * // => 'Fred'
+     */
+    function mixin(object, source, options) {
+      var chain = true,
+          methodNames = source && functions(source);
+
+      if (!source || (!options && !methodNames.length)) {
+        if (options == null) {
+          options = source;
+        }
+        ctor = lodashWrapper;
+        source = object;
+        object = lodash;
+        methodNames = functions(source);
+      }
+      if (options === false) {
+        chain = false;
+      } else if (isObject(options) && 'chain' in options) {
+        chain = options.chain;
+      }
+      var ctor = object,
+          isFunc = isFunction(ctor);
+
+      forEach(methodNames, function(methodName) {
+        var func = object[methodName] = source[methodName];
+        if (isFunc) {
+          ctor.prototype[methodName] = function() {
+            var chainAll = this.__chain__,
+                value = this.__wrapped__,
+                args = [value];
+
+            push.apply(args, arguments);
+            var result = func.apply(object, args);
+            if (chain || chainAll) {
+              if (value === result && isObject(result)) {
+                return this;
+              }
+              result = new ctor(result);
+              result.__chain__ = chainAll;
+            }
+            return result;
+          };
+        }
+      });
+    }
+
+    /**
+     * Reverts the '_' variable to its previous value and returns a reference 
to
+     * the `lodash` function.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @returns {Function} Returns the `lodash` function.
+     * @example
+     *
+     * var lodash = _.noConflict();
+     */
+    function noConflict() {
+      context._ = oldDash;
+      return this;
+    }
+
+    /**
+     * A no-operation function.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @example
+     *
+     * var object = { 'name': 'fred' };
+     * _.noop(object) === undefined;
+     * // => true
+     */
+    function noop() {
+      // no operation performed
+    }
+
+    /**
+     * Gets the number of milliseconds that have elapsed since the Unix epoch
+     * (1 January 1970 00:00:00 UTC).
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @example
+     *
+     * var stamp = _.now();
+     * _.defer(function() { console.log(_.now() - stamp); });
+     * // => logs the number of milliseconds it took for the deferred function 
to be called
+     */
+    var now = isNative(now = Date.now) && now || function() {
+      return new Date().getTime();
+    };
+
+    /**
+     * Converts the given value into an integer of the specified radix.
+     * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
+     * `value` is a hexadecimal, in which case a `radix` of `16` is used.
+     *
+     * Note: This method avoids differences in native ES3 and ES5 `parseInt`
+     * implementations. See http://es5.github.io/#E.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {string} value The value to parse.
+     * @param {number} [radix] The radix used to interpret the value to parse.
+     * @returns {number} Returns the new integer value.
+     * @example
+     *
+     * _.parseInt('08');
+     * // => 8
+     */
+    var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : 
function(value, radix) {
+      // Firefox < 21 and Opera < 15 follow the ES3 specified implementation 
of `parseInt`
+      return nativeParseInt(isString(value) ? 
value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
+    };
+
+    /**
+     * Creates a "_.pluck" style function, which returns the `key` value of a
+     * given object.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {string} key The name of the property to retrieve.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'fred',   'age': 40 },
+     *   { 'name': 'barney', 'age': 36 }
+     * ];
+     *
+     * var getName = _.property('name');
+     *
+     * _.map(characters, getName);
+     * // => ['barney', 'fred']
+     *
+     * _.sortBy(characters, getName);
+     * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
+     */
+    function property(key) {
+      return function(object) {
+        return object[key];
+      };
+    }
+
+    /**
+     * Produces a random number between `min` and `max` (inclusive). If only 
one
+     * argument is provided a number between `0` and the given number will be
+     * returned. If `floating` is truey or either `min` or `max` are floats a
+     * floating-point number will be returned instead of an integer.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {number} [min=0] The minimum possible value.
+     * @param {number} [max=1] The maximum possible value.
+     * @param {boolean} [floating=false] Specify returning a floating-point 
number.
+     * @returns {number} Returns a random number.
+     * @example
+     *
+     * _.random(0, 5);
+     * // => an integer between 0 and 5
+     *
+     * _.random(5);
+     * // => also an integer between 0 and 5
+     *
+     * _.random(5, true);
+     * // => a floating-point number between 0 and 5
+     *
+     * _.random(1.2, 5.2);
+     * // => a floating-point number between 1.2 and 5.2
+     */
+    function random(min, max, floating) {
+      var noMin = min == null,
+          noMax = max == null;
+
+      if (floating == null) {
+        if (typeof min == 'boolean' && noMax) {
+          floating = min;
+          min = 1;
+        }
+        else if (!noMax && typeof max == 'boolean') {
+          floating = max;
+          noMax = true;
+        }
+      }
+      if (noMin && noMax) {
+        max = 1;
+      }
+      min = +min || 0;
+      if (noMax) {
+        max = min;
+        min = 0;
+      } else {
+        max = +max || 0;
+      }
+      if (floating || min % 1 || max % 1) {
+        var rand = nativeRandom();
+        return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand 
+'').length - 1)))), max);
+      }
+      return baseRandom(min, max);
+    }
+
+    /**
+     * Resolves the value of property `key` on `object`. If `key` is a function
+     * it will be invoked with the `this` binding of `object` and its result 
returned,
+     * else the property value is returned. If `object` is falsey then 
`undefined`
+     * is returned.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {Object} object The object to inspect.
+     * @param {string} key The name of the property to resolve.
+     * @returns {*} Returns the resolved value.
+     * @example
+     *
+     * var object = {
+     *   'cheese': 'crumpets',
+     *   'stuff': function() {
+     *     return 'nonsense';
+     *   }
+     * };
+     *
+     * _.result(object, 'cheese');
+     * // => 'crumpets'
+     *
+     * _.result(object, 'stuff');
+     * // => 'nonsense'
+     */
+    function result(object, key) {
+      if (object) {
+        var value = object[key];
+        return isFunction(value) ? object[key]() : value;
+      }
+    }
+
+    /**
+     * A micro-templating method that handles arbitrary delimiters, preserves
+     * whitespace, and correctly escapes quotes within interpolated code.
+     *
+     * Note: In the development build, `_.template` utilizes sourceURLs for 
easier
+     * debugging. See 
http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+     *
+     * For more information on precompiling templates see:
+     * http://lodash.com/custom-builds
+     *
+     * For more information on Chrome extension sandboxes see:
+     * http://developer.chrome.com/stable/extensions/sandboxingEval.html
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {string} text The template text.
+     * @param {Object} data The data object used to populate the text.
+     * @param {Object} [options] The options object.
+     * @param {RegExp} [options.escape] The "escape" delimiter.
+     * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
+     * @param {Object} [options.imports] An object to import into the template 
as local variables.
+     * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
+     * @param {string} [sourceURL] The sourceURL of the template's compiled 
source.
+     * @param {string} [variable] The data object variable name.
+     * @returns {Function|string} Returns a compiled function when no `data` 
object
+     *  is given, else it returns the interpolated text.
+     * @example
+     *
+     * // using the "interpolate" delimiter to create a compiled template
+     * var compiled = _.template('hello <%= name %>');
+     * compiled({ 'name': 'fred' });
+     * // => 'hello fred'
+     *
+     * // using the "escape" delimiter to escape HTML in data property values
+     * _.template('<b><%- value %></b>', { 'value': '<script>' });
+     * // => '<b>&lt;script&gt;</b>'
+     *
+     * // using the "evaluate" delimiter to generate HTML
+     * var list = '<% _.forEach(people, function(name) { %><li><%- name 
%></li><% }); %>';
+     * _.template(list, { 'people': ['fred', 'barney'] });
+     * // => '<li>fred</li><li>barney</li>'
+     *
+     * // using the ES6 delimiter as an alternative to the default 
"interpolate" delimiter
+     * _.template('hello ${ name }', { 'name': 'pebbles' });
+     * // => 'hello pebbles'
+     *
+     * // using the internal `print` function in "evaluate" delimiters
+     * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
+     * // => 'hello barney!'
+     *
+     * // using a custom template delimiters
+     * _.templateSettings = {
+     *   'interpolate': /{{([\s\S]+?)}}/g
+     * };
+     *
+     * _.template('hello {{ name }}!', { 'name': 'mustache' });
+     * // => 'hello mustache!'
+     *
+     * // using the `imports` option to import jQuery
+     * var list = '<% jq.each(people, function(name) { %><li><%- name 
%></li><% }); %>';
+     * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': 
jQuery } });
+     * // => '<li>fred</li><li>barney</li>'
+     *
+     * // using the `sourceURL` option to specify a custom sourceURL for the 
template
+     * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': 
'/basic/greeting.jst' });
+     * compiled(data);
+     * // => find the source of "greeting.jst" under the Sources tab or 
Resources panel of the web inspector
+     *
+     * // using the `variable` option to ensure a with-statement isn't used in 
the compiled template
+     * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 
'data' });
+     * compiled.source;
+     * // => function(data) {
+     *   var __t, __p = '', __e = _.escape;
+     *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
+     *   return __p;
+     * }
+     *
+     * // using the `source` property to inline compiled templates for 
meaningful
+     * // line numbers in error messages and a stack trace
+     * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
+     *   var JST = {\
+     *     "main": ' + _.template(mainText).source + '\
+     *   };\
+     * ');
+     */
+    function template(text, data, options) {
+      // based on John Resig's `tmpl` implementation
+      // http://ejohn.org/blog/javascript-micro-templating/
+      // and Laura Doktorova's doT.js
+      // https://github.com/olado/doT
+      var settings = lodash.templateSettings;
+      text = String(text || '');
+
+      // avoid missing dependencies when `iteratorTemplate` is not defined
+      options = defaults({}, options, settings);
+
+      var imports = defaults({}, options.imports, settings.imports),
+          importsKeys = keys(imports),
+          importsValues = values(imports);
+
+      var isEvaluating,
+          index = 0,
+          interpolate = options.interpolate || reNoMatch,
+          source = "__p += '";
+
+      // compile the regexp to match each delimiter
+      var reDelimiters = RegExp(
+        (options.escape || reNoMatch).source + '|' +
+        interpolate.source + '|' +
+        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + 
'|' +
+        (options.evaluate || reNoMatch).source + '|$'
+      , 'g');
+
+      text.replace(reDelimiters, function(match, escapeValue, 
interpolateValue, esTemplateValue, evaluateValue, offset) {
+        interpolateValue || (interpolateValue = esTemplateValue);
+
+        // escape characters that cannot be included in string literals
+        source += text.slice(index, offset).replace(reUnescapedString, 
escapeStringChar);
+
+        // replace delimiters with snippets
+        if (escapeValue) {
+          source += "' +\n__e(" + escapeValue + ") +\n'";
+        }
+        if (evaluateValue) {
+          isEvaluating = true;
+          source += "';\n" + evaluateValue + ";\n__p += '";
+        }
+        if (interpolateValue) {
+          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : 
__t) +\n'";
+        }
+        index = offset + match.length;
+
+        // the JS engine embedded in Adobe products requires returning the 
`match`
+        // string in order to produce the correct `offset` value
+        return match;
+      });
+
+      source += "';\n";
+
+      // if `variable` is not specified, wrap a with-statement around the 
generated
+      // code to add the data object to the top of the scope chain
+      var variable = options.variable,
+          hasVariable = variable;
+
+      if (!hasVariable) {
+        variable = 'obj';
+        source = 'with (' + variable + ') {\n' + source + '\n}\n';
+      }
+      // cleanup code by stripping empty strings
+      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : 
source)
+        .replace(reEmptyStringMiddle, '$1')
+        .replace(reEmptyStringTrailing, '$1;');
+
+      // frame code as the function body
+      source = 'function(' + variable + ') {\n' +
+        (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
+        "var __t, __p = '', __e = _.escape" +
+        (isEvaluating
+          ? ', __j = Array.prototype.join;\n' +
+            "function print() { __p += __j.call(arguments, '') }\n"
+          : ';\n'
+        ) +
+        source +
+        'return __p\n}';
+
+      // Use a sourceURL for easier debugging.
+      // 
http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+      var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || 
'/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
+
+      try {
+        var result = Function(importsKeys, 'return ' + source + 
sourceURL).apply(undefined, importsValues);
+      } catch(e) {
+        e.source = source;
+        throw e;
+      }
+      if (data) {
+        return result(data);
+      }
+      // provide the compiled function's source by its `toString` method, in
+      // supported environments, or the `source` property as a convenience for
+      // inlining compiled templates during the build process
+      result.source = source;
+      return result;
+    }
+
+    /**
+     * Executes the callback `n` times, returning an array of the results
+     * of each callback execution. The callback is bound to `thisArg` and 
invoked
+     * with one argument; (index).
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {number} n The number of times to execute the callback.
+     * @param {Function} callback The function called per iteration.
+     * @param {*} [thisArg] The `this` binding of `callback`.
+     * @returns {Array} Returns an array of the results of each `callback` 
execution.
+     * @example
+     *
+     * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
+     * // => [3, 6, 4]
+     *
+     * _.times(3, function(n) { mage.castSpell(n); });
+     * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, 
and `2` respectively
+     *
+     * _.times(3, function(n) { this.cast(n); }, mage);
+     * // => also calls `mage.castSpell(n)` three times
+     */
+    function times(n, callback, thisArg) {
+      n = (n = +n) > -1 ? n : 0;
+      var index = -1,
+          result = Array(n);
+
+      callback = baseCreateCallback(callback, thisArg, 1);
+      while (++index < n) {
+        result[index] = callback(index);
+      }
+      return result;
+    }
+
+    /**
+     * The inverse of `_.escape` this method converts the HTML entities
+     * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
+     * corresponding characters.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {string} string The string to unescape.
+     * @returns {string} Returns the unescaped string.
+     * @example
+     *
+     * _.unescape('Fred, Barney &amp; Pebbles');
+     * // => 'Fred, Barney & Pebbles'
+     */
+    function unescape(string) {
+      return string == null ? '' : String(string).replace(reEscapedHtml, 
unescapeHtmlChar);
+    }
+
+    /**
+     * Generates a unique ID. If `prefix` is provided the ID will be appended 
to it.
+     *
+     * @static
+     * @memberOf _
+     * @category Utilities
+     * @param {string} [prefix] The value to prefix the ID with.
+     * @returns {string} Returns the unique ID.
+     * @example
+     *
+     * _.uniqueId('contact_');
+     * // => 'contact_104'
+     *
+     * _.uniqueId();
+     * // => '105'
+     */
+    function uniqueId(prefix) {
+      var id = ++idCounter;
+      return String(prefix == null ? '' : prefix) + id;
+    }
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * Creates a `lodash` object that wraps the given value with explicit
+     * method chaining enabled.
+     *
+     * @static
+     * @memberOf _
+     * @category Chaining
+     * @param {*} value The value to wrap.
+     * @returns {Object} Returns the wrapper object.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney',  'age': 36 },
+     *   { 'name': 'fred',    'age': 40 },
+     *   { 'name': 'pebbles', 'age': 1 }
+     * ];
+     *
+     * var youngest = _.chain(characters)
+     *     .sortBy('age')
+     *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
+     *     .first()
+     *     .value();
+     * // => 'pebbles is 1'
+     */
+    function chain(value) {
+      value = new lodashWrapper(value);
+      value.__chain__ = true;
+      return value;
+    }
+
+    /**
+     * Invokes `interceptor` with the `value` as the first argument and then
+     * returns `value`. The purpose of this method is to "tap into" a method
+     * chain in order to perform operations on intermediate results within
+     * the chain.
+     *
+     * @static
+     * @memberOf _
+     * @category Chaining
+     * @param {*} value The value to provide to `interceptor`.
+     * @param {Function} interceptor The function to invoke.
+     * @returns {*} Returns `value`.
+     * @example
+     *
+     * _([1, 2, 3, 4])
+     *  .tap(function(array) { array.pop(); })
+     *  .reverse()
+     *  .value();
+     * // => [3, 2, 1]
+     */
+    function tap(value, interceptor) {
+      interceptor(value);
+      return value;
+    }
+
+    /**
+     * Enables explicit method chaining on the wrapper object.
+     *
+     * @name chain
+     * @memberOf _
+     * @category Chaining
+     * @returns {*} Returns the wrapper object.
+     * @example
+     *
+     * var characters = [
+     *   { 'name': 'barney', 'age': 36 },
+     *   { 'name': 'fred',   'age': 40 }
+     * ];
+     *
+     * // without explicit chaining
+     * _(characters).first();
+     * // => { 'name': 'barney', 'age': 36 }
+     *
+     * // with explicit chaining
+     * _(characters).chain()
+     *   .first()
+     *   .pick('age')
+     *   .value();
+     * // => { 'age': 36 }
+     */
+    function wrapperChain() {
+      this.__chain__ = true;
+      return this;
+    }
+
+    /**
+     * Produces the `toString` result of the wrapped value.
+     *
+     * @name toString
+     * @memberOf _
+     * @category Chaining
+     * @returns {string} Returns the string result.
+     * @example
+     *
+     * _([1, 2, 3]).toString();
+     * // => '1,2,3'
+     */
+    function wrapperToString() {
+      return String(this.__wrapped__);
+    }
+
+    /**
+     * Extracts the wrapped value.
+     *
+     * @name valueOf
+     * @memberOf _
+     * @alias value
+     * @category Chaining
+     * @returns {*} Returns the wrapped value.
+     * @example
+     *
+     * _([1, 2, 3]).valueOf();
+     * // => [1, 2, 3]
+     */
+    function wrapperValueOf() {
+      return this.__wrapped__;
+    }
+
+    
/*--------------------------------------------------------------------------*/
+
+    // add functions that return wrapped values when chaining
+    lodash.after = after;
+    lodash.assign = assign;
+    lodash.at = at;
+    lodash.bind = bind;
+    lodash.bindAll = bindAll;
+    lodash.bindKey = bindKey;
+    lodash.chain = chain;
+    lodash.compact = compact;
+    lodash.compose = compose;
+    lodash.constant = constant;
+    lodash.countBy = countBy;
+    lodash.create = create;
+    lodash.createCallback = createCallback;
+    lodash.curry = curry;
+    lodash.debounce = debounce;
+    lodash.defaults = defaults;
+    lodash.defer = defer;
+    lodash.delay = delay;
+    lodash.difference = difference;
+    lodash.filter = filter;
+    lodash.flatten = flatten;
+    lodash.forEach = forEach;
+    lodash.forEachRight = forEachRight;
+    lodash.forIn = forIn;
+    lodash.forInRight = forInRight;
+    lodash.forOwn = forOwn;
+    lodash.forOwnRight = forOwnRight;
+    lodash.functions = functions;
+    lodash.groupBy = groupBy;
+    lodash.indexBy = indexBy;
+    lodash.initial = initial;
+    lodash.intersection = intersection;
+    lodash.invert = invert;
+    lodash.invoke = invoke;
+    lodash.keys = keys;
+    lodash.map = map;
+    lodash.mapValues = mapValues;
+    lodash.max = max;
+    lodash.memoize = memoize;
+    lodash.merge = merge;
+    lodash.min = min;
+    lodash.omit = omit;
+    lodash.once = once;
+    lodash.pairs = pairs;
+    lodash.partial = partial;
+    lodash.partialRight = partialRight;
+    lodash.pick = pick;
+    lodash.pluck = pluck;
+    lodash.property = property;
+    lodash.pull = pull;
+    lodash.range = range;
+    lodash.reject = reject;
+    lodash.remove = remove;
+    lodash.rest = rest;
+    lodash.shuffle = shuffle;
+    lodash.sortBy = sortBy;
+    lodash.tap = tap;
+    lodash.throttle = throttle;
+    lodash.times = times;
+    lodash.toArray = toArray;
+    lodash.transform = transform;
+    lodash.union = union;
+    lodash.uniq = uniq;
+    lodash.values = values;
+    lodash.where = where;
+    lodash.without = without;
+    lodash.wrap = wrap;
+    lodash.xor = xor;
+    lodash.zip = zip;
+    lodash.zipObject = zipObject;
+
+    // add aliases
+    lodash.collect = map;
+    lodash.drop = rest;
+    lodash.each = forEach;
+    lodash.eachRight = forEachRight;
+    lodash.extend = assign;
+    lodash.methods = functions;
+    lodash.object = zipObject;
+    lodash.select = filter;
+    lodash.tail = rest;
+    lodash.unique = uniq;
+    lodash.unzip = zip;
+
+    // add functions to `lodash.prototype`
+    mixin(lodash);
+
+    
/*--------------------------------------------------------------------------*/
+
+    // add functions that return unwrapped values when chaining
+    lodash.clone = clone;
+    lodash.cloneDeep = cloneDeep;
+    lodash.contains = contains;
+    lodash.escape = escape;
+    lodash.every = every;
+    lodash.find = find;
+    lodash.findIndex = findIndex;
+    lodash.findKey = findKey;
+    lodash.findLast = findLast;
+    lodash.findLastIndex = findLastIndex;
+    lodash.findLastKey = findLastKey;
+    lodash.has = has;
+    lodash.identity = identity;
+    lodash.indexOf = indexOf;
+    lodash.isArguments = isArguments;
+    lodash.isArray = isArray;
+    lodash.isBoolean = isBoolean;
+    lodash.isDate = isDate;
+    lodash.isElement = isElement;
+    lodash.isEmpty = isEmpty;
+    lodash.isEqual = isEqual;
+    lodash.isFinite = isFinite;
+    lodash.isFunction = isFunction;
+    lodash.isNaN = isNaN;
+    lodash.isNull = isNull;
+    lodash.isNumber = isNumber;
+    lodash.isObject = isObject;
+    lodash.isPlainObject = isPlainObject;
+    lodash.isRegExp = isRegExp;
+    lodash.isString = isString;
+    lodash.isUndefined = isUndefined;
+    lodash.lastIndexOf = lastIndexOf;
+    lodash.mixin = mixin;
+    lodash.noConflict = noConflict;
+    lodash.noop = noop;
+    lodash.now = now;
+    lodash.parseInt = parseInt;
+    lodash.random = random;
+    lodash.reduce = reduce;
+    lodash.reduceRight = reduceRight;
+    lodash.result = result;
+    lodash.runInContext = runInContext;
+    lodash.size = size;
+    lodash.some = some;
+    lodash.sortedIndex = sortedIndex;
+    lodash.template = template;
+    lodash.unescape = unescape;
+    lodash.uniqueId = uniqueId;
+
+    // add aliases
+    lodash.all = every;
+    lodash.any = some;
+    lodash.detect = find;
+    lodash.findWhere = find;
+    lodash.foldl = reduce;
+    lodash.foldr = reduceRight;
+    lodash.include = contains;
+    lodash.inject = reduce;
+
+    mixin(function() {
+      var source = {}
+      forOwn(lodash, function(func, methodName) {
+        if (!lodash.prototype[methodName]) {
+          source[methodName] = func;
+        }
+      });
+      return source;
+    }(), false);
+
+    
/*--------------------------------------------------------------------------*/
+
+    // add functions capable of returning wrapped and unwrapped values when 
chaining
+    lodash.first = first;
+    lodash.last = last;
+    lodash.sample = sample;
+
+    // add aliases
+    lodash.take = first;
+    lodash.head = first;
+
+    forOwn(lodash, function(func, methodName) {
+      var callbackable = methodName !== 'sample';
+      if (!lodash.prototype[methodName]) {
+        lodash.prototype[methodName]= function(n, guard) {
+          var chainAll = this.__chain__,
+              result = func(this.__wrapped__, n, guard);
+
+          return !chainAll && (n == null || (guard && !(callbackable && typeof 
n == 'function')))
+            ? result
+            : new lodashWrapper(result, chainAll);
+        };
+      }
+    });
+
+    
/*--------------------------------------------------------------------------*/
+
+    /**
+     * The semantic version number.
+     *
+     * @static
+     * @memberOf _
+     * @type string
+     */
+    lodash.VERSION = '2.4.1';
+
+    // add "Chaining" functions to the wrapper
+    lodash.prototype.chain = wrapperChain;
+    lodash.prototype.toString = wrapperToString;
+    lodash.prototype.value = wrapperValueOf;
+    lodash.prototype.valueOf = wrapperValueOf;
+
+    // add `Array` functions that return unwrapped values
+    forEach(['join', 'pop', 'shift'], function(methodName) {
+      var func = arrayRef[methodName];
+      lodash.prototype[methodName] = function() {
+        var chainAll = this.__chain__,
+            result = func.apply(this.__wrapped__, arguments);
+
+        return chainAll
+          ? new lodashWrapper(result, chainAll)
+          : result;
+      };
+    });
+
+    // add `Array` functions that return the existing wrapped value
+    forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
+      var func = arrayRef[methodName];
+      lodash.prototype[methodName] = function() {
+        func.apply(this.__wrapped__, arguments);
+        return this;
+      };
+    });
+
+    // add `Array` functions that return new wrapped values
+    forEach(['concat', 'slice', 'splice'], function(methodName) {
+      var func = arrayRef[methodName];
+      lodash.prototype[methodName] = function() {
+        return new lodashWrapper(func.apply(this.__wrapped__, arguments), 
this.__chain__);
+      };
+    });
+
+    return lodash;
+  }
+
+  
/*--------------------------------------------------------------------------*/
+
+  // expose Lo-Dash
+  var _ = runInContext();
+
+  // some AMD build optimizers like r.js check for condition patterns like the 
following:
+  if (typeof define == 'function' && typeof define.amd == 'object' && 
define.amd) {
+    // Expose Lo-Dash to the global object even when an AMD loader is present 
in
+    // case Lo-Dash is loaded with a RequireJS shim config.
+    // See http://requirejs.org/docs/api.html#config-shim
+    root._ = _;
+
+    // define as an anonymous module so, through path mapping, it can be
+    // referenced as the "underscore" module
+    define(function() {
+      return _;
+    });
+  }
+  // check for `exports` after `define` in case a build optimizer adds an 
`exports` object
+  else if (freeExports && freeModule) {
+    // in Node.js or RingoJS
+    if (moduleExports) {
+      (freeModule.exports = _)._ = _;
+    }
+    // in Narwhal or Rhino -require
+    else {
+      freeExports._ = _;
+    }
+  }
+  else {
+    // in a browser or Rhino
+    root._ = _;
+  }
+}.call(this));
diff --git a/packages/context-coloring/benchmark/fixtures/mkdirp-0.5.0.js 
b/packages/context-coloring/benchmark/fixtures/mkdirp-0.5.0.js
new file mode 100644
index 0000000..a1742b2
--- /dev/null
+++ b/packages/context-coloring/benchmark/fixtures/mkdirp-0.5.0.js
@@ -0,0 +1,97 @@
+var path = require('path');
+var fs = require('fs');
+
+module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;
+
+function mkdirP (p, opts, f, made) {
+    if (typeof opts === 'function') {
+        f = opts;
+        opts = {};
+    }
+    else if (!opts || typeof opts !== 'object') {
+        opts = { mode: opts };
+    }
+    
+    var mode = opts.mode;
+    var xfs = opts.fs || fs;
+    
+    if (mode === undefined) {
+        mode = 0777 & (~process.umask());
+    }
+    if (!made) made = null;
+    
+    var cb = f || function () {};
+    p = path.resolve(p);
+    
+    xfs.mkdir(p, mode, function (er) {
+        if (!er) {
+            made = made || p;
+            return cb(null, made);
+        }
+        switch (er.code) {
+            case 'ENOENT':
+                mkdirP(path.dirname(p), opts, function (er, made) {
+                    if (er) cb(er, made);
+                    else mkdirP(p, opts, cb, made);
+                });
+                break;
+
+            // In the case of any other error, just see if there's a dir
+            // there already.  If so, then hooray!  If not, then something
+            // is borked.
+            default:
+                xfs.stat(p, function (er2, stat) {
+                    // if the stat fails, then that's super weird.
+                    // let the original error be the failure reason.
+                    if (er2 || !stat.isDirectory()) cb(er, made)
+                    else cb(null, made);
+                });
+                break;
+        }
+    });
+}
+
+mkdirP.sync = function sync (p, opts, made) {
+    if (!opts || typeof opts !== 'object') {
+        opts = { mode: opts };
+    }
+    
+    var mode = opts.mode;
+    var xfs = opts.fs || fs;
+    
+    if (mode === undefined) {
+        mode = 0777 & (~process.umask());
+    }
+    if (!made) made = null;
+
+    p = path.resolve(p);
+
+    try {
+        xfs.mkdirSync(p, mode);
+        made = made || p;
+    }
+    catch (err0) {
+        switch (err0.code) {
+            case 'ENOENT' :
+                made = sync(path.dirname(p), opts, made);
+                sync(p, opts, made);
+                break;
+
+            // In the case of any other error, just see if there's a dir
+            // there already.  If so, then hooray!  If not, then something
+            // is borked.
+            default:
+                var stat;
+                try {
+                    stat = xfs.statSync(p);
+                }
+                catch (err1) {
+                    throw err0;
+                }
+                if (!stat.isDirectory()) throw err0;
+                break;
+        }
+    }
+
+    return made;
+};
diff --git a/packages/context-coloring/context-coloring.el 
b/packages/context-coloring/context-coloring.el
new file mode 100644
index 0000000..849d392
--- /dev/null
+++ b/packages/context-coloring/context-coloring.el
@@ -0,0 +1,859 @@
+;;; context-coloring.el --- Syntax highlighting, except not for syntax. -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2015  Free Software Foundation, Inc.
+
+;; Author: Jackson Ray Hamilton <address@hidden>
+;; URL: https://github.com/jacksonrayhamilton/context-coloring
+;; Keywords: context coloring syntax highlighting
+;; Version: 6.0.0
+;; Package-Requires: ((emacs "24") (js2-mode "20150126"))
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Highlights code according to function context.
+
+;; - Code in the global scope is one color.  Code in functions within the 
global
+;;   scope is a different color, and code within such functions is another
+;;   color, and so on.
+;; - Identifiers retain the color of the scope in which they are declared.
+
+;; Lexical scope information at-a-glance can assist a programmer in
+;; understanding the overall structure of a program.  It can help to curb nasty
+;; bugs like name shadowing.  A rainbow can indicate excessive complexity.
+;; State change within a closure is easily monitored.
+
+;; By default, Context Coloring still highlights comments and strings
+;; syntactically.  It is still easy to differentiate code from non-code, and
+;; strings cannot be confused for variables.
+
+;; To use, add the following to your ~/.emacs:
+
+;; (require 'context-coloring)
+;; (add-hook 'js2-mode-hook 'context-coloring-mode)
+
+;; js-mode or js3-mode support requires Node.js 0.10+ and the scopifier
+;; executable.
+
+;; $ npm install -g scopifier
+
+;;; Code:
+
+(require 'js2-mode)
+
+
+;;; Local variables
+
+(defvar-local context-coloring-buffer nil
+  "Reference to this buffer (for timers).")
+
+
+;;; Faces
+
+(defun context-coloring-defface (level tty light dark)
+  "Define a face for LEVEL with colors for TTY, LIGHT and DARK
+backgrounds."
+  (let ((face (intern (format "context-coloring-level-%s-face" level)))
+        (doc (format "Context coloring face, level %s." level)))
+    (custom-declare-face
+     face
+     `((((type tty)) (:foreground ,tty))
+       (((background light)) (:foreground ,light))
+       (((background dark)) (:foreground ,dark)))
+     doc
+     :group 'context-coloring)))
+
+(defun context-coloring-defface-neutral (level)
+  "Define a face for LEVEL with the default neutral colors."
+  (context-coloring-defface level nil "#3f3f3f" "#cdcdcd"))
+
+(context-coloring-defface 0 nil       "#000000" "#ffffff")
+(context-coloring-defface 1 "yellow"  "#007f80" "#ffff80")
+(context-coloring-defface 2 "green"   "#001580" "#cdfacd")
+(context-coloring-defface 3 "cyan"    "#550080" "#d8d8ff")
+(context-coloring-defface 4 "blue"    "#802b00" "#e7c7ff")
+(context-coloring-defface 5 "magenta" "#6a8000" "#ffcdcd")
+(context-coloring-defface 6 "red"     "#008000" "#ffe390")
+(context-coloring-defface-neutral 7)
+
+(defvar context-coloring-maximum-face nil
+  "Index of the highest face available for coloring.")
+
+(defvar context-coloring-original-maximum-face nil
+  "Fallback value for `context-coloring-maximum-face' when all
+  themes have been disabled.")
+
+(setq context-coloring-maximum-face 7)
+
+(setq context-coloring-original-maximum-face
+      context-coloring-maximum-face)
+
+;; Theme authors can have up to 26 levels: 1 (0th) for globals, 24 (1st-24th)
+;; for nested levels, and 1 (25th) for infinity.
+(dotimes (number 18)
+  (context-coloring-defface-neutral (+ number context-coloring-maximum-face 
1)))
+
+
+;;; Face functions
+
+(defsubst context-coloring-level-face (level)
+  "Return the symbol for a face with LEVEL."
+  ;; `concat' is faster than `format' here.
+  (intern-soft
+   (concat "context-coloring-level-" (number-to-string level) "-face")))
+
+(defsubst context-coloring-bounded-level-face (level)
+  "Return the symbol for a face with LEVEL, bounded by
+`context-coloring-maximum-face'."
+  (context-coloring-level-face (min level context-coloring-maximum-face)))
+
+
+;;; Colorization utilities
+
+(defsubst context-coloring-colorize-region (start end level)
+  "Color characters from the 1-indexed START point (inclusive) to
+the END point (exclusive) with the face corresponding to LEVEL."
+  (add-text-properties
+   start
+   end
+   `(face ,(context-coloring-bounded-level-face level))))
+
+(defcustom context-coloring-comments-and-strings t
+  "If non-nil, also color comments and strings using `font-lock'."
+  :group 'context-coloring)
+
+(defsubst context-coloring-maybe-colorize-comments-and-strings ()
+  "Color the current buffer's comments and strings if
+`context-coloring-comments-and-strings' is non-nil."
+  (when context-coloring-comments-and-strings
+    (save-excursion
+      (font-lock-fontify-syntactically-region (point-min) (point-max)))))
+
+
+;;; js2-mode colorization
+
+(defvar-local context-coloring-js2-scope-level-hash-table nil
+  "Associate `js2-scope' structures and with their scope
+  levels.")
+
+(defcustom context-coloring-js-block-scopes nil
+  "If non-nil, also color block scopes in the scope hierarchy in JavaScript.
+
+The block-scoped `let' and `const' are introduced in ES6.  Enable
+this for ES6 code; disable it elsewhere.
+
+Supported modes: `js2-mode'"
+  :group 'context-coloring)
+
+(defsubst context-coloring-js2-scope-level (scope)
+  "Return the level of SCOPE."
+  (cond ((gethash scope context-coloring-js2-scope-level-hash-table))
+        (t
+         (let ((level 0)
+               (current-scope scope)
+               enclosing-scope)
+           (while (and current-scope
+                       (js2-node-parent current-scope)
+                       (setq enclosing-scope
+                             (js2-node-get-enclosing-scope current-scope)))
+             (when (or context-coloring-js-block-scopes
+                       (let ((type (js2-scope-type current-scope)))
+                         (or (= type js2-SCRIPT)
+                             (= type js2-FUNCTION)
+                             (= type js2-CATCH))))
+               (setq level (+ level 1)))
+             (setq current-scope enclosing-scope))
+           (puthash scope level 
context-coloring-js2-scope-level-hash-table)))))
+
+(defsubst context-coloring-js2-local-name-node-p (node)
+  "Determine if NODE is a `js2-name-node' representing a local
+variable."
+  (and (js2-name-node-p node)
+       (let ((parent (js2-node-parent node)))
+         (not (or (and (js2-object-prop-node-p parent)
+                       (eq node (js2-object-prop-node-left parent)))
+                  (and (js2-prop-get-node-p parent)
+                       ;; For nested property lookup, the node on the left is a
+                       ;; `js2-prop-get-node', so this always works.
+                       (eq node (js2-prop-get-node-right parent))))))))
+
+(defsubst context-coloring-js2-colorize-node (node level)
+  "Color NODE with the color for LEVEL."
+  (let ((start (js2-node-abs-pos node)))
+    (context-coloring-colorize-region
+     start
+     (+ start (js2-node-len node)) ; End
+     level)))
+
+(defun context-coloring-js2-colorize ()
+  "Color the current buffer using the abstract syntax tree
+generated by `js2-mode'."
+  ;; Reset the hash table; the old one could be obsolete.
+  (setq context-coloring-js2-scope-level-hash-table (make-hash-table :test 
'eq))
+  (with-silent-modifications
+    (js2-visit-ast
+     js2-mode-ast
+     (lambda (node end-p)
+       (when (null end-p)
+         (cond
+          ((js2-scope-p node)
+           (context-coloring-js2-colorize-node
+            node
+            (context-coloring-js2-scope-level node)))
+          ((context-coloring-js2-local-name-node-p node)
+           (let* ((enclosing-scope (js2-node-get-enclosing-scope node))
+                  (defining-scope (js2-get-defining-scope
+                                   enclosing-scope
+                                   (js2-name-node-name node))))
+             ;; The tree seems to be walked lexically, so an entire scope will
+             ;; be colored, including its name nodes, before they are reached.
+             ;; Coloring the nodes defined in that scope would be redundant, so
+             ;; don't do it.
+             (when (not (eq defining-scope enclosing-scope))
+               (context-coloring-js2-colorize-node
+                node
+                (context-coloring-js2-scope-level defining-scope))))))
+         ;; The `t' indicates to search children.
+         t)))
+    (context-coloring-maybe-colorize-comments-and-strings)))
+
+
+;;; Shell command scopification / colorization
+
+(defun context-coloring-apply-tokens (tokens)
+  "Process a vector of TOKENS to apply context-based coloring to
+the current buffer.  Tokens are 3 integers: start, end, level.
+The vector is flat, with a new token occurring after every 3rd
+element."
+  (with-silent-modifications
+    (let ((i 0)
+          (len (length tokens)))
+      (while (< i len)
+        (context-coloring-colorize-region
+         (elt tokens i)
+         (elt tokens (+ i 1))
+         (elt tokens (+ i 2)))
+        (setq i (+ i 3))))
+    (context-coloring-maybe-colorize-comments-and-strings)))
+
+(defun context-coloring-parse-array (array)
+  "Parse ARRAY as a flat JSON array of numbers."
+  (vconcat
+   (mapcar 'string-to-number (split-string (substring array 1 -1) ","))))
+
+(defvar-local context-coloring-scopifier-process nil
+  "The single scopifier process that can be running.")
+
+(defun context-coloring-kill-scopifier ()
+  "Kill the currently-running scopifier process."
+  (when (not (null context-coloring-scopifier-process))
+    (delete-process context-coloring-scopifier-process)
+    (setq context-coloring-scopifier-process nil)))
+
+(defun context-coloring-scopify-shell-command (command &optional callback)
+  "Invoke a scopifier via COMMAND with the current buffer's contents,
+read the scopifier's response asynchronously and apply a parsed
+list of tokens to `context-coloring-apply-tokens'.
+
+Invoke CALLBACK when complete."
+
+  ;; Prior running tokenization is implicitly obsolete if this function is
+  ;; called.
+  (context-coloring-kill-scopifier)
+
+  ;; Start the process.
+  (setq context-coloring-scopifier-process
+        (start-process-shell-command "scopifier" nil command))
+
+  (let ((output "")
+        (buffer context-coloring-buffer))
+
+    ;; The process may produce output in multiple chunks.  This filter
+    ;; accumulates the chunks into a message.
+    (set-process-filter
+     context-coloring-scopifier-process
+     (lambda (_process chunk)
+       (setq output (concat output chunk))))
+
+    ;; When the process's message is complete, this sentinel parses it as JSON
+    ;; and applies the tokens to the buffer.
+    (set-process-sentinel
+     context-coloring-scopifier-process
+     (lambda (_process event)
+       (when (equal "finished\n" event)
+         (let ((tokens (context-coloring-parse-array output)))
+           (with-current-buffer buffer
+             (context-coloring-apply-tokens tokens))
+           (setq context-coloring-scopifier-process nil)
+           (when callback (funcall callback)))))))
+
+  ;; Give the process its input so it can begin.
+  (process-send-region
+   context-coloring-scopifier-process
+   (point-min) (point-max))
+  (process-send-eof
+   context-coloring-scopifier-process))
+
+
+;;; Dispatch
+
+(defvar context-coloring-dispatch-hash-table (make-hash-table :test 'eq)
+  "Map dispatch strategy names to their corresponding property
+  lists, which contain details about the strategies.")
+
+(defvar context-coloring-mode-hash-table (make-hash-table :test 'eq)
+  "Map major mode names to dispatch property lists.")
+
+(defun context-coloring-select-dispatch (mode dispatch)
+  "Use DISPATCH for MODE."
+  (puthash
+   mode
+   (gethash
+    dispatch
+    context-coloring-dispatch-hash-table)
+   context-coloring-mode-hash-table))
+
+(defun context-coloring-define-dispatch (symbol &rest properties)
+  "Define a new dispatch named SYMBOL with PROPERTIES.
+
+A \"dispatch\" is a property list describing a strategy for
+coloring a buffer.  There are three possible strategies: Parse
+and color in a single function (`:colorizer'), parse in a
+function that returns scope data (`:scopifier'), or parse with a
+shell command that returns scope data (`:command').  In the
+latter two cases, the scope data will be used to automatically
+color the buffer.
+
+PROPERTIES must include `:modes' and one of `:colorizer',
+`:scopifier' or `:command'.
+
+`:modes' - List of major modes this dispatch is valid for.
+
+`:colorizer' - Symbol referring to a function that parses and
+colors the buffer.
+
+`:scopifier' - Symbol referring to a function that parses the
+buffer a returns a flat vector of start, end and level data.
+
+`:executable' - Optional name of an executable required by
+`:command'.
+
+`:command' - Shell command to execute with the current buffer
+sent via stdin, and with a flat JSON array of start, end and
+level data returned via stdout.
+
+`:setup' - Arbitrary code to set up this dispatch when
+`context-coloring-mode' is enabled.
+
+`:teardown' - Arbitrary code to tear down this dispatch when
+`context-coloring-mode' is disabled."
+  (let ((modes (plist-get properties :modes))
+        (colorizer (plist-get properties :colorizer))
+        (scopifier (plist-get properties :scopifier))
+        (command (plist-get properties :command)))
+    (when (null modes)
+      (error "No mode defined for dispatch"))
+    (when (not (or colorizer
+                   scopifier
+                   command))
+      (error "No colorizer, scopifier or command defined for dispatch"))
+    (puthash symbol properties context-coloring-dispatch-hash-table)
+    (dolist (mode modes)
+      (when (null (gethash mode context-coloring-mode-hash-table))
+        (puthash mode properties context-coloring-mode-hash-table)))))
+
+(context-coloring-define-dispatch
+ 'javascript-node
+ :modes '(js-mode js3-mode)
+ :executable "scopifier"
+ :command "scopifier")
+
+(context-coloring-define-dispatch
+ 'javascript-js2
+ :modes '(js2-mode)
+ :colorizer 'context-coloring-js2-colorize
+ :setup
+ (lambda ()
+   (add-hook 'js2-post-parse-callbacks 'context-coloring-colorize nil t))
+ :teardown
+ (lambda ()
+   (remove-hook 'js2-post-parse-callbacks 'context-coloring-colorize t)))
+
+(defun context-coloring-dispatch (&optional callback)
+  "Determine the optimal track for scopification / coloring of
+the current buffer, then execute it.
+
+Invoke CALLBACK when complete.  It is invoked synchronously for
+elisp tracks, and asynchronously for shell command tracks."
+  (let ((dispatch (gethash major-mode context-coloring-mode-hash-table)))
+    (when (null dispatch)
+      (message "%s" "Context coloring is not available for this major mode"))
+    (let (colorizer
+          scopifier
+          command
+          executable)
+      (cond
+       ((setq colorizer (plist-get dispatch :colorizer))
+        (funcall colorizer)
+        (when callback (funcall callback)))
+       ((setq scopifier (plist-get dispatch :scopifier))
+        (context-coloring-apply-tokens (funcall scopifier))
+        (when callback (funcall callback)))
+       ((setq command (plist-get dispatch :command))
+        (setq executable (plist-get dispatch :executable))
+        (if (and executable
+                 (null (executable-find executable)))
+            (progn
+              (message "Executable \"%s\" not found" executable))
+          (context-coloring-scopify-shell-command command callback)))))))
+
+
+;;; Colorization
+
+(defun context-coloring-colorize (&optional callback)
+  "Color the current buffer by function context.
+
+Invoke CALLBACK when complete; see `context-coloring-dispatch'."
+  (interactive)
+  (context-coloring-dispatch
+   (lambda ()
+     (when callback (funcall callback)))))
+
+(defvar-local context-coloring-changed nil
+  "Indication that the buffer has changed recently, which implies
+that it should be colored again by
+`context-coloring-colorize-idle-timer' if that timer is being
+used.")
+
+(defun context-coloring-change-function (_start _end _length)
+  "Register a change so that a buffer can be colorized soon."
+  ;; Tokenization is obsolete if there was a change.
+  (context-coloring-kill-scopifier)
+  (setq context-coloring-changed t))
+
+(defun context-coloring-maybe-colorize ()
+  "Colorize the current buffer if it has changed."
+  (when (and (eq context-coloring-buffer (window-buffer (selected-window)))
+             context-coloring-changed)
+    (setq context-coloring-changed nil)
+    (context-coloring-colorize)))
+
+
+;;; Themes
+
+(defvar context-coloring-theme-hash-table (make-hash-table :test 'eq)
+  "Map theme names to theme properties.")
+
+(defun context-coloring-theme-p (theme)
+  "Return t if THEME is defined, nil otherwise."
+  (and (gethash theme context-coloring-theme-hash-table)))
+
+(defconst context-coloring-level-face-regexp
+  "context-coloring-level-\\([[:digit:]]+\\)-face"
+  "Extract a level from a face.")
+
+(defvar context-coloring-originally-set-theme-hash-table
+  (make-hash-table :test 'eq)
+  "Cache custom themes who originally set their own
+  `context-coloring-level-N-face' faces.")
+
+(defun context-coloring-theme-originally-set-p (theme)
+  "Return t if there is a `context-coloring-level-N-face'
+originally set for THEME, nil otherwise."
+  (let (originally-set)
+    (cond
+     ;; `setq' might return a non-nil value for the sake of this `cond'.
+     ((setq
+       originally-set
+       (gethash
+        theme
+        context-coloring-originally-set-theme-hash-table))
+      (eq originally-set 'yes))
+     (t
+      (let* ((settings (get theme 'theme-settings))
+             (tail settings)
+             found)
+        (while (and tail (not found))
+          (and (eq (nth 0 (car tail)) 'theme-face)
+               (string-match
+                context-coloring-level-face-regexp
+                (symbol-name (nth 1 (car tail))))
+               (setq found t))
+          (setq tail (cdr tail)))
+        found)))))
+
+(defun context-coloring-cache-originally-set (theme originally-set)
+  "Remember if THEME had colors originally set for it.  If
+ORIGINALLY-SET is non-nil, it did, otherwise it didn't."
+  ;; Caching whether a theme was originally set is kind of dirty, but we have 
to
+  ;; do it to remember the past state of the theme.  There are probably some
+  ;; edge cases where caching will be an issue, but they are probably rare.
+  (puthash
+   theme
+   (if originally-set 'yes 'no)
+   context-coloring-originally-set-theme-hash-table))
+
+(defun context-coloring-warn-theme-originally-set (theme)
+  "Warn the user that the colors for THEME are already originally
+set."
+  (warn "Context coloring colors for theme `%s' are already defined" theme))
+
+(defun context-coloring-theme-highest-level (theme)
+  "Return the highest level N of a face like
+`context-coloring-level-N-face' set for THEME, or `-1' if there
+is none."
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         face-string
+         number
+         (found -1))
+    (while tail
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (setq face-string (symbol-name (nth 1 (car tail))))
+           (string-match
+            context-coloring-level-face-regexp
+            face-string)
+           (setq number (string-to-number
+                         (substring face-string
+                                    (match-beginning 1)
+                                    (match-end 1))))
+           (> number found)
+           (setq found number))
+      (setq tail (cdr tail)))
+    found))
+
+(defun context-coloring-apply-theme (theme)
+  "Apply THEME's properties to its respective custom theme,
+which must already exist and which *should* already be enabled."
+  (let* ((properties (gethash theme context-coloring-theme-hash-table))
+         (colors (plist-get properties :colors))
+         (level -1))
+    (setq context-coloring-maximum-face (- (length colors) 1))
+    (apply
+     'custom-theme-set-faces
+     theme
+     (mapcar
+      (lambda (color)
+        (setq level (+ level 1))
+        `(,(context-coloring-level-face level) ((t (:foreground ,color)))))
+      colors))))
+
+(defun context-coloring-define-theme (theme &rest properties)
+  "Define a context theme named THEME for coloring scope levels.
+
+PROPERTIES is a property list specifiying the following details:
+
+`:aliases': List of symbols of other custom themes that these
+colors are applicable to.
+
+`:colors': List of colors that this context theme uses.
+
+`:override': If non-nil, this context theme is intentionally
+overriding colors set by a custom theme.  Don't set this non-nil
+unless there is a custom theme you want to use which sets
+`context-coloring-level-N-face' faces that you want to replace.
+
+`:recede': If non-nil, this context theme should not apply its
+colors if a custom theme already sets
+`context-coloring-level-N-face' faces.  This option is
+optimistic; set this non-nil if you would rather confer the duty
+of picking colors to a custom theme author (if / when he ever
+gets around to it).
+
+By default, context themes will always override custom themes,
+even if those custom themes set `context-coloring-level-N-face'
+faces.  If a context theme does override a custom theme, a
+warning will be raised, at which point you may want to enable the
+`:override' option, or just delete your context theme and opt to
+use your custom theme's author's colors instead.
+
+Context themes only work for the custom theme with the highest
+precedence, i.e. the car of `custom-enabled-themes'."
+  (let ((aliases (plist-get properties :aliases))
+        (override (plist-get properties :override))
+        (recede (plist-get properties :recede)))
+    (dolist (name (append `(,theme) aliases))
+      (puthash name properties context-coloring-theme-hash-table)
+      (when (custom-theme-p name)
+        (let ((originally-set (context-coloring-theme-originally-set-p name)))
+          (context-coloring-cache-originally-set name originally-set)
+          ;; In the particular case when you innocently define colors that a
+          ;; custom theme originally set, warn.  Arguably this only has to be
+          ;; done at enable time, but it is probably more useful to do it at
+          ;; definition time for prompter feedback.
+          (when (and originally-set
+                     (not recede)
+                     (not override))
+            (context-coloring-warn-theme-originally-set name))
+          ;; Set (or overwrite) colors.
+          (when (not (and originally-set
+                          recede))
+            (context-coloring-apply-theme name)))))))
+
+(defun context-coloring-enable-theme (theme)
+  "Apply THEME if its colors are not already set, else just set
+`context-coloring-maximum-face' to the correct value for THEME."
+  (let* ((properties (gethash theme context-coloring-theme-hash-table))
+         (recede (plist-get properties :recede))
+         (override (plist-get properties :override)))
+    (cond
+     (recede
+      (let ((highest-level (context-coloring-theme-highest-level theme)))
+        (cond
+         ;; This can be true whether originally set by a custom theme or by a
+         ;; context theme.
+         ((> highest-level -1)
+          (setq context-coloring-maximum-face highest-level))
+         ;; It is possible that the corresponding custom theme did not exist at
+         ;; the time of defining this context theme, and in that case the above
+         ;; condition proves the custom theme did not originally set any faces,
+         ;; so we have license to apply the context theme for the first time
+         ;; here.
+         (t
+          (context-coloring-apply-theme theme)))))
+     (t
+      (let ((originally-set (context-coloring-theme-originally-set-p theme)))
+        ;; Cache now in case the context theme was defined after the custom
+        ;; theme.
+        (context-coloring-cache-originally-set theme originally-set)
+        (when (and originally-set
+                   (not override))
+          (context-coloring-warn-theme-originally-set theme))
+        (context-coloring-apply-theme theme))))))
+
+(defadvice enable-theme (after context-coloring-enable-theme (theme) activate)
+  "Enable colors for context themes just-in-time."
+  (when (and (not (eq theme 'user)) ; Called internally by `enable-theme'.
+             (custom-theme-p theme) ; Guard against non-existent themes.
+             (context-coloring-theme-p theme))
+    (when (= (length custom-enabled-themes) 0)
+      ;; Cache because we can't reliably figure it out in reverse.
+      (setq context-coloring-original-maximum-face
+            context-coloring-maximum-face))
+    (context-coloring-enable-theme theme)))
+
+(defadvice disable-theme (after context-coloring-disable-theme (theme) 
activate)
+  "Update `context-coloring-maximum-face'."
+  (when (custom-theme-p theme) ; Guard against non-existent themes.
+    (let ((enabled-theme (car custom-enabled-themes)))
+      (if (context-coloring-theme-p enabled-theme)
+          (progn
+            (context-coloring-enable-theme enabled-theme))
+        ;; Assume we are back to no theme; act as if nothing ever happened.
+        ;; This is still prone to intervention, but rather extraordinarily.
+        (setq context-coloring-maximum-face
+              context-coloring-original-maximum-face)))))
+
+(context-coloring-define-theme
+ 'ample
+ :recede t
+ :colors '("#bdbdb3"
+           "#baba36"
+           "#6aaf50"
+           "#5180b3"
+           "#ab75c3"
+           "#cd7542"
+           "#dF9522"
+           "#454545"))
+
+(context-coloring-define-theme
+ 'anti-zenburn
+ :recede t
+ :colors '("#232333"
+           "#6c1f1c"
+           "#401440"
+           "#0f2050"
+           "#205070"
+           "#437c7c"
+           "#23733c"
+           "#6b400c"
+           "#603a60"
+           "#2f4070"
+           "#235c5c"))
+
+(context-coloring-define-theme
+ 'grandshell
+ :recede t
+ :colors '("#bebebe"
+           "#5af2ee"
+           "#b2baf6"
+           "#f09fff"
+           "#efc334"
+           "#f6df92"
+           "#acfb5a"
+           "#888888"))
+
+(context-coloring-define-theme
+ 'leuven
+ :recede t
+ :colors '("#333333"
+           "#0000FF"
+           "#6434A3"
+           "#BA36A5"
+           "#D0372D"
+           "#036A07"
+           "#006699"
+           "#006FE0"
+           "#808080"))
+
+(context-coloring-define-theme
+ 'monokai
+ :recede t
+ :colors '("#F8F8F2"
+           "#66D9EF"
+           "#A1EFE4"
+           "#A6E22E"
+           "#E6DB74"
+           "#FD971F"
+           "#F92672"
+           "#FD5FF0"
+           "#AE81FF"))
+
+(context-coloring-define-theme
+ 'solarized
+ :recede t
+ :aliases '(solarized-light
+            solarized-dark
+            sanityinc-solarized-light
+            sanityinc-solarized-dark)
+ :colors '("#839496"
+           "#268bd2"
+           "#2aa198"
+           "#859900"
+           "#b58900"
+           "#cb4b16"
+           "#dc322f"
+           "#d33682"
+           "#6c71c4"
+           "#69B7F0"
+           "#69CABF"
+           "#B4C342"
+           "#DEB542"
+           "#F2804F"
+           "#FF6E64"
+           "#F771AC"
+           "#9EA0E5"))
+
+(context-coloring-define-theme
+ 'spacegray
+ :recede t
+ :colors '("#ffffff"
+           "#89AAEB"
+           "#C189EB"
+           "#bf616a"
+           "#DCA432"
+           "#ebcb8b"
+           "#B4EB89"
+           "#89EBCA"))
+
+(context-coloring-define-theme
+ 'tango
+ :recede t
+ :colors '("#2e3436"
+           "#346604"
+           "#204a87"
+           "#5c3566"
+           "#a40000"
+           "#b35000"
+           "#c4a000"
+           "#8ae234"
+           "#8cc4ff"
+           "#ad7fa8"
+           "#ef2929"
+           "#fcaf3e"
+           "#fce94f"))
+
+(context-coloring-define-theme
+ 'zenburn
+ :recede t
+ :colors '("#DCDCCC"
+           "#93E0E3"
+           "#BFEBBF"
+           "#F0DFAF"
+           "#DFAF8F"
+           "#BC8383"
+           "#DC8CC3"
+           "#94BFF3"
+           "#9FC59F"
+           "#D0BF8F"
+           "#DCA3A3"))
+
+
+;;; Minor mode
+
+(defvar-local context-coloring-colorize-idle-timer nil
+  "The currently-running idle timer.")
+
+(defcustom context-coloring-delay 0.25
+  "Delay between a buffer update and colorization.
+
+Increase this if your machine is high-performing.  Decrease it if
+it ain't.
+
+Supported modes: `js-mode', `js3-mode'"
+  :group 'context-coloring)
+
+;;;###autoload
+(define-minor-mode context-coloring-mode
+  "Context-based code coloring, inspired by Douglas Crockford."
+  nil " Context" nil
+  (if (not context-coloring-mode)
+      (progn
+        (context-coloring-kill-scopifier)
+        (when context-coloring-colorize-idle-timer
+          (cancel-timer context-coloring-colorize-idle-timer))
+        (let ((dispatch (gethash major-mode context-coloring-mode-hash-table)))
+          (when dispatch
+            (let ((command (plist-get dispatch :command))
+                  (teardown (plist-get dispatch :teardown)))
+              (when command
+                (remove-hook
+                 'after-change-functions 'context-coloring-change-function t))
+              (when teardown
+                (funcall teardown)))))
+        (font-lock-mode)
+        (jit-lock-mode t))
+
+    ;; Remember this buffer.  This value should not be dynamically-bound.
+    (setq context-coloring-buffer (current-buffer))
+
+    ;; Font lock is incompatible with this mode; the converse is also true.
+    (font-lock-mode 0)
+    (jit-lock-mode nil)
+
+    (let ((dispatch (gethash major-mode context-coloring-mode-hash-table)))
+      (when dispatch
+        (let ((command (plist-get dispatch :command))
+              (setup (plist-get dispatch :setup)))
+          (when command
+            ;; Shell commands recolor on change, idly.
+            (add-hook
+             'after-change-functions 'context-coloring-change-function nil t)
+            (setq context-coloring-colorize-idle-timer
+                  (run-with-idle-timer
+                   context-coloring-delay
+                   t
+                   'context-coloring-maybe-colorize)))
+          (when setup
+            (funcall setup)))))
+
+    ;; Colorize once initially.
+    (context-coloring-colorize)))
+
+(provide 'context-coloring)
+
+;;; context-coloring.el ends here
diff --git a/packages/context-coloring/scopifier.png 
b/packages/context-coloring/scopifier.png
new file mode 100644
index 0000000..1ec5d10
Binary files /dev/null and b/packages/context-coloring/scopifier.png differ
diff --git a/packages/context-coloring/screenshot.png 
b/packages/context-coloring/screenshot.png
new file mode 100644
index 0000000..89665b7
Binary files /dev/null and b/packages/context-coloring/screenshot.png differ
diff --git a/packages/context-coloring/scripts/download-dependencies.el 
b/packages/context-coloring/scripts/download-dependencies.el
new file mode 100644
index 0000000..54211cc
--- /dev/null
+++ b/packages/context-coloring/scripts/download-dependencies.el
@@ -0,0 +1,52 @@
+;;; scripts/download-dependencies.el --- Get files for development. -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2015  Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;; This script downloads some dependencies for development so they don't need 
to
+;; be version-controlled.
+
+;;; Code:
+
+(defconst directory (file-name-directory (or load-file-name buffer-file-name))
+  "This file's directory.")
+
+(defun resolve-path (path)
+  "Resolve a path relative to this file's directory."
+  (expand-file-name path directory))
+
+(defun strip-headers ()
+  "Remove the http headers included in the output of
+`url-retrieve-synchronously'."
+  (goto-char 1)
+  (kill-paragraph 1) ; The headers are 1 paragraph. I hope.
+  (kill-line)        ; A line separates the headers from the file's content.
+  )
+
+;; Download any missing dependencies.
+(let ((files 
'("https://raw.githubusercontent.com/mooz/js2-mode/master/js2-mode.el";
+               
"https://raw.githubusercontent.com/rejeep/ert-async.el/master/ert-async.el";)))
+  (make-directory (resolve-path "../libraries") t)
+  (dolist (file files)
+    (let* ((basename (file-name-nondirectory file))
+           (destination (resolve-path (concat "../libraries/" basename))))
+      (when (null (file-exists-p destination))
+        (with-current-buffer (url-retrieve-synchronously file)
+          (strip-headers)
+          (write-file destination))))))
+
+;;; download-dependencies.el ends here
diff --git a/packages/context-coloring/test/context-coloring-test.el 
b/packages/context-coloring/test/context-coloring-test.el
new file mode 100644
index 0000000..88a7158
--- /dev/null
+++ b/packages/context-coloring/test/context-coloring-test.el
@@ -0,0 +1,722 @@
+;;; test/context-coloring-test.el --- Tests for context coloring. -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2014-2015  Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for context-coloring.
+
+;; Tests for both synchronous (elisp) and asynchronous (shell command) coloring
+;; are available.  Basic plugin functionality is also tested.
+
+;; To run, execute `make test' from the project root.
+
+;;; Code:
+
+(require 'ert-async)
+
+
+;;; Test running utilities
+
+(defconst context-coloring-test-path
+  (file-name-directory (or load-file-name buffer-file-name))
+  "This file's directory.")
+
+(defun context-coloring-test-read-file (path)
+  "Read a file's contents from PATH into a string."
+  (with-temp-buffer
+    (insert-file-contents (expand-file-name path context-coloring-test-path))
+    (buffer-string)))
+
+(defun context-coloring-test-setup ()
+  "Prepare before all tests."
+  (setq context-coloring-comments-and-strings nil))
+
+(defun context-coloring-test-cleanup ()
+  "Cleanup after all tests."
+  (setq context-coloring-comments-and-strings t)
+  (setq context-coloring-after-colorize-hook nil)
+  (setq context-coloring-js-block-scopes nil))
+
+(defmacro context-coloring-test-with-fixture (fixture &rest body)
+  "With the relative FIXTURE, evaluate BODY in a temporary
+buffer."
+  `(with-temp-buffer
+     (unwind-protect
+         (progn
+           (context-coloring-test-setup)
+           (insert (context-coloring-test-read-file ,fixture))
+           ,@body)
+       (context-coloring-test-cleanup))))
+
+(defun context-coloring-test-with-temp-buffer-async (callback)
+  "Create a temporary buffer, and evaluate CALLBACK there.  A
+teardown callback is passed to CALLBACK for it to invoke when it
+is done."
+  (let ((temp-buffer (make-symbol "temp-buffer")))
+    (let ((previous-buffer (current-buffer))
+          (temp-buffer (generate-new-buffer " *temp*")))
+      (set-buffer temp-buffer)
+      (funcall
+       callback
+       (lambda ()
+         (and (buffer-name temp-buffer)
+              (kill-buffer temp-buffer))
+         (set-buffer previous-buffer))))))
+
+(defun context-coloring-test-with-fixture-async
+    (fixture callback &optional setup)
+  "With the relative FIXTURE, evaluate CALLBACK in a temporary
+buffer.  A teardown callback is passed to CALLBACK for it to
+invoke when it is done.  An optional SETUP callback can run
+arbitrary code before the mode is invoked."
+  (context-coloring-test-with-temp-buffer-async
+   (lambda (done-with-temp-buffer)
+     (context-coloring-test-setup)
+     (when setup (funcall setup))
+     (insert (context-coloring-test-read-file fixture))
+     (funcall
+      callback
+      (lambda ()
+        (context-coloring-test-cleanup)
+        (funcall done-with-temp-buffer))))))
+
+
+;;; Test defining utilities
+
+(defun context-coloring-test-js-mode (fixture callback &optional setup)
+  "Use FIXTURE as the subject matter for test logic in CALLBACK.
+Optionally, provide setup code to run before the mode is
+instantiated in SETUP."
+  (context-coloring-test-with-fixture-async
+   fixture
+   (lambda (done-with-test)
+     (js-mode)
+     (context-coloring-mode)
+     (context-coloring-colorize
+      (lambda ()
+        (funcall callback done-with-test))))
+   setup))
+
+(defmacro context-coloring-test-js2-mode (fixture &rest body)
+  "Use FIXTURE as the subject matter for test logic in BODY."
+  `(context-coloring-test-with-fixture
+    ,fixture
+    (require 'js2-mode)
+    (setq js2-mode-show-parse-errors nil)
+    (setq js2-mode-show-strict-warnings nil)
+    (js2-mode)
+    (context-coloring-mode)
+    ,@body))
+
+(defmacro context-coloring-test-deftest-js-mode (name)
+  "Define an asynchronous test for `js-mode' with the name NAME
+in the typical format."
+  (let ((test-name (intern (format "context-coloring-test-js-mode-%s" name)))
+        (fixture (format "./fixtures/%s.js" name))
+        (function-name (intern-soft
+                        (format "context-coloring-test-js-%s" name))))
+    `(ert-deftest-async ,test-name (done)
+                        (context-coloring-test-js-mode
+                         ,fixture
+                         (lambda (teardown)
+                           (unwind-protect
+                               (,function-name)
+                             (funcall teardown))
+                           (funcall done))))))
+
+(defmacro context-coloring-test-deftest-js2-mode (name)
+  "Define a test for `js2-mode' with the name NAME in the typical
+format."
+  (let ((test-name (intern (format "context-coloring-test-js2-mode-%s" name)))
+        (fixture (format "./fixtures/%s.js" name))
+        (function-name (intern-soft
+                        (format "context-coloring-test-js-%s" name))))
+    `(ert-deftest ,test-name ()
+       (context-coloring-test-js2-mode
+        ,fixture
+        (,function-name)))))
+
+
+;;; Assertion functions
+
+(defmacro context-coloring-test-assert-region (&rest body)
+  "Assert something about the face of points in a region.
+Provides the free variables `i', `length', `point', `face' and
+`actual-level' to the code in BODY."
+  `(let ((i 0)
+         (length (- end start)))
+     (while (< i length)
+       (let* ((point (+ i start))
+              (face (get-text-property point 'face))
+              actual-level)
+         ,@body)
+       (setq i (+ i 1)))))
+
+(defun context-coloring-test-assert-region-level (start end level)
+  "Assert that all points in the range [START, END) are of level
+LEVEL."
+  (context-coloring-test-assert-region
+   (when (not (when face
+                (let* ((face-string (symbol-name face))
+                       (matches (string-match
+                                 context-coloring-level-face-regexp
+                                 face-string)))
+                  (when matches
+                    (setq actual-level (string-to-number
+                                        (substring face-string
+                                                   (match-beginning 1)
+                                                   (match-end 1))))
+                    (= level actual-level)))))
+     (ert-fail (format (concat "Expected level in region [%s, %s), "
+                               "which is \"%s\", to be %s; "
+                               "but at point %s, it was %s")
+                       start end
+                       (buffer-substring-no-properties start end) level
+                       point actual-level)))))
+
+(defun context-coloring-test-assert-region-face (start end expected-face)
+  "Assert that all points in the range [START, END) have the face
+EXPECTED-FACE."
+  (context-coloring-test-assert-region
+   (when (not (eq face expected-face))
+     (ert-fail (format (concat "Expected face in region [%s, %s), "
+                               "which is \"%s\", to be %s; "
+                               "but at point %s, it was %s")
+                       start end
+                       (buffer-substring-no-properties start end) expected-face
+                       point face)))))
+
+(defun context-coloring-test-assert-region-comment-delimiter (start end)
+  "Assert that all points in the range [START, END) have
+`font-lock-comment-delimiter-face'."
+  (context-coloring-test-assert-region-face
+   start end 'font-lock-comment-delimiter-face))
+
+(defun context-coloring-test-assert-region-comment (start end)
+  "Assert that all points in the range [START, END) have
+`font-lock-comment-face'."
+  (context-coloring-test-assert-region-face
+   start end 'font-lock-comment-face))
+
+(defun context-coloring-test-assert-region-string (start end)
+  "Assert that all points in the range [START, END) have
+`font-lock-string-face'."
+  (context-coloring-test-assert-region-face
+   start end 'font-lock-string-face))
+
+(defun context-coloring-test-assert-message (expected buffer)
+  "Assert that message EXPECTED exists in BUFFER."
+  (when (null (get-buffer buffer))
+    (ert-fail
+     (format
+      (concat
+       "Expected buffer `%s' to have message \"%s\", "
+       "but the buffer did not have any messages.")
+      buffer expected)))
+  (with-current-buffer buffer
+    (let ((messages (split-string
+                     (buffer-substring-no-properties
+                      (point-min)
+                      (point-max))
+                     "\n")))
+      (let ((message (car (nthcdr (- (length messages) 2) messages))))
+        (when (not (equal message expected))
+          (ert-fail
+           (format
+            (concat
+             "Expected buffer `%s' to have message \"%s\", "
+             "but instead it was \"%s\"")
+            buffer expected
+            message)))))))
+
+(defun context-coloring-test-assert-no-message (buffer)
+  "Assert that BUFFER has no message."
+  (when (get-buffer buffer)
+    (ert-fail (format (concat "Expected buffer `%s' to have no messages, "
+                              "but it did: `%s'")
+                      buffer
+                      (with-current-buffer buffer
+                        (buffer-string))))))
+
+(defun context-coloring-test-kill-buffer (buffer)
+  "Kill BUFFER if it exists."
+  (when (get-buffer buffer) (kill-buffer buffer)))
+
+(defun context-coloring-test-assert-face (level foreground &optional negate)
+  "Assert that a face for LEVEL exists and that its `:foreground'
+is FOREGROUND, or the inverse if NEGATE is non-nil."
+  (let* ((face (context-coloring-level-face level))
+         actual-foreground)
+    (when (not (or negate
+                   face))
+      (ert-fail (format (concat "Expected face for level `%s' to exist; "
+                                "but it didn't")
+                        level)))
+    (setq actual-foreground (face-attribute face :foreground))
+    (when (funcall (if negate 'identity 'not)
+                   (string-equal foreground actual-foreground))
+      (ert-fail (format (concat "Expected face for level `%s' "
+                                "%sto have foreground `%s'; "
+                                "but it %s.")
+                        level
+                        (if negate "not " "") foreground
+                        (if negate "did" (format "was `%s'" 
actual-foreground)))))))
+
+(defun context-coloring-test-assert-not-face (&rest arguments)
+  "Assert that LEVEL does not have a face with `:foreground'
+FOREGROUND.  Apply ARGUMENTS to
+`context-coloring-test-assert-face', see that function."
+  (apply 'context-coloring-test-assert-face
+         (append arguments '(t))))
+
+
+;;; The tests
+
+(ert-deftest context-coloring-test-unsupported-mode ()
+  (context-coloring-test-with-fixture
+   "./fixtures/function-scopes.js"
+   (context-coloring-mode)
+   (context-coloring-test-assert-message
+    "Context coloring is not available for this major mode"
+    "*Messages*")))
+
+(defvar context-coloring-test-theme-index 0
+  "Unique index for unique theme names.")
+
+(defun context-coloring-test-get-next-theme ()
+  "Return a unique symbol for a throwaway theme."
+  (prog1
+      (intern (format "context-coloring-test-theme-%s"
+                      context-coloring-test-theme-index))
+    (setq context-coloring-test-theme-index
+          (+ context-coloring-test-theme-index 1))))
+
+(defun context-coloring-test-assert-theme-originally-set-p
+    (settings &optional negate)
+  "Assert that `context-coloring-theme-originally-set-p' returns
+t for a theme with SETTINGS, or the inverse if NEGATE is
+non-nil."
+  (let ((theme (context-coloring-test-get-next-theme)))
+    (put theme 'theme-settings settings)
+    (when (funcall (if negate 'identity 'not)
+                   (context-coloring-theme-originally-set-p theme))
+      (ert-fail (format (concat "Expected theme `%s' with settings `%s' "
+                                "%sto be considered to have defined a level, "
+                                "but it %s.")
+                        theme settings
+                        (if negate "not " "")
+                        (if negate "was" "wasn't"))))))
+
+(defun context-coloring-test-assert-not-theme-originally-set-p (&rest 
arguments)
+  "Assert that `context-coloring-theme-originally-set-p' does not
+return t for a theme with SETTINGS.  Apply ARGUMENTS to
+`context-coloring-test-assert-theme-originally-set-p', see that
+function."
+  (apply 'context-coloring-test-assert-theme-originally-set-p
+         (append arguments '(t))))
+
+(ert-deftest context-coloring-test-theme-originally-set-p ()
+  (context-coloring-test-assert-theme-originally-set-p
+   '((theme-face context-coloring-level-0-face)))
+  (context-coloring-test-assert-theme-originally-set-p
+   '((theme-face face)
+     (theme-face context-coloring-level-0-face)))
+  (context-coloring-test-assert-theme-originally-set-p
+   '((theme-face context-coloring-level-0-face)
+     (theme-face face)))
+  (context-coloring-test-assert-not-theme-originally-set-p
+   '((theme-face face)))
+  )
+
+(defun context-coloring-test-assert-theme-settings-highest-level
+    (settings expected-level)
+  "Assert that a theme with SETTINGS has the highest level
+EXPECTED-LEVEL."
+  (let ((theme (context-coloring-test-get-next-theme)))
+    (put theme 'theme-settings settings)
+    (context-coloring-test-assert-theme-highest-level theme expected-level)))
+
+(defun context-coloring-test-assert-theme-highest-level
+    (theme expected-level &optional negate)
+  "Assert that THEME has the highest level EXPECTED-LEVEL, or the
+inverse if NEGATE is non-nil."
+  (let ((highest-level (context-coloring-theme-highest-level theme)))
+    (when (funcall (if negate 'identity 'not) (eq highest-level 
expected-level))
+      (ert-fail (format (concat "Expected theme with settings `%s' "
+                                "%sto have a highest level of `%s', "
+                                "but it %s.")
+                        (get theme 'theme-settings)
+                        (if negate "not " "") expected-level
+                        (if negate "did" (format "was %s" highest-level)))))))
+
+(defun context-coloring-test-assert-theme-not-highest-level (&rest arguments)
+  "Assert that THEME's highest level is not EXPECTED-LEVEL.
+Apply ARGUMENTS to
+`context-coloring-test-assert-theme-highest-level', see that
+function."
+  (apply 'context-coloring-test-assert-theme-highest-level
+         (append arguments '(t))))
+
+(ert-deftest context-coloring-test-theme-highest-level ()
+  (context-coloring-test-assert-theme-settings-highest-level
+   '((theme-face foo))
+   -1)
+  (context-coloring-test-assert-theme-settings-highest-level
+   '((theme-face context-coloring-level-0-face))
+   0)
+  (context-coloring-test-assert-theme-settings-highest-level
+   '((theme-face context-coloring-level-1-face))
+   1)
+  (context-coloring-test-assert-theme-settings-highest-level
+   '((theme-face context-coloring-level-1-face)
+     (theme-face context-coloring-level-0-face))
+   1)
+  (context-coloring-test-assert-theme-settings-highest-level
+   '((theme-face context-coloring-level-0-face)
+     (theme-face context-coloring-level-1-face))
+   1)
+  )
+
+(defmacro context-coloring-test-deftest-define-theme (name &rest body)
+  "Define a test with name NAME and an automatically-generated
+theme symbol available as a free variable `theme'.  Side-effects
+from enabling themes are reversed after BODY is executed and the
+test completes."
+  (declare (indent defun))
+  (let ((deftest-name (intern
+                       (format "context-coloring-test-define-theme-%s" name))))
+    `(ert-deftest ,deftest-name ()
+       (context-coloring-test-kill-buffer "*Warnings*")
+       (let ((theme (context-coloring-test-get-next-theme)))
+         (unwind-protect
+             (progn
+               ,@body)
+           ;; Always cleanup.
+           (disable-theme theme))))))
+
+(defun context-coloring-test-deftheme (theme)
+  "Dynamically define theme THEME."
+  (eval (macroexpand `(deftheme ,theme))))
+
+(context-coloring-test-deftest-define-theme additive
+  (context-coloring-test-deftheme theme)
+  (context-coloring-define-theme
+   theme
+   :colors '("#aaaaaa"
+             "#bbbbbb"))
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (enable-theme theme)
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb"))
+
+(defun context-coloring-test-assert-defined-warning (theme)
+  "Assert that a warning about colors already being defined for
+theme THEME is signaled."
+  (context-coloring-test-assert-message
+   (format (concat "Warning (emacs): Context coloring colors for theme "
+                   "`%s' are already defined")
+           theme)
+   "*Warnings*"))
+
+(context-coloring-test-deftest-define-theme unintentional-override
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
+   '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
+  (context-coloring-define-theme
+   theme
+   :colors '("#cccccc"
+             "#dddddd"))
+  (context-coloring-test-assert-defined-warning theme)
+  (context-coloring-test-kill-buffer "*Warnings*")
+  (enable-theme theme)
+  (context-coloring-test-assert-defined-warning theme)
+  (context-coloring-test-assert-face 0 "#cccccc")
+  (context-coloring-test-assert-face 1 "#dddddd"))
+
+(context-coloring-test-deftest-define-theme intentional-override
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
+   '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
+  (context-coloring-define-theme
+   theme
+   :override t
+   :colors '("#cccccc"
+             "#dddddd"))
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (enable-theme theme)
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#cccccc")
+  (context-coloring-test-assert-face 1 "#dddddd"))
+
+(context-coloring-test-deftest-define-theme pre-recede
+  (context-coloring-define-theme
+   theme
+   :recede t
+   :colors '("#aaaaaa"
+             "#bbbbbb"))
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
+   '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
+  (enable-theme theme)
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#cccccc")
+  (context-coloring-test-assert-face 1 "#dddddd"))
+
+(context-coloring-test-deftest-define-theme post-recede
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(context-coloring-level-0-face ((t (:foreground "#aaaaaa"))))
+   '(context-coloring-level-1-face ((t (:foreground "#bbbbbb")))))
+  (context-coloring-define-theme
+   theme
+   :recede t
+   :colors '("#cccccc"
+             "#dddddd"))
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb")
+  (enable-theme theme)
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb"))
+
+(context-coloring-test-deftest-define-theme recede-not-defined
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(foo-face ((t (:foreground "#ffffff")))))
+  (context-coloring-define-theme
+   theme
+   :recede t
+   :colors '("#aaaaaa"
+             "#bbbbbb"))
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb")
+  (enable-theme theme)
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb"))
+
+(context-coloring-test-deftest-define-theme unintentional-obstinance
+  (context-coloring-define-theme
+   theme
+   :colors '("#aaaaaa"
+             "#bbbbbb"))
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
+   '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
+  (enable-theme theme)
+  (context-coloring-test-assert-defined-warning theme)
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb"))
+
+(context-coloring-test-deftest-define-theme intentional-obstinance
+  (context-coloring-define-theme
+   theme
+   :override t
+   :colors '("#aaaaaa"
+             "#bbbbbb"))
+  (context-coloring-test-deftheme theme)
+  (custom-theme-set-faces
+   theme
+   '(context-coloring-level-0-face ((t (:foreground "#cccccc"))))
+   '(context-coloring-level-1-face ((t (:foreground "#dddddd")))))
+  (enable-theme theme)
+  (context-coloring-test-assert-no-message "*Warnings*")
+  (context-coloring-test-assert-face 0 "#aaaaaa")
+  (context-coloring-test-assert-face 1 "#bbbbbb"))
+
+(defun context-coloring-test-assert-maximum-face (maximum &optional negate)
+  "Assert that `context-coloring-maximum-face' is MAXIMUM, or the
+inverse if NEGATE is non-nil."
+  (when (funcall (if negate 'identity 'not)
+                 (eq context-coloring-maximum-face maximum))
+    (ert-fail (format (concat "Expected `context-coloring-maximum-face' "
+                              "%sto be `%s', "
+                              "but it %s.")
+                      (if negate "not " "") maximum
+                      (if negate
+                          "was"
+                        (format "was `%s'" context-coloring-maximum-face))))))
+
+(defun context-coloring-test-assert-not-maximum-face (&rest arguments)
+  "Assert that `context-coloring-maximum-face' is not MAXIMUM.
+Apply ARGUMENTS to `context-coloring-test-assert-maximum-face',
+see that function."
+  (apply 'context-coloring-test-assert-maximum-face
+         (append arguments '(t))))
+
+(context-coloring-test-deftest-define-theme disable-cascade
+  (context-coloring-test-deftheme theme)
+  (context-coloring-define-theme
+   theme
+   :colors '("#aaaaaa"
+             "#bbbbbb"))
+  (let ((second-theme (context-coloring-test-get-next-theme)))
+    (context-coloring-test-deftheme second-theme)
+    (context-coloring-define-theme
+     second-theme
+     :colors '("#cccccc"
+               "#dddddd"
+               "#eeeeee"))
+    (let ((third-theme (context-coloring-test-get-next-theme)))
+      (context-coloring-test-deftheme third-theme)
+      (context-coloring-define-theme
+       third-theme
+       :colors '("#111111"
+                 "#222222"
+                 "#333333"
+                 "#444444"))
+      (enable-theme theme)
+      (enable-theme second-theme)
+      (enable-theme third-theme)
+      (disable-theme third-theme)
+      (context-coloring-test-assert-face 0 "#cccccc")
+      (context-coloring-test-assert-face 1 "#dddddd")
+      (context-coloring-test-assert-face 2 "#eeeeee")
+      (context-coloring-test-assert-maximum-face 2))
+    (disable-theme second-theme)
+    (context-coloring-test-assert-face 0 "#aaaaaa")
+    (context-coloring-test-assert-face 1 "#bbbbbb")
+    (context-coloring-test-assert-maximum-face 1))
+  (disable-theme theme)
+  (context-coloring-test-assert-not-face 0 "#aaaaaa")
+  (context-coloring-test-assert-not-face 1 "#bbbbbb")
+  (context-coloring-test-assert-not-maximum-face 1))
+
+(defun context-coloring-test-js-function-scopes ()
+  "Test fixtures/functions-scopes.js."
+  (context-coloring-test-assert-region-level 1 9 0)
+  (context-coloring-test-assert-region-level 9 23 1)
+  (context-coloring-test-assert-region-level 23 25 0)
+  (context-coloring-test-assert-region-level 25 34 1)
+  (context-coloring-test-assert-region-level 34 35 0)
+  (context-coloring-test-assert-region-level 35 52 1)
+  (context-coloring-test-assert-region-level 52 66 2)
+  (context-coloring-test-assert-region-level 66 72 1)
+  (context-coloring-test-assert-region-level 72 81 2)
+  (context-coloring-test-assert-region-level 81 82 1)
+  (context-coloring-test-assert-region-level 82 87 2)
+  (context-coloring-test-assert-region-level 87 89 1))
+
+(context-coloring-test-deftest-js-mode function-scopes)
+(context-coloring-test-deftest-js2-mode function-scopes)
+
+(defun context-coloring-test-js-global ()
+  "Test fixtures/global.js."
+  (context-coloring-test-assert-region-level 20 28 1)
+  (context-coloring-test-assert-region-level 28 35 0)
+  (context-coloring-test-assert-region-level 35 41 1))
+
+(context-coloring-test-deftest-js-mode global)
+(context-coloring-test-deftest-js2-mode global)
+
+(defun context-coloring-test-js-block-scopes ()
+  "Test fixtures/block-scopes.js."
+  (context-coloring-test-assert-region-level 20 64 1)
+   (setq context-coloring-js-block-scopes t)
+   (context-coloring-colorize)
+   (context-coloring-test-assert-region-level 20 27 1)
+   (context-coloring-test-assert-region-level 27 41 2)
+   (context-coloring-test-assert-region-level 41 42 1)
+   (context-coloring-test-assert-region-level 42 64 2))
+
+(context-coloring-test-deftest-js2-mode block-scopes)
+
+(defun context-coloring-test-js-catch ()
+  "Test fixtures/js-catch.js."
+  (context-coloring-test-assert-region-level 20 27 1)
+  (context-coloring-test-assert-region-level 27 51 2)
+  (context-coloring-test-assert-region-level 51 52 1)
+  (context-coloring-test-assert-region-level 52 73 2)
+  (context-coloring-test-assert-region-level 73 101 3)
+  (context-coloring-test-assert-region-level 101 102 1)
+  (context-coloring-test-assert-region-level 102 117 3)
+  (context-coloring-test-assert-region-level 117 123 2))
+
+(context-coloring-test-deftest-js-mode catch)
+(context-coloring-test-deftest-js2-mode catch)
+
+(defun context-coloring-test-js-key-names ()
+  "Test fixtures/key-names.js."
+  (context-coloring-test-assert-region-level 20 63 1))
+
+(context-coloring-test-deftest-js-mode key-names)
+(context-coloring-test-deftest-js2-mode key-names)
+
+(defun context-coloring-test-js-property-lookup ()
+  "Test fixtures/property-lookup.js."
+  (context-coloring-test-assert-region-level 20 26 0)
+  (context-coloring-test-assert-region-level 26 38 1)
+  (context-coloring-test-assert-region-level 38 44 0)
+  (context-coloring-test-assert-region-level 44 52 1)
+  (context-coloring-test-assert-region-level 57 63 0)
+  (context-coloring-test-assert-region-level 63 74 1))
+
+(context-coloring-test-deftest-js-mode property-lookup)
+(context-coloring-test-deftest-js2-mode property-lookup)
+
+(defun context-coloring-test-js-key-values ()
+  "Test fixtures/key-values.js."
+  (context-coloring-test-assert-region-level 78 79 1))
+
+(context-coloring-test-deftest-js-mode key-values)
+(context-coloring-test-deftest-js2-mode key-values)
+
+(defun context-coloring-test-js-comments-and-strings ()
+  "Test fixtures/comments-and-strings.js."
+  (context-coloring-test-assert-region-comment-delimiter 1 4)
+  (context-coloring-test-assert-region-comment 4 8)
+  (context-coloring-test-assert-region-comment-delimiter 9 12)
+  (context-coloring-test-assert-region-comment 12 19)
+  (context-coloring-test-assert-region-string 20 32)
+  (context-coloring-test-assert-region-level 32 33 0))
+
+(ert-deftest-async context-coloring-test-js-mode-comments-and-strings (done)
+  (context-coloring-test-js-mode
+   "./fixtures/comments-and-strings.js"
+   (lambda (teardown)
+     (unwind-protect
+         (context-coloring-test-js-comments-and-strings)
+       (funcall teardown))
+     (funcall done))
+   (lambda ()
+     (setq context-coloring-comments-and-strings t))))
+
+(ert-deftest context-coloring-test-js2-mode-comments-and-strings ()
+  (context-coloring-test-js2-mode
+   "./fixtures/comments-and-strings.js"
+   (setq context-coloring-comments-and-strings t)
+   (context-coloring-colorize)
+   (context-coloring-test-js-comments-and-strings)))
+
+(provide 'context-coloring-test)
+
+;;; context-coloring-test.el ends here
diff --git a/packages/context-coloring/test/fixtures/block-scopes.js 
b/packages/context-coloring/test/fixtures/block-scopes.js
new file mode 100644
index 0000000..735ca6f
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/block-scopes.js
@@ -0,0 +1,6 @@
+(function () {
+    if (1) {
+        var a;
+        let b;
+    }
+}());
diff --git a/packages/context-coloring/test/fixtures/catch.js 
b/packages/context-coloring/test/fixtures/catch.js
new file mode 100644
index 0000000..a542ce9
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/catch.js
@@ -0,0 +1,8 @@
+(function () {
+    try {} catch (e) {
+        var a = e;
+        try {} catch (e) {
+            var a = e;
+        }
+    }
+}());
diff --git a/packages/context-coloring/test/fixtures/comments-and-strings.js 
b/packages/context-coloring/test/fixtures/comments-and-strings.js
new file mode 100644
index 0000000..9910b02
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/comments-and-strings.js
@@ -0,0 +1,3 @@
+// Foo.
+/* Bar. */
+'use strict';
diff --git a/packages/context-coloring/test/fixtures/function-scopes.js 
b/packages/context-coloring/test/fixtures/function-scopes.js
new file mode 100644
index 0000000..2f6ed32
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/function-scopes.js
@@ -0,0 +1,5 @@
+var a = function () {};
+function b() {
+    var c = function () {};
+    function d() {}
+}
diff --git a/packages/context-coloring/test/fixtures/global.js 
b/packages/context-coloring/test/fixtures/global.js
new file mode 100644
index 0000000..a35619d
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/global.js
@@ -0,0 +1,3 @@
+(function () {
+    var a = require('a');
+}());
diff --git a/packages/context-coloring/test/fixtures/key-names.js 
b/packages/context-coloring/test/fixtures/key-names.js
new file mode 100644
index 0000000..d8ad17c
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/key-names.js
@@ -0,0 +1,6 @@
+(function () {
+    return {
+        a: 0,
+        b : 2
+    };
+}());
diff --git a/packages/context-coloring/test/fixtures/key-values.js 
b/packages/context-coloring/test/fixtures/key-values.js
new file mode 100644
index 0000000..41bdedd
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/key-values.js
@@ -0,0 +1,8 @@
+(function () {
+    var a;
+    (function () {
+        return {
+            b: a
+        };
+    }());
+}());
diff --git a/packages/context-coloring/test/fixtures/property-lookup.js 
b/packages/context-coloring/test/fixtures/property-lookup.js
new file mode 100644
index 0000000..4edcb41
--- /dev/null
+++ b/packages/context-coloring/test/fixtures/property-lookup.js
@@ -0,0 +1,5 @@
+(function () {
+    window.foo();
+    window. bar();
+    window.foo.bar();
+}());
diff --git a/packages/debbugs/Debbugs.wsdl b/packages/debbugs/Debbugs.wsdl
index b186c80..427a381 100644
--- a/packages/debbugs/Debbugs.wsdl
+++ b/packages/debbugs/Debbugs.wsdl
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<!-- Copyright (C) 2011-2014  Free Software Foundation, Inc.
+<!-- Copyright (C) 2011-2015  Free Software Foundation, Inc.
 
 This file is not part of GNU Emacs.
 
diff --git a/packages/debbugs/debbugs-gnu.el b/packages/debbugs/debbugs-gnu.el
index 3fe88ca..97c67e4 100644
--- a/packages/debbugs/debbugs-gnu.el
+++ b/packages/debbugs/debbugs-gnu.el
@@ -1,6 +1,6 @@
 ;;; debbugs-gnu.el --- interface for the GNU bug tracker
 
-;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2011-2015 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <address@hidden>
 ;;         Michael Albinus <address@hidden>
@@ -92,6 +92,8 @@
 ;;   RET: Show corresponding messages in Gnus
 ;;   "C": Send a control message
 ;;   "t": Mark the bug locally as tagged
+;;   "b": Show bugs this bug is blocked by
+;;   "B": Show bugs this bug is blocking
 ;;   "d": Show bug attributes
 
 ;; Furthermore, you could apply the global actions
@@ -791,6 +793,8 @@ Used instead of `tabulated-list-print-entry'."
     (define-key map "x" 'debbugs-gnu-toggle-suppress)
     (define-key map "/" 'debbugs-gnu-narrow-to-status)
     (define-key map "w" 'debbugs-gnu-widen)
+    (define-key map "b" 'debbugs-gnu-show-blocked-by-reports)
+    (define-key map "B" 'debbugs-gnu-show-blocking-reports)
     (define-key map "C" 'debbugs-gnu-send-control-message)
     map))
 
@@ -926,6 +930,24 @@ The following commands are available:
     (when id
       (debbugs-gnu-goto id))))
 
+(defun debbugs-gnu-show-blocked-by-reports ()
+  "Display all bug reports this report is blocked by."
+  (interactive)
+  (let ((id (debbugs-gnu-current-id))
+       (status (debbugs-gnu-current-status)))
+    (if (null (cdr (assq 'blockedby status)))
+       (message "Bug %d is not blocked by any other bug" id)
+      (apply 'debbugs-gnu-bugs (cdr (assq 'blockedby status))))))
+
+(defun debbugs-gnu-show-blocking-reports ()
+  "Display all bug reports this report is blocking."
+  (interactive)
+  (let ((id (debbugs-gnu-current-id))
+       (status (debbugs-gnu-current-status)))
+    (if (null (cdr (assq 'blocks status)))
+       (message "Bug %d is not blocking any other bug" id)
+      (apply 'debbugs-gnu-bugs (cdr (assq 'blocks status))))))
+
 (defun debbugs-gnu-narrow-to-status (string &optional status-only)
   "Only display the bugs matching STRING.
 If STATUS-ONLY (the prefix), ignore matches in the From and
@@ -1104,8 +1126,9 @@ removed instead."
          "Control message: "
          '("serious" "important" "normal" "minor" "wishlist"
            "done" "donenotabug" "donewontfix" "doneunreproducible"
-           "unarchive" "reopen" "close"
+           "unarchive" "unmerge" "reopen" "close"
            "merge" "forcemerge"
+           "block" "unblock"
            "owner" "noowner"
            "invalid"
            "reassign"
@@ -1134,18 +1157,31 @@ removed instead."
               (format "%s.%s"
                       (match-string 1 emacs-version)
                       (match-string 2 emacs-version)))
-             (t emacs-version))))))
+             (t emacs-version)))))
+        (status (debbugs-gnu-current-status)))
     (with-temp-buffer
       (insert "To: address@hidden"
              "From: " (message-make-from) "\n"
              (format "Subject: control message for bug #%d\n" id)
              "\n"
              (cond
-              ((member message '("unarchive" "reopen" "noowner"))
+              ((member message '("unarchive" "unmerge" "reopen" "noowner"))
                (format "%s %d\n" message id))
               ((member message '("merge" "forcemerge"))
                (format "%s %d %s\n" message id
                        (read-string "Merge with bug #: ")))
+              ((member message '("block" "unblock"))
+               (format
+                "%s %d by %s\n" message id
+                (mapconcat
+                 'identity
+                 (completing-read-multiple
+                  (format "%s with bug(s) #: " (capitalize message))
+                  (if (equal message "unblock")
+                      (mapcar 'number-to-string
+                              (cdr (assq 'blockedby status))))
+                  nil (and (equal message "unblock") status))
+                 " ")))
               ((equal message "owner")
                (format "owner %d !\n" id))
               ((equal message "reassign")
diff --git a/packages/debbugs/debbugs-org.el b/packages/debbugs/debbugs-org.el
index 8a98aec..d49219f 100644
--- a/packages/debbugs/debbugs-org.el
+++ b/packages/debbugs/debbugs-org.el
@@ -1,6 +1,6 @@
 ;;; debbugs-org.el --- Org-mode interface for the GNU bug tracker
 
-;; Copyright (C) 2013-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2013-2015 Free Software Foundation, Inc.
 
 ;; Author: Michael Albinus <address@hidden>
 ;; Keywords: comm, hypermedia, maint, outlines
diff --git a/packages/debbugs/debbugs.el b/packages/debbugs/debbugs.el
index 725a394..35caf83 100644
--- a/packages/debbugs/debbugs.el
+++ b/packages/debbugs/debbugs.el
@@ -1,6 +1,6 @@
 ;;; debbugs.el --- SOAP library to access debbugs servers
 
-;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2011-2015 Free Software Foundation, Inc.
 
 ;; Author: Michael Albinus <address@hidden>
 ;; Keywords: comm, hypermedia
@@ -309,10 +309,13 @@ Example:
             (setcdr y (mapcar
                        (lambda (z) (if (numberp z) (number-to-string z) z))
                        (cdr y))))
-          ;; "mergedwith" is a string, containing blank separated bug numbers.
-          (setq y (assoc 'mergedwith (cdr (assoc 'value x))))
-          (when (stringp (cdr y))
-            (setcdr y (mapcar 'string-to-number (split-string (cdr y) " " t))))
+          ;; "mergedwith", "blocks" and "blockedby are strings,
+          ;; containing blank separated bug numbers.
+          (dolist (attribute '(mergedwith blocks blockedby))
+            (setq y (assoc attribute (cdr (assoc 'value x))))
+            (when (stringp (cdr y))
+              (setcdr y (mapcar
+                         'string-to-number (split-string (cdr y) " " t)))))
           ;; "package" is a string, containing comma separated
           ;; package names.  "keywords" and "tags" are strings,
           ;; containing blank separated package names.
diff --git a/packages/debbugs/debbugs.texi b/packages/debbugs/debbugs.texi
index 8c70e26..c26717a 100644
--- a/packages/debbugs/debbugs.texi
+++ b/packages/debbugs/debbugs.texi
@@ -8,7 +8,7 @@
 @end direntry
 
 @copying
-Copyright @copyright{} 2011-2014 Free Software Foundation, Inc.
+Copyright @copyright{} 2011-2015 Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
diff --git a/packages/hydra/Makefile b/packages/hydra/Makefile
index 97bcea6..4b6451f 100644
--- a/packages/hydra/Makefile
+++ b/packages/hydra/Makefile
@@ -1,12 +1,18 @@
 EMACS = emacs
 # EMACS = emacs-24.3
 
+LOAD = -l lv.el -l hydra.el -l hydra-test.el
+
 .PHONY: all test clean
 
 all: test
 
 test:
-       $(EMACS) -batch -l hydra.el -l hydra-test.el -f 
ert-run-tests-batch-and-exit
+       $(EMACS) -batch $(LOAD) -f ert-run-tests-batch-and-exit
+
+compile:
+       $(EMACS) -q $(LOAD) -l init.el --eval "(progn (mapc #'byte-compile-file 
'(\"hydra.el\" \"init.el\")) (switch-to-buffer \"*Compile-Log*\") (ert t))"
+       make clean
 
 clean:
        rm -f *.elc
diff --git a/packages/hydra/README.md b/packages/hydra/README.md
index 79175bd..70b31bf 100644
--- a/packages/hydra/README.md
+++ b/packages/hydra/README.md
@@ -16,29 +16,45 @@ Hydra, will still serve his orignal purpose, calling his 
proper
 command.  This makes the Hydra very seamless, it's like a minor mode
 that disables itself auto-magically.
 
-## Simplified usage
-
-Here's how to quickly bind the examples bundled with Hydra:
+## Sample global Hydras
+### Zoom
 
 ```cl
-(require 'hydra-examples)
-(hydra-create "C-M-y" hydra-example-move-window-splitter)
-(hydra-create "M-g" hydra-example-goto-error)
-(hydra-create "<f2>" hydra-example-text-scale)
+(defhydra hydra-zoom (global-map "<f2>")
+  "zoom"
+  ("g" text-scale-increase "in")
+  ("l" text-scale-decrease "out"))
 ```
 
-## Using Hydra for global bindings
+### Goto-error
 
-But it's much better to just take the examples as a template and write
-down everything explicitly:
+```cl
+(defhydra hydra-error (global-map "M-g")
+  "goto-error"
+  ("h" first-error "first")
+  ("j" next-error "next")
+  ("k" previous-error "prev")
+  ("v" recenter-top-bottom "recenter")
+  ("q" nil "quit"))
+```
+
+### Splitter
 
 ```cl
-(defhydra hydra-zoom (global-map "<f2>")
-  "zoom"
-  ("g" text-scale-increase "in")
-  ("l" text-scale-decrease "out"))
+(require 'hydra-examples)
+(defhydra hydra-splitter (global-map "C-M-s")
+  "splitter"
+  ("h" hydra-move-splitter-left)
+  ("j" hydra-move-splitter-down)
+  ("k" hydra-move-splitter-up)
+  ("l" hydra-move-splitter-right))
 ```
 
+### Community wiki
+A few useful hydras are aggregated in projects [community 
wiki](https://github.com/abo-abo/hydra/wiki/Hydras%20by%20Topic). Feel free to 
add your own or edit existing ones.
+
+## Using the functions generated by `defhydra`
+
 With the example above, you can e.g.:
 
 ```cl
@@ -163,3 +179,131 @@ However, there are two important differences:
 
 - you can cancel <kbd>C-c C-v</kbd> with a command while executing that 
command, instead of e.g.
 getting an error `C-c C-v C-n is undefined` for <kbd>C-c C-v C-n</kbd>.
+
+## Hydras and numeric arguments
+
+Since version `0.6.0`, for any Hydra:
+
+- `digit-argment` can be called with <kbd>0</kbd>-<kbd>9</kbd>.
+- `negative-argument` can be called with <kbd>-</kbd>
+- `universal-argument` can be called with <kbd>C-u</kbd>
+
+## Hydras can have `:pre` and `:post` statements
+
+Since version `0.7.0`, you can specify code that will be called before each 
head, and
+after the body. For example:
+
+```cl
+(global-set-key
+ (kbd "C-z")
+ (defhydra hydra-vi
+     (:pre
+      (set-cursor-color "#40e0d0")
+      :post
+      (progn
+        (set-cursor-color "#ffffff")
+        (message
+         "Thank you, come again.")))
+   "vi"
+   ("l" forward-char)
+   ("h" backward-char)
+   ("j" next-line)
+   ("k" previous-line)
+   ("q" nil "quit")))
+```
+
+## New Hydra color: amaranth
+
+Since version `0.8.0`, a new color - amaranth, in addition to the previous red 
and blue, is
+available for the Hydra body.
+
+According to [Wikipedia](http://en.wikipedia.org/wiki/Amaranth):
+
+> The word amaranth comes from the Greek word amaranton, meaning "unwilting" 
(from the
+> verb marainesthai, meaning "wilt").  The word was applied to amaranth 
because it did not
+> soon fade and so symbolized immortality.
+
+Hydras with amaranth body are impossible to quit with any binding *except* a 
blue head.
+A check for at least one blue head exists in `defhydra`, so that you don't get 
stuck by accident.
+
+Here's an example of an amaranth Hydra:
+
+```cl
+(global-set-key
+ (kbd "C-z")
+ (defhydra hydra-vi
+     (:pre
+      (set-cursor-color "#40e0d0")
+      :post
+      (set-cursor-color "#ffffff")
+      :color amaranth)
+   "vi"
+   ("l" forward-char)
+   ("h" backward-char)
+   ("j" next-line)
+   ("k" previous-line)
+   ("q" nil "quit")))
+```
+
+The only way to exit it, is to press <kbd>q</kbd>. No other methods will work. 
 You can
+use an amaranth Hydra instead of a red one, if for you the cost of being able 
to exit only
+though certain bindings is less than the cost of accidentally exiting a red 
Hydra by
+pressing the wrong prefix.
+
+Note that it does not make sense to define a single amaranth head, so this 
color can only
+be assigned to the body. An amaranth body will always have some amaranth heads 
and some
+blue heads (otherwise, it's impossible to exit), no reds.
+
+## Generate simple lambdas in-place:
+
+Since version `0.9.0` it's possible to pass a single sexp instead of a 
function name or a lambda
+to a head. This sexp will be wrapped in an interactive lambda. Here's an 
example:
+
+```cl
+(defhydra hydra-launcher (:color blue)
+   "Launch"
+   ("h" man "man")
+   ("r" (browse-url "http://www.reddit.com/r/emacs/";) "reddit")
+   ("w" (browse-url "http://www.emacswiki.org/";) "emacswiki")
+   ("s" shell "shell")
+   ("q" nil "cancel"))
+(global-set-key (kbd "C-c r") 'hydra-launcher/body)
+```
+
+## Define Hydra heads that don't show up in the hint at all
+
+This can be done by setting the head's hint explicitly to `nil`, instead of 
the usual string.
+
+## Use a dedicated window for Hydra hints
+
+Since version `0.10.0`, setting `hydra-lv` to `t` (the default setting) will 
make it use a dedicated
+window right above the Echo Area for hints. This has the advantage that you 
can immediately see
+any `message` output from the functions that you call, since Hydra no longer 
uses `message` to display
+the hint. You can still have the old behavior by setting `hydra-lv` to `nil`.
+
+## Color table
+
+
+    | Body Color | Head Inherited | Executing NON-HEADS   | Executing HEADS |
+    |------------+----------------+-----------------------+-----------------|
+    | amaranth   | red            | Disallow and Continue | Continue        |
+    | teal       | blue           | Disallow and Continue | Quit            |
+    | pink       | red            | Allow and Continue    | Continue        |
+    | red        | red            | Allow and Quit        | Continue        |
+    | blue       | blue           | Allow and Quit        | Quit            |
+
+## Color to toggle correspondence
+
+By popular demand, an alternative syntax has been implemented that translates 
to colors without
+using them in the syntax. `:exit` can be used both in body (heads will 
inherit) and in heads
+(possible to override body). `:exit` is nil by default, corresponding to `red` 
head; you don't need
+to set it explicitly to nil.  `:foreign-keys` can be used only in body and can 
be either nil (default),
+`warn` or `run`.
+
+    | color    | toggle                     |
+    |----------+----------------------------|
+    | red      |                            |
+    | blue     | :exit t                    |
+    | amaranth | :foreign-keys warn         |
+    | teal     | :foreign-keys warn :exit t |
+    | pink     | :foreign-keys run          |
diff --git a/packages/hydra/hydra-examples.el b/packages/hydra/hydra-examples.el
index 834db70..50773b0 100644
--- a/packages/hydra/hydra-examples.el
+++ b/packages/hydra/hydra-examples.el
@@ -21,81 +21,254 @@
 
 ;;; Commentary:
 ;;
-;; These are the sample Hydras that you can use.
+;; These are the sample Hydras.
 ;;
-;; Note that the better way to create Hydras is with `defhydra':
-;;
-;; (defhydra hydra-zoom (global-map "<f2>")
-;;   "zoom"
-;;   ("g" text-scale-increase "in")
-;;   ("l" text-scale-decrease "out"))
-;;
-;; This way, you have more options, and everything is in one place.
+;; If you want to use them plainly, set `hydra-examples-verbatim' to t
+;; before requiring this file. But it's probably better to only look
+;; at them and use them as templates for building your own.
 
 ;;; Code:
 
 (require 'hydra)
 
-(defvar hydra-example-text-scale
-  '(("g" text-scale-increase "zoom in")
-    ("l" text-scale-decrease "zoom out"))
-  "A two-headed hydra for text scale manipulation.")
+;;* Examples
+;;** Example 1: text scale
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-zoom (global-map "<f2>")
+    "zoom"
+    ("g" text-scale-increase "in")
+    ("l" text-scale-decrease "out")))
+
+;; This example generates three commands:
+;;
+;;     `hydra-zoom/text-scale-increase'
+;;     `hydra-zoom/text-scale-decrease'
+;;     `hydra-zoom/body'
+;;
+;; In addition, two of them are bound like this:
+;;
+;;     (global-set-key (kbd "<f2> g") 'hydra-zoom/text-scale-increase)
+;;     (global-set-key (kbd "<f2> l") 'hydra-zoom/text-scale-decrease)
+;;
+;; Note that you can substitute `global-map' with e.g. `emacs-lisp-mode-map' 
if you need.
+;; The functions generated will be the same, except the binding code will 
change to:
+;;
+;;     (define-key emacs-lisp-mode-map [f2 103]
+;;       (function hydra-zoom/text-scale-increase))
+;;     (define-key emacs-lisp-mode-map [f2 108]
+;;       (function hydra-zoom/text-scale-decrease))
+
+;;** Example 2: move window splitter
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-splitter (global-map "C-M-s")
+    "splitter"
+    ("h" hydra-move-splitter-left)
+    ("j" hydra-move-splitter-down)
+    ("k" hydra-move-splitter-up)
+    ("l" hydra-move-splitter-right)))
+
+;;** Example 3: jump to error
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-error (global-map "M-g")
+    "goto-error"
+    ("h" first-error "first")
+    ("j" next-error "next")
+    ("k" previous-error "prev")
+    ("v" recenter-top-bottom "recenter")
+    ("q" nil "quit")))
+
+;; This example introduces only one new thing: since the command
+;; passed to the "q" head is nil, it will quit the Hydra without doing
+;; anything. Heads that quit the Hydra instead of continuing are
+;; referred to as having blue :color. All the other heads have red
+;; :color, unless other is specified.
+
+;;** Example 4: toggle rarely used modes
+(when (bound-and-true-p hydra-examples-verbatim)
+  (global-set-key
+   (kbd "C-c C-v")
+   (defhydra hydra-toggle (:color blue)
+     "toggle"
+     ("a" abbrev-mode "abbrev")
+     ("d" toggle-debug-on-error "debug")
+     ("f" auto-fill-mode "fill")
+     ("t" toggle-truncate-lines "truncate")
+     ("w" whitespace-mode "whitespace")
+     ("q" nil "cancel"))))
+
+;; Note that in this case, `defhydra' returns the `hydra-toggle/body'
+;; symbol, which is then passed to `global-set-key'.
+;;
+;; Another new thing is that both the keymap and the body prefix are
+;; skipped.  This means that `defhydra' will bind nothing - that's why
+;; `global-set-key' is necessary.
+;;
+;; One more new thing is that you can assign a :color to the body. All
+;; heads will inherit this color. The code above is very much equivalent to:
+;;
+;;     (global-set-key (kbd "C-c C-v a") 'abbrev-mode)
+;;     (global-set-key (kbd "C-c C-v d") 'toggle-debug-on-error)
+;;
+;; The differences are:
+;;
+;; * You get a hint immediately after "C-c C-v"
+;; * You can cancel and call a command immediately, e.g. "C-c C-v C-n"
+;;   is equivalent to "C-n" with Hydra approach, while it will error
+;;   that "C-c C-v C-n" isn't bound with the usual approach.
+
+;;** Example 5: mini-vi
+(defun hydra-vi/pre ()
+  (set-cursor-color "#e52b50"))
+
+(defun hydra-vi/post ()
+  (set-cursor-color "#ffffff"))
+
+(when (bound-and-true-p hydra-examples-verbatim)
+  (global-set-key
+   (kbd "C-z")
+   (defhydra hydra-vi (:pre hydra-vi/pre :post hydra-vi/post :color amaranth)
+     "vi"
+     ("l" forward-char)
+     ("h" backward-char)
+     ("j" next-line)
+     ("k" previous-line)
+     ("m" set-mark-command "mark")
+     ("a" move-beginning-of-line "beg")
+     ("e" move-end-of-line "end")
+     ("d" delete-region "del" :color blue)
+     ("y" kill-ring-save "yank" :color blue)
+     ("q" nil "quit"))))
+
+;; This example introduces :color amaranth. It's similar to red,
+;; except while you can quit red with any binding which isn't a Hydra
+;; head, you can quit amaranth only with a blue head. So you can quit
+;; this mode only with "d", "y", "q" or "C-g".
+;;
+;; Another novelty are the :pre and :post handlers. :pre will be
+;; called before each command, while :post will be called when the
+;; Hydra quits. In this case, they're used to override the cursor
+;; color while Hydra is active.
+
+;;** Example 6: selective global bind
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-next-error (global-map "C-x")
+    "next-error"
+    ("`" next-error "next")
+    ("j" next-error "next" :bind nil)
+    ("k" previous-error "previous" :bind nil)))
+
+;; This example will bind "C-x `" in `global-map', but it will not
+;; bind "C-x j" and "C-x k".
+;; You can still "C-x `jjk" though.
+;;** Example 7: toggle with Ruby-style docstring
+(when (bound-and-true-p hydra-examples-verbatim)
+  (defhydra hydra-toggle (:color pink)
+    "
+_a_ abbrev-mode:       %`abbrev-mode
+_d_ debug-on-error:    %`debug-on-error
+_f_ auto-fill-mode:    %`auto-fill-function
+_g_ golden-ratio-mode: %`golden-ratio-mode
+_t_ truncate-lines:    %`truncate-lines
+_w_ whitespace-mode:   %`whitespace-mode
+
+"
+    ("a" abbrev-mode nil)
+    ("d" toggle-debug-on-error nil)
+    ("f" auto-fill-mode nil)
+    ("g" golden-ratio-mode nil)
+    ("t" toggle-truncate-lines nil)
+    ("w" whitespace-mode nil)
+    ("q" nil "quit"))
+  (global-set-key (kbd "C-c C-v") 'hydra-toggle/body))
+
+;; Here, using e.g. "_a_" translates to "a" with proper face.
+;; More interestingly:
+;;
+;;     "foobar %`abbrev-mode" means roughly (format "foobar %S" abbrev-mode)
+;;
+;; This means that you actually see the state of the mode that you're changing.
+;;** Example 8: the whole menu for `Buffer-menu-mode'
+(defhydra hydra-buffer-menu (:color pink)
+  "
+  Mark               Unmark             Actions            Search
+-------------------------------------------------------------------------      
                  (__)
+_m_: mark          _u_: unmark        _x_: execute       _R_: re-isearch       
                  (oo)
+_s_: save          _U_: unmark up     _b_: bury          _I_: isearch          
            /------\\/
+_d_: delete                           _g_: refresh       _O_: multi-occur      
           / |    ||
+_D_: delete up                        _T_: files only: % 
-28`Buffer-menu-files-only      *  /\\---/\\
+_~_: modified                                                                  
             ~~   ~~
+"
+  ("m" Buffer-menu-mark nil)
+  ("u" Buffer-menu-unmark nil)
+  ("U" Buffer-menu-backup-unmark nil)
+  ("d" Buffer-menu-delete nil)
+  ("D" Buffer-menu-delete-backwards nil)
+  ("s" Buffer-menu-save nil)
+  ("~" Buffer-menu-not-modified nil)
+  ("x" Buffer-menu-execute nil)
+  ("b" Buffer-menu-bury nil)
+  ("g" revert-buffer nil)
+  ("T" Buffer-menu-toggle-files-only nil)
+  ("O" Buffer-menu-multi-occur nil :color blue)
+  ("I" Buffer-menu-isearch-buffers nil :color blue)
+  ("R" Buffer-menu-isearch-buffers-regexp nil :color blue)
+  ("c" nil "cancel")
+  ("v" Buffer-menu-select "select" :color blue)
+  ("o" Buffer-menu-other-window "other-window" :color blue)
+  ("q" quit-window "quit" :color blue))
+;; Recommended binding:
+;; (define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)
+;;** Example 9: s-expressions in the docstring
+;; You can inline s-expresssions into the docstring like this:
+(when (bound-and-true-p hydra-examples-verbatim)
+  (eval-after-load 'dired
+    (defhydra hydra-marked-items (dired-mode-map "")
+      "
+Number of marked items: %(length (dired-get-marked-files))
+"
+      ("m" dired-mark "mark"))))
+
+;; This results in the following dynamic docstring:
+;;
+;;     (format "Number of marked items: %S\n"
+;;             (length (dired-get-marked-files)))
+;;
+;; You can use `format'-style width specs, e.g. % 10(length nil).
 
+;;* Windmove helpers
 (require 'windmove)
 
-(defun hydra-move-splitter-left ()
+(defun hydra-move-splitter-left (arg)
   "Move window splitter left."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'right))
-      (shrink-window-horizontally 1)
-    (enlarge-window-horizontally 1)))
+      (shrink-window-horizontally arg)
+    (enlarge-window-horizontally arg)))
 
-(defun hydra-move-splitter-right ()
+(defun hydra-move-splitter-right (arg)
   "Move window splitter right."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'right))
-      (enlarge-window-horizontally 1)
-    (shrink-window-horizontally 1)))
+      (enlarge-window-horizontally arg)
+    (shrink-window-horizontally arg)))
 
-(defun hydra-move-splitter-up ()
+(defun hydra-move-splitter-up (arg)
   "Move window splitter up."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'up))
-      (enlarge-window 1)
-    (shrink-window 1)))
+      (enlarge-window arg)
+    (shrink-window arg)))
 
-(defun hydra-move-splitter-down ()
+(defun hydra-move-splitter-down (arg)
   "Move window splitter down."
-  (interactive)
+  (interactive "p")
   (if (let ((windmove-wrap-around))
         (windmove-find-other-window 'up))
-      (shrink-window 1)
-    (enlarge-window 1)))
-
-(defvar hydra-example-move-window-splitter
-  '(("h" hydra-move-splitter-left)
-    ("j" hydra-move-splitter-down)
-    ("k" hydra-move-splitter-up)
-    ("l" hydra-move-splitter-right))
-  "A four-headed hydra for the window splitter manipulation.
-Works best if you have not more than 4 windows.")
-
-(defvar hydra-example-goto-error
-  '(("h" first-error "first")
-    ("j" next-error "next")
-    ("k" previous-error "prev"))
-  "A three-headed hydra for jumping between \"errors\".
-Useful for e.g. `occur', `rgrep' and the like.")
-
-(defvar hydra-example-windmove
-  '(("h" windmove-left)
-    ("j" windmove-down)
-    ("k" windmove-up)
-    ("l" windmove-right))
-  "A four-headed hydra for `windmove'.")
+      (shrink-window arg)
+    (enlarge-window arg)))
 
 (provide 'hydra-examples)
 ;;; hydra-examples.el ends here
diff --git a/packages/hydra/hydra-ox.el b/packages/hydra/hydra-ox.el
new file mode 100644
index 0000000..4053081
--- /dev/null
+++ b/packages/hydra/hydra-ox.el
@@ -0,0 +1,118 @@
+;;; hydra-ox.el --- Org mode export widget implemented in Hydra
+
+;; Copyright (C) 2015  Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This shows how a complex dispatch menu can be built with Hydra.
+
+;;; Code:
+(require 'org)
+
+(defhydradio hydra-ox ()
+  (body-only)
+  (export-scope [buffer subtree])
+  (async-export)
+  (visible-only)
+  (force-publishing))
+
+(defhydra hydra-ox-html (:color blue)
+  "ox-html"
+  ("H" (org-html-export-as-html
+        hydra-ox/async-export
+        (eq hydra-ox/export-scope 'subtree)
+        hydra-ox/visible-only
+        hydra-ox/body-only)
+       "As HTML buffer")
+  ("h" (org-html-export-to-html
+        hydra-ox/async-export
+        (eq hydra-ox/export-scope 'subtree)
+        hydra-ox/visible-only
+        hydra-ox/body-only) "As HTML file")
+  ("o" (org-open-file
+        (org-html-export-to-html
+         hydra-ox/async-export
+         (eq hydra-ox/export-scope 'subtree)
+         hydra-ox/visible-only
+         hydra-ox/body-only)) "As HTML file and open")
+  ("b" hydra-ox/body "back")
+  ("q" nil "quit"))
+
+(defhydra hydra-ox-latex (:color blue)
+  "ox-latex"
+  ("L" org-latex-export-as-latex "As LaTeX buffer")
+  ("l" org-latex-export-to-latex "As LaTeX file")
+  ("p" org-latex-export-to-pdf "As PDF file")
+  ("o" (org-open-file (org-latex-export-to-pdf)) "As PDF file and open")
+  ("b" hydra-ox/body "back")
+  ("q" nil "quit"))
+
+(defhydra hydra-ox-text (:color blue)
+  "ox-text"
+  ("A" (org-ascii-export-as-ascii
+        nil nil nil nil
+        '(:ascii-charset ascii))
+       "As ASCII buffer")
+
+  ("a" (org-ascii-export-to-ascii
+        nil nil nil nil
+        '(:ascii-charset ascii))
+       "As ASCII file")
+  ("L" (org-ascii-export-as-ascii
+        nil nil nil nil
+        '(:ascii-charset latin1))
+       "As Latin1 buffer")
+  ("l" (org-ascii-export-to-ascii
+        nil nil nil nil
+        '(:ascii-charset latin1))
+       "As Latin1 file")
+  ("U" (org-ascii-export-as-ascii
+        nil nil nil nil
+        '(:ascii-charset utf-8))
+       "As UTF-8 buffer")
+  ("u" (org-ascii-export-to-ascii
+        nil nil nil nil
+        '(:ascii-charset utf-8))
+       "As UTF-8 file")
+  ("b" hydra-ox/body "back")
+  ("q" nil "quit"))
+
+(defhydra hydra-ox ()
+  "
+_C-b_ Body only:    % -15`hydra-ox/body-only^^^ _C-v_ Visible only:     
%`hydra-ox/visible-only
+_C-s_ Export scope: % -15`hydra-ox/export-scope _C-f_ Force publishing: 
%`hydra-ox/force-publishing
+_C-a_ Async export: %`hydra-ox/async-export
+
+"
+  ("C-b" (hydra-ox/body-only) nil)
+  ("C-v" (hydra-ox/visible-only) nil)
+  ("C-s" (hydra-ox/export-scope) nil)
+  ("C-f" (hydra-ox/force-publishing) nil)
+  ("C-a" (hydra-ox/async-export) nil)
+  ("h" hydra-ox-html/body "Export to HTML" :exit t)
+  ("l" hydra-ox-latex/body "Export to LaTeX" :exit t)
+  ("t" hydra-ox-text/body "Export to Plain Text" :exit t)
+  ("q" nil "quit"))
+
+(define-key org-mode-map (kbd "C-c C-,") 'hydra-ox/body)
+
+(provide 'hydra-ox)
+
+;;; hydra-ox.el ends here
diff --git a/packages/hydra/hydra-test.el b/packages/hydra/hydra-test.el
index f3b3c27..754984d 100644
--- a/packages/hydra/hydra-test.el
+++ b/packages/hydra/hydra-test.el
@@ -26,7 +26,7 @@
 
 (require 'ert)
 
-(ert-deftest defhydra-red-error ()
+(ert-deftest hydra-red-error ()
   (should
    (equal
     (macroexpand
@@ -34,196 +34,1061 @@
        "error"
        ("h" first-error "first")
        ("j" next-error "next")
-       ("k" previous-error "prev")))
+       ("k" previous-error "prev")
+       ("SPC" hydra-repeat "rep" :bind nil)))
     '(progn
-      (defun hydra-error/first-error ()
-        "Create a hydra with a \"M-g\" body and the heads:
+      (defun hydra-error/first-error nil "Create a hydra with a \"M-g\" body 
and the heads:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
-\"k\":    `previous-error'
+\"k\":    `previous-error',
+\"SPC\":    `hydra-repeat'
 
 The body can be accessed via `hydra-error/body'.
 
 Call the head: `first-error'."
-        (interactive)
-        (call-interactively #'first-error)
-        (when hydra-is-helpful
-          (message #("error: [h]: first, [j]: next, [k]: prev."
-                     8 9 (face font-lock-keyword-face)
-                     20 21 (face font-lock-keyword-face)
-                     31 32 (face font-lock-keyword-face))))
-        (setq hydra-last
-              (hydra-set-transient-map
-               '(keymap
-                 (107 . hydra-error/previous-error)
-                 (106 . hydra-error/next-error)
-                 (104 . hydra-error/first-error)) t)))
-
-      (defun hydra-error/next-error ()
-        "Create a hydra with a \"M-g\" body and the heads:
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
first-error)))
+                 ((quit error)
+                  (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-error/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (32 . hydra-repeat)
+                                           (107 . hydra-error/previous-error)
+                                           (106 . hydra-error/next-error)
+                                           (104 . hydra-error/first-error)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
+      (defun hydra-error/next-error nil "Create a hydra with a \"M-g\" body 
and the heads:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
-\"k\":    `previous-error'
+\"k\":    `previous-error',
+\"SPC\":    `hydra-repeat'
 
 The body can be accessed via `hydra-error/body'.
 
 Call the head: `next-error'."
-        (interactive)
-        (call-interactively #'next-error)
-        (when hydra-is-helpful
-          (message #("error: [h]: first, [j]: next, [k]: prev."
-                     8 9 (face font-lock-keyword-face)
-                     20 21 (face font-lock-keyword-face)
-                     31 32 (face font-lock-keyword-face))))
-        (setq hydra-last
-              (hydra-set-transient-map
-               '(keymap
-                 (107 . hydra-error/previous-error)
-                 (106 . hydra-error/next-error)
-                 (104 . hydra-error/first-error)) t)))
-
-      (defun hydra-error/previous-error ()
-        "Create a hydra with a \"M-g\" body and the heads:
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
next-error)))
+                 ((quit error)
+                  (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-error/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (32 . hydra-repeat)
+                                           (107 . hydra-error/previous-error)
+                                           (106 . hydra-error/next-error)
+                                           (104 . hydra-error/first-error)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
+      (defun hydra-error/previous-error nil "Create a hydra with a \"M-g\" 
body and the heads:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
-\"k\":    `previous-error'
+\"k\":    `previous-error',
+\"SPC\":    `hydra-repeat'
 
 The body can be accessed via `hydra-error/body'.
 
 Call the head: `previous-error'."
-        (interactive)
-        (call-interactively #'previous-error)
-        (when hydra-is-helpful
-          (message #("error: [h]: first, [j]: next, [k]: prev."
-                     8 9 (face font-lock-keyword-face)
-                     20 21 (face font-lock-keyword-face)
-                     31 32 (face font-lock-keyword-face))))
-        (setq hydra-last
-              (hydra-set-transient-map
-               '(keymap
-                 (107 . hydra-error/previous-error)
-                 (106 . hydra-error/next-error)
-                 (104 . hydra-error/first-error)) t)))
-
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
previous-error)))
+                 ((quit error)
+                  (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-error/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (32 . hydra-repeat)
+                                           (107 . hydra-error/previous-error)
+                                           (106 . hydra-error/next-error)
+                                           (104 . hydra-error/first-error)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra--digit-argument)
+                                           (48 . hydra--digit-argument)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
       (unless (keymapp (lookup-key global-map (kbd "M-g")))
-        (define-key global-map (kbd "M-g") nil))
-      (define-key global-map [134217831 104] #'hydra-error/first-error)
-      (define-key global-map [134217831 106] #'hydra-error/next-error)
-      (define-key global-map [134217831 107] #'hydra-error/previous-error)
-
-      (defun hydra-error/body ()
-        "Create a hydra with a \"M-g\" body and the heads:
+        (define-key global-map (kbd "M-g")
+          nil))
+      (define-key global-map [134217831 104]
+        (function hydra-error/first-error))
+      (define-key global-map [134217831 106]
+        (function hydra-error/next-error))
+      (define-key global-map [134217831 107]
+        (function hydra-error/previous-error))
+      (defun hydra-error/hint nil
+        (if hydra-lv (lv-message (format #("error: [h]: first, [j]: next, [k]: 
prev, [SPC]: rep." 8 9 (face hydra-face-red)
+                                           20 21 (face hydra-face-red)
+                                           31 32 (face hydra-face-red)
+                                           42 45 (face hydra-face-red))))
+          (message (format #("error: [h]: first, [j]: next, [k]: prev, [SPC]: 
rep." 8 9 (face hydra-face-red)
+                             20 21 (face hydra-face-red)
+                             31 32 (face hydra-face-red)
+                             42 45 (face hydra-face-red))))))
+      (defun hydra-error/body nil "Create a hydra with a \"M-g\" body and the 
heads:
 
 \"h\":    `first-error',
 \"j\":    `next-error',
-\"k\":    `previous-error'
+\"k\":    `previous-error',
+\"SPC\":    `hydra-repeat'
 
 The body can be accessed via `hydra-error/body'."
-        (interactive)
-        (when hydra-is-helpful
-          (message #("error: [h]: first, [j]: next, [k]: prev."
-                     8 9 (face font-lock-keyword-face)
-                     20 21 (face font-lock-keyword-face)
-                     31 32 (face font-lock-keyword-face))))
-        (setq hydra-last
-              (hydra-set-transient-map
-               '(keymap
-                 (107 . hydra-error/previous-error)
-                 (106 . hydra-error/next-error)
-                 (104 . hydra-error/first-error)) t)))))))
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (when hydra-is-helpful (hydra-error/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote
+                             (keymap (7 . hydra-keyboard-quit)
+                                     (32 . hydra-repeat)
+                                     (107 . hydra-error/previous-error)
+                                     (106 . hydra-error/next-error)
+                                     (104 . hydra-error/first-error)
+                                     (kp-subtract . hydra--negative-argument)
+                                     (kp-9 . hydra--digit-argument)
+                                     (kp-8 . hydra--digit-argument)
+                                     (kp-7 . hydra--digit-argument)
+                                     (kp-6 . hydra--digit-argument)
+                                     (kp-5 . hydra--digit-argument)
+                                     (kp-4 . hydra--digit-argument)
+                                     (kp-3 . hydra--digit-argument)
+                                     (kp-2 . hydra--digit-argument)
+                                     (kp-1 . hydra--digit-argument)
+                                     (kp-0 . hydra--digit-argument)
+                                     (57 . hydra--digit-argument)
+                                     (56 . hydra--digit-argument)
+                                     (55 . hydra--digit-argument)
+                                     (54 . hydra--digit-argument)
+                                     (53 . hydra--digit-argument)
+                                     (52 . hydra--digit-argument)
+                                     (51 . hydra--digit-argument)
+                                     (50 . hydra--digit-argument)
+                                     (49 . hydra--digit-argument)
+                                     (48 . hydra--digit-argument)
+                                     (45 . hydra--negative-argument)
+                                     (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))
+               (setq prefix-arg current-prefix-arg)))))))
 
 (ert-deftest hydra-blue-toggle ()
   (should
    (equal
     (macroexpand
-     '(defhydra toggle (:color blue)
+     '(defhydra hydra-toggle (:color blue)
        "toggle"
        ("t" toggle-truncate-lines "truncate")
        ("f" auto-fill-mode "fill")
        ("a" abbrev-mode "abbrev")
        ("q" nil "cancel")))
     '(progn
-      (defun toggle/toggle-truncate-lines ()
-        "Create a hydra with no body and the heads:
+      (defun hydra-toggle/toggle-truncate-lines nil "Create a hydra with no 
body and the heads:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    `nil'
 
-The body can be accessed via `toggle/body'.
+The body can be accessed via `hydra-toggle/body'.
 
 Call the head: `toggle-truncate-lines'."
-        (interactive)
-        (hydra-disable)
-        (call-interactively #'toggle-truncate-lines))
-      (defun toggle/auto-fill-mode ()
-        "Create a hydra with no body and the heads:
+             (interactive)
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (call-interactively (function toggle-truncate-lines))))
+      (defun hydra-toggle/auto-fill-mode nil "Create a hydra with no body and 
the heads:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    `nil'
 
-The body can be accessed via `toggle/body'.
+The body can be accessed via `hydra-toggle/body'.
 
 Call the head: `auto-fill-mode'."
-        (interactive)
-        (hydra-disable)
-        (call-interactively #'auto-fill-mode))
-      (defun toggle/abbrev-mode ()
-        "Create a hydra with no body and the heads:
+             (interactive)
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (call-interactively (function auto-fill-mode))))
+      (defun hydra-toggle/abbrev-mode nil "Create a hydra with no body and the 
heads:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    `nil'
 
-The body can be accessed via `toggle/body'.
+The body can be accessed via `hydra-toggle/body'.
 
 Call the head: `abbrev-mode'."
-        (interactive)
-        (hydra-disable)
-        (call-interactively #'abbrev-mode))
-      (defun toggle/nil ()
-        "Create a hydra with no body and the heads:
+             (interactive)
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (call-interactively (function abbrev-mode))))
+      (defun hydra-toggle/nil nil "Create a hydra with no body and the heads:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    `nil'
 
-The body can be accessed via `toggle/body'.
+The body can be accessed via `hydra-toggle/body'.
 
 Call the head: `nil'."
-        (interactive)
-        (hydra-disable))
-      (defun toggle/body ()
-        "Create a hydra with no body and the heads:
+             (interactive)
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)))
+      (defun hydra-toggle/hint nil
+        (if hydra-lv (lv-message (format #("toggle: [t]: truncate, [f]: fill, 
[a]: abbrev, [q]: cancel." 9 10 (face hydra-face-blue)
+                                           24 25 (face hydra-face-blue)
+                                           35 36 (face hydra-face-blue)
+                                           48 49 (face hydra-face-blue))))
+          (message (format #("toggle: [t]: truncate, [f]: fill, [a]: abbrev, 
[q]: cancel." 9 10 (face hydra-face-blue)
+                             24 25 (face hydra-face-blue)
+                             35 36 (face hydra-face-blue)
+                             48 49 (face hydra-face-blue))))))
+      (defun hydra-toggle/body nil "Create a hydra with no body and the heads:
 
 \"t\":    `toggle-truncate-lines',
 \"f\":    `auto-fill-mode',
 \"a\":    `abbrev-mode',
 \"q\":    `nil'
 
-The body can be accessed via `toggle/body'."
-        (interactive)
-        (when hydra-is-helpful
-          (message #("toggle: [t]: truncate, [f]: fill, [a]: abbrev, [q]: 
cancel."
-                     9 10 (face hydra-face-blue)
-                     24 25 (face hydra-face-blue)
-                     35 36 (face hydra-face-blue)
-                     48 49 (face hydra-face-blue))))
-        (setq hydra-last
-              (hydra-set-transient-map
-               '(keymap (113 . toggle/nil)
-                 (97 . toggle/abbrev-mode)
-                 (102 . toggle/auto-fill-mode)
-                 (116 . toggle/toggle-truncate-lines))
-               t)))))))
+The body can be accessed via `hydra-toggle/body'."
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (when hydra-is-helpful (hydra-toggle/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote
+                             (keymap (7 . hydra-keyboard-quit)
+                                     (113 . hydra-toggle/nil)
+                                     (97 . hydra-toggle/abbrev-mode)
+                                     (102 . hydra-toggle/auto-fill-mode)
+                                     (116 . hydra-toggle/toggle-truncate-lines)
+                                     (kp-subtract . hydra--negative-argument)
+                                     (kp-9 . hydra--digit-argument)
+                                     (kp-8 . hydra--digit-argument)
+                                     (kp-7 . hydra--digit-argument)
+                                     (kp-6 . hydra--digit-argument)
+                                     (kp-5 . hydra--digit-argument)
+                                     (kp-4 . hydra--digit-argument)
+                                     (kp-3 . hydra--digit-argument)
+                                     (kp-2 . hydra--digit-argument)
+                                     (kp-1 . hydra--digit-argument)
+                                     (kp-0 . hydra--digit-argument)
+                                     (57 . hydra--digit-argument)
+                                     (56 . hydra--digit-argument)
+                                     (55 . hydra--digit-argument)
+                                     (54 . hydra--digit-argument)
+                                     (53 . hydra--digit-argument)
+                                     (52 . hydra--digit-argument)
+                                     (51 . hydra--digit-argument)
+                                     (50 . hydra--digit-argument)
+                                     (49 . hydra--digit-argument)
+                                     (48 . hydra--digit-argument)
+                                     (45 . hydra--negative-argument)
+                                     (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))
+               (setq prefix-arg current-prefix-arg)))))))
+
+(ert-deftest hydra-amaranth-vi ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-vi
+       (:pre
+        (set-cursor-color "#e52b50")
+        :post
+        (set-cursor-color "#ffffff")
+        :color amaranth)
+       "vi"
+       ("j" next-line)
+       ("k" previous-line)
+       ("q" nil "quit")))
+    '(progn
+      (defun hydra-vi/next-line nil "Create a hydra with no body and the heads:
+
+\"j\":    `next-line',
+\"k\":    `previous-line',
+\"q\":    `nil'
+
+The body can be accessed via `hydra-vi/body'.
+
+Call the head: `next-line'."
+             (interactive)
+             (set-cursor-color "#e52b50")
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
next-line)))
+                 ((quit error) (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-vi/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote
+                             (keymap (t lambda nil (interactive)
+                                        (message "An amaranth Hydra can only 
exit through a blue head")
+                                        (hydra-set-transient-map 
hydra-curr-map t)
+                                        (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
+                                              (hydra-vi/hint)))
+                                     (7 . hydra-keyboard-quit)
+                                     (113 . hydra-vi/nil)
+                                     (107 . hydra-vi/previous-line)
+                                     (106 . hydra-vi/next-line)
+                                     (kp-subtract . hydra--negative-argument)
+                                     (kp-9 . hydra--digit-argument)
+                                     (kp-8 . hydra--digit-argument)
+                                     (kp-7 . hydra--digit-argument)
+                                     (kp-6 . hydra--digit-argument)
+                                     (kp-5 . hydra--digit-argument)
+                                     (kp-4 . hydra--digit-argument)
+                                     (kp-3 . hydra--digit-argument)
+                                     (kp-2 . hydra--digit-argument)
+                                     (kp-1 . hydra--digit-argument)
+                                     (kp-0 . hydra--digit-argument)
+                                     (57 . hydra--digit-argument)
+                                     (56 . hydra--digit-argument)
+                                     (55 . hydra--digit-argument)
+                                     (54 . hydra--digit-argument)
+                                     (53 . hydra--digit-argument)
+                                     (52 . hydra--digit-argument)
+                                     (51 . hydra--digit-argument)
+                                     (50 . hydra--digit-argument)
+                                     (49 . hydra--digit-argument)
+                                     (48 . hydra--digit-argument)
+                                     (45 . hydra--negative-argument)
+                                     (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
+      (defun hydra-vi/previous-line nil "Create a hydra with no body and the 
heads:
+
+\"j\":    `next-line',
+\"k\":    `previous-line',
+\"q\":    `nil'
+
+The body can be accessed via `hydra-vi/body'.
+
+Call the head: `previous-line'."
+             (interactive)
+             (set-cursor-color "#e52b50")
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
previous-line)))
+                 ((quit error) (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-vi/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote
+                             (keymap (t lambda nil (interactive)
+                                        (message "An amaranth Hydra can only 
exit through a blue head")
+                                        (hydra-set-transient-map 
hydra-curr-map t)
+                                        (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
+                                              (hydra-vi/hint)))
+                                     (7 . hydra-keyboard-quit)
+                                     (113 . hydra-vi/nil)
+                                     (107 . hydra-vi/previous-line)
+                                     (106 . hydra-vi/next-line)
+                                     (kp-subtract . hydra--negative-argument)
+                                     (kp-9 . hydra--digit-argument)
+                                     (kp-8 . hydra--digit-argument)
+                                     (kp-7 . hydra--digit-argument)
+                                     (kp-6 . hydra--digit-argument)
+                                     (kp-5 . hydra--digit-argument)
+                                     (kp-4 . hydra--digit-argument)
+                                     (kp-3 . hydra--digit-argument)
+                                     (kp-2 . hydra--digit-argument)
+                                     (kp-1 . hydra--digit-argument)
+                                     (kp-0 . hydra--digit-argument)
+                                     (57 . hydra--digit-argument)
+                                     (56 . hydra--digit-argument)
+                                     (55 . hydra--digit-argument)
+                                     (54 . hydra--digit-argument)
+                                     (53 . hydra--digit-argument)
+                                     (52 . hydra--digit-argument)
+                                     (51 . hydra--digit-argument)
+                                     (50 . hydra--digit-argument)
+                                     (49 . hydra--digit-argument)
+                                     (48 . hydra--digit-argument)
+                                     (45 . hydra--negative-argument)
+                                     (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
+      (defun hydra-vi/nil nil "Create a hydra with no body and the heads:
+
+\"j\":    `next-line',
+\"k\":    `previous-line',
+\"q\":    `nil'
+
+The body can be accessed via `hydra-vi/body'.
+
+Call the head: `nil'."
+             (interactive)
+             (set-cursor-color "#e52b50")
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (set-cursor-color "#ffffff")))
+      (defun hydra-vi/hint nil
+        (if hydra-lv (lv-message (format #("vi: j, k, [q]: quit." 4 5 (face 
hydra-face-amaranth)
+                                           7 8 (face hydra-face-amaranth)
+                                           11 12 (face hydra-face-blue))))
+          (message (format #("vi: j, k, [q]: quit." 4 5 (face 
hydra-face-amaranth)
+                             7 8 (face hydra-face-amaranth)
+                             11 12 (face hydra-face-blue))))))
+      (defun hydra-vi/body nil "Create a hydra with no body and the heads:
+
+\"j\":    `next-line',
+\"k\":    `previous-line',
+\"q\":    `nil'
+
+The body can be accessed via `hydra-vi/body'."
+             (interactive)
+             (set-cursor-color "#e52b50")
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (when hydra-is-helpful (hydra-vi/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote
+                             (keymap (t lambda nil (interactive)
+                                        (message "An amaranth Hydra can only 
exit through a blue head")
+                                        (hydra-set-transient-map 
hydra-curr-map t)
+                                        (when hydra-is-helpful (unless 
hydra-lv (sit-for 0.8))
+                                              (hydra-vi/hint)))
+                                     (7 . hydra-keyboard-quit)
+                                     (113 . hydra-vi/nil)
+                                     (107 . hydra-vi/previous-line)
+                                     (106 . hydra-vi/next-line)
+                                     (kp-subtract . hydra--negative-argument)
+                                     (kp-9 . hydra--digit-argument)
+                                     (kp-8 . hydra--digit-argument)
+                                     (kp-7 . hydra--digit-argument)
+                                     (kp-6 . hydra--digit-argument)
+                                     (kp-5 . hydra--digit-argument)
+                                     (kp-4 . hydra--digit-argument)
+                                     (kp-3 . hydra--digit-argument)
+                                     (kp-2 . hydra--digit-argument)
+                                     (kp-1 . hydra--digit-argument)
+                                     (kp-0 . hydra--digit-argument)
+                                     (57 . hydra--digit-argument)
+                                     (56 . hydra--digit-argument)
+                                     (55 . hydra--digit-argument)
+                                     (54 . hydra--digit-argument)
+                                     (53 . hydra--digit-argument)
+                                     (52 . hydra--digit-argument)
+                                     (51 . hydra--digit-argument)
+                                     (50 . hydra--digit-argument)
+                                     (49 . hydra--digit-argument)
+                                     (48 . hydra--digit-argument)
+                                     (45 . hydra--negative-argument)
+                                     (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))
+               (setq prefix-arg current-prefix-arg)))))))
+
+(ert-deftest defhydradio ()
+  (should (equal
+           (macroexpand
+            '(defhydradio hydra-test ()
+              (num "Num" [0 1 2 3 4 5 6 7 8 9 10])
+              (str "Str" ["foo" "bar" "baz"])))
+           '(progn
+             (defvar hydra-test/num 0
+               "Num")
+             (put 'hydra-test/num 'range [0 1 2 3 4 5 6 7 8 9 10])
+             (defun hydra-test/num ()
+               (hydra--cycle-radio 'hydra-test/num))
+             (defvar hydra-test/str "foo"
+               "Str")
+             (put 'hydra-test/str 'range ["foo" "bar" "baz"])
+             (defun hydra-test/str ()
+               (hydra--cycle-radio 'hydra-test/str))
+             (defvar hydra-test/names '(hydra-test/num hydra-test/str))))))
+
+(ert-deftest hydra-blue-compat ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-toggle (:color blue)
+       "toggle"
+       ("t" toggle-truncate-lines "truncate")
+       ("f" auto-fill-mode "fill")
+       ("a" abbrev-mode "abbrev")
+       ("q" nil "cancel")))
+    (macroexpand
+     '(defhydra hydra-toggle (:exit t)
+       "toggle"
+       ("t" toggle-truncate-lines "truncate")
+       ("f" auto-fill-mode "fill")
+       ("a" abbrev-mode "abbrev")
+       ("q" nil "cancel"))))))
+
+(ert-deftest hydra-amaranth-compat ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-vi
+       (:pre
+        (set-cursor-color "#e52b50")
+        :post
+        (set-cursor-color "#ffffff")
+        :color amaranth)
+       "vi"
+       ("j" next-line)
+       ("k" previous-line)
+       ("q" nil "quit")))
+    (macroexpand
+     '(defhydra hydra-vi
+       (:pre
+        (set-cursor-color "#e52b50")
+        :post
+        (set-cursor-color "#ffffff")
+        :foreign-keys warn)
+       "vi"
+       ("j" next-line)
+       ("k" previous-line)
+       ("q" nil "quit"))))))
+
+(ert-deftest hydra-pink-compat ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-zoom (global-map "<f2>"
+                            :color pink)
+       "zoom"
+       ("g" text-scale-increase "in")
+       ("l" text-scale-decrease "out")
+       ("q" nil "quit")))
+    (macroexpand
+     '(defhydra hydra-zoom (global-map "<f2>"
+                            :foreign-keys run)
+       "zoom"
+       ("g" text-scale-increase "in")
+       ("l" text-scale-decrease "out")
+       ("q" nil "quit"))))))
+
+(ert-deftest hydra-teal-compat ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-zoom (global-map "<f2>"
+                            :color teal)
+       "zoom"
+       ("g" text-scale-increase "in")
+       ("l" text-scale-decrease "out")
+       ("q" nil "quit")))
+    (macroexpand
+     '(defhydra hydra-zoom (global-map "<f2>"
+                            :foreign-keys warn
+                            :exit t)
+       "zoom"
+       ("g" text-scale-increase "in")
+       ("l" text-scale-decrease "out")
+       ("q" nil "quit"))))))
+
+(ert-deftest hydra-format ()
+  (should (equal
+           (let ((hydra-fontify-head-function
+                  'hydra-fontify-head-greyscale))
+             (hydra--format
+              'hydra-toggle
+              nil
+              "
+_a_ abbrev-mode:       %`abbrev-mode
+_d_ debug-on-error:    %`debug-on-error
+_f_ auto-fill-mode:    %`auto-fill-function
+" '(("a" abbrev-mode nil)
+    ("d" toggle-debug-on-error nil)
+    ("f" auto-fill-mode nil)
+    ("g" golden-ratio-mode nil)
+    ("t" toggle-truncate-lines nil)
+    ("w" whitespace-mode nil)
+    ("q" nil "quit"))))
+           '(concat (format "%s abbrev-mode:       %S
+%s debug-on-error:    %S
+%s auto-fill-mode:    %S
+" "{a}" abbrev-mode "{d}" debug-on-error "{f}" auto-fill-function) "[[q]]: 
quit"))))
+
+(ert-deftest hydra-format-with-sexp ()
+  (should (equal
+           (let ((hydra-fontify-head-function
+                  'hydra-fontify-head-greyscale))
+             (hydra--format
+              'hydra-toggle nil
+              "\n_n_ narrow-or-widen-dwim %(progn (message 
\"checking\")(buffer-narrowed-p))asdf\n"
+              '(("n" narrow-to-region nil) ("q" nil "cancel"))))
+           '(concat (format "%s narrow-or-widen-dwim %Sasdf\n"
+                     "{n}"
+                     (progn
+                       (message "checking")
+                       (buffer-narrowed-p)))
+             "[[q]]: cancel"))))
+
+(ert-deftest hydra-compat-colors-1 ()
+  (should (equal (hydra--head-color
+                  '("e" (message "Exiting now") "blue")
+                  '(nil nil :color blue))
+                 'blue))
+  (should (equal (hydra--head-color
+                  '("c" (message "Continuing") "red" :color red)
+                  '(nil nil :color blue))
+                 'red))
+  (should (equal (hydra--head-color
+                  '("e" (message "Exiting now") "blue")
+                  '(nil nil :exit t))
+                 'blue))
+  (should (equal (hydra--head-color
+                  '("c" (message "Continuing") "red" :exit nil)
+                  '(nil nil :exit t))
+                 'red))
+  (equal (hydra--head-color
+          '("a" abbrev-mode nil)
+          '(nil nil :color teal))
+         'teal)
+  (equal (hydra--head-color
+          '("a" abbrev-mode :exit nil)
+          '(nil nil :color teal))
+         'amaranth))
+
+(ert-deftest hydra-compat-colors-2 ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-test (:color amaranth)
+       ("a" fun-a)
+       ("b" fun-b :color blue)
+       ("c" fun-c :color blue)
+       ("d" fun-d :color blue)
+       ("e" fun-e :color blue)
+       ("f" fun-f :color blue)))
+    (macroexpand
+     '(defhydra hydra-test (:color teal)
+       ("a" fun-a :color red)
+       ("b" fun-b)
+       ("c" fun-c)
+       ("d" fun-d)
+       ("e" fun-e)
+       ("f" fun-f))))))
+
+(ert-deftest hydra-compat-colors-3 ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-test ()
+       ("a" fun-a)
+       ("b" fun-b :color blue)
+       ("c" fun-c :color blue)
+       ("d" fun-d :color blue)
+       ("e" fun-e :color blue)
+       ("f" fun-f :color blue)))
+    (macroexpand
+     '(defhydra hydra-test (:color blue)
+       ("a" fun-a :color red)
+       ("b" fun-b)
+       ("c" fun-c)
+       ("d" fun-d)
+       ("e" fun-e)
+       ("f" fun-f))))))
+
+(ert-deftest hydra-compat-colors-4 ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-test ()
+       ("a" fun-a)
+       ("b" fun-b :exit t)
+       ("c" fun-c :exit t)
+       ("d" fun-d :exit t)
+       ("e" fun-e :exit t)
+       ("f" fun-f :exit t)))
+    (macroexpand
+     '(defhydra hydra-test (:exit t)
+       ("a" fun-a :exit nil)
+       ("b" fun-b)
+       ("c" fun-c)
+       ("d" fun-d)
+       ("e" fun-e)
+       ("f" fun-f))))))
+
+(ert-deftest hydra-zoom-duplicate-1 ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-zoom ()
+       "zoom"
+       ("r" (text-scale-set 0) "reset")
+       ("0" (text-scale-set 0) :bind nil :exit t)
+       ("1" (text-scale-set 0) nil :bind nil :exit t)))
+    '(progn
+      (defun hydra-zoom/lambda-r nil "Create a hydra with no body and the 
heads:
+
+\"r\":    `(text-scale-set 0)',
+\"0\":    `(text-scale-set 0)',
+\"1\":    `(text-scale-set 0)'
+
+The body can be accessed via `hydra-zoom/body'.
+
+Call the head: `(text-scale-set 0)'."
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
(lambda nil (interactive)
+                                                                             
(text-scale-set 0)))))
+                 ((quit error)
+                  (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-zoom/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (114 . hydra-zoom/lambda-r)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra-zoom/lambda-0)
+                                           (48 . hydra-zoom/lambda-0)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
+      (defun hydra-zoom/lambda-0 nil "Create a hydra with no body and the 
heads:
+
+\"r\":    `(text-scale-set 0)',
+\"0\":    `(text-scale-set 0)',
+\"1\":    `(text-scale-set 0)'
+
+The body can be accessed via `hydra-zoom/body'.
+
+Call the head: `(text-scale-set 0)'."
+             (interactive)
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (call-interactively (function (lambda nil (interactive)
+                                                (text-scale-set 0))))))
+      (defun hydra-zoom/hint nil
+        (if hydra-lv (lv-message (format #("zoom: [r 0]: reset." 7 8 (face 
hydra-face-red)
+                                           9 10 (face hydra-face-blue))))
+          (message (format #("zoom: [r 0]: reset." 7 8 (face hydra-face-red)
+                             9 10 (face hydra-face-blue))))))
+      (defun hydra-zoom/body nil "Create a hydra with no body and the heads:
+
+\"r\":    `(text-scale-set 0)',
+\"0\":    `(text-scale-set 0)',
+\"1\":    `(text-scale-set 0)'
+
+The body can be accessed via `hydra-zoom/body'."
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (when hydra-is-helpful (hydra-zoom/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (114 . hydra-zoom/lambda-r)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra-zoom/lambda-0)
+                                           (48 . hydra-zoom/lambda-0)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))
+               (setq prefix-arg current-prefix-arg)))))))
+
+(ert-deftest hydra-zoom-duplicate-2 ()
+  (should
+   (equal
+    (macroexpand
+     '(defhydra hydra-zoom ()
+       "zoom"
+       ("r" (text-scale-set 0) "reset")
+       ("0" (text-scale-set 0) :bind nil :exit t)
+       ("1" (text-scale-set 0) nil :bind nil)))
+    '(progn
+      (defun hydra-zoom/lambda-r nil "Create a hydra with no body and the 
heads:
+
+\"r\":    `(text-scale-set 0)',
+\"0\":    `(text-scale-set 0)',
+\"1\":    `(text-scale-set 0)'
+
+The body can be accessed via `hydra-zoom/body'.
+
+Call the head: `(text-scale-set 0)'."
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (condition-case err (prog1 t (call-interactively (function 
(lambda nil (interactive)
+                                                                             
(text-scale-set 0)))))
+                 ((quit error)
+                  (message "%S" err)
+                  (unless hydra-lv (sit-for 0.8))
+                  nil))
+               (when hydra-is-helpful (hydra-zoom/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (114 . hydra-zoom/lambda-r)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra-zoom/lambda-r)
+                                           (48 . hydra-zoom/lambda-0)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))))
+      (defun hydra-zoom/lambda-0 nil "Create a hydra with no body and the 
heads:
+
+\"r\":    `(text-scale-set 0)',
+\"0\":    `(text-scale-set 0)',
+\"1\":    `(text-scale-set 0)'
+
+The body can be accessed via `hydra-zoom/body'.
+
+Call the head: `(text-scale-set 0)'."
+             (interactive)
+             (hydra-disable)
+             (hydra-cleanup)
+             (catch (quote hydra-disable)
+               (call-interactively (function (lambda nil (interactive)
+                                                (text-scale-set 0))))))
+      (defun hydra-zoom/hint nil
+        (if hydra-lv (lv-message (format #("zoom: [r 0]: reset." 7 8 (face 
hydra-face-red)
+                                           9 10 (face hydra-face-blue))))
+          (message (format #("zoom: [r 0]: reset." 7 8 (face hydra-face-red)
+                             9 10 (face hydra-face-blue))))))
+      (defun hydra-zoom/body nil "Create a hydra with no body and the heads:
+
+\"r\":    `(text-scale-set 0)',
+\"0\":    `(text-scale-set 0)',
+\"1\":    `(text-scale-set 0)'
+
+The body can be accessed via `hydra-zoom/body'."
+             (interactive)
+             (hydra-disable)
+             (catch (quote hydra-disable)
+               (when hydra-is-helpful (hydra-zoom/hint))
+               (setq hydra-last
+                     (hydra-set-transient-map
+                      (setq hydra-curr-map
+                            (quote (keymap (7 . hydra-keyboard-quit)
+                                           (114 . hydra-zoom/lambda-r)
+                                           (kp-subtract . 
hydra--negative-argument)
+                                           (kp-9 . hydra--digit-argument)
+                                           (kp-8 . hydra--digit-argument)
+                                           (kp-7 . hydra--digit-argument)
+                                           (kp-6 . hydra--digit-argument)
+                                           (kp-5 . hydra--digit-argument)
+                                           (kp-4 . hydra--digit-argument)
+                                           (kp-3 . hydra--digit-argument)
+                                           (kp-2 . hydra--digit-argument)
+                                           (kp-1 . hydra--digit-argument)
+                                           (kp-0 . hydra--digit-argument)
+                                           (57 . hydra--digit-argument)
+                                           (56 . hydra--digit-argument)
+                                           (55 . hydra--digit-argument)
+                                           (54 . hydra--digit-argument)
+                                           (53 . hydra--digit-argument)
+                                           (52 . hydra--digit-argument)
+                                           (51 . hydra--digit-argument)
+                                           (50 . hydra--digit-argument)
+                                           (49 . hydra-zoom/lambda-r)
+                                           (48 . hydra-zoom/lambda-0)
+                                           (45 . hydra--negative-argument)
+                                           (21 . hydra--universal-argument))))
+                      t (lambda nil (hydra-cleanup))))
+               (setq prefix-arg current-prefix-arg)))))))
+
+(ert-deftest hydra--pad ()
+  (should (equal (hydra--pad '(a b c) 3)
+                 '(a b c)))
+  (should (equal (hydra--pad '(a) 3)
+                 '(a nil nil))))
+
+(ert-deftest hydra--matrix ()
+  (should (equal (hydra--matrix '(a b c) 2 2)
+                 '((a b) (c nil))))
+  (should (equal (hydra--matrix '(a b c d e f g h i) 4 3)
+                 '((a b c d) (e f g h) (i nil nil nil)))))
+
+(ert-deftest hydra--cell ()
+  (should (equal (hydra--cell "% -75s %%`%s" '(hydra-lv hydra-verbose))
+                 "When non-nil, `lv-message' (not `message') will be used to 
display hints.   %`hydra-lv^^^^^
+When non-nil, hydra will issue some non essential style warnings.           
%`hydra-verbose")))
+
+(ert-deftest hydra--vconcat ()
+  (should (equal (hydra--vconcat '("abc\ndef" "012\n34" "def\nabc"))
+                 "abc012def\ndef34abc")))
+
+(defhydradio hydra-tng ()
+  (picard "_p_ Captain Jean Luc Picard:")
+  (riker "_r_ Commander William Riker:")
+  (data "_d_ Lieutenant Commander Data:")
+  (worf "_w_ Worf:")
+  (la-forge "_f_ Geordi La Forge:")
+  (troi "_t_ Deanna Troi:")
+  (dr-crusher "_c_ Doctor Beverly Crusher:")
+  (phaser "_h_ Set phasers to " [stun kill]))
+
+(ert-deftest hydra--table ()
+  (let ((hydra-cell-format "% -30s %% -8`%s"))
+    (should (equal (hydra--table hydra-tng/names 5 2)
+                   (substring "
+_p_ Captain Jean Luc Picard:   % -8`hydra-tng/picard^^    _t_ Deanna Troi:     
          % -8`hydra-tng/troi^^^^^^
+_r_ Commander William Riker:   % -8`hydra-tng/riker^^^    _c_ Doctor Beverly 
Crusher:    % -8`hydra-tng/dr-crusher
+_d_ Lieutenant Commander Data: % -8`hydra-tng/data^^^^    _h_ Set phasers to   
          % -8`hydra-tng/phaser^^^^
+_w_ Worf:                      % -8`hydra-tng/worf^^^^
+_f_ Geordi La Forge:           % -8`hydra-tng/la-forge" 1)))
+    (should (equal (hydra--table hydra-tng/names 4 3)
+                   (substring "
+_p_ Captain Jean Luc Picard:   % -8`hydra-tng/picard    _f_ Geordi La Forge:   
        % -8`hydra-tng/la-forge^^
+_r_ Commander William Riker:   % -8`hydra-tng/riker^    _t_ Deanna Troi:       
        % -8`hydra-tng/troi^^^^^^
+_d_ Lieutenant Commander Data: % -8`hydra-tng/data^^    _c_ Doctor Beverly 
Crusher:    % -8`hydra-tng/dr-crusher
+_w_ Worf:                      % -8`hydra-tng/worf^^    _h_ Set phasers to     
        % -8`hydra-tng/phaser^^^^" 1)))))
 
 (provide 'hydra-test)
 
diff --git a/packages/hydra/hydra.el b/packages/hydra/hydra.el
index 95d3a42..dcdf03b 100644
--- a/packages/hydra/hydra.el
+++ b/packages/hydra/hydra.el
@@ -5,7 +5,7 @@
 ;; Author: Oleh Krehel <address@hidden>
 ;; Maintainer: Oleh Krehel <address@hidden>
 ;; URL: https://github.com/abo-abo/hydra
-;; Version: 0.5.0
+;; Version: 0.11.0
 ;; Keywords: bindings
 ;; Package-Requires: ((cl-lib "0.5"))
 
@@ -37,32 +37,68 @@
 ;; command.  This makes the Hydra very seamless, it's like a minor
 ;; mode that disables itself automagically.
 ;;
-;; Here's how to use the examples bundled with Hydra:
+;; Here's an example Hydra, bound in the global map (you can use any
+;; keymap in place of `global-map'):
 ;;
-;;    (require 'hydra-examples)
-;;    (hydra-create "C-M-y" hydra-example-move-window-splitter)
-;;    (hydra-create "M-g" hydra-example-goto-error)
+;;     (defhydra hydra-zoom (global-map "<f2>")
+;;       "zoom"
+;;       ("g" text-scale-increase "in")
+;;       ("l" text-scale-decrease "out"))
 ;;
-;; You can expand the examples in-place, it still looks elegant:
+;; It allows to start a command chain either like this:
+;; "<f2> gg4ll5g", or "<f2> lgllg".
 ;;
-;;     (hydra-create "<f2>"
-;;       '(("g" text-scale-increase "zoom in")
-;;         ("l" text-scale-decrease "zoom out")))
+;; Here's another approach, when you just want a "callable keymap":
 ;;
-;; The third element of each list is the optional doc string that will
-;; be displayed in the echo area when `hydra-is-helpful' is t.
+;;     (defhydra hydra-toggle (:color blue)
+;;       "toggle"
+;;       ("a" abbrev-mode "abbrev")
+;;       ("d" toggle-debug-on-error "debug")
+;;       ("f" auto-fill-mode "fill")
+;;       ("t" toggle-truncate-lines "truncate")
+;;       ("w" whitespace-mode "whitespace")
+;;       ("q" nil "cancel"))
 ;;
-;; It's better to take the examples simply as templates and use
-;; `defhydra' instead of `hydra-create', since it's more flexible.
+;; This binds nothing so far, but if you follow up with:
 ;;
-;;     (defhydra hydra-zoom (global-map "<f2>")
-;;       "zoom"
-;;       ("g" text-scale-increase "in")
-;;       ("l" text-scale-decrease "out"))
+;;     (global-set-key (kbd "C-c C-v") 'hydra-toggle/body)
+;;
+;; you will have bound "C-c C-v a", "C-c C-v d" etc.
+;;
+;; Knowing that `defhydra' defines e.g. `hydra-toggle/body' command,
+;; you can nest Hydras if you wish, with `hydra-toggle/body' possibly
+;; becoming a blue head of another Hydra.
+;;
+;; Initially, Hydra shipped with a simplified `hydra-create' macro, to
+;; which you could hook up the examples from hydra-examples.el.  It's
+;; better to take the examples simply as templates and use `defhydra'
+;; instead of `hydra-create', since it's more flexible.
 
 ;;; Code:
+;;* Requires
 (require 'cl-lib)
+(require 'lv)
 
+(defalias 'hydra-set-transient-map
+    (if (fboundp 'set-transient-map)
+        'set-transient-map
+      (lambda (map keep-pred &optional on-exit)
+        (with-no-warnings
+          (set-temporary-overlay-map map (hydra--pred on-exit))))))
+
+(defun hydra--pred (on-exit)
+  "Generate a predicate on whether to continue the Hydra state.
+Call ON-EXIT for clean-up.
+This is a compatibility code for Emacs older than 24.4."
+  `(lambda ()
+     (if (lookup-key hydra-curr-map (this-command-keys-vector))
+         t
+       (hydra-cleanup)
+       ,(when on-exit
+              `(funcall ,(hydra--make-callable on-exit)))
+       nil)))
+
+;;* Customize
 (defgroup hydra nil
   "Make bindings that stick around."
   :group 'bindings
@@ -73,99 +109,421 @@
   :type 'boolean
   :group 'hydra)
 
+(defcustom hydra-keyboard-quit ""
+  "This binding will quit an amaranth Hydra.
+It's the only other way to quit it besides though a blue head.
+It's possible to set this to nil.")
+
+(defcustom hydra-lv t
+  "When non-nil, `lv-message' (not `message') will be used to display hints."
+  :type 'boolean)
+
+(defcustom hydra-verbose nil
+  "When non-nil, hydra will issue some non essential style warnings."
+  :type 'boolean)
+
+(defcustom hydra-key-format-spec "%s"
+  "Default `format'-style specifier for _a_  syntax in docstrings.
+When nil, you can specify your own at each location like this: _ 5a_.")
+
 (defface hydra-face-red
-    '((t (:foreground "#7F0055" :bold t)))
+    '((t (:foreground "#FF0000" :bold t)))
   "Red Hydra heads will persist indefinitely."
   :group 'hydra)
 
 (defface hydra-face-blue
-    '((t (:foreground "#758BC6" :bold t)))
+    '((t (:foreground "#0000FF" :bold t)))
   "Blue Hydra heads will vanquish the Hydra.")
 
-(defalias 'hydra-set-transient-map
-  (if (fboundp 'set-transient-map)
-      'set-transient-map
-    'set-temporary-overlay-map))
-
+(defface hydra-face-amaranth
+    '((t (:foreground "#E52B50" :bold t)))
+  "Amaranth body has red heads and warns on intercepting non-heads.
+Vanquishable only through a blue head.")
+
+(defface hydra-face-pink
+    '((t (:foreground "#FF6EB4" :bold t)))
+  "Pink body has red heads and on intercepting non-heads calls them without 
quitting.
+Vanquishable only through a blue head.")
+
+(defface hydra-face-teal
+    '((t (:foreground "#367588" :bold t)))
+  "Teal body has blue heads an warns on intercepting non-heads.
+Vanquishable only through a blue head.")
+
+;;* Fontification
+(defun hydra-add-font-lock ()
+  "Fontify `defhydra' statements."
+  (font-lock-add-keywords
+   'emacs-lisp-mode
+   '(("(\\(defhydra\\)\\_> +\\(.*?\\)\\_>"
+      (1 font-lock-keyword-face)
+      (2 font-lock-type-face))
+     ("(\\(defhydradio\\)\\_> +\\(.*?\\)\\_>"
+      (1 font-lock-keyword-face)
+      (2 font-lock-type-face)))))
+
+;;* Universal Argument
+(defvar hydra-base-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [?\C-u] 'hydra--universal-argument)
+    (define-key map [?-] 'hydra--negative-argument)
+    (define-key map [?0] 'hydra--digit-argument)
+    (define-key map [?1] 'hydra--digit-argument)
+    (define-key map [?2] 'hydra--digit-argument)
+    (define-key map [?3] 'hydra--digit-argument)
+    (define-key map [?4] 'hydra--digit-argument)
+    (define-key map [?5] 'hydra--digit-argument)
+    (define-key map [?6] 'hydra--digit-argument)
+    (define-key map [?7] 'hydra--digit-argument)
+    (define-key map [?8] 'hydra--digit-argument)
+    (define-key map [?9] 'hydra--digit-argument)
+    (define-key map [kp-0] 'hydra--digit-argument)
+    (define-key map [kp-1] 'hydra--digit-argument)
+    (define-key map [kp-2] 'hydra--digit-argument)
+    (define-key map [kp-3] 'hydra--digit-argument)
+    (define-key map [kp-4] 'hydra--digit-argument)
+    (define-key map [kp-5] 'hydra--digit-argument)
+    (define-key map [kp-6] 'hydra--digit-argument)
+    (define-key map [kp-7] 'hydra--digit-argument)
+    (define-key map [kp-8] 'hydra--digit-argument)
+    (define-key map [kp-9] 'hydra--digit-argument)
+    (define-key map [kp-subtract] 'hydra--negative-argument)
+    map)
+  "Keymap that all Hydras inherit.  See `universal-argument-map'.")
+
+(defvar hydra-curr-map
+  (make-sparse-keymap)
+  "Keymap of the current Hydra called.")
+
+(defun hydra--universal-argument (arg)
+  "Forward to (`universal-argument' ARG)."
+  (interactive "P")
+  (setq prefix-arg (if (consp arg)
+                       (list (* 4 (car arg)))
+                     (if (eq arg '-)
+                         (list -4)
+                       '(4))))
+  (hydra-set-transient-map hydra-curr-map t))
+
+(defun hydra--digit-argument (arg)
+  "Forward to (`digit-argument' ARG)."
+  (interactive "P")
+  (let ((universal-argument-map hydra-curr-map))
+    (digit-argument arg)))
+
+(defun hydra--negative-argument (arg)
+  "Forward to (`negative-argument' ARG)."
+  (interactive "P")
+  (let ((universal-argument-map hydra-curr-map))
+    (negative-argument arg)))
+;;* Repeat
+(defvar hydra-repeat--prefix-arg nil
+  "Prefix arg to use with `hydra-repeat'.")
+
+(defvar hydra-repeat--command nil
+  "Command to use with `hydra-repeat'.")
+
+(defun hydra-repeat ()
+  "Repeat last command with last prefix arg."
+  (interactive)
+  (unless (string-match "hydra-repeat$" (symbol-name last-command))
+    (setq hydra-repeat--command last-command)
+    (setq hydra-repeat--prefix-arg (or last-prefix-arg 1)))
+  (setq current-prefix-arg hydra-repeat--prefix-arg)
+  (funcall hydra-repeat--command))
+
+;;* Misc internals
 (defvar hydra-last nil
   "The result of the last `hydra-set-transient-map' call.")
 
-;;;###autoload
-(defmacro hydra-create (body heads &optional method)
-  "Create a hydra with a BODY prefix and HEADS with METHOD.
-This will result in `global-set-key' statements with the keys
-being the concatenation of BODY and each head in HEADS.  HEADS is
-an list of (KEY FUNCTION &optional HINT).
-
-After one of the HEADS is called via BODY+KEY, it and the other
-HEADS can be called with only KEY (no need for BODY).  This state
-is broken once any key binding that is not in HEADS is called.
-
-METHOD is a lambda takes two arguments: a KEY and a COMMAND.
-It defaults to `global-set-key'.
-When `(keymapp METHOD)`, it becomes:
-
-    (lambda (key command) (define-key METHOD key command))"
-  (declare (indent 1))
-  `(defhydra ,(intern
-               (concat
-                "hydra-" (replace-regexp-in-string " " "_" body)))
-       ,(cond ((hydra--callablep method)
-              method)
-             ((null method)
-              `(global-map ,body))
-             (t
-              (list method body)))
-     "hydra"
-     ,@(eval heads)))
-
 (defun hydra--callablep (x)
   "Test if X is callable."
   (or (functionp x)
       (and (consp x)
            (memq (car x) '(function quote)))))
 
-(defun hydra--color (h body-color)
-  "Return the color of a Hydra head H with BODY-COLOR."
-  (if (null (cadr h))
-      'blue
-    (let ((plist (if (stringp (cl-caddr h))
-                     (cl-cdddr h)
-                   (cddr h))))
-      (or (plist-get plist :color) body-color))))
-
-(defun hydra--face (h body-color)
-  "Return the face for a Hydra head H with BODY-COLOR."
-  (cl-case (hydra--color h body-color)
+(defun hydra--make-callable (x)
+  "Generate a callable symbol from X.
+If X is a function symbol or a lambda, return it.  Otherwise, it
+should be a single statement.  Wrap it in an interactive lambda."
+  (if (or (symbolp x) (functionp x))
+      x
+    `(lambda ()
+       (interactive)
+       ,x)))
+
+(defun hydra--head-property (h prop &optional default)
+  "Return for Hydra head H the value of property PROP.
+Return DEFAULT if PROP is not in H."
+  (let ((plist (cl-cdddr h)))
+    (if (memq prop h)
+        (plist-get plist prop)
+      default)))
+
+(defun hydra--aggregate-color (head-color body-color)
+  "Return the resulting head color for HEAD-COLOR and BODY-COLOR."
+  (cond ((eq head-color 'red)
+         (cl-case body-color
+           (red 'red)
+           (blue 'red)
+           (amaranth 'amaranth)
+           (pink 'pink)
+           (cyan 'amaranth)))
+        ((eq head-color 'blue)
+         (cl-case body-color
+           (red 'blue)
+           (blue 'blue)
+           (amaranth 'teal)
+           (pink 'blue)
+           (cyan 'teal)))
+        (t
+         (error "Can't aggregate head %S to body %S"
+                head-color body-color))))
+
+(defun hydra--head-color (h body)
+  "Return the color of a Hydra head H with BODY."
+  (let* ((exit (hydra--head-property h :exit 'default))
+         (color (hydra--head-property h :color))
+         (foreign-keys (hydra--body-foreign-keys body))
+         (head-color
+          (cond ((eq exit 'default)
+                 (cl-case color
+                   (blue 'blue)
+                   (red 'red)
+                   (t
+                    (unless (null color)
+                      (error "Use only :blue or :red for heads: %S" h)))))
+                ((null exit)
+                 (if color
+                     (error "Don't mix :color and :exit - they are aliases: 
%S" h)
+                   (cl-case foreign-keys
+                     (run 'pink)
+                     (warn 'amaranth)
+                     (t 'red))))
+                ((eq exit t)
+                 (if color
+                     (error "Don't mix :color and :exit - they are aliases: 
%S" h)
+                   'blue))
+                (t
+                 (error "Unknown :exit %S" exit)))))
+    (let ((body-exit (plist-get (cddr body) :exit)))
+      (cond ((null (cadr h))
+             (when head-color
+               (hydra--complain
+                "Doubly specified blue head - nil cmd is already blue: %S" h))
+             'blue)
+            ((null head-color)
+             (hydra--body-color body))
+            ((null foreign-keys)
+             head-color)
+            ((eq foreign-keys 'run)
+             (if (eq head-color 'red)
+                 'pink
+               'blue))
+            ((eq foreign-keys 'warn)
+             (if (memq head-color '(red amaranth))
+                 'amaranth
+               'teal))
+            (t
+             (error "Unexpected %S %S" h body))))))
+
+(defun hydra--body-foreign-keys (body)
+  "Return what BODY does with a non-head binding."
+  (or
+   (plist-get (cddr body) :foreign-keys)
+   (let ((color (plist-get (cddr body) :color)))
+     (cl-case color
+       ((amaranth teal) 'warn)
+       (pink 'run)))))
+
+(defun hydra--body-color (body)
+  "Return the color of BODY.
+BODY is the second argument to `defhydra'"
+  (let ((color (plist-get (cddr body) :color))
+        (exit (plist-get (cddr body) :exit))
+        (foreign-keys (plist-get (cddr body) :foreign-keys)))
+    (cond ((eq foreign-keys 'warn)
+           (if exit 'teal 'amaranth))
+          ((eq foreign-keys 'run) 'pink)
+          (exit 'blue)
+          (color color)
+          (t 'red))))
+
+(defun hydra--face (h body)
+  "Return the face for a Hydra head H with BODY."
+  (cl-case (hydra--head-color h body)
     (blue 'hydra-face-blue)
     (red 'hydra-face-red)
+    (amaranth 'hydra-face-amaranth)
+    (pink 'hydra-face-pink)
+    (teal 'hydra-face-teal)
     (t (error "Unknown color for %S" h))))
 
-(defun hydra--hint (docstring heads)
-  "Generate a hint from DOCSTRING and HEADS.
-It's intended for the echo area, when a Hydra is active."
-  (format "%s: %s."
-          docstring
-          (mapconcat
-           (lambda (h)
-             (format
-              (if (stringp (cl-caddr h))
-                  (concat "[%s]: " (cl-caddr h))
-                "%s")
-              (propertize
-               (car h) 'face
-               (hydra--face h body-color))))
-           heads ", ")))
+(defun hydra-cleanup ()
+  "Clean up after a Hydra."
+  (when (window-live-p lv-wnd)
+    (let ((buf (window-buffer lv-wnd)))
+      (delete-window lv-wnd)
+      (kill-buffer buf))))
+
+(defun hydra-keyboard-quit ()
+  "Quitting function similar to `keyboard-quit'."
+  (interactive)
+  (hydra-disable)
+  (hydra-cleanup)
+  (cancel-timer hydra-timer)
+  nil)
 
 (defun hydra-disable ()
   "Disable the current Hydra."
-  (if (functionp hydra-last)
-      (funcall hydra-last)
-    (while (and (consp (car emulation-mode-map-alists))
-                (consp (caar emulation-mode-map-alists))
-                (equal (cl-cdaar emulation-mode-map-alists) ',keymap))
-      (setq emulation-mode-map-alists
-            (cdr emulation-mode-map-alists)))))
+  (cond
+    ;; Emacs 25
+    ((functionp hydra-last)
+     (funcall hydra-last))
+
+    ;; Emacs 24.3 or older
+    ((< emacs-minor-version 4)
+     (setq emulation-mode-map-alists
+           (cl-remove-if
+            (lambda (x)
+              (and (consp x)
+                   (consp (car x))
+                   (equal (cdar x) hydra-curr-map)))
+            emulation-mode-map-alists)))
+
+    ;; Emacs 24.4.1
+    (t
+     (setq overriding-terminal-local-map nil))))
+
+(defun hydra--unalias-var (str prefix)
+  "Return the symbol named STR if it's bound as a variable.
+Otherwise, add PREFIX to the symbol name."
+  (let ((sym (intern-soft str)))
+    (if (boundp sym)
+        sym
+      (intern (concat prefix "/" str)))))
+
+(defun hydra--hint (name body docstring heads)
+  "Generate a hint for the echo area.
+NAME, BODY, DOCSTRING and HEADS are parameters to `defhydra'."
+  (let (alist)
+    (dolist (h heads)
+      (let ((val (assoc (cadr h) alist))
+            (pstr (hydra-fontify-head h body)))
+        (unless (null (cl-caddr h))
+          (if val
+              (setf (cadr val)
+                    (concat (cadr val) " " pstr))
+            (push
+             (cons (cadr h)
+                   (cons pstr (cl-caddr h)))
+             alist)))))
+    (mapconcat
+     (lambda (x)
+       (format
+        (if (> (length (cdr x)) 0)
+            (concat "[%s]: " (cdr x))
+          "%s")
+        (car x)))
+     (nreverse (mapcar #'cdr alist))
+     ", ")))
+
+(defvar hydra-fontify-head-function nil
+  "Possible replacement for `hydra-fontify-head-default'.")
+
+(defun hydra-fontify-head-default (head body)
+  "Produce a pretty string from HEAD and BODY.
+HEAD's binding is returned as a string with a colored face."
+  (propertize (car head) 'face (hydra--face head body)))
+
+(defun hydra-fontify-head-greyscale (head body)
+  "Produce a pretty string from HEAD and BODY.
+HEAD's binding is returned as a string wrapped with [] or {}."
+  (let ((color (hydra--head-color head body)))
+    (format
+     (if (eq color 'blue)
+         "[%s]"
+       "{%s}") (car head))))
+
+(defun hydra-fontify-head (head body)
+  "Produce a pretty string from HEAD and BODY."
+  (funcall (or hydra-fontify-head-function 'hydra-fontify-head-default)
+           head body))
+
+(defun hydra--format (name body docstring heads)
+  "Generate a `format' statement from STR.
+\"%`...\" expressions are extracted into \"%S\".
+NAME, BODY, DOCSTRING and HEADS are parameters of `defhydra'.
+The expressions can be auto-expanded according to NAME."
+  (setq docstring (replace-regexp-in-string "\\^" "" docstring))
+  (let ((rest (hydra--hint name body docstring heads))
+        (body-color (hydra--body-color body))
+        (prefix (symbol-name name))
+        (start 0)
+        varlist
+        offset)
+    (while (setq start
+                 (string-match
+                  "\\(?:%\\( 
?-?[0-9]*s?\\)\\(`[a-z-A-Z/0-9]+\\|(\\)\\)\\|\\(?:_\\( 
?-?[0-9]*\\)\\([a-z-~A-Z0-9/|?<>={}]+\\)_\\)"
+                  docstring start))
+      (cond ((eq ?_ (aref (match-string 0 docstring) 0))
+             (let* ((key (match-string 4 docstring))
+                    (head (assoc key heads)))
+               (if head
+                   (progn
+                     (push (hydra-fontify-head head body) varlist)
+                     (setq docstring
+                           (replace-match
+                            (or
+                             hydra-key-format-spec
+                             (concat "%" (match-string 3 docstring) "s"))
+                            nil nil docstring)))
+                 (error "Unrecognized key: _%s_" key))))
+
+            ((eq ?` (aref (match-string 2 docstring) 0))
+             (push (hydra--unalias-var
+                    (substring (match-string 2 docstring) 1) prefix) varlist)
+             (setq docstring
+                   (replace-match
+                    (concat "%" (match-string 1 docstring) "S")
+                    nil nil docstring 0)))
+
+            (t
+             (let* ((spec (match-string 1 docstring))
+                    (lspec (length spec)))
+               (setq offset
+                     (with-temp-buffer
+                       (insert (substring docstring (+ 1 start (length spec))))
+                       (goto-char (point-min))
+                       (push (read (current-buffer)) varlist)
+                       (point)))
+               (when (or (zerop lspec)
+                         (/= (aref spec (1- (length spec))) ?s))
+                 (setq spec (concat spec "S")))
+               (setq docstring
+                     (concat
+                      (substring docstring 0 start)
+                      "%" spec
+                      (substring docstring
+                                 (+ (match-end 2) offset -2))))))))
+    (if (eq ?\n (aref docstring 0))
+        `(concat (format ,(substring docstring 1) ,@(nreverse varlist))
+                 ,rest)
+      `(format ,(concat docstring ": " rest ".")))))
+
+(defun hydra--message (name body docstring heads)
+  "Generate code to display the hint in the preferred echo area.
+Set `hydra-lv' to choose the echo area.
+NAME, BODY, DOCSTRING, and HEADS are parameters of `defhydra'."
+  (let ((format-expr (hydra--format name body docstring heads)))
+    `(if hydra-lv
+         (lv-message ,format-expr)
+       (message ,format-expr))))
+
+(defun hydra--complain (format-string &rest args)
+  "Forward to (`message' FORMAT-STRING ARGS) unless `hydra-verbose' is nil."
+  (when hydra-verbose
+    (apply #'warn format-string args)))
 
 (defun hydra--doc (body-key body-name heads)
   "Generate a part of Hydra docstring.
@@ -183,69 +541,341 @@ HEADS is a list of heads."
     heads ",\n")
    (format "The body can be accessed via `%S'." body-name)))
 
+(defun hydra--make-defun (name body doc head
+                          keymap body-pre body-post &optional other-post)
+  "Make a defun wrapper, using NAME, BODY, DOC, HEAD, and KEYMAP.
+NAME and BODY are the arguments to `defhydra'.
+DOC was generated with `hydra--doc'.
+HEAD is one of the HEADS passed to `defhydra'.
+BODY-PRE and BODY-POST are pre-processed in `defhydra'.
+OTHER-POST is an optional extension to the :post key of BODY."
+  (let ((name (hydra--head-name head name))
+        (cmd (when (car head)
+               (hydra--make-callable
+                (cadr head))))
+        (color (when (car head)
+                 (hydra--head-color head body)))
+        (doc (if (car head)
+                 (format "%s\n\nCall the head: `%S'." doc (cadr head))
+               doc))
+        (hint (intern (format "%S/hint" name)))
+        (body-color (hydra--body-color body))
+        (body-timeout (plist-get body :timeout)))
+    `(defun ,name ()
+       ,doc
+       (interactive)
+       ,@(when body-pre (list body-pre))
+       (hydra-disable)
+       ,@(when (memq color '(blue teal)) '((hydra-cleanup)))
+       (catch 'hydra-disable
+         ,@(delq nil
+                 (if (memq color '(blue teal))
+                     `(,(when cmd `(call-interactively #',cmd))
+                        ,body-post)
+                   `(,(when cmd
+                            `(condition-case err
+                                 (prog1 t
+                                   (call-interactively #',cmd))
+                               ((quit error)
+                                (message "%S" err)
+                                (unless hydra-lv
+                                  (sit-for 0.8))
+                                nil)))
+                      (when hydra-is-helpful
+                        (,hint))
+                      (setq hydra-last
+                            (hydra-set-transient-map
+                             (setq hydra-curr-map ',keymap)
+                             t
+                             ,(if (and
+                                   (not (memq body-color
+                                              '(amaranth pink teal)))
+                                   body-post)
+                                  `(lambda () (hydra-cleanup) ,body-post)
+                                  `(lambda () (hydra-cleanup)))))
+                      ,(or other-post
+                           (when body-timeout
+                             `(hydra-timeout ,body-timeout))))))))))
+
+(defun hydra-pink-fallback ()
+  "On intercepting a non-head, try to run it."
+  (let ((keys (this-command-keys))
+        kb)
+    (when (equal keys [backspace])
+      (setq keys ""))
+    (setq kb (key-binding keys))
+    (if kb
+        (if (commandp kb)
+            (condition-case err
+                (call-interactively kb)
+              ((quit error)
+               (message "%S" err)
+               (unless hydra-lv
+                 (sit-for 0.8))))
+          (message "Pink Hydra can't currently handle prefixes, continuing"))
+      (message "Pink Hydra could not resolve: %S" keys))))
+
+(defun hydra--handle-nonhead (keymap name body heads)
+  "Setup KEYMAP for intercepting non-head bindings.
+NAME, BODY and HEADS are parameters to `defhydra'."
+  (let ((body-color (hydra--body-color body))
+        (body-post (plist-get (cddr body) :post)))
+    (when (and body-post (symbolp body-post))
+      (setq body-post `(funcall #',body-post)))
+    (when hydra-keyboard-quit
+      (define-key keymap hydra-keyboard-quit #'hydra-keyboard-quit))
+    (when (memq body-color '(amaranth pink teal))
+      (if (cl-some `(lambda (h)
+                      (memq (hydra--head-color h body) '(blue teal)))
+                   heads)
+          (progn
+            (define-key keymap [t]
+              `(lambda ()
+                 (interactive)
+                 ,(cond
+                   ((memq body-color '(amaranth teal))
+                    '(message "An amaranth Hydra can only exit through a blue 
head"))
+                   (t
+                    '(hydra-pink-fallback)))
+                 (hydra-set-transient-map hydra-curr-map t)
+                 (when hydra-is-helpful
+                   (unless hydra-lv
+                     (sit-for 0.8))
+                   (,(intern (format "%S/hint" name)))))))
+        (unless (eq body-color 'teal)
+          (error
+           "An %S Hydra must have at least one blue head in order to exit"
+           body-color))))))
+
+(defun hydra--head-name (h body-name)
+  "Return the symbol for head H of body BODY-NAME."
+  (intern (format "%S/%s" body-name
+                  (if (symbolp (cadr h))
+                      (cadr h)
+                    (concat "lambda-" (car h))))))
+
+(defun hydra--delete-duplicates (heads)
+  "Return HEADS without entries that have the same CMD part.
+In duplicate HEADS, :cmd-name is modified to whatever they duplicate."
+  (let ((ali '(((hydra-repeat . red) . hydra-repeat)))
+        res entry)
+    (dolist (h heads)
+      (if (setq entry (assoc (cons (cadr h)
+                                   (hydra--head-color h '(nil nil)))
+                             ali))
+          (setf (cl-cdddr h) (plist-put (cl-cdddr h) :cmd-name (cdr entry)))
+        (push (cons (cons (cadr h)
+                          (hydra--head-color h '(nil nil)))
+                    (plist-get (cl-cdddr h) :cmd-name))
+              ali)
+        (push h res)))
+    (nreverse res)))
+
+(defun hydra--pad (lst n)
+  "Pad LST with nil until length N."
+  (let ((len (length lst)))
+    (if (= len n)
+        lst
+      (append lst (make-list (- n len) nil)))))
+
+(defun hydra--matrix (lst rows cols)
+  "Create a matrix from elements of LST.
+The matrix size is ROWS times COLS."
+  (let ((ls (copy-sequence lst))
+        res)
+    (dotimes (c cols)
+      (push (hydra--pad (hydra-multipop ls rows) rows) res))
+    (nreverse res)))
+
+(defun hydra--cell (fstr names)
+  "Format a rectangular cell based on FSTR and NAMES.
+FSTR is a format-style string with two string inputs: one for the
+doc and one for the symbol name.
+NAMES is a list of variables."
+  (let ((len (cl-reduce
+              (lambda (acc it) (max (length (symbol-name it)) acc))
+              names
+              :initial-value 0)))
+    (mapconcat
+     (lambda (sym)
+       (if sym
+           (format fstr
+                   (documentation-property sym 'variable-documentation)
+                   (let ((name (symbol-name sym)))
+                     (concat name (make-string (- len (length name)) ?^)))
+                   sym)
+         ""))
+     names
+     "\n")))
+
+(defun hydra--vconcat (strs &optional joiner)
+  "Glue STRS vertically.  They must be the same height.
+JOINER is a function similar to `concat'."
+  (setq joiner (or joiner #'concat))
+  (mapconcat
+   (lambda (s)
+     (if (string-match " +$" s)
+         (replace-match "" nil nil s)
+       s))
+   (apply #'cl-mapcar joiner
+          (mapcar
+           (lambda (s) (split-string s "\n"))
+           strs))
+   "\n"))
+
+(defcustom hydra-cell-format "% -20s %% -8`%s"
+  "The default format for docstring cells."
+  :type 'string)
+
+(defun hydra--table (names rows cols &optional cell-formats)
+  "Format a `format'-style table from variables in NAMES.
+The size of the table is ROWS times COLS.
+CELL-FORMATS are `format' strings for each column.
+If CELL-FORMATS is a string, it's used for all columns.
+If CELL-FORMATS is nil, `hydra-cell-format' is used for all columns."
+  (setq cell-formats
+        (cond ((null cell-formats)
+               (make-list cols hydra-cell-format))
+              ((stringp cell-formats)
+               (make-list cols cell-formats))
+              (t
+               cell-formats)))
+  (hydra--vconcat
+   (cl-mapcar
+    #'hydra--cell
+    cell-formats
+    (hydra--matrix names rows cols))
+   (lambda (&rest x)
+     (mapconcat #'identity x "    "))))
+
+(defun hydra-reset-radios (names)
+  "Set varibles NAMES to their defaults.
+NAMES should be defined by `defhydradio' or similar."
+  (dolist (n names)
+    (set n (aref (get n 'range) 0))))
+
+(defvar hydra-timer (timer-create)
+  "Timer for `hydra-timeout'.")
+
+(defun hydra-timeout (secs &optional function)
+  "In SECS seconds call FUNCTION.
+FUNCTION defaults to `hydra-disable'.
+Cancel the previous `hydra-timeout'."
+  (cancel-timer hydra-timer)
+  (setq hydra-timer (timer-create))
+  (timer-set-time hydra-timer
+                  (timer-relative-time nil secs))
+  (timer-set-function
+   hydra-timer
+   (or function #'hydra-keyboard-quit))
+  (timer-activate hydra-timer))
+
+;;* Macros
+;;** defhydra
 ;;;###autoload
 (defmacro defhydra (name body &optional docstring &rest heads)
-  "Create a hydra named NAME with a prefix BODY.
+  "Create a Hydra - a family of functions with prefix NAME.
 
 NAME should be a symbol, it will be the prefix of all functions
 defined here.
 
-BODY should be either:
+BODY has the format:
 
-    (BODY-MAP &optional BODY-KEY &rest PLIST)
-or:
-
-    (lambda (KEY CMD) ...)
-
-BODY-MAP should be a keymap; `global-map' is acceptable here.
-BODY-KEY should be a string processable by `kbd'.
+    (BODY-MAP BODY-KEY &rest PLIST)
 
 DOCSTRING will be displayed in the echo area to identify the
-hydra.
-
-HEADS is a list of (KEY CMD &optional HINT &rest PLIST).
-
-PLIST in both cases recognizes only the :color key so far, which
-in turn can be either red or blue."
-  (unless (stringp docstring)
-    (setq heads (cons docstring heads))
-    (setq docstring "hydra"))
+Hydra.
+
+Functions are created on basis of HEADS, each of which has the
+format:
+
+    (KEY CMD &optional HINT &rest PLIST)
+
+BODY-MAP is a keymap; `global-map' is used quite often.  Each
+function generated from HEADS will be bound in BODY-MAP to
+BODY-KEY + KEY (both are strings passed to `kbd'), and will set
+the transient map so that all following heads can be called
+though KEY only.
+
+CMD is a callable expression: either an interactive function
+name, or an interactive lambda, or a single sexp (it will be
+wrapped in an interactive lambda).
+
+HINT is a short string that identifies its head.  It will be
+printed beside KEY in the echo erea if `hydra-is-helpful' is not
+nil.  If you don't even want the KEY to be printed, set HINT
+explicitly to nil.
+
+The heads inherit their PLIST from the body and are allowed to
+override each key.  The keys recognized are :color and :bind.
+:color can be:
+
+- red (default): this head will continue the Hydra state.
+- blue: this head will stop the Hydra state.
+- amaranth (applies to body only): similar to red, but no binding
+except a blue head can stop the Hydra state.
+
+:bind can be:
+- nil: this head will not be bound in BODY-MAP.
+- a lambda taking KEY and CMD used to bind a head
+
+It is possible to omit both BODY-MAP and BODY-KEY if you don't
+want to bind anything.  In that case, typically you will bind the
+generated NAME/body command.  This command is also the return
+result of `defhydra'."
+  (declare (indent defun))
+  (cond ((stringp docstring))
+        ((and (consp docstring)
+              (memq (car docstring) '(hydra--table concat format)))
+         (setq docstring (concat "\n" (eval docstring))))
+        (t
+         (setq heads (cons docstring heads))
+         (setq docstring "hydra")))
   (when (keywordp (car body))
     (setq body (cons nil (cons nil body))))
-  (let* ((keymap (make-sparse-keymap))
-         (names (mapcar
-                 (lambda (x)
-                   (define-key keymap (kbd (car x))
-                     (intern (format "%S/%s" name (cadr x)))))
-                 heads))
+  (dolist (h heads)
+    (let ((len (length h))
+          (cmd-name (hydra--head-name h name)))
+      (cond ((< len 2)
+             (error "Each head should have at least two items: %S" h))
+            ((= len 2)
+             (setcdr (cdr h) `("" :cmd-name ,cmd-name)))
+            (t
+             (let ((hint (cl-caddr h)))
+               (unless (or (null hint)
+                           (stringp hint))
+                 (setcdr (cdr h) (cons "" (cddr h))))
+               (setcdr (cddr h) `(:cmd-name ,cmd-name ,@(cl-cdddr h))))))))
+  (let* ((keymap (copy-keymap hydra-base-map))
          (body-name (intern (format "%S/body" name)))
          (body-key (unless (hydra--callablep body)
                      (cadr body)))
-         (body-color (if (hydra--callablep body)
-                         'red
-                       (or (plist-get (cddr body) :color)
-                           'red)))
-         (method (if (hydra--callablep body)
-                     body
-                   (car body)))
-         (hint (hydra--hint docstring heads))
-         (doc (hydra--doc body-key body-name heads)))
+         (body-color (hydra--body-color body))
+         (body-pre (plist-get (cddr body) :pre))
+         (body-body-pre (plist-get (cddr body) :body-pre))
+         (body-post (plist-get (cddr body) :post))
+         (method (or (plist-get body :bind)
+                     (car body)))
+         (doc (hydra--doc body-key body-name heads))
+         (heads-nodup (hydra--delete-duplicates heads)))
+    (mapc
+     (lambda (x)
+       (define-key keymap (kbd (car x))
+         (plist-get (cl-cdddr x) :cmd-name)))
+     heads)
+    (when (and body-pre (symbolp body-pre))
+      (setq body-pre `(funcall #',body-pre)))
+    (when (and body-body-pre (symbolp body-body-pre))
+      (setq body-body-pre `(funcall #',body-body-pre)))
+    (when (and body-post (symbolp body-post))
+      (setq body-post `(funcall #',body-post)))
+    (hydra--handle-nonhead keymap name body heads)
     `(progn
-       ,@(cl-mapcar
-          (lambda (head name)
-            `(defun ,name ()
-               ,(format "%s\n\nCall the head: `%S'." doc (cadr head))
-               (interactive)
-               ,@(if (eq (hydra--color head body-color) 'blue)
-                     `((hydra-disable)
-                       ,@(unless (null (cadr head))
-                                 `((call-interactively #',(cadr head)))))
-                     `((call-interactively #',(cadr head))
-                       (when hydra-is-helpful
-                         (message ,hint))
-                       (setq hydra-last
-                             (hydra-set-transient-map ',keymap t))))))
-          heads names)
+       ,@(mapcar
+          (lambda (head)
+            (hydra--make-defun name body doc head keymap
+                               body-pre body-post))
+          heads-nodup)
        ,@(unless (or (null body-key)
                      (null method)
                      (hydra--callablep method))
@@ -253,23 +883,117 @@ in turn can be either red or blue."
                      (define-key ,method (kbd ,body-key) nil))))
        ,@(delq nil
                (cl-mapcar
-                (lambda (head name)
-                  (unless (or (null body-key) (null method))
-                    (list
-                     (if (hydra--callablep method)
-                         'funcall
-                       'define-key)
-                     method
-                     (vconcat (kbd body-key) (kbd (car head)))
-                     (list 'function name))))
-                heads names))
-       (defun ,body-name ()
-         ,doc
-         (interactive)
-         (when hydra-is-helpful
-           (message ,hint))
-         (setq hydra-last
-               (hydra-set-transient-map ',keymap t))))))
+                (lambda (head)
+                  (let ((name (hydra--head-property head :cmd-name)))
+                    (when (cadr head)
+                      (when (or body-key method)
+                        (let ((bind (hydra--head-property head :bind 'default))
+                              (final-key
+                               (if body-key
+                                   (vconcat (kbd body-key) (kbd (car head)))
+                                 (kbd (car head)))))
+                          (cond ((null bind) nil)
+
+                                ((eq bind 'default)
+                                 (list
+                                  (if (hydra--callablep method)
+                                      'funcall
+                                    'define-key)
+                                  method
+                                  final-key
+                                  (list 'function name)))
+
+                                ((hydra--callablep bind)
+                                 `(funcall (function ,bind)
+                                           ,final-key
+                                           (function ,name)))
+
+                                (t
+                                 (error "Invalid :bind property %S" 
head))))))))
+                heads))
+       (defun ,(intern (format "%S/hint" name)) ()
+         ,(hydra--message name body docstring heads))
+       ,(hydra--make-defun
+         name body doc '(nil body)
+         keymap
+         (or body-body-pre body-pre) body-post
+         '(setq prefix-arg current-prefix-arg)))))
+
+(defmacro defhydradio (name body &rest heads)
+  "Create radios with prefix NAME.
+BODY specifies the options; there are none currently.
+HEADS have the format:
+
+    (TOGGLE-NAME &optional VALUE DOC)
+
+TOGGLE-NAME will be used along with NAME to generate a variable
+name and a function that cycles it with the same name.  VALUE
+should be an array.  The first element of VALUE will be used to
+inialize the variable.
+VALUE defaults to [nil t].
+DOC defaults to TOGGLE-NAME split and capitalized."
+  (declare (indent defun))
+  `(progn
+     ,@(apply #'append
+              (mapcar (lambda (h)
+                        (hydra--radio name h))
+                      heads))
+     (defvar ,(intern (format "%S/names" name))
+       ',(mapcar (lambda (h) (intern (format "%S/%S" name (car h))))
+                 heads))))
+
+(defmacro hydra-multipop (lst n)
+  "Return LST's first N elements while removing them."
+  `(if (<= (length ,lst) ,n)
+       (prog1 ,lst
+         (setq ,lst nil))
+     (prog1 ,lst
+       (setcdr
+        (nthcdr (1- ,n) (prog1 ,lst (setq ,lst (nthcdr ,n ,lst))))
+        nil))))
+
+(defun hydra--radio (parent head)
+  "Generate a hydradio with PARENT from HEAD."
+  (let* ((name (car head))
+         (full-name (intern (format "%S/%S" parent name)))
+         (doc (cadr head))
+         (val (or (cl-caddr head) [nil t])))
+    `((defvar ,full-name ,(hydra--quote-maybe (aref val 0)) ,doc)
+      (put ',full-name 'range ,val)
+      (defun ,full-name ()
+        (hydra--cycle-radio ',full-name)))))
+
+(defun hydra--quote-maybe (x)
+  "Quote X if it's a symbol."
+  (cond ((null x)
+         nil)
+        ((symbolp x)
+         (list 'quote x))
+        (t
+         x)))
+
+(defun hydra--cycle-radio (sym)
+  "Set SYM to the next value in its range."
+  (let* ((val (symbol-value sym))
+         (range (get sym 'range))
+         (i 0)
+         (l (length range)))
+    (setq i (catch 'done
+              (while (< i l)
+                (if (equal (aref range i) val)
+                    (throw 'done (1+ i))
+                  (incf i)))
+              (error "Val not in range for %S" sym)))
+    (set sym
+         (aref range
+               (if (>= i l)
+                   0
+                 i)))))
 
 (provide 'hydra)
+
+;;; Local Variables:
+;;; outline-regexp: ";;\\*+"
+;;; End:
+
 ;;; hydra.el ends here
diff --git a/packages/hydra/lv.el b/packages/hydra/lv.el
new file mode 100644
index 0000000..7b19074
--- /dev/null
+++ b/packages/hydra/lv.el
@@ -0,0 +1,75 @@
+;;; lv.el --- Other echo area
+
+;; Copyright (C) 2015  Free Software Foundation, Inc.
+
+;; Author: Oleh Krehel
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This package provides `lv-message' intended to be used in place of
+;; `message' when semi-permanent hints are needed, in order to not
+;; interfere with Echo Area.
+;;
+;;    "Я тихо-тихо пiдглядаю,
+;;     І тiшуся собi, як бачу то,
+;;     Шо страшить i не пiдпускає,
+;;     А iншi п’ють тебе, як воду пiсок."
+;;     --  Андрій Кузьменко, L.V.
+
+;;; Code:
+
+(defvar lv-wnd nil
+  "Holds the current LV window.")
+
+(defun lv-window ()
+  "Ensure that LV window is live and return it."
+  (if (window-live-p lv-wnd)
+      lv-wnd
+    (let ((ori (selected-window))
+          (golden-ratio-mode nil)
+          buf)
+      (prog1 (setq lv-wnd
+                   (select-window
+                    (split-window
+                     (frame-root-window) -1 'below)))
+        (if (setq buf (get-buffer "*LV*"))
+            (switch-to-buffer buf)
+          (switch-to-buffer "*LV*")
+          (setq truncate-lines nil)
+          (setq mode-line-format nil)
+          (setq cursor-type nil)
+          (set-window-dedicated-p lv-wnd t)
+          (set-window-parameter lv-wnd 'no-other-window t))
+        (select-window ori)))))
+
+(defun lv-message (format-string &rest args)
+  "Set LV window contents to (`format' FORMAT-STRING ARGS)."
+  (let ((ori (selected-window))
+        (str (apply #'format format-string args))
+        deactivate-mark)
+    (select-window (lv-window))
+    (unless (string= (buffer-string) str)
+      (delete-region (point-min) (point-max))
+      (insert str)
+      (fit-window-to-buffer nil nil 1))
+    (goto-char (point-min))
+    (select-window ori)))
+
+(provide 'lv)
+
+;;; lv.el ends here
diff --git a/packages/jgraph-mode/jgraph-mode.el 
b/packages/jgraph-mode/jgraph-mode.el
index a56449e..ea2a0d2 100644
--- a/packages/jgraph-mode/jgraph-mode.el
+++ b/packages/jgraph-mode/jgraph-mode.el
@@ -1,9 +1,9 @@
 ;;; jgraph-mode.el --- Major mode for Jgraph files  -*- lexical-binding:t -*-
 
-;; Copyright (C) 2006, 2011-2012, 2014  Free Software Foundation, Inc
+;; Copyright (C) 2006, 2011-2012, 2014, 2015  Free Software Foundation, Inc
 
 ;; Author: Stefan Monnier <address@hidden>
-;; Version: 1.0
+;; Version: 1.1
 ;; Package-Requires: ((cl-lib "0.5"))
 ;; Keywords: tex, wp
 
@@ -138,7 +138,8 @@
     (,(concat "\\_<"
               (regexp-opt (cons "include"
                                 (apply 'append (mapcar 'cdr jgraph-commands))))
-              "\\_>") . font-lock-keyword-face)
+              "\\_>")
+     . font-lock-keyword-face)
     )
   "Keyword highlighting specification for `jgraph-mode'.")
 
@@ -172,6 +173,20 @@
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.jgr\\'" . jgraph-mode))
 
+(defun jgraph--syntax-end-of-string (limit)
+  (when (eq t (nth 3 (syntax-ppss)))
+    (when (re-search-forward "\\(?:\\=\\|[^\\]\\)\\(\n\\)" limit t)
+      (put-text-property (match-beginning 1) (match-end 1)
+                         'syntax-table (string-to-syntax "|")))))
+
+(defun jgraph--syntax-propertize (start end)
+  (goto-char start)
+  (jgraph--syntax-end-of-string end)
+  (funcall
+   (syntax-propertize-rules
+    ("\\s-:\\(\\s-\\)" (1 (prog1 "|" (jgraph--syntax-end-of-string end)))))
+   start end))
+
 ;;;###autoload
 (define-derived-mode jgraph-mode prog-mode "Jgraph"
   "A major mode for editing Jgraph files."
@@ -182,9 +197,7 @@
   (set (make-local-variable 'font-lock-defaults)
        '(jgraph-font-lock-keywords))
   (set (make-local-variable 'syntax-propertize-function)
-       (syntax-propertize-rules
-        ;; FIXME: naive(broken) multiline pattern.
-        ("\\s-\\(:\\)\\s-\\(?:.*\\\\\n\\)*.*\\(\n\\)" (1 "|") (2 "|"))))
+       #'jgraph--syntax-propertize)
   (set (make-local-variable 'indent-line-function) 'jgraph-indent-line)
   ;; (set (make-local-variable 'imenu-generic-expression)
   ;;      jgraph-imenu-generic-expression)
@@ -195,7 +208,6 @@
 
 (defcustom jgraph-indent-offset 4
   "Basic indentation step size in `jgraph-mode'."
-  :group 'jgraph-mode
   :type 'integer)
 
 (defun jgraph-indent-line ()
diff --git a/packages/load-relative/.gitignore 
b/packages/load-relative/.gitignore
new file mode 100644
index 0000000..61da6af
--- /dev/null
+++ b/packages/load-relative/.gitignore
@@ -0,0 +1,16 @@
+/*.elc
+/*~
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/config.log
+/config.status
+/configure
+/configure.lineno
+/elc-stamp
+/elc-temp
+/elpa
+/emacs-load-relative-*.tar.gz
+/install-sh
+/missing
diff --git a/packages/load-relative/.travis.yml 
b/packages/load-relative/.travis.yml
new file mode 100644
index 0000000..bc22a2f
--- /dev/null
+++ b/packages/load-relative/.travis.yml
@@ -0,0 +1,17 @@
+language: emacs-lisp
+
+
+install:
+  - if [ "$EMACS" = 'emacs24' ]; then
+        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo apt-get -qq update &&
+        sudo apt-get -qq -f install &&
+        sudo apt-get -qq install emacs24 emacs24-el;
+    fi
+
+env:
+  - EMACS=emacs24
+
+# run the tests
+script:
+  - /bin/bash ./autogen.sh && cd test && make check-elget
diff --git a/packages/load-relative/AUTHORS b/packages/load-relative/AUTHORS
new file mode 100644
index 0000000..fee42c0
--- /dev/null
+++ b/packages/load-relative/AUTHORS
@@ -0,0 +1 @@
+Rocky Bernstein (address@hidden)
diff --git a/packages/load-relative/COPYING b/packages/load-relative/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/packages/load-relative/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/packages/load-relative/ChangeLog b/packages/load-relative/ChangeLog
new file mode 100644
index 0000000..5f20404
--- /dev/null
+++ b/packages/load-relative/ChangeLog
@@ -0,0 +1,228 @@
+2010-09-30  rocky <address@hidden>
+
+       * .gitignore: git Administrivia.
+
+2010-09-30  rocky <address@hidden>
+
+       Merge branch 'master' of github.com:rocky/emacs-load-relative
+       Conflicts:      .gitignore
+
+2010-09-30  rocky <address@hidden>
+
+       * .gitignore, COPYING, Makefile.am, README, configure.ac: 
+       Administrivia. Add COPYING, update README and .gitignore, bump
+       version number.
+
+2010-08-17  R. Bernstein <address@hidden>
+
+       * INSTALL: Customize more for emacs.
+
+2010-08-13  R. Bernstein <address@hidden>
+
+       * .gitignore, INSTALL: Make INSTALL less generic and more specific
+       to Emacs
+
+2010-07-25  rocky <address@hidden>
+
+       * AUTHORS, Makefile.am, configure.ac, load-relative.el: Add Emacs
+       Lisp Code Archive (ELCA) meta-comments.
+
+2010-03-08  rocky <address@hidden>
+
+       Merge branch 'master' of
+       address@hidden:rocky/emacs-load-relative
+
+2010-03-08  rocky <address@hidden>
+
+       * .gitignore: elisp-comp is now in the repository
+
+2009-12-18  rocky <address@hidden>
+
+       * .gitignore, autogen.sh, elisp-comp: Don't overwrigte elisp-comp.
+
+2009-12-18  rocky <address@hidden>
+
+       * autogen.sh: Add --enable-maintainer-mode to configure when running
+       autogen.sh
+
+2009-12-14  rocky <address@hidden>
+
+       Merge branch 'master' of
+       address@hidden:rocky/emacs-load-relative
+
+2009-12-13  rocky <address@hidden>
+
+       * test/behave.el, test/test-load.el, test/test-require-list.el: 
+       Remove local behave.el in favor of new installed package test-unit.
+
+
+2009-12-13  rocky <address@hidden>
+
+       * .gitignore, ChangeLog, Makefile.am, configure.ac: Administrivia.
+
+2009-12-13  rocky <address@hidden>
+
+       Merge branch 'master' of
+       address@hidden:rocky/emacs-load-relative
+
+2009-12-13  rocky <address@hidden>
+
+       * configure.ac: Fix package name typo.
+
+2009-12-13  rocky <address@hidden>
+
+       * Makefile.am: Include textile README in distribution tarball
+
+2009-12-12  rocky <address@hidden>
+
+       * README.textile: Reformat without line breaks
+
+2009-12-12  rocky <address@hidden>
+
+       * README.md, README.textile: Try textile for readme
+
+2009-12-12  rocky <address@hidden>
+
+       * README.md, README.redcloth: Try using .md extension for doc.
+
+2009-11-29  rocky <address@hidden>
+
+       * test/behave.el: Add assert-raises.
+
+2009-11-25  rocky <address@hidden>
+
+       * test/behave.el: behave.el: fix incorrect initialization on
+       *behave-total-assertions*.
+
+2009-11-24  rocky <address@hidden>
+
+       * test/behave.el: Show number of assertions run.
+
+2009-11-22  rocky <address@hidden>
+
+       * load-relative.el: Add provision for getting __FILE__ when we are
+       byte compiling.
+
+2009-11-22  rocky <address@hidden>
+
+       * load-relative.el, test/require-file2.el, test/require-file3.el,
+       test/test-load.el: Add optional prefix to require-relative,
+       require-relative and provide-me which will add that prefix to the
+       feature name.
+
+2009-11-22  rocky <address@hidden>
+
+       * test/test-load.el: Minimal test of provide-me.
+
+2009-11-22  rocky <address@hidden>
+
+       * load-relative.el: Doc string fix.
+
+2009-11-21  rocky <address@hidden>
+
+       * Makefile.am, README, README.redcloth: Turn README back into text.
+       Add special redcloth version.
+
+2009-11-21  rocky <address@hidden>
+
+       * README, README.markup: Nope changing the name made things worse.
+
+2009-11-21  rocky <address@hidden>
+
+       * README, README.markup: See if changing the name from README to
+       README.markup gives github a clue
+
+2009-11-21  rocky <address@hidden>
+
+       * README, load-relative.el: load-relative.el: Add provide-me and
+       make GPL v3. README: expand and turn into red-cloth markup.
+
+2009-11-19  R. Bernstein <address@hidden>
+
+       * test/test-load.el: Another test of (__FILE__). Make test-load more
+       eval-current'able.
+
+2009-11-19  R. Bernstein <address@hidden>
+
+       * test/test-load.el: Add first __FILE__ test.
+
+2009-11-17  R. Bernstein <address@hidden>
+
+       * load-relative.el: Bug: was not require-relative when not at
+       compile time.
+
+2009-11-15  rocky <address@hidden>
+
+       * load-relative.el: Working towards a more perfect __FILE__. Perhaps
+       I am flailing here. Need much better tests.
+
+2009-11-15  rocky <address@hidden>
+
+       * Makefile.am, load-relative.el, test/test-require-list.el: Add
+       macro to handle relative requires using a list. And use this list
+       eval-when-compile to remove the undefined function messages in
+       byte-compilation.
+
+2009-11-13  rocky <address@hidden>
+
+       * load-relative.el: Go over __FILE__ test ordering and more comments
+       to as to why we do what we do.
+
+2009-11-13  rocky <address@hidden>
+
+       * load-relative.el: Update __FILE__ docstring comment.
+
+2009-11-13  rocky <address@hidden>
+
+       * load-relative.el: Also try #$ - "the name of this file as a
+       string". Thanks due to grischka for the suggestion.
+
+2009-11-13  rocky <address@hidden>
+
+       * test/require-file1.el: Used in testing require-relative
+
+2009-11-13  rocky <address@hidden>
+
+       * load-relative.el, test/load-file2.el, test/test-load.el: 
+       load-relative.el: Use current-load-list to get loaded/eval'd file
+       name. It is perhaps is the most reliable but also the most low-level
+       and it is an undocumented API. Update doc strings to record what we
+       now understand. Allow an optional symbol -- just in case. Update
+       tests.
+
+2009-11-12  rocky <address@hidden(none)>
+
+       * test/behave.el, test/test-load.el: test-load.el: add a
+       require-relative test behave.el: sync up with emacs-dbgr - one bug
+       removed.
+
+2009-11-12  rocky <address@hidden>
+
+       * load-relative.el: Add require-relative.
+
+2009-11-12  rocky <address@hidden>
+
+       Merge branch 'master' of
+       address@hidden:rocky/emacs-load-relative  Conflicts:
+       load-relative.el
+
+2009-11-12  rocky <address@hidden>
+
+       * load-relative.el, test/test-load.el: Add require-relative.
+
+2009-11-10  R. Bernstein <address@hidden>
+
+       * load-relative.el, test/behave.el, test/test-load.el: test-load.el:
+       I think we need to expand the filename before calling load.
+       behave.el: reduce dependency on spec part.
+
+2009-11-09  rocky <address@hidden>
+
+       * load-relative.el, test/load-file1.el, test/test-load.el: Allow
+       load-relative to accept a list of strings of files to load.
+
+2009-11-09  rocky <address@hidden>
+
+       * Relative loads for Emacs Lisp files. Adds functions __FILE__ and
+       load-relative.
+
diff --git a/packages/load-relative/INSTALL b/packages/load-relative/INSTALL
new file mode 100644
index 0000000..aaa3bf8
--- /dev/null
+++ b/packages/load-relative/INSTALL
@@ -0,0 +1,246 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure && make' should configure,
+and build this package.  If that succeeds `make install' will install
+the package. However on some systems you may need root privileges, you 
+may have use `sudo make install' or perhaps `su root' beforehand.
+
+Generic Information
+===================
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It also creates a shell script `config.status' that you can run in
+the future to recreate the current configuration, and a file
+`config.log' containing compiler output (useful mainly for debugging
+`configure').
+
+   The configure script can also use an optional file (typically
+called `config.cache' and enabled with `--cache-file=config.cache' or
+simply `-C') that saves the results of its tests to speed up
+reconfiguring.  Caching is disabled by default to prevent problems
+with accidental use of stale cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' is used to create `configure' by a program
+called `autoconf'.  You need `configure.ac' if you want to change it
+or regenerate `configure' using a newer version of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. You can remove the compiled Emacs Lisp files and other derived
+     files from the source code directory by typing `make clean'.  To
+     also remove the files that `configure' created (so you can
+     compile the package for a different kind of computer), type `make
+     distclean'.  There is also a `make maintainer-clean' target, but
+     that is intended mainly for the package's developers.  If you use
+     it, you may have to get all sorts of other programs in order to
+     regenerate files that came with the distribution.
+
+  6. You can also type `make uninstall' to remove the installed files
+     again.  
+
+  7. We don't provide `make distcheck' right now, but perhaps someday
+     we will. This is by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Options
+=====================
+
+   Run `./configure --help' for details on the pertinent
+environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 EMACS=/usr/bin/emacs23-x
+
+   *Note Defining Variables::, for more details.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's emacs files under
+`/usr/local/share/emacs/site-lisp', You can specify an installation
+prefix other than `/usr/local/emacs/site-lisp' by giving `configure'
+the option `--with-site-lisp=PREFIX', where PREFIX must be an absolute
+file name.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure EMACS=/usr/bin/emacs23-x
+
+causes the specified `/usr/bin/emacs23-x' to be used as the Emacs program
+to use.
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/packages/load-relative/Makefile.am 
b/packages/load-relative/Makefile.am
new file mode 100644
index 0000000..04aca09
--- /dev/null
+++ b/packages/load-relative/Makefile.am
@@ -0,0 +1,55 @@
+lisp_files := $(wildcard *.el)
+lisp_LISP = $(lisp_files)
+
+PHONY=check check-short clean dist distclean test
+
+EXTRA_DIST = $(lisp_files) $(test_files) README.md THANKS COPYING
+GIT2CL ?= git2cl
+
+#: Run all tests
+check: $(test-files)
+       $(MAKE) -C test check
+
+#: Run all tests with minimum verbosity
+check-short:
+       $(MAKE) -C test check 2>&1  | ruby make-check-filter.rb
+
+
+#: same as check
+test: check
+
+#: same as check-short
+test-short: check-short
+
+#: Read this first.
+README: README.md
+       ln -s README.md README
+
+if MAINTAINER_MODE
+
+CL = ChangeLog
+#: Create a log file from the individual commits via git2cl
+ChangeLog:
+       git log --pretty --numstat --summary | $(GIT2CL) > $@
+
+ACLOCAL_AMFLAGS=-I .
+
+endif
+
+CR_EXCEPTIONS=copyright_exceptions
+#: Check for GNU Copyrights.
+check_copyrights:
+       @echo "Compute exceptions >$(CR_EXCEPTIONS)~"
+       @export LANG=C;                                                 \
+       find . -name '.git' -prune -o -name '*.el' -print0 |            \
+           xargs -0 grep -L 'Free Software Foundation, Inc' |          \
+           grep -v '\(\.dir-locals\|.-\(pkg\|autoloads\)\)\.el$$';     \
+       find . -name '.git' -prune -o -name '*.el' -print |             \
+           while read f; do                                            \
+               fquoted="$$(echo $$f|tr '|' '_')";                      \
+               sed -n -e '/[Cc]opyright.*, *[1-9][-0-9]*,\?$$/N'       \
+                   -e '/Free Software Foundation/d'                    \
+                   -e "s|^\\(.*[Cc]opyright\\)|$$fquoted:\\1|p"        \
+                  "$$f";                                               \
+           done | sort >$(CR_EXCEPTIONS)~
+       diff -u "$(CR_EXCEPTIONS)" "$(CR_EXCEPTIONS)~"
diff --git a/packages/load-relative/NEWS b/packages/load-relative/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/packages/load-relative/README.md b/packages/load-relative/README.md
new file mode 100644
index 0000000..563db03
--- /dev/null
+++ b/packages/load-relative/README.md
@@ -0,0 +1,136 @@
+[![Build 
Status](https://travis-ci.org/rocky/emacs-load-relative.png)](https://travis-ci.org/rocky/emacs-load-relative)
+
+# Emacs multi-file develop/run-from-of-source routines
+
+The rational behind module is to be able to write small Emacs
+functions or modules in a larger multi-file Emacs package and
+facilitate running from the source tree without having to "install"
+the code or fiddle with evil *load-path*'s . See my [NYC Lisp 
talk](https://github.com/rocky/emacs-load-relative/wiki/NYC-Lisp-talk) for more 
background on this.
+
+
+## Contents ##
+
+* [\__FILE__](https://github.com/rocky/emacs-load-relative#file)
+* [load-relative](https://github.com/rocky/emacs-load-relative#load-relative)
+* 
[require-relative](https://github.com/rocky/emacs-load-relative#require-relative-require-relative-list)
+* [provide-me](https://github.com/rocky/emacs-load-relative#provide-me)
+
+The latest version is at http://github.com/rocky/emacs-load-relative
+
+## \__FILE__
+
+\__FILE__ returns the file name that that the calling program is
+running.  If you are *eval*'ing a buffer then the file name of that
+buffer is used. The name was selected to be analogous to the name used
+in C, Perl, and Ruby.
+
+For an common example of using this, see [How to Insert Demo Code into an 
Emacs Lisp 
Module](https://github.com/rocky/emacs-load-relative/wiki/How-to-Insert-Demo-Code-into-an-Emacs-Lisp-Module).
+
+## load-relative
+
+*load-relative* loads an Emacs Lisp file relative to another
+ (presumably currently running) Emacs Lisp file. For example suppose
+ you have Emacs Lisp files `foo.el` and `bar.el` in the same directory.
+ To load Emacs Lisp file `bar.el` from inside Emacs lisp file `foo.el`:
+
+```lisp
+    (require 'load-relative)
+    (load-relative "baz")
+```
+
+That *load-relative* line could above have also been written as:
+
+```lisp
+   (load-relative "./baz")
+```
+
+or:
+
+```lisp
+   (load-relative "baz.el")  # if you want to exclude any byte-compiled files
+```
+
+## require-relative, require-relative-list
+
+Use *require-relative* if you want to *require* the file instead of
+*load*'ing it:
+
+```lisp
+   (require-relative "baz")
+```
+
+or:
+
+```lisp
+   (require-relative "./baz")
+```
+
+The above not only does a *require* on `'baz`, but makes sure you get
+that from the same file as you would have if you had issued
+*load_relative*.
+
+Use *require-relative-list* when you have a list of files you want to
+*require*. To *require-relative* them in one shot:
+
+```lisp
+   (require-relative-list '("dbgr-init" "dbgr-fringe"))
+```
+
+## provide-me
+
+The macro *provide-me* saves you the trouble of adding a symbol
+after *provide*, by using the file basename (without directory or file
+extension) as the name of the thing you want to provide. Using this
+forces the *provide* names to be the same as the filename, but I
+consider that a good thing.
+
+*provide-me* also takes an optional string which will be prepended to the 
provide name. This is useful if you have a multi-file package and want the 
files to bue prefaced with the name of the package.
+
+Assume your package *foo* and contains simply file `foo.el`. Then
+adding:
+
+```lisp
+   (provide-me)
+```
+
+inside that file is the same thing as writing:
+
+```lisp
+   (provide 'foo)
+```
+
+Now suppose `foo.el` is part of a larger package called *bar*. Then if
+you write:
+
+```lisp
+   (provide-me "bar-")
+```
+
+this is the same as writing:
+
+```lisp
+   (provide 'bar-foo)
+```
+
+
+## find-file-noselect-relative
+
+The function *find-file-noselect-relative* provides a way of accessing
+resources which are located relative to the currently running Emacs lisp file.
+This is probably most useful when running Emacs as a scripting engine for
+batch processing or with tests cases.
+
+```lisp
+   (find-file-noselect-relative "README.md")
+```
+
+## with-relative-file
+
+The macro *with-relative-file* runs in a buffer with the contents of the given
+relative file.
+
+```lisp
+   (with-relative-file "README.md"
+     (buffer-substring))
+```
+     
diff --git a/packages/load-relative/THANKS b/packages/load-relative/THANKS
new file mode 100644
index 0000000..f74a3ef
--- /dev/null
+++ b/packages/load-relative/THANKS
@@ -0,0 +1,2 @@
+Phil Lord - Contribute find-file-noselect-relative, and with-relative-file
+Lars Anderson - Melapa packaging, among other things
diff --git a/packages/load-relative/autogen.sh 
b/packages/load-relative/autogen.sh
new file mode 100755
index 0000000..8a72837
--- /dev/null
+++ b/packages/load-relative/autogen.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+autoreconf -vi && \
+autoconf && {
+  echo "Running configure with --enable-maintainer-mode $@"
+  ./configure --enable-maintainer-mode $@
+}
diff --git a/packages/load-relative/common.mk b/packages/load-relative/common.mk
new file mode 100644
index 0000000..26b6325
--- /dev/null
+++ b/packages/load-relative/common.mk
@@ -0,0 +1,5 @@
+short:
+       $(MAKE) 2>&1 >/dev/null | ruby $(top_srcdir)/make-check-filter.rb
+
+%.short:
+       $(MAKE) $(@:.short=) 2>&1 >/dev/null
diff --git a/packages/load-relative/configure.ac 
b/packages/load-relative/configure.ac
new file mode 100644
index 0000000..35bddab
--- /dev/null
+++ b/packages/load-relative/configure.ac
@@ -0,0 +1,28 @@
+AC_INIT(emacs-load-relative, 1.0,)
+AC_CONFIG_SRCDIR(load-relative.el)
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+AM_MISSING_PROG(GIT2CL, git2cl, $missing_dir)
+
+AC_PATH_PROG(EMACS, emacs, no)
+if test x$EMACS != xno ; then
+  $EMACS -batch -q -no-site-file -eval \
+  '(if (<= emacs-major-version 22)
+     (progn
+       (error "You need GNU Emacs 23 or better for this package.")
+       (kill-emacs 1)
+     ))'
+  if test $? -ne 0 ; then
+    EMACS=no
+  fi
+fi
+
+
+##
+## Find out where to install the debugger emacs lisp files
+##
+AM_PATH_LISPDIR
+AM_CONDITIONAL(INSTALL_EMACS_LISP, test "x$lispdir" != "x")
+
+AC_CONFIG_FILES([Makefile test/Makefile])
+AC_OUTPUT
diff --git a/packages/load-relative/copyright_exceptions 
b/packages/load-relative/copyright_exceptions
new file mode 100644
index 0000000..e69de29
diff --git a/packages/load-relative/elisp-comp 
b/packages/load-relative/elisp-comp
new file mode 100755
index 0000000..263a26d
--- /dev/null
+++ b/packages/load-relative/elisp-comp
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Copyright (C) 1995, 2000, 2003, 2004, 2005  Free Software Foundation, Inc.
+
+scriptversion=2009-11-26.09
+
+# Franc,ois Pinard <address@hidden>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 
USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <address@hidden> or send patches to
+# <address@hidden>.
+
+case $1 in
+  '')
+     echo "$0: No files.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: elisp-comp [--help] [--version] FILES...
+
+This script byte-compiles all `.el' files listed as FILES using GNU
+Emacs, and put the resulting `.elc' files into the current directory,
+so disregarding the original directories used in `.el' arguments.
+
+This script manages in such a way that all Emacs LISP files to
+be compiled are made visible between themselves, in the event
+they require or load-library one another.
+
+Report bugs to <address@hidden>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "elisp-comp $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test -z "$EMACS" || test "$EMACS" = "t"; then
+  # Value of "t" means we are running in a shell under Emacs.
+  # Just assume Emacs is called "emacs".
+  EMACS=emacs
+fi
+
+tempdir=.
+
+# Cleanup the temporary directory on exit.
+# trap 'ret=$?; rm -rf "$tempdir" && exit $ret' 0
+trap 'ret=$?; rm -rf "./script" && exit $ret' 0
+trap '(exit $?); exit' 1 2 13 15
+
+(
+  cd $tempdir
+  echo "(setq load-path (cons nil load-path))" > script
+  $EMACS -batch -q -l script -f batch-byte-compile *.el || exit $?
+  # mv *.elc ..
+) || exit $?
+
+(exit 0); exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/packages/load-relative/install-from-git.sh 
b/packages/load-relative/install-from-git.sh
new file mode 100755
index 0000000..f36afa4
--- /dev/null
+++ b/packages/load-relative/install-from-git.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+# This installs all realgud and its prerequisites. If you are lucky
+# you can just run this:
+#
+#   bash ./install-from-git.sh
+#
+# However we do provide for some customization...
+#
+# 1. GIT PROTOCOL
+# ===============
+#
+# If your "git clone" can't handle the "http" protocol, you might be
+# able to use the "git" protocol. To do this set the GIT_PROTOCOL
+# variable like this:
+#
+#     GIT_PROTOCOL=git sh ./install-from-git.sh
+#
+# 2. configure options (e.g --prefix)
+# ====================================
+
+# If you want to customize configuration parameters, for example,
+# choose where to install, you can pass configure options to this
+# script. For example:# can pass configure options.
+#
+#     sh ./install-from-git.sh --prefix=/tmp
+#
+# 3. TO "sudo" or not to "sudo"?
+# ==============================
+# If you are running as root on a *Nix-like box, then there's no problem.
+#
+# If you are not running as root, "sudo" might be invoked to install
+# code.  On systems that don't have a "sudo" command but need
+# filesystem permission, then you get by with setting SUDO_CMD to "su root-c"
+# For example:
+#
+#    SUDO_CMD='su root -c' sh ./install-from-git.sh
+#
+# If you have sufficient filesystem permission (which is often the
+# case on Windows or cygwin) then you might not need or want sudo. So
+# here, set SUDO_CMD to a blank:
+#
+#      SUDO_CMD=' ' sh ./install-from-git.sh
+#
+#
+# To finish here is an invocation using all 3 above options:
+#   GIT_PROTOCOL='git' SUDO_CMD=' ' sh ./install-from-git.sh --prefix=/tmp
+
+GIT_PROTOCOL=${GIT_PROTOCOL:-http}
+
+# Run and echo a command
+run_cmd() {
+    echo "--- Running command: $@"
+    $@
+    rc=$?
+    echo "--- $@ exit status is $?"
+    return $rc
+}
+
+# environment variable SUDO_CMD could be "sudo" or "su root -c" or " "
+# for don't need sudo
+
+if (( $(id -u) != 0)) ; then
+    if [[ -z "$SUDO_CMD" ]] ; then
+       need_sudo='sudo'
+       if which $need_sudo >/dev/null 2>&1 ; then
+           try_cmd=''
+       else
+           need_sudo='su root -c'
+           try_cmd='su'
+       fi
+    else
+       need_sudo="$SUDO_CMD"
+    fi
+else
+    need_sudo=''
+    try_cmd=''
+fi
+
+for program in git make $need_sudo ; do
+    if ! which $program >/dev/null 2>&1 ; then
+       echo "Cant find program $program in $PATH"
+       exit 1
+    fi
+done
+
+for pkg in emacs-{test-simple,load-relative} ; do
+    echo '******************************************'
+    echo Trying to install ${pkg}...
+    echo '******************************************'
+    run_cmd git clone ${GIT_PROTOCOL}://github.com/rocky/${pkg}.git
+    (cd $pkg && \
+        run_cmd $SHELL ./autogen.sh && \
+       run_cmd ./configure $@ && \
+       run_cmd make && \
+       run_cmd make check && \
+        run_cmd $need_sudo make install
+    )
+done
diff --git a/packages/load-relative/load-relative.el 
b/packages/load-relative/load-relative.el
new file mode 100644
index 0000000..a57748a
--- /dev/null
+++ b/packages/load-relative/load-relative.el
@@ -0,0 +1,302 @@
+;;; load-relative.el --- relative file load (within a multi-file Emacs package)
+
+;; Author: Rocky Bernstein <address@hidden>
+;; Version: 1.2
+;; Keywords: internal
+;; URL: http://github.com/rocky/emacs-load-relative
+;; Compatibility: GNU Emacs 23.x
+
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Here we provide functions which facilitate writing multi-file Emacs
+;; packages and facilitate running from the source tree without having
+;; to "install" code or fiddle with evil `load-path'. See
+;; https://github.com/rocky/emacs-load-relative/wiki/NYC-Lisp-talk for
+;; the the rationale behind this.
+;;
+;; The functions we add are relative versions of `load', `require' and
+;; `find-file-no-select' and versions which take list arguments. We also add a
+;; `__FILE__' function and a `provide-me' macro.
+
+;; The latest version of this code is at:
+;;     http://github.com/rocky/emacs-load-relative/
+
+;; `__FILE__' returns the file name that that the calling program is
+;; running.  If you are `eval''ing a buffer then the file name of that
+;; buffer is used. The name was selected to be analogous to the name
+;; used in C, Perl, Python, and Ruby.
+
+;; `load-relative' loads an Emacs Lisp file relative to another
+;; (presumably currently running) Emacs Lisp file. For example suppose
+;; you have Emacs Lisp files "foo.el" and "bar.el" in the same
+;; directory. To load "bar.el" from inside Emacs lisp file "foo.el":
+;;
+;;     (require 'load-relative)
+;;     (load-relative "baz")
+;;
+;; The above `load-relative' line could above have also been written as:
+;;
+;;     (load-relative "./baz")
+;; or:
+;;     (load-relative "baz.el")  # if you want to exclude any byte-compiled 
files
+;;
+;; Use `require-relative' if you want to `require' the file instead of
+;; `load'ing it:
+;;
+;;    (require-relative "baz")
+;;
+;; or:
+;;
+;;    (require-relative "./baz")
+;;
+;; The above not only does a `require' on 'baz', but makes sure you
+;; get that from the same file as you would have if you had issued
+;; `load_relative'.
+;;
+;; Use `require-relative-list' when you have a list of files you want
+;; to `require'. To `require-relative' them all in one shot:
+;;
+;;     (require-relative-list '("dbgr-init" "dbgr-fringe"))
+;;
+;; The macro `provide-me' saves you the trouble of adding a
+;; symbol after `provide' using the file basename (without directory
+;; or file extension) as the name of the thing you want to
+;; provide.
+;;
+;; Using this constrains the `provide' name to be the same as
+;; the filename, but I consider that a good thing.
+;;
+;; The function `find-file-noselect-relative' provides a way of accessing
+;; resources which are located relative to the currently running Emacs lisp
+;; file. This is probably most useful when running Emacs as a scripting engine
+;; for batch processing or with tests cases. For example, this form will find
+;; the README file for this package.
+;;
+;;     (find-file-noselect-relative "README.md")
+;;
+;; `find-file-noselect-relative' also takes wildcards, as does it's
+;; non-relative namesake.
+;;
+;; The macro `with-relative-file' runs in a buffer with the contents of the
+;; given relative file.
+;;
+;;    (with-relative-file "README.md"
+;;      (buffer-substring))
+;;
+;; This is easier if you care about the contents of the file, rather than
+;; a buffer.
+
+
+;;; Code:
+
+;;;###autoload
+(defun __FILE__ (&optional symbol)
+  "Return the string name of file/buffer that is currently begin executed.
+
+The first approach for getting this information is perhaps the
+most pervasive and reliable. But it the most low-level and not
+part of a public API, so it might change in future
+implementations. This method uses the name that is recorded by
+readevalloop of `lread.c' as the car of variable
+`current-load-list'.
+
+Failing that, we use `load-file-name' which should work in some
+subset of the same places that the first method works. However
+`load-file-name' will be nil for code that is eval'd. To cover
+those cases, we try `buffer-file-name' which is initially
+correct, for eval'd code, but will change and may be wrong if the
+code sets or switches buffers after the initial execution.
+
+As a last resort, you can pass in SYMBOL which should be some
+symbol that has been previously defined if none of the above
+methods work we will use the file-name value find via
+`symbol-file'."
+  ;; Not used right now:
+  ;; Failing the above the next approach we try is to use the value of
+  ;; $# - 'the name of this file as a string'. Although it doesn't
+  ;; work for eval-like things, it has the advantage that this value
+  ;; persists after loading or evaluating a file. So it would be
+  ;; suitable if __FILE__ were called from inside a function.
+
+
+  (cond
+   ;; lread.c's readevalloop sets (car current-load-list)
+   ;; via macro LOADHIST_ATTACH of lisp.h. At least in Emacs
+   ;; 23.0.91 and this code goes back to '93.
+   ((stringp (car-safe current-load-list)) (car current-load-list))
+
+   ;; load-like things. 'relative-file-expand' tests in
+   ;; test/test-load.el indicates we should put this ahead of
+   ;; $#.
+   (load-file-name)
+
+   ;; Pick up "name of this file as a string" which is set on
+   ;; reading and persists. In contrast, load-file-name is set only
+   ;; inside eval. As such, it won't work when not in the middle of
+   ;; loading.
+   ;; (#$)
+
+   ;; eval-like things
+   ((buffer-file-name))
+
+   ;; When byte compiling. FIXME: use a more thorough precondition like
+   ;; byte-compile-file is somehwere in the backtrace or that
+   ;; bytecomp-filename comes from that routine?
+   ((boundp 'bytecomp-filename) bytecomp-filename)
+
+   (t (symbol-file symbol)) ;; last resort
+   ))
+
+(defun autoload-relative (function-or-list
+                          file &optional docstring interactive type
+                          symbol)
+  "Autoload an Emacs Lisp file relative to Emacs Lisp code that is in
+the process of being loaded or eval'd.
+
+
+Define FUNCTION to autoload from FILE. FUNCTION is a symbol.
+
+FILE is a string to pass to `load'.
+
+DOCSTRING is documentation for the function.
+
+INTERACATIVE if non-nil says function can be called
+interactively.
+
+TYPE indicates the type of the object: nil or omitted says
+function is a function, `keymap' says function is really a
+keymap, and `macro' or t says function is really a macro.  Third
+through fifth args give info about the real definition.  They
+default to nil.  If function is already defined other than as an
+autoload, this does nothing and returns nil.
+
+SYMBOL is the location of of the file of where that was
+defined (as given by `symbol-file' is used if other methods of
+finding __FILE__ don't work."
+
+  (if (listp function-or-list)
+      (mapcar (lambda(function)
+                (autoload function-or-list
+                  (relative-expand-file-name file symbol)
+                  docstring interactive type))
+              file)
+    (autoload function-or-list (relative-expand-file-name file symbol)
+      docstring interactive type))
+  )
+
+;;;###autoload
+(defun find-file-noselect-relative (filename &optional nowarn rawfile 
wildcards)
+  "Read relative FILENAME into a buffer and return the buffer.
+If a buffer exists visiting FILENAME, return that one, but
+verify that the file has not changed since visited or saved.
+The buffer is not selected, just returned to the caller.
+Optional second arg NOWARN non-nil means suppress any warning messages.
+Optional third arg RAWFILE non-nil means the file is read literally.
+Optional fourth arg WILDCARDS non-nil means do wildcard processing
+and visit all the matching files.  When wildcards are actually
+used and expanded, return a list of buffers that are visiting
+the various files."
+  (find-file-noselect (relative-expand-file-name filename)
+                      nowarn rawfile wildcards))
+
+;;;###autoload
+(defmacro with-relative-file (file &rest body)
+  "Read the relative FILE into a temporary buffer and evaluate BODY
+in this buffer."
+  (declare (indent 1) (debug t))
+  `(with-temp-buffer
+     (insert-file-contents
+      (relative-expand-file-name
+       ,file))
+     ,@body))
+
+;;;###autoload
+(defun load-relative (file-or-list &optional symbol)
+  "Load an Emacs Lisp file relative to Emacs Lisp code that is in
+the process of being loaded or eval'd.
+
+FILE-OR-LIST is either a string or a list of strings containing
+files that you want to loaded. If SYMBOL is given, the location of
+of the file of where that was defined (as given by `symbol-file' is used
+if other methods of finding __FILE__ don't work."
+
+  (if (listp file-or-list)
+      (mapcar (lambda(relative-file)
+                (load (relative-expand-file-name relative-file symbol)))
+              file-or-list)
+    (load (relative-expand-file-name file-or-list symbol)))
+  )
+
+(defun relative-expand-file-name(relative-file &optional opt-file)
+  "Expand RELATIVE-FILE relative to the Emacs Lisp code that is in
+the process of being loaded or eval'd.
+
+WARNING: it is best to to run this function before any
+buffer-setting or buffer changing operations."
+  (let ((file (or opt-file (__FILE__) default-directory))
+        (prefix))
+    (unless file
+      (error "Can't expand __FILE__ here and no file name given"))
+    (setq prefix (file-name-directory file))
+    (expand-file-name (concat prefix relative-file))))
+
+;;;###autoload
+(defun require-relative (relative-file &optional opt-file opt-prefix)
+  "Run `require' on an Emacs Lisp file relative to the Emacs Lisp code
+that is in the process of being loaded or eval'd. The symbol used in require
+is the base file name (without directory or file extension) treated as a
+symbol.
+
+WARNING: it is best to to run this function before any
+buffer-setting or buffer changing operations."
+  (let ((require-string-name
+         (concat opt-prefix (file-name-sans-extension
+                             (file-name-nondirectory relative-file)))))
+    (require (intern require-string-name)
+             (relative-expand-file-name relative-file opt-file))))
+
+;;;###autoload
+(defmacro require-relative-list (list &optional opt-prefix)
+  "Run `require-relative' on each name in LIST which should be a list of
+strings, each string being the relative name of file you want to run."
+  `(progn
+     (eval-when-compile
+       (require 'cl
+                (dolist (rel-file ,list)
+                  (require-relative rel-file (__FILE__) ,opt-prefix))))
+     (dolist (rel-file ,list)
+       (require-relative rel-file (__FILE__) ,opt-prefix))))
+
+;;;###autoload
+(defmacro provide-me ( &optional prefix )
+  "Call `provide' with the feature's symbol name made from
+source-code's file basename sans extension. For example if you
+write (provide-me) inside file ~/lisp/foo.el, this is the same as
+writing: (provide 'foo).
+
+With a prefix, that prefix is prepended to the `provide' So in
+the previous example, if you write (provide-me \"bar-\") this is the
+same as writing (provide 'bar-foo)
+"
+  `(provide (intern (concat ,prefix (file-name-sans-extension
+                                     (file-name-nondirectory (__FILE__)))))))
+
+(provide-me)
+
+;;; load-relative.el ends here
diff --git a/packages/load-relative/make-check-filter.rb 
b/packages/load-relative/make-check-filter.rb
new file mode 100644
index 0000000..329bdf1
--- /dev/null
+++ b/packages/load-relative/make-check-filter.rb
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+# Use this to cut out the crud from make check.
+# Use like this:
+#   make check 2>&1  | ruby ../make-check-filter.rb
+# See Makefile.am
+pats = ["^(?:Loading",
+        '(re)?make\[',
+        "Making check in",
+        "^Wrote",
+        '\(cd \.\.',
+        "make -C",
+        "Test-Unit",
+        "Fontifying",
+        '\s*$',
+        '##[<>]+$'
+       ].join('|') + ')'
+# puts pats
+skip_re = /#{pats}/
+
+while gets()
+  next if $_ =~ skip_re
+  puts $_
+end
diff --git a/packages/load-relative/test/.gitignore 
b/packages/load-relative/test/.gitignore
new file mode 100644
index 0000000..ddeeca7
--- /dev/null
+++ b/packages/load-relative/test/.gitignore
@@ -0,0 +1,3 @@
+/*~
+/Makefile
+/Makefile.in
diff --git a/packages/load-relative/test/Makefile.am 
b/packages/load-relative/test/Makefile.am
new file mode 100644
index 0000000..80518c2
--- /dev/null
+++ b/packages/load-relative/test/Makefile.am
@@ -0,0 +1,68 @@
+include $(top_srcdir)/common.mk
+
+PHONY=check test all check-elget test-elget help
+
+#: overall help on running the make targets
+help:
+       @echo "The main function of this Makefile is to facilitate running 
tests."
+       @echo
+       @echo "To run all of the tests, use targets \"test\", \"check\" or 
\"check-short\"."
+       @echo "For example:"
+       @echo
+       @echo "    make check"
+       @echo "or:"
+       @echo "    make check-short"
+       @echo
+       @echo "The -short target uses a filter written in Ruby to remove 
extreanous output."
+       @echo
+       @echo "To run a specific test like test-srcbuf.el, change \".el\" to"
+       @echo "\".run\". For example:"
+       @echo
+       @echo "    make test-srcbuf.run"
+       @echo
+       @echo "Tests can also be run via the Emacs el-get package and this 
loads dependent emacs "
+       @echo "package, like load-relative. To do this, use targets, 
\"check-elget\","
+       @echo "\"test-elget\", or \"check-short-elget\"."
+       @echo
+       @echo  "To run a specific test like test-srcbuf.el via el-get change 
\".el\""
+       @echo "to \".elrun\" For example:"
+       @echo
+       @echo "    make test-srcbuf.elrun"
+
+#: same thing as "check"
+test: check
+
+test_files := $(wildcard test-*.el)
+
+CHECK_FILES = $(notdir $(test_files:.el=.run))
+EL_GET_CHECK_FILES = $(notdir $(test_files:.el=.elrun))
+
+#: Run all tests
+check: $(CHECK_FILES)
+
+#: Run all tests via el-get
+check-elget:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load ./install-pkgs.el --load test-load.el)
+# Leave out until we can get dependecies worked out
+# #: Run all tests via el-get
+#check-elget: $(EL_GET_CHECK_FILES)s
+
+#: Run all tests with minimum verbosity
+check-short:
+       $(MAKE) check 2>&1  | ruby ../make-check-filter.rb
+
+#: Run all tests with minimum verbosity via el-get
+check-short-elget:
+       $(MAKE) check-elget 2>&1  | ruby ../make-check-filter.rb
+
+test-%.run:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load $(@:.run=.el))
+
+#: Run tests getting external Lisp dependencies
+test-%.elrun:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load ./install-pkgs.el --load $(@:.elrun=.el))
+
+# Whatever it is you want to do, it should be forwarded to the
+# to top-level directories
+# %:
+#      $(MAKE) -C .. $@
diff --git a/packages/load-relative/test/install-pkgs.el 
b/packages/load-relative/test/install-pkgs.el
new file mode 100644
index 0000000..d43575c
--- /dev/null
+++ b/packages/load-relative/test/install-pkgs.el
@@ -0,0 +1,24 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'package)
+(package-refresh-contents)
+(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/";)))
+(condition-case nil
+    (package-install 'test-simple)
+  ((debug error) nil))
+(load-library "test-simple")
diff --git a/packages/load-relative/test/load-file1.el 
b/packages/load-relative/test/load-file1.el
new file mode 100644
index 0000000..00930a5
--- /dev/null
+++ b/packages/load-relative/test/load-file1.el
@@ -0,0 +1,18 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(setq loaded-file "load-file1")
+(setq loaded-file1 't)
diff --git a/packages/load-relative/test/load-file2.el 
b/packages/load-relative/test/load-file2.el
new file mode 100644
index 0000000..835a4be
--- /dev/null
+++ b/packages/load-relative/test/load-file2.el
@@ -0,0 +1,17 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(load-relative "load-file3")
diff --git a/packages/load-relative/test/load-file3.el 
b/packages/load-relative/test/load-file3.el
new file mode 100644
index 0000000..f788421
--- /dev/null
+++ b/packages/load-relative/test/load-file3.el
@@ -0,0 +1,17 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(setq loaded-file "load-file3")
diff --git a/packages/load-relative/test/require-file1.el 
b/packages/load-relative/test/require-file1.el
new file mode 100644
index 0000000..8524f53
--- /dev/null
+++ b/packages/load-relative/test/require-file1.el
@@ -0,0 +1,17 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(provide 'require-file1)
diff --git a/packages/load-relative/test/require-file2.el 
b/packages/load-relative/test/require-file2.el
new file mode 100644
index 0000000..c84b014
--- /dev/null
+++ b/packages/load-relative/test/require-file2.el
@@ -0,0 +1,17 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(provide-me "my-")
diff --git a/packages/load-relative/test/require-file3.el 
b/packages/load-relative/test/require-file3.el
new file mode 100644
index 0000000..2271059
--- /dev/null
+++ b/packages/load-relative/test/require-file3.el
@@ -0,0 +1,17 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(provide 'require-file3)
diff --git a/packages/load-relative/test/simple.txt 
b/packages/load-relative/test/simple.txt
new file mode 100644
index 0000000..ab23474
--- /dev/null
+++ b/packages/load-relative/test/simple.txt
@@ -0,0 +1 @@
+simple
diff --git a/packages/load-relative/test/subdir/.gitignore 
b/packages/load-relative/test/subdir/.gitignore
new file mode 100644
index 0000000..aeaec0f
--- /dev/null
+++ b/packages/load-relative/test/subdir/.gitignore
@@ -0,0 +1 @@
+/*~
diff --git a/packages/load-relative/test/subdir/Makefile 
b/packages/load-relative/test/subdir/Makefile
new file mode 100644
index 0000000..bc80236
--- /dev/null
+++ b/packages/load-relative/test/subdir/Makefile
@@ -0,0 +1,7 @@
+# Whatever it is you want to do, it should be forwarded to the 
+# to top-level irectories
+PHONY=check all
+all: check
+
+%: 
+       $(MAKE) -C .. $@
diff --git 
a/packages/load-relative/test/subdir/test-require-list-from-subdir.el 
b/packages/load-relative/test/subdir/test-require-list-from-subdir.el
new file mode 100644
index 0000000..880b4f3
--- /dev/null
+++ b/packages/load-relative/test/subdir/test-require-list-from-subdir.el
@@ -0,0 +1,34 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(require 'cl)
+(require 'test-unit)
+(load-file "../../load-relative.el")
+
+(test-unit-clear-contexts)
+
+(context "load-relative-list-from-subdir"
+        (tag load-relative-list-from-subdir)
+        (if (featurep 'require-file1)
+            (unload-feature 'require-file1))
+        (specify "relative-relative-list"
+                 (require-relative-list '("../require-file1"))
+                 (assert-t (featurep 'require-file1))
+                 )
+
+)
+
+(test-unit "load-relative-list-from-subdir")
diff --git a/packages/load-relative/test/test-file.el 
b/packages/load-relative/test/test-file.el
new file mode 100644
index 0000000..db3db8c
--- /dev/null
+++ b/packages/load-relative/test/test-file.el
@@ -0,0 +1,62 @@
+;;; test-file.el --- Simple test for load-relative
+
+;; Copyright (C) 2015  Free Software Foundation, Inc.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(load-file "../load-relative.el")
+
+(require 'ert)
+
+
+(ert-deftest test-name ()
+  (should
+   ;; not sure how I can test the full path here because, well, I need to
+   ;; resolve a relative path to do so...
+   (equal
+    "simple.txt"
+    (let ((bf
+           (find-file-noselect-relative "simple.txt")))
+      (kill-buffer bf)
+      (file-name-nondirectory
+       (buffer-file-name bf))))))
+
+(ert-deftest test-contents ()
+  (should
+   (equal
+    "simple\n"
+    (let* ((bf
+            (find-file-noselect-relative "simple.txt"))
+           (ct
+            (with-current-buffer
+                bf
+              (buffer-string))))
+      (kill-buffer bf)
+      ct))))
+
+(ert-deftest test-contents-with-relative-file ()
+  (should
+   (equal
+    "simple\n"
+    (with-relative-file
+        "simple.txt"
+      (buffer-string)))))
+
+(provide 'test-file)
+
+;;; test-file.el ends here
diff --git a/packages/load-relative/test/test-load.el 
b/packages/load-relative/test/test-load.el
new file mode 100644
index 0000000..af47412
--- /dev/null
+++ b/packages/load-relative/test/test-load.el
@@ -0,0 +1,97 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(require 'cl)
+(require 'test-simple)
+(load-file "../load-relative.el")
+
+(test-simple-start)
+
+;; (setq tempbuf (generate-new-buffer "*cmdbuf-test*"))
+;; (assert-nil
+;;  (with-current-buffer tempbuf
+;;    (insert "(__FILE__)\n")
+;;    (eval-current-buffer))
+;;  (kill-buffer tempbuf) "(__FILE__) on temporary buffer")
+
+(assert-equal "test-load"
+             (file-name-sans-extension
+              (file-name-nondirectory (__FILE__)))
+             "(__FILE__) on this running program"
+             )
+
+(dolist (file-name
+        '("load-file1.el" "./load-file1.el" "../test/load-file1.el"))
+  (assert-equal
+   (expand-file-name file-name)
+   (relative-expand-file-name file-name))
+  "relative-expand-filename"
+)
+
+(note "Basic load-relative")
+(setq loaded-file nil)
+(assert-equal t (load-relative "load-file2"))
+(assert-equal "load-file3" loaded-file)
+
+(setq loaded-file nil)
+(setq loaded-file1 nil)
+(assert-equal '(t t)
+             (load-relative '("load-file1" "load-file2")
+                            ))
+(assert-equal 't loaded-file1)
+(assert-equal "load-file3" loaded-file)
+
+
+(dolist (file-name
+        '("load-file1.el" "./load-file1.el" "../test/load-file1.el"))
+  (setq loaded-file nil)
+  (assert-equal t (load-relative file-name)
+               (format "load-relative with list file %s" loaded-file))
+  (assert-equal "load-file1" loaded-file
+               (format "load-relative value with list file %s" loaded-file)
+  ))
+
+(if (featurep 'require-file1 t)
+    (unload-feature 'require-file1))
+
+(require-relative "require-file1")
+(assert-t (featurep 'require-file1) "require-relative")
+
+(if (featurep 'require-file1 t)
+            (unload-feature 'require-file1))
+
+(require-relative-list '("require-file1" "require-file3"))
+(assert-t (and (featurep 'require-file1)
+              (featurep 'require-file3)) "require-relative-list")
+
+(if (featurep 'my-require-file2 t)
+    (unload-feature 'my-require-file2))
+
+(require-relative-list '("require-file2") "my-")
+(assert-t (featurep 'my-require-file2) "require-relative-list with prefix")
+
+
+(if (featurep 'test-load t)
+    (unload-feature 'test-load) "provide-me - no prefix")
+(provide-me)
+(assert-t (featurep 'test-load))
+
+(if (featurep 'my-test-load t)
+    (unload-feature 'my-test-load))
+(provide-me "my-")
+(assert-t (featurep 'my-test-load) "provide-me - prefix")
+
+(end-tests)
diff --git a/packages/load-relative/test/test-require-list.el 
b/packages/load-relative/test/test-require-list.el
new file mode 100644
index 0000000..fae8421
--- /dev/null
+++ b/packages/load-relative/test/test-require-list.el
@@ -0,0 +1,28 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+(require 'cl)
+(require 'test-simple)
+(load-file "../load-relative.el")
+
+(test-simple-start)
+
+(if (featurep 'require-file1)
+    (unload-feature 'require-file1))
+(require-relative-list '("./require-file1"))
+(assert-t (featurep 'require-file1) "relative-relative-list")
+
+(end-tests)
diff --git a/packages/loc-changes/.gitignore b/packages/loc-changes/.gitignore
new file mode 100644
index 0000000..eadfb92
--- /dev/null
+++ b/packages/loc-changes/.gitignore
@@ -0,0 +1,14 @@
+/*.elc
+/*~
+/ChangeLog
+/aclocal.m4
+/autom4te.cache
+/config.log
+/config.status
+/configure
+/elc-stamp
+/install-sh
+/missing
+/script
+Makefile
+Makefile.in
diff --git a/packages/loc-changes/.travis.yml b/packages/loc-changes/.travis.yml
new file mode 100644
index 0000000..93ff22f
--- /dev/null
+++ b/packages/loc-changes/.travis.yml
@@ -0,0 +1,18 @@
+language: emacs-lisp
+
+env:
+  - EMACS=emacs24
+
+before_install:
+  - if [ "$EMACS" = 'emacs24' ]; then
+      sudo add-apt-repository -y ppa:cassou/emacs &&
+      sudo apt-get update -qq &&
+      sudo apt-get install -qq
+          emacs24 emacs24-el emacs24-common-non-dfsg;
+    fi
+
+  - sudo apt-get install -qq $EMACS
+
+# run the tests
+script:
+  - NO_CHECK_EMACS_PACKAGES=1 /bin/bash ./autogen.sh && cd test && make 
check-elget
diff --git a/packages/loc-changes/AUTHORS b/packages/loc-changes/AUTHORS
new file mode 100644
index 0000000..60fc84e
--- /dev/null
+++ b/packages/loc-changes/AUTHORS
@@ -0,0 +1 @@
address@hidden
diff --git a/packages/loc-changes/COPYING b/packages/loc-changes/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/packages/loc-changes/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/packages/loc-changes/INSTALL b/packages/loc-changes/INSTALL
new file mode 100644
index 0000000..2099840
--- /dev/null
+++ b/packages/loc-changes/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
+Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell command `./configure && make && make install'
+should configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved.  Use GNU `make'
+instead.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf limitation.  Until the limitation is lifted, you can use
+this workaround:
+
+     CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
diff --git a/packages/loc-changes/Makefile.am b/packages/loc-changes/Makefile.am
new file mode 100644
index 0000000..0b381fc
--- /dev/null
+++ b/packages/loc-changes/Makefile.am
@@ -0,0 +1,48 @@
+lispdir = @lispdir@
+
+lisp_files := $(wildcard *.el)
+lisp_LISP = $(lisp_files)
+
+include common.mk
+
+EXTRA_DIST = $(lisp_files) $(test_files) README.md THANKS
+
+test_files := $(wildcard test/test-*.el)
+
+if MAINTAINER_MODE
+
+CL = ChangeLog
+ChangeLog:
+       git log --pretty --numstat --summary | $(GIT2CL) > $@
+
+ACLOCAL_AMFLAGS=-I .
+
+endif
+
+#: Run all tests
+test: check
+
+#: Run all tests without bloated output
+check-short:
+       $(MAKE) check 2>&1  | ruby test/make-check-filter.rb
+
+check:
+       $(MAKE) -C test $@
+
+CR_EXCEPTIONS=copyright_exceptions
+#: Check for GNU Copyrights.
+check_copyrights:
+       @echo "Compute exceptions >$(CR_EXCEPTIONS)~"
+       @export LANG=C;                                                 \
+       find . -name '.git' -prune -o -name '*.el' -print0 |            \
+           xargs -0 grep -L 'Free Software Foundation, Inc' |          \
+           grep -v '\(\.dir-locals\|.-\(pkg\|autoloads\)\)\.el$$';     \
+       find . -name '.git' -prune -o -name '*.el' -print |             \
+           while read f; do                                            \
+               fquoted="$$(echo $$f|tr '|' '_')";                      \
+               sed -n -e '/[Cc]opyright.*, *[1-9][-0-9]*,\?$$/N'       \
+                   -e '/Free Software Foundation/d'                    \
+                   -e "s|^\\(.*[Cc]opyright\\)|$$fquoted:\\1|p"        \
+                  "$$f";                                               \
+           done | sort >$(CR_EXCEPTIONS)~
+       diff -u "$(CR_EXCEPTIONS)" "$(CR_EXCEPTIONS)~"
diff --git a/packages/loc-changes/NEWS b/packages/loc-changes/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/packages/loc-changes/README b/packages/loc-changes/README
new file mode 120000
index 0000000..42061c0
--- /dev/null
+++ b/packages/loc-changes/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/packages/loc-changes/README.md b/packages/loc-changes/README.md
new file mode 100644
index 0000000..b0fe3a9
--- /dev/null
+++ b/packages/loc-changes/README.md
@@ -0,0 +1,15 @@
+[![Build 
Status](https://travis-ci.org/rocky/emacs-loc-changes.png)](https://travis-ci.org/rocky/emacs-loc-changes)
+
+Keeps track of important buffer positions after buffer changes.
+
+Sometimes it is useful to make note of certain locations in program
+code. For example these might be error locations reported in a
+compilation. Or you could be inside a debugger and change the source
+code but want to continue debugging.
+
+Without this, the positions that a compilation error report or that a
+debugger refers to may be a little off from the modified source.
+
+This package tries to ameliorate that by allowing a user or program
+(e.g. a debugger front-end) to set marks to track the original
+locations.
diff --git a/packages/loc-changes/THANKS b/packages/loc-changes/THANKS
new file mode 100644
index 0000000..e336992
--- /dev/null
+++ b/packages/loc-changes/THANKS
@@ -0,0 +1 @@
+Lars Anderson - Melpa packaging, among other things
diff --git a/packages/loc-changes/autogen.sh b/packages/loc-changes/autogen.sh
new file mode 100755
index 0000000..8a72837
--- /dev/null
+++ b/packages/loc-changes/autogen.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+autoreconf -vi && \
+autoconf && {
+  echo "Running configure with --enable-maintainer-mode $@"
+  ./configure --enable-maintainer-mode $@
+}
diff --git a/packages/loc-changes/common.mk b/packages/loc-changes/common.mk
new file mode 100644
index 0000000..26b6325
--- /dev/null
+++ b/packages/loc-changes/common.mk
@@ -0,0 +1,5 @@
+short:
+       $(MAKE) 2>&1 >/dev/null | ruby $(top_srcdir)/make-check-filter.rb
+
+%.short:
+       $(MAKE) $(@:.short=) 2>&1 >/dev/null
diff --git a/packages/loc-changes/configure.ac 
b/packages/loc-changes/configure.ac
new file mode 100644
index 0000000..439ceff
--- /dev/null
+++ b/packages/loc-changes/configure.ac
@@ -0,0 +1,13 @@
+AC_INIT(emacs-loc-changes, 1.1)
+AC_CONFIG_SRCDIR(loc-changes.el)
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+
+##
+## Find out where to install the debugger emacs lisp files
+##
+AM_PATH_LISPDIR
+AM_CONDITIONAL(INSTALL_EMACS_LISP, test "x$lispdir" != "x")
+
+AC_CONFIG_FILES([Makefile test/Makefile])
+AC_OUTPUT
diff --git a/packages/loc-changes/copyright_exceptions 
b/packages/loc-changes/copyright_exceptions
new file mode 100644
index 0000000..e69de29
diff --git a/packages/loc-changes/elisp-comp b/packages/loc-changes/elisp-comp
new file mode 100755
index 0000000..73a5eda
--- /dev/null
+++ b/packages/loc-changes/elisp-comp
@@ -0,0 +1,93 @@
+#!/bin/sh
+# Copyright (C) 1995-2012 Free Software Foundation, Inc.
+
+scriptversion=2013-03-27.22
+
+# Franc,ois Pinard <address@hidden>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <address@hidden> or send patches to
+# <address@hidden>.
+
+case $1 in
+  '')
+     echo "$0: No files.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: elisp-comp [--help] [--version] FILES...
+
+This script byte-compiles all '.el' files listed as FILES using GNU
+Emacs, and put the resulting '.elc' files into the current directory,
+so disregarding the original directories used in '.el' arguments.
+
+This script manages in such a way that all Emacs LISP files to
+be compiled are made visible between themselves, in the event
+they require or load-library one another.
+
+Report bugs to <address@hidden>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "elisp-comp $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test -z "$EMACS" || test "$EMACS" = "t"; then
+  # Value of "t" means we are running in a shell under Emacs.
+  # Just assume Emacs is called "emacs".
+  EMACS=emacs
+fi
+
+tempdir=elc.$$
+
+# Cleanup the temporary directory on exit.
+trap 'ret=$?; rm -rf "$tempdir" && exit $ret' 0
+do_exit='(exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+
+# mkdir $tempdir
+# cp "$@" $tempdir
+
+(
+  # cd $tempdir
+  echo "(setq load-path (cons nil (cons \"$abs_srcdir\" load-path)))" > script
+  $EMACS -batch -q -l script -f batch-byte-compile *.el || exit $?
+  # mv *.elc ..
+) || exit $?
+
+(exit 0); exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/packages/loc-changes/loc-changes.el 
b/packages/loc-changes/loc-changes.el
new file mode 100644
index 0000000..a269c0a
--- /dev/null
+++ b/packages/loc-changes/loc-changes.el
@@ -0,0 +1,257 @@
+;;; loc-changes.el --- keep track of positions even after buffer changes
+
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+;; Version: 1.2
+;; URL: http://github.com/rocky/emacs-loc-changes
+;; Compatibility: GNU Emacs 24.x
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package lets users or programs set marks in a buffer prior to
+;; changes so that we can track the original positions after the
+;; change.
+
+;; One common use is say when debugging a program.  The debugger has its static
+;; notion of the file and positions inside that.  However it may be convenient
+;; for a programmer to edit the program but not restart execution of the 
program.
+
+;; Another use might be in a compilation buffer for errors and
+;; warnings which refer to file and line positions.
+
+;;; Code:
+
+(make-variable-buffer-local 'loc-changes-alist)
+(defvar loc-changes-alist '()
+  "A buffer-local association-list (alist) of line numbers and
+their corresponding markers in the buffer. The 'key' is the line number; the 
value
+the marker"
+  )
+
+(defun loc-changes:follow-mark(event)
+  (interactive "e")
+  (let* ((pos (posn-point (event-end event)))
+        (mark (get-text-property pos 'mark)))
+    (switch-to-buffer-other-window  (marker-buffer mark))
+    (goto-char (marker-position mark))
+    ))
+
+
+(defun loc-changes:alist-describe (&optional opt-buffer)
+  "Display buffer-local variable loc-changes-alist. If BUFFER is
+not given, the current buffer is used. Information is put in an
+internal buffer called *Describe*."
+  (interactive "")
+  (let ((buffer (or opt-buffer (current-buffer)))
+       (alist))
+    (with-current-buffer buffer
+         (setq alist loc-changes-alist)
+         (unless (listp alist) (error "expecting loc-changes-alist to be a 
list"))
+         )
+    (switch-to-buffer (get-buffer-create "*Describe*"))
+    (setq buffer-read-only 'nil)
+    (delete-region (point-min) (point-max))
+    (dolist (assoc alist)
+         (put-text-property
+          (insert-text-button
+           (format "line %d: %s\n" (car assoc) (cdr assoc))
+           'action 'loc-changes:follow-mark
+           'help-echo "mouse-2: go to this location")
+          (point)
+          'mark (cdr assoc)
+           )
+         )
+    (setq buffer-read-only 't)
+    ))
+
+;;;###autoload
+(defun loc-changes-goto-line (line-number &optional column-number)
+  "Position `point' at LINE-NUMBER of the current buffer. If
+COLUMN-NUMBER is given, position `point' at that column just
+before that column number within the line. Note that the beginning of
+the line starts at column 0, so the column number display will be one less
+than COLUMN-NUMBER. For example COLUMN-NUMBER 1 will set before the first
+column on the line and show 0.
+
+The Emacs `goto-line' docstring says it is the wrong to use that
+function in a Lisp program. So here is something that I proclaim
+is okay to use in a Lisp program."
+  (interactive
+   (if (and current-prefix-arg (not (consp current-prefix-arg)))
+       (list (prefix-numeric-value current-prefix-arg))
+     ;; Look for a default, a number in the buffer at point.
+     (let* ((default
+             (save-excursion
+               (skip-chars-backward "0-9")
+               (if (looking-at "[0-9]")
+                   (string-to-number
+                    (buffer-substring-no-properties
+                     (point)
+                     (progn (skip-chars-forward "0-9")
+                            (point)))))))
+           ;; Decide if we're switching buffers.
+           (buffer
+            (if (consp current-prefix-arg)
+                (other-buffer (current-buffer) t)))
+           (buffer-prompt
+            (if buffer
+                (concat " in " (buffer-name buffer))
+              "")))
+       ;; Read the argument, offering that number (if any) as default.
+       (list (read-number (format "Goto line%s: " buffer-prompt)
+                          (list default (line-number-at-pos)))
+            buffer))))
+  (unless (wholenump line-number)
+    (error "Expecting line-number parameter `%s' to be a whole number"
+          line-number))
+  (unless (> line-number 0)
+    (error "Expecting line-number parameter `%d' to be greater than 0"
+          line-number))
+  (let ((last-line (line-number-at-pos (point-max))))
+    (unless (<= line-number last-line)
+      (error
+       "Line number %d should not exceed %d, the number of lines in the buffer"
+       line-number last-line))
+    (goto-char (point-min))
+    (forward-line (1- line-number))
+    (if column-number
+       (let ((last-column
+              (save-excursion
+                (move-end-of-line 1)
+                (current-column))))
+         (cond ((not (wholenump column-number))
+                (message
+                 "Column ignored. Expecting column-number parameter `%s' to be 
a whole number"
+                         column-number))
+               ((<= column-number 0)
+                (message
+                 "Column ignored. Expecting column-number parameter `%d' to be 
a greater than 1"
+                         column-number))
+               ((>= column-number last-column)
+                (message
+                 "Column ignored. Expecting column-number parameter `%d' to be 
a less than %d"
+                  column-number last-column))
+               (t (forward-char (1- column-number)))))
+      )
+    (redisplay)
+    )
+  )
+
+(defun loc-changes-add-elt (pos)
+  "Add an element `loc-changes-alist'. The car will be POS and a
+marker for it will be created at the point."
+  (setq loc-changes-alist
+       (cons (cons pos (point-marker)) loc-changes-alist)))
+
+;;;###autoload
+(defun loc-changes-add-and-goto (line-number &optional opt-buffer)
+  "Add a marker at LINE-NUMBER and record LINE-NUMBER and its
+marker association in `loc-changes-alist'."
+  (interactive
+   (if (and current-prefix-arg (not (consp current-prefix-arg)))
+       (list (prefix-numeric-value current-prefix-arg))
+     ;; Look for a default, a number in the buffer at point.
+     (let* ((default
+             (save-excursion
+               (skip-chars-backward "0-9")
+               (if (looking-at "[0-9]")
+                   (string-to-number
+                    (buffer-substring-no-properties
+                     (point)
+                     (progn (skip-chars-forward "0-9")
+                            (point)))))))
+           ;; Decide if we're switching buffers.
+           (buffer
+            (if (consp current-prefix-arg)
+                (other-buffer (current-buffer) t)))
+           (buffer-prompt
+            (if buffer
+                (concat " in " (buffer-name buffer))
+              "")))
+       ;; Read the argument, offering that number (if any) as default.
+       (list (read-number (format "Goto line%s: " buffer-prompt)
+                          (list default (line-number-at-pos)))
+            buffer))))
+
+  (let ((buffer (or opt-buffer (current-buffer))))
+    (with-current-buffer buffer
+      (loc-changes-goto-line line-number)
+      (loc-changes-add-elt line-number)
+      ))
+  )
+
+;;;###autoload
+(defun loc-changes-clear-buffer (&optional opt-buffer)
+  "Remove all location-tracking associations in BUFFER."
+  (interactive "bbuffer: ")
+  (let ((buffer (or opt-buffer (current-buffer)))
+       )
+    (with-current-buffer buffer
+      (setq loc-changes-alist '())
+      ))
+  )
+
+;;;###autoload
+(defun loc-changes-reset-position (&optional opt-buffer no-insert)
+  "Update `loc-changes-alist' so that the line number of point is
+used to when aline number is requested.
+
+Updates any existing line numbers referred to in marks at this
+position.
+
+This may be useful for example in debugging if you save the
+buffer and then cause the debugger to reread/reevaluate the file
+so that its positions are will be reflected."
+  (interactive "")
+  (let* ((line-number (line-number-at-pos (point)))
+        (elt (assq line-number loc-changes-alist)))
+    (let ((buffer (or opt-buffer (current-buffer)))
+         )
+      (with-current-buffer buffer
+       (if elt
+           (setcdr elt (point))
+         (unless no-insert
+           (loc-changes-add-elt line-number)
+           )
+         ))
+      )
+    ))
+
+
+(defun loc-changes-goto (position &optional opt-buffer no-update)
+  "Go to the position inside BUFFER taking into account the
+previous location marks. Normally if the position hasn't been
+seen before, we will add a new mark for this position. However if
+NO-UPDATE is set, no mark is added."
+  (unless (wholenump position)
+    (error "Expecting line-number parameter `%s' to be a whole number"
+          position))
+  (let ((elt (assq position loc-changes-alist)))
+    (if elt
+       (let ((marker (cdr elt)))
+         (unless (markerp marker)
+           (error "Internal error: loc-changes-alist is not a marker"))
+         (goto-char (marker-position marker)))
+      (if no-update
+         (loc-changes-goto-line position)
+       (loc-changes-add-and-goto position))
+      )
+    )
+  )
+
+(provide 'loc-changes)
+;;; loc-changes.el ends here
diff --git a/packages/loc-changes/test/Makefile.am 
b/packages/loc-changes/test/Makefile.am
new file mode 100644
index 0000000..48f7f72
--- /dev/null
+++ b/packages/loc-changes/test/Makefile.am
@@ -0,0 +1,72 @@
+include $(top_srcdir)/common.mk
+
+PHONY=check test all check-elget test-elget help
+
+all: check
+
+#: same thing as "check"
+test: check
+
+#: overall help on running the make targets
+help:
+       @echo "The main function of this Makefile is to facilitate running 
tests."
+       @echo
+       @echo "To run all of the tests, use targets \"test\", \"check\" or 
\"check-short\"."
+       @echo "For example:"
+       @echo
+       @echo "    make check"
+       @echo "or:"
+       @echo "    make check-short"
+       @echo
+       @echo "The -short target uses a filter written in Ruby to remove 
extreanous output."
+       @echo
+       @echo "To run a specific test like test-srcbuf.el, change \".el\" to"
+       @echo "\".run\". For example:"
+       @echo
+       @echo "    make test-srcbuf.run"
+       @echo
+       @echo "Tests can also be run via the Emacs el-get package and this 
loads dependent emacs "
+       @echo "package, like load-relative. To do this, use targets, 
\"check-elget\","
+       @echo "\"test-elget\", or \"check-short-elget\"."
+       @echo
+       @echo  "To run a specific test like test-srcbuf.el via el-get change 
\".el\""
+       @echo "to \".elrun\" For example:"
+       @echo
+       @echo "    make test-srcbuf.elrun"
+
+EXTRA_DIST=sample.txt
+
+#: same thing as "check-elget"
+test-elget: check-elget
+
+test_files := $(wildcard test-*.el)
+
+CHECK_FILES = $(notdir $(test_files:.el=.run))
+EL_GET_CHECK_FILES = $(notdir $(test_files:.el=.elrun))
+
+#: Run all tests
+check: $(CHECK_FILES)
+
+#: Run all tests via el-get
+check-elget:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load ./install-pkgs.el --load test-basic.el)
+
+#: Run all tests with minimum verbosity
+check-short:
+       $(MAKE) check 2>&1  | ruby ../make-check-filter.rb
+
+#: Run all tests with minimum verbosity via el-get
+check-short-elget:
+       $(MAKE) check-elget 2>&1  | ruby ./make-check-filter.rb
+
+test-%.run:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load $(@:.run=.el))
+
+#: Run tests using el-get to specify external Lisp dependencies
+test-%.elrun:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load ../el-get-install.el --load $(@:.elrun=.el))
+
+# Whatever it is you want to do, it should be forwarded to the
+# to top-level directories
+# %:
+#      $(MAKE) -C .. $@
diff --git a/packages/loc-changes/test/install-pkgs.el 
b/packages/loc-changes/test/install-pkgs.el
new file mode 100644
index 0000000..d43575c
--- /dev/null
+++ b/packages/loc-changes/test/install-pkgs.el
@@ -0,0 +1,24 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'package)
+(package-refresh-contents)
+(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/";)))
+(condition-case nil
+    (package-install 'test-simple)
+  ((debug error) nil))
+(load-library "test-simple")
diff --git a/packages/loc-changes/test/make-check-filter.rb 
b/packages/loc-changes/test/make-check-filter.rb
new file mode 100644
index 0000000..88cad14
--- /dev/null
+++ b/packages/loc-changes/test/make-check-filter.rb
@@ -0,0 +1,25 @@
+#!/usr/bin/env ruby
+# Use this to cut out the crud from make check.
+# Use like this:
+#   make check 2>&1  | ruby ../make-check-filter.rb
+# See Makefile.am
+pats = ["^(?:Loading",
+        '(re)?make\[',
+        "Making check in",
+        '\(cd \.\.',
+        "Column ignored",
+        "buffer \\*scratch\\*",
+        "\\*scratch\\*",
+        "make -C",
+        "Test-Unit",
+        "Fontifying",
+        '\s*$',
+        '##[<>]+$'
+       ].join('|') + ')'
+# puts pats
+skip_re = /#{pats}/
+
+while gets()
+  next if $_ =~ skip_re
+  puts $_
+end
diff --git a/packages/loc-changes/test/sample.txt 
b/packages/loc-changes/test/sample.txt
new file mode 100644
index 0000000..7f07c10
--- /dev/null
+++ b/packages/loc-changes/test/sample.txt
@@ -0,0 +1,14 @@
+This is line 1
+This is line 2
+This is line 3
+This is line 4
+This is line 5
+This is line 6
+This is line 7
+This is line 8
+This is line 9
+This is line 10
+This is line 11
+This is line 12
+This is line 13
+This is line 14
diff --git a/packages/loc-changes/test/test-basic.el 
b/packages/loc-changes/test/test-basic.el
new file mode 100644
index 0000000..190d1dd
--- /dev/null
+++ b/packages/loc-changes/test/test-basic.el
@@ -0,0 +1,107 @@
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'cl)
+(require 'test-simple)
+(load-file "../loc-changes.el")
+
+(test-simple-start)
+
+(setq sample-buffer (find-file-noselect "./sample.txt"))
+
+(note "loc-changes-goto-line error conditions")
+(assert-raises error (loc-changes-goto-line "foo"))
+(message "buffer %s" (current-buffer))
+(assert-raises error (loc-changes-goto-line "0"))
+(assert-raises error (loc-changes-goto-line 0))
+(assert-raises error (loc-changes-goto-line 10000))
+
+(note "loc-changes-goto-line")
+(save-excursion
+  (set-buffer sample-buffer)
+  (loc-changes-goto-line 5)
+  (assert-equal 5 (line-number-at-pos (point))))
+
+(note "loc-changes-goto-line-with-column")
+(with-current-buffer sample-buffer
+  (set-buffer sample-buffer)
+  (loc-changes-goto-line 1 3)
+  (assert-equal 1 (line-number-at-pos (point)))
+  ;; FIXME:
+  ;; (assert-equal 2 (current-column))
+  )
+
+(note "loc-changes-goto-line-invalid-column")
+(save-excursion
+  (set-buffer sample-buffer)
+  (loc-changes-goto-line 1 300)
+  (assert-equal 1 (line-number-at-pos (point)))
+  ;; FIXME
+  ;; (assert-equal 0 (current-column))
+  (assert-t (or
+            (not (current-message))
+            (string-match "^Column ignored." (current-message))))
+  ;; FIXME:
+  ;; (loc-changes-goto-line 2 -5)
+  ;; (assert-equal 2 (line-number-at-pos (point)))
+  ;; (assert-equal 0 (current-column))
+  ;; (assert-t (or
+  ;;        (not (current-message))
+  ;;        (string-match "^Column ignored." (current-message))))
+  )
+
+(note "loc-changes-clear-buffer null")
+(loc-changes-clear-buffer)
+(assert-equal '() loc-changes-alist)
+
+(note "loc-changes-add-and-goto - update")
+(save-excursion
+  (set-buffer sample-buffer)
+  (loc-changes-add-and-goto 10)
+  (assert-equal 10 (line-number-at-pos)
+               "point should be at line 10")
+  ;; FIXME:
+  ;; (assert-t (assq 10 loc-changes-alist)
+  ;;       "Should find 10 in loc-changes-alist")
+  ;; (assert-t (markerp (cdr (assq 10 loc-changes-alist)))
+  ;;       "10 in loc-changes-alist should be a marker")
+  )
+
+(note "loc-changes-goto - update")
+(save-excursion
+  (set-buffer sample-buffer)
+  (loc-changes-goto 11)
+  (assert-equal 11 (line-number-at-pos)
+               "point should be at line 11")
+  ;; FIXME:
+  ;; (assert-t (assq 11 loc-changes-alist)
+  ;;       "Should find 11 in loc-changes-alist")
+  ;; (assert-t (markerp (cdr (assq 11 loc-changes-alist)))
+  ;;       "11 in loc-changes-alist should be a marker")
+  )
+
+(note "loc-changes-goto - no update")
+(save-excursion
+  (set-buffer sample-buffer)
+  (loc-changes-goto 12 nil 't)
+  (assert-equal 12 (line-number-at-pos)
+               "point should be at line 12")
+  (assert-nil (assq 12 loc-changes-alist)
+             "Should not find 12 in loc-changes-alist")
+  )
+
+(end-tests)
diff --git a/packages/nlinum/nlinum.el b/packages/nlinum/nlinum.el
index 82e274c..2505c98 100644
--- a/packages/nlinum/nlinum.el
+++ b/packages/nlinum/nlinum.el
@@ -1,10 +1,10 @@
 ;;; nlinum.el --- Show line numbers in the margin  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2012, 2014  Free Software Foundation, Inc.
+;; Copyright (C) 2012, 2014, 2015  Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <address@hidden>
 ;; Keywords: convenience
-;; Version: 1.5
+;; Version: 1.6
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@ Linum mode is a buffer-local minor mode."
   :lighter nil ;; (" NLinum" nlinum--desc)
   (jit-lock-unregister #'nlinum--region)
   (remove-hook 'window-configuration-change-hook #'nlinum--setup-window t)
+  (remove-hook 'text-scale-mode-hook #'nlinum--setup-window t)
   (remove-hook 'after-change-functions #'nlinum--after-change t)
   (kill-local-variable 'nlinum--line-number-cache)
   (remove-overlays (point-min) (point-max) 'nlinum t)
@@ -63,6 +64,7 @@ Linum mode is a buffer-local minor mode."
     ;; FIXME: Another approach would be to make the mode permanent-local,
     ;; which might indeed be preferable.
     (add-hook 'change-major-mode-hook (lambda () (nlinum-mode -1)))
+    (add-hook 'text-scale-mode-hook #'nlinum--setup-window nil t)
     (add-hook 'window-configuration-change-hook #'nlinum--setup-window nil t)
     (add-hook 'after-change-functions #'nlinum--after-change nil t)
     (jit-lock-register #'nlinum--region t))
@@ -71,14 +73,24 @@ Linum mode is a buffer-local minor mode."
 (defun nlinum--face-height (face)
   (aref (font-info (face-font face)) 2))
 
+(defun nlinum--face-width (face)        ;New info only in Emacs>=25.
+  (let ((fi (font-info (face-font face))))
+    (when (> (length fi) 11)
+      (let ((width (aref fi 11)))
+        (if (<= width 0)
+            (aref fi 10)
+          width)))))
+
 (defun nlinum--setup-window ()
   (let ((width (if (display-graphic-p)
                    (ceiling
-                    ;; We'd really want to check the widths rather than the
-                    ;; heights, but it's a start.
-                    (/ (* nlinum--width 1.0
-                          (nlinum--face-height 'linum))
-                       (frame-char-height)))
+                    (let ((width (nlinum--face-width 'linum)))
+                      (if width
+                          (/ (* nlinum--width 1.0 width)
+                             (frame-char-width))
+                        (/ (* nlinum--width 1.0
+                              (nlinum--face-height 'linum))
+                           (frame-char-height)))))
                  nlinum--width)))
     (set-window-margins nil (if nlinum-mode width)
                         (cdr (window-margins)))))
diff --git a/packages/rainbow-mode/rainbow-mode.el 
b/packages/rainbow-mode/rainbow-mode.el
index 55bec4a..93c99e3 100644
--- a/packages/rainbow-mode/rainbow-mode.el
+++ b/packages/rainbow-mode/rainbow-mode.el
@@ -1,10 +1,10 @@
 ;;; rainbow-mode.el --- Colorize color names in buffers
 
-;; Copyright (C) 2010-2014 Free Software Foundation, Inc
+;; Copyright (C) 2010-2015 Free Software Foundation, Inc
 
 ;; Author: Julien Danjou <address@hidden>
 ;; Keywords: faces
-;; Version: 0.10
+;; Version: 0.11
 
 ;; This file is part of GNU Emacs.
 
@@ -1163,7 +1163,9 @@ This will fontify with colors the string like \"#aabbcc\" 
or \"blue\"."
   (progn
     (if rainbow-mode
         (rainbow-turn-on)
-      (rainbow-turn-off))))
+      (rainbow-turn-off))
+    ;; Call font-lock-mode to refresh the buffer when used e.g. interactively
+    (font-lock-mode 1)))
 
 (provide 'rainbow-mode)
 
diff --git a/packages/seq/seq.el b/packages/seq/seq.el
index 679c82b..5366fd2 100644
--- a/packages/seq/seq.el
+++ b/packages/seq/seq.el
@@ -1,10 +1,10 @@
 ;;; seq.el --- Sequence manipulation functions  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2014 Free Software Foundation, Inc.
+;; Copyright (C) 2014-2015 Free Software Foundation, Inc.
 
-;; Author: Nicolas Petton <address@hidden>
+;; Author: Nicolas Petton <address@hidden>
 ;; Keywords: sequences
-;; Version: 1.0
+;; Version: 1.2
 ;; Package: seq
 
 ;; Maintainer: address@hidden
@@ -93,14 +93,14 @@ returned."
     (seq-subseq seq 0 (min (max n 0) (seq-length seq)))))
 
 (defun seq-drop-while (pred seq)
-  "Return a sequence, from the first element for which (PRED element) is nil, 
of SEQ.
+  "Return a sequence from the first element for which (PRED element) is nil in 
SEQ.
 The result is a sequence of the same type as SEQ."
   (if (listp seq)
       (seq--drop-while-list pred seq)
     (seq-drop seq (seq--count-successive pred seq))))
 
 (defun seq-take-while (pred seq)
-  "Return a sequence of the successive elements for which (PRED element) is 
non-nil in SEQ.
+  "Return the successive elements for which (PRED element) is non-nil in SEQ.
 The result is a sequence of the same type as SEQ."
   (if (listp seq)
       (seq--take-while-list pred seq)
@@ -153,7 +153,7 @@ If SEQ is empty, return INITIAL-VALUE and FUNCTION is not 
called."
     t))
 
 (defun seq-count (pred seq)
-  "Return the number of elements for which (PRED element) returns non-nil in 
seq."
+  "Return the number of elements for which (PRED element) is non-nil in SEQ."
   (let ((count 0))
     (seq-doseq (elt seq)
       (when (funcall pred elt)
@@ -172,9 +172,7 @@ The result is a sequence of the same type as SEQ."
   (if (listp seq)
       (sort (seq-copy seq) pred)
     (let ((result (seq-sort pred (append seq nil))))
-      (cond ((stringp seq) (concat result))
-            ((vectorp seq) (vconcat result))
-            (t (error "Unsupported sequence: %s" seq))))))
+      (seq--into result (type-of seq)))))
 
 (defun seq-contains-p (seq elt &optional testfn)
   "Return the first element in SEQ that equals to ELT.
@@ -198,14 +196,18 @@ If END is omitted, it defaults to the length of the 
sequence.
 If START or END is negative, it counts from the end."
   (cond ((or (stringp seq) (vectorp seq)) (substring seq start end))
         ((listp seq)
-         (let (len)
+         (let (len (errtext (format "Bad bounding indices: %s, %s" start end)))
            (and end (< end 0) (setq end (+ end (setq len (seq-length seq)))))
            (if (< start 0) (setq start (+ start (or len (setq len (seq-length 
seq))))))
-           (if (> start 0) (setq seq (nthcdr start seq)))
+           (when (> start 0)
+             (setq seq (nthcdr (1- start) seq))
+             (or seq (error "%s" errtext))
+             (setq seq (cdr seq)))
            (if end
                (let ((res nil))
-                 (while (>= (setq end (1- end)) start)
+                 (while (and (>= (setq end (1- end)) start) seq)
                    (push (pop seq) res))
+                 (or (= (1+ end) start) (error "%s" errtext))
                  (nreverse res))
              (seq-copy seq))))
         (t (error "Unsupported sequence: %s" seq))))
@@ -221,15 +223,70 @@ TYPE must be one of following symbols: vector, string or 
list.
     (`list (apply #'append (append seqs '(nil))))
     (t (error "Not a sequence type name: %s" type))))
 
+(defun seq-mapcat (function seq &optional type)
+  "Concatenate the result of applying FUNCTION to each element of SEQ.
+The result is a sequence of type TYPE, or a list if TYPE is nil."
+  (apply #'seq-concatenate (or type 'list)
+         (seq-map function seq)))
+
+(defun seq-partition (seq n)
+  "Return a list of the elements of SEQ grouped into sub-sequences of length N.
+The last sequence may contain less than N elements.  If N is a
+negative integer or 0, nil is returned."
+  (unless (< n 1)
+    (let ((result '()))
+      (while (not (seq-empty-p seq))
+        (push (seq-take seq n) result)
+        (setq seq (seq-drop seq n)))
+      (nreverse result))))
+
+(defun seq-group-by (function seq)
+  "Apply FUNCTION to each element of SEQ.
+Separate the elements of SEQ into an alist using the results as
+keys.  Keys are compared using `equal'."
+  (seq-reduce
+   (lambda (acc elt)
+     (let* ((key (funcall function elt))
+            (cell (assoc key acc)))
+       (if cell
+           (setcdr cell (push elt (cdr cell)))
+         (push (list key elt) acc))
+       acc))
+   (seq-reverse seq)
+   nil))
+
+(defalias 'seq-reverse
+  (if (ignore-errors (reverse [1 2]))
+      #'reverse
+    (lambda (seq)
+      "Return the reversed copy of list, vector, or string SEQ.
+See also the function `nreverse', which is used more often."
+      (let ((result '()))
+        (seq-map (lambda (elt) (push elt result))
+                 seq)
+        (if (listp seq)
+            result
+          (seq--into result (type-of seq)))))))
+
+(defun seq--into (seq type)
+  "Convert the sequence SEQ into a sequence of type TYPE."
+  (pcase type
+    (`vector (vconcat seq))
+    (`string (concat seq))
+    (`list (append seq nil))
+    (t (error "Not a sequence type name: %s" type))))
+
 (defun seq--drop-list (list n)
-  "Optimized version of `seq-drop' for lists."
+  "Return a list from LIST without its first N elements.
+This is an optimization for lists in `seq-drop'."
   (while (and list (> n 0))
     (setq list (cdr list)
           n (1- n)))
   list)
 
 (defun seq--take-list (list n)
-  "Optimized version of `seq-take' for lists."
+  "Return a list from LIST made of its first N elements.
+This is an optimization for lists in `seq-take'."
   (let ((result '()))
     (while (and list (> n 0))
       (setq n (1- n))
@@ -237,13 +294,15 @@ TYPE must be one of following symbols: vector, string or 
list.
     (nreverse result)))
 
 (defun seq--drop-while-list (pred list)
-  "Optimized version of `seq-drop-while' for lists."
+  "Return a list from the first element for which (PRED element) is nil in 
LIST.
+This is an optimization for lists in `seq-drop-while'."
   (while (and list (funcall pred (car list)))
     (setq list (cdr list)))
   list)
 
 (defun seq--take-while-list (pred list)
-  "Optimized version of `seq-take-while' for lists."
+  "Return the successive elements for which (PRED element) is non-nil in LIST.
+This is an optimization for lists in `seq-take-while'."
   (let ((result '()))
     (while (and list (funcall pred (car list)))
       (push (pop list) result))
@@ -260,7 +319,6 @@ TYPE must be one of following symbols: vector, string or 
list.
 
 (defalias 'seq-copy #'copy-sequence)
 (defalias 'seq-elt #'elt)
-(defalias 'seq-reverse #'reverse)
 (defalias 'seq-length #'length)
 (defalias 'seq-do #'mapc)
 (defalias 'seq-each #'seq-do)
diff --git a/packages/seq/tests/seq-tests.el b/packages/seq/tests/seq-tests.el
index 9fcda7f..badb326 100644
--- a/packages/seq/tests/seq-tests.el
+++ b/packages/seq/tests/seq-tests.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2014-2015 Free Software Foundation, Inc.
 
-;; Author: Nicolas Petton <address@hidden>
+;; Author: Nicolas Petton <address@hidden>
 ;; Maintainer: address@hidden
 
 ;; This file is part of GNU Emacs.
@@ -182,7 +182,12 @@ Evaluate BODY for each created sequence.
     (should (same-contents-p (seq-subseq seq 1 -1) '(3 4))))
   (should (vectorp (seq-subseq [2 3 4 5] 2)))
   (should (stringp (seq-subseq "foo" 2 3)))
-  (should (listp (seq-subseq '(2 3 4 4) 2 3))))
+  (should (listp (seq-subseq '(2 3 4 4) 2 3)))
+  (should-error (seq-subseq '(1 2 3) 4))
+  (should-not   (seq-subseq '(1 2 3) 3))
+  (should       (seq-subseq '(1 2 3) -3))
+  (should-error (seq-subseq '(1 2 3) 1 4))
+  (should       (seq-subseq '(1 2 3) 1 3)))
 
 (ert-deftest test-seq-concatenate ()
   (with-test-sequences (seq '(2 4 6))
@@ -192,5 +197,36 @@ Evaluate BODY for each created sequence.
     (should (equal (seq-concatenate 'vector nil '(8 10)) [8 10]))
     (should (equal (seq-concatenate 'vector seq nil) [2 4 6]))))
 
+(ert-deftest test-seq-mapcat ()
+  (should (equal (seq-mapcat #'seq-reverse '((3 2 1) (6 5 4)))
+                 '(1 2 3 4 5 6)))
+  (should (equal (seq-mapcat #'seq-reverse '[(3 2 1) (6 5 4)])
+                 '(1 2 3 4 5 6)))
+  (should (equal (seq-mapcat #'seq-reverse '((3 2 1) (6 5 4)) 'vector)
+                 '[1 2 3 4 5 6])))
+
+(ert-deftest test-seq-partition ()
+  (should (same-contents-p (seq-partition '(0 1 2 3 4 5 6 7) 3)
+                           '((0 1 2) (3 4 5) (6 7))))
+  (should (same-contents-p (seq-partition '[0 1 2 3 4 5 6 7] 3)
+                           '([0 1 2] [3 4 5] [6 7])))
+  (should (same-contents-p (seq-partition "Hello world" 2)
+                           '("He" "ll" "o " "wo" "rl" "d")))
+  (should (equal (seq-partition '() 2) '()))
+  (should (equal (seq-partition '(1 2 3) -1) '())))
+
+(ert-deftest test-seq-group-by ()
+  (with-test-sequences (seq '(1 2 3 4))
+   (should (equal (seq-group-by #'test-sequences-oddp seq)
+                  '((t 1 3) (nil 2 4)))))
+  (should (equal (seq-group-by #'car '((a 1) (b 3) (c 4) (a 2)))
+                 '((b (b 3)) (c (c 4)) (a (a 1) (a 2))))))
+
+(ert-deftest test-seq-reverse ()
+  (with-test-sequences (seq '(1 2 3 4))
+    (should (same-contents-p (seq-reverse seq) '(4 3 2 1)))
+    (should (equal (type-of (seq-reverse seq))
+                   (type-of seq)))))
+
 (provide 'seq-tests)
 ;;; seq-tests.el ends here
diff --git a/packages/sml-mode/sml-mode.el b/packages/sml-mode/sml-mode.el
index f4d06cc..85fcdcf 100644
--- a/packages/sml-mode/sml-mode.el
+++ b/packages/sml-mode/sml-mode.el
@@ -1,9 +1,9 @@
 ;;; sml-mode.el --- Major mode for editing (Standard) ML  -*- lexical-binding: 
t; coding: utf-8 -*-
 
-;; Copyright (C) 1989,1999,2000,2004,2007,2010-2014  Free Software Foundation, 
Inc.
+;; Copyright (C) 1989,1999,2000,2004,2007,2010-2015  Free Software Foundation, 
Inc.
 
 ;; Maintainer: (Stefan Monnier) <address@hidden>
-;; Version: 6.5
+;; Version: 6.7
 ;; Keywords: SML
 ;; Author:     Lars Bo Nielsen
 ;;             Olin Shivers
@@ -266,6 +266,9 @@ notion of \"the end of an outline\".")
 This may sound like a neat trick, but be extra careful: it changes the
 alignment and can thus lead to nasty surprises w.r.t layout."
   :type 'boolean)
+(if (fboundp 'prettify-symbols-mode)
+    (make-obsolete-variable 'sml-font-lock-symbols
+                            'prettify-symbols-mode "24.4"))
 
 (defconst sml-font-lock-symbols-alist
   '(("fn" . ?λ)
@@ -297,8 +300,8 @@ Regexp match data 0 points to the chars."
   ;; Check that the chars should really be composed into a symbol.
   (let* ((start (match-beginning 0))
         (end (match-end 0))
-        (syntaxes (if (eq (char-syntax (char-after start)) ?w)
-                      '(?w) '(?. ?\\))))
+        (syntaxes (if (memq (char-syntax (char-after start)) '(?w ?_))
+                      '(?w ?_) '(?. ?\\))))
     (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes)
            (memq (char-syntax (or (char-after end) ?\ )) syntaxes)
            (memq (get-text-property start 'face)
@@ -529,8 +532,9 @@ Regexp match data 0 points to the chars."
      (if (and (smie-rule-parent-p "val") (smie-rule-next-p "fn")) -3))
     (`(:before . "=>") (if (smie-rule-parent-p "fn") 3))
     (`(:before . "of") 1)
-    ;; In case the language is extended to allow a | directly after of.
-    (`(:before . ,(and `"|" (guard (smie-rule-prev-p "of")))) 1)
+    ;; FIXME: pcase in Emacs<24.4 bumps into a bug if we do this:
+    ;;(`(:before . ,(and `"|" (guard (smie-rule-prev-p "of")))) 1)
+    (`(:before . "|") (if (smie-rule-prev-p "of") 1 (smie-rule-separator 
kind)))
     (`(:before . ,(or `"|" `"d|" `";" `",")) (smie-rule-separator kind))
     ;; Treat purely syntactic block-constructs as being part of their parent,
     ;; when the opening statement is hanging.
@@ -551,6 +555,7 @@ Regexp match data 0 points to the chars."
     (`(:before . "withtype") 0)
     (`(:before . "d=")
      (cond
+      ((smie-rule-parent-p "fun") 2)
       ((smie-rule-parent-p "datatype") (if (smie-rule-bolp) 2))
       ((smie-rule-parent-p "structure" "signature" "functor") 0)))
     ;; Indent an expression starting with "local" as if it were starting
@@ -586,7 +591,7 @@ Assumes point is right before the = sign."
   ;; where the "type t = s.t" is mistaken for a type definition.
   (save-excursion
     (let ((res (smie-backward-sexp "=")))
-      (member (nth 2 res) `(":" ,@sml-=-starter-syms)))))
+      (member (nth 2 res) `(":" ":>" ,@sml-=-starter-syms)))))
 
 (defun sml-smie-non-nested-of-p ()
   ;; FIXME: Maybe datatype-|-p makes this nested-of business unnecessary.
@@ -775,6 +780,9 @@ Assumes point is right before the | symbol."
     ;; Maybe we should insert the command into the buffer and then call
     ;; comint-send-input?
     (sml-prog-proc-comint-input-filter-function nil)
+    (save-excursion (goto-char (process-mark proc))
+                    (unless (bolp) (insert "\n"))
+                    (set-marker (process-mark proc) (point)))
     (comint-send-string proc (concat str (sml-prog-proc--prop command-eol)))))
 
 (defun sml-prog-proc-load-file (file &optional and-go)
@@ -984,8 +992,24 @@ The format specifier \"%s\" will be converted into the 
directory name
 specified when running the command \\[sml-cd].")
 
 (defvar sml-error-regexp-alist
-  `( ;; Poly/ML messages
-    ("^\\(Error\\|Warning:\\) in '\\(.+\\)', line \\([0-9]+\\)" 2 3)
+  `(;; Poly/ML messages
+    ;;
+    ;; Warning- in 'polyml.ML', line 135.
+    ;; Matches are not exhaustive.
+    ;; Found near
+    ;;   fun
+    ;;      convert _ (... ...) = ML_Pretty.Break (false, ...) |
+    ;;         convert _ ... = ML_Pretty.Break (...) |
+    ;;         convert ... = let ... in ... end |
+    ;;         convert ... = …
+    ;;
+    ;; Error- in 'HTTP.sml', line 370.
+    ;; Value or constructor (read_line) has not been declared
+    ;; Found near
+    ;;   case read_line bin of
+    ;;      NONE => () |
+    ;;      SOME s => (if s = "" then print "DONE\n" else (... ...; ...))
+    ("^\\(?:> \\)?\\(?:Error\\|W\\(arning\\)\\)[-:] in '\\(.+\\)', line 
\\([0-9]+\\)" 2 3 nil (1))
     ;; Moscow ML
     ("^File \"\\([^\"]+\\)\", line \\([0-9]+\\)\\(-\\([0-9]+\\)\\)?, 
characters \\([0-9]+\\)-\\([0-9]+\\):" 1 2 5)
     ;; SML/NJ:  the file-pattern is anchored to avoid
@@ -1235,6 +1259,8 @@ This mode runs `sml-mode-hook' just before exiting.
 See also (info \"(sml-mode)Top\").
 \\{sml-mode-map}"
   (set (make-local-variable 'font-lock-defaults) sml-font-lock-defaults)
+  (set (make-local-variable 'prettify-symbols-alist)
+       sml-font-lock-symbols-alist)
   (set (make-local-variable 'outline-regexp) sml-outline-regexp)
   (set (make-local-variable 'imenu-create-index-function)
        'sml-imenu-create-index)
diff --git a/packages/sotlisp/sotlisp.el b/packages/sotlisp/sotlisp.el
index 1b58911..61d598e 100644
--- a/packages/sotlisp/sotlisp.el
+++ b/packages/sotlisp/sotlisp.el
@@ -1,534 +1,533 @@
-;;; sotlisp.el --- Write lisp at the speed of thought.  -*- lexical-binding: 
t; -*-
-
-;; Copyright (C) 2014 Free Software Foundation, Inc.
-
-;; Author: Artur Malabarba  <address@hidden>
-;; Keywords: convenience, lisp
-;; Package-Requires: ((emacs "24.1"))
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This defines a new global minor-mode `speed-of-thought-mode', which
-;; activates locally on any supported buffer.  Currently, only
-;; `emacs-lisp-mode' buffers are supported.
-;;
-;; The mode is quite simple, and is composed of two parts:
-;;
-;;; Abbrevs
-;;
-;; A large number of abbrevs which expand function
-;; initials to their name.  A few examples:
-;; 
-;; - wcb -> with-current-buffer
-;; - i -> insert
-;; - r -> require '
-;; - a -> and
-;; 
-;; However, these are defined in a way such that they ONLY expand in a
-;; place where you would use a function, so hitting SPC after "(r"
-;; expands to "(require '", but hitting SPC after "(delete-region r"
-;; will NOT expand the `r', because that's obviously not a function.
-;; Furtheromre, "#'r" will expand to "#'require" (note how it ommits
-;; that extra quote, since it would be useless here).
-;;
-;;; Commands
-;;
-;; It also defines 4 commands, which really fit into this "follow the
-;; thought-flow" way of writing.  The bindings are as follows, I
-;; understand these don't fully adhere to conventions, and I'd
-;; appreciate suggestions on better bindings.
-;; 
-;; - M-RET :: Break line, and insert "()" with point in the middle.
-;; - C-RET :: Do `forward-up-list', then do M-RET.
-;; 
-;; Hitting RET followed by a `(' was one of the most common key sequences
-;; for me while writing elisp, so giving it a quick-to-hit key was a
-;; significant improvement.
-;; 
-;; - C-c f :: Find function under point.  If it is not defined, create a
-;; definition for it below the current function and leave point inside.
-;; - C-c v :: Same, but for variable.
-;; 
-;; With these commands, you just write your code as you think of it.  Once
-;; you hit a "stop-point" of sorts in your tought flow, you hit `C-c f/v`
-;; on any undefined functions/variables, write their definitions, and hit
-;; `C-u C-SPC` to go back to the main function.
-;; 
-;;; Small Example
-;;
-;; With the above (assuming you use something like paredit or
-;; electric-pair-mode), if you write:
-;;
-;;   ( w t b M-RET i SPC text
-;; 
-;; You get
-;; 
-;;   (with-temp-buffer (insert text))
-
-
-;;; Code:
-
-;;; Predicates
-(defun sotlisp--auto-paired-p ()
-  "Non-nil if this buffer auto-inserts parentheses."
-  (or (bound-and-true-p electric-pair-mode)
-      (bound-and-true-p paredit-mode)
-      (bound-and-true-p smartparens-mode)))
-
-(defun sotlisp--function-form-p ()
-  "Non-nil if point is at the start of a sexp.
-Specially, avoids matching inside argument lists."
-  (and (eq (char-before) ?\()
-       (not (looking-back "(\\(defun\\s-+.*\\|lambda\\s-+\\)("))
-       (not (string-match (rx (syntax symbol)) (string last-command-event)))))
-
-(defun sotlisp--function-quote-p ()
-  "Non-nil if point is at a sharp-quote."
-  (looking-back "#'"))
-
-(defun sotlisp--function-p ()
-  "Non-nil if point is at reasonable place for a function name.
-Returns non-nil if, after moving backwards by a sexp, either
-`sotlisp--function-form-p' or `sotlisp--function-quote-p' return
-non-nil."
-  (save-excursion
-    (ignore-errors
-      (skip-chars-backward (rx alnum))
-      (or (sotlisp--function-form-p)
-          (sotlisp--function-quote-p)))))
-
-(defun sotlisp--whitespace-p ()
-  "Non-nil if current `self-insert'ed char is whitespace."
-  (ignore-errors
-    (string-match (rx space) (string last-command-event))))
-
-
-;;; Expansion logic
-(defvar sotlisp--needs-moving nil
-  "Will `sotlisp--move-to-$' move point after insertion?")
-
-(defun sotlisp--move-to-$ ()
-  "Move backwards until `$' and delete it.
-Point is left where the `$' char was.  Does nothing if variable
-`sotlisp-mode' is nil."
-  (when (bound-and-true-p speed-of-thought-mode)
-    (when sotlisp--needs-moving
-      (setq sotlisp--needs-moving nil)
-      (skip-chars-backward "^\\$")
-      (delete-char -1))))
-
-(add-hook 'post-command-hook #'sotlisp--move-to-$ 'append)
-
-(defun sotlisp--maybe-skip-closing-paren ()
-  "Move past `)' if variable `electric-pair-mode' is enabled."
-  (when (and (char-after ?\))
-             (sotlisp--auto-paired-p))
-    (forward-char 1)))
-
-(defvar sotlisp--function-table (make-hash-table :test #'equal)
-  "Table where function abbrev expansions are stored.")
-
-(defun sotlisp--expand-function ()
-  "Expand the function abbrev before point.
-See `sotlisp-define-function-abbrev'."
-  (let ((r (point)))
-    (skip-chars-backward (rx alnum))
-    (let* ((name (buffer-substring (point) r))
-           (expansion (gethash name sotlisp--function-table)))
-      (delete-region (point) r)
-      (if (sotlisp--function-quote-p)
-          ;; After #' use the simple expansion.
-          (insert (sotlisp--simplify-function-expansion expansion))
-        ;; Inside a form, use the full expansion.
-        (insert expansion)
-        (when (string-match "\\$" expansion)
-          (setq sotlisp--needs-moving t))))
-    ;; Inform `expand-abbrev' that `self-insert-command' should not
-    ;; trigger, by returning non-nil on SPC.
-    (when (sotlisp--whitespace-p)
-      ;; And maybe move out of closing paren if expansion ends with $.
-      (when (eq (char-before) ?$)
-        (delete-char -1)
-        (setq sotlisp--needs-moving nil)
-        (sotlisp--maybe-skip-closing-paren))
-      t)))
-
-(put 'sotlisp--expand-function 'no-self-insert t)
-
-(defun sotlisp--simplify-function-expansion (expansion)
-  "Take a substring of EXPANSION up to first space.
-The space char is not included.  Any \"$\" are also removed."
-  (replace-regexp-in-string
-   "\\$" ""
-   (substring expansion 0 (string-match " " expansion))))
-
-
-;;; Abbrev definitions
-(defconst sotlisp--default-function-abbrevs
-  '(
-    ("a" . "and ")
-    ("ah" . "add-hook '")
-    ("atl" . "add-to-list '")
-    ("bb" . "bury-buffer")
-    ("bc" . "forward-char -1")
-    ("bfn" . "buffer-file-name")
-    ("bl" . "buffer-list$")
-    ("bn" . "buffer-name")
-    ("bod" . "beginning-of-defun")
-    ("bol" . "forward-line 0$")
-    ("bp" . "boundp '")
-    ("bs" . "buffer-string$")
-    ("bsn" . "buffer-substring-no-properties")
-    ("bss" . "buffer-substring ")
-    ("bw" . "forward-word -1")
-    ("c" . "concat ")
-    ("ca" . "char-after$")
-    ("cb" . "current-buffer$")
-    ("cc" . "condition-case er\n$\n(error nil)")
-    ("ci" . "call-interactively ")
-    ("cip" . "called-interactively-p 'any")
-    ("csv" . "customize-save-variable '")
-    ("d" . "delete-char 1")
-    ("dc" . "delete-char 1")
-    ("dcu" . "defcustom $ t\n  \"\"\n  :type 'boolean")
-    ("df" . "defun $ ()\n  \"\"\n  ")
-    ("dfa" . "defface $ \n  '((t))\n  \"\"\n  ")
-    ("dfc" . "defcustom $ t\n  \"\"\n  :type 'boolean")
-    ("dff" . "defface $ \n  '((t))\n  \"\"\n  ")
-    ("dfv" . "defvar $ t\n  \"\"")
-    ("dk" . "define-key ")
-    ("dl" . "dolist (it $)")
-    ("dmp" . "derived-mode-p '")
-    ("dr" . "delete-region ")
-    ("dv" . "defvar $ t\n  \"\"")
-    ("e" . "error \"$\"")
-    ("efn" . "expand-file-name ")
-    ("eol" . "end-of-line")
-    ("f" . "format \"$\"")
-    ("fb" . "fboundp '")
-    ("fbp" . "fboundp '")
-    ("fc" . "forward-char 1")
-    ("ff" . "find-file ")
-    ("fl" . "forward-line 1")
-    ("fp" . "functionp ")
-    ("frp" . "file-readable-p ")
-    ("fs" . "forward-sexp 1")
-    ("fw" . "forward-word 1")
-    ("g" . "goto-char ")
-    ("gc" . "goto-char ")
-    ("gsk" . "global-set-key ")
-    ("i" . "insert ")
-    ("ie" . "ignore-errors ")
-    ("ii" . "interactive")
-    ("ir" . "indent-region ")
-    ("jcl" . "justify-current-line ")
-    ("jl" . "delete-indentation")
-    ("jos" . "just-one-space")
-    ("jr" . "json-read$")
-    ("jtr" . "jump-to-register ")
-    ("k" . "kbd \"$\"")
-    ("kb" . "kill-buffer")
-    ("kn" . "kill-new ")
-    ("l" . "lambda ($)")
-    ("la" . "looking-at \"$\"")
-    ("lap" . "looking-at-p \"$\"")
-    ("lb" . "looking-back \"$\"")
-    ("lbp" . "line-beginning-position")
-    ("lep" . "line-end-position")
-    ("let" . "let (($))")
-    ("lp" . "listp ")
-    ("m" . "message \"$%s\"")
-    ("mb" . "match-beginning 0")
-    ("me" . "match-end 0")
-    ("ms" . "match-string 0")
-    ("msn" . "match-string-no-properties 0")
-    ("msnp" . "match-string-no-properties 0")
-    ("msp" . "match-string-no-properties 0")
-    ("n" . "not ")
-    ("nai" . "newline-and-indent$")
-    ("nl" . "forward-line 1")
-    ("np" . "numberp ")
-    ("ntr" . "narrow-to-region ")
-    ("ow" . "other-window 1")
-    ("p" . "point$")
-    ("pa" . "point-max$")
-    ("pg" . "plist-get ")
-    ("pi" . "point-min$")
-    ("r" . "require '")
-    ("ra" . "use-region-p$")
-    ("rap" . "use-region-p$")
-    ("rb" . "region-beginning")
-    ("re" . "region-end")
-    ("rh" . "remove-hook '")
-    ("rm" . "replace-match \"$\"")
-    ("ro" . "regexp-opt ")
-    ("rq" . "regexp-quote ")
-    ("rris" . "replace-regexp-in-string ")
-    ("rrs" . "replace-regexp-in-string ")
-    ("rs" . "while (search-forward $ nil t)\n(replace-match \"\") nil t)")
-    ("rsb" . "re-search-backward $ nil 'noerror")
-    ("rsf" . "re-search-forward $ nil 'noerror")
-    ("s" . "setq ")
-    ("sb" . "search-backward $ nil 'noerror")
-    ("sbr" . "search-backward-regexp $ nil 'noerror")
-    ("scb" . "skip-chars-backward \"$\r\n[:blank:]\"")
-    ("scf" . "skip-chars-forward \"$\r\n[:blank:]\"")
-    ("se" . "save-excursion")
-    ("sf" . "search-forward $ nil 'noerror")
-    ("sfr" . "search-forward-regexp $ nil 'noerror")
-    ("sic" . "self-insert-command")
-    ("sl" . "string<")
-    ("sm" . "string-match \"$\"")
-    ("smd" . "save-match-data")
-    ("sn" . "symbol-name ")
-    ("sp" . "stringp ")
-    ("sq" . "string= ")
-    ("sr" . "save-restriction")
-    ("ss" . "substring ")
-    ("ssn" . "substring-no-properties ")
-    ("ssnp" . "substring-no-properties ")
-    ("stb" . "switch-to-buffer ")
-    ("sw" . "selected-window$")
-    ("syp" . "symbolp ")
-    ("tap" . "thing-at-point 'symbol")
-    ("u" . "unless ")
-    ("ul" . "up-list")
-    ("up" . "unwind-protect\n(progn $)")
-    ("urp" . "use-region-p$")
-    ("w" . "when ")
-    ("wcb" . "with-current-buffer ")
-    ("wf" . "write-file ")
-    ("wh" . "while ")
-    ("wl" . "window-list nil 'nominibuffer")
-    ("wtb" . "with-temp-buffer")
-    ("wtf" . "with-temp-file ")
-    )
-  "Alist of (ABBREV . EXPANSION) used by `sotlisp'.")
-
-(defun sotlisp-define-function-abbrev (name expansion)
-  "Define a function abbrev expanding NAME to EXPANSION.
-This abbrev will only be expanded in places where a function name is
-sensible.  Roughly, this is right after a `(' or a `#''.
-
-If EXPANSION is any string, it doesn't have to be the just the
-name of a function.  In particular:
-  - if it contains a `$', this char will not be inserted and
-    point will be moved to its position after expansion.
-  - if it contains a space, only a substring of it up to the
-first space is inserted when expanding after a `#'' (this is done
-by defining two different abbrevs).
-
-For instance, if one defines
-   (sotlisp-define-function-abbrev \"d\" \"delete-char 1\")
-
-then triggering `expand-abbrev' after \"d\" expands in the
-following way:
-   (d    => (delete-char 1
-   #'d   => #'delete-char"
-  (define-abbrev emacs-lisp-mode-abbrev-table
-    name t #'sotlisp--expand-function
-    ;; Don't override user abbrevs
-    :system t
-    ;; Only expand in function places.
-    :enable-function #'sotlisp--function-p)
-  (puthash name expansion sotlisp--function-table))
-
-(defun sotlisp-erase-all-abbrevs ()
-  "Undefine all abbrevs defined by `sotlisp'."
-  (interactive)
-  (maphash (lambda (x _) (define-abbrev emacs-lisp-mode-abbrev-table x nil))
-           sotlisp--function-table))
-
-(defun sotlisp-define-all-abbrevs ()
-  "Define all abbrevs in `sotlisp--default-function-abbrevs'."
-  (interactive)
-  (mapc (lambda (x) (sotlisp-define-function-abbrev (car x) (cdr x)))
-    sotlisp--default-function-abbrevs))
-
-
-;;; The global minor-mode
-(defvar speed-of-thought-turn-on-hook '(sotlisp-turn-on-everywhere)
-  "Hook run once when `speed-of-thought-mode' is enabled.
-Note that `speed-of-thought-mode' is global, so this is not run
-on every buffer.
-
-See `sotlisp-turn-on-everywhere' for an example of what a
-function in this hook should do.")
-
-(defvar speed-of-thought-turn-off-hook '(sotlisp-turn-off-everywhere)
-  "Hook run once when `speed-of-thought-mode' is disabled.
-Note that `speed-of-thought-mode' is global, so this is not run
-on every buffer.
-
-See `sotlisp-turn-on-everywhere' for an example of what a
-function in this hook should do.")
-
-;;;###autoload
-(define-minor-mode speed-of-thought-mode nil nil nil nil
-  :global t
-  (run-hooks (if speed-of-thought-mode
-                 'speed-of-thought-turn-on-hook
-               'speed-of-thought-turn-off-hook)))
-
-
-;;; The local minor-mode
-(defun sotlisp-turn-on-everywhere ()
-  "Call-once function to turn on sotlisp everywhere.
-Calls `sotlisp-mode' on all `emacs-lisp-mode' buffers, and sets
-up a hook and abbrevs."
-  (add-hook 'emacs-lisp-mode-hook #'sotlisp-mode)
-  (sotlisp-define-all-abbrevs)
-  (mapc (lambda (b)
-          (with-current-buffer b
-            (when (derived-mode-p 'emacs-lisp-mode)
-              (sotlisp-mode 1))))
-    (buffer-list)))
-
-(defun sotlisp-turn-off-everywhere ()
-  "Call-once function to turn off sotlisp everywhere.
-Removes `sotlisp-mode' from all `emacs-lisp-mode' buffers, and
-removes hooks and abbrevs."
-  (remove-hook 'emacs-lisp-mode-hook #'sotlisp-mode)
-  (sotlisp-erase-all-abbrevs)
-  (mapc (lambda (b)
-          (with-current-buffer b
-            (when (derived-mode-p 'emacs-lisp-mode)
-              (sotlisp-mode -1))))
-    (buffer-list)))
-
-(define-minor-mode sotlisp-mode nil nil " SoT"
-  '(([M-return] . sotlisp-newline-and-parentheses)
-    ([C-return] . sotlisp-downlist-newline-and-parentheses)
-    ("\C-cf"    . sotlisp-find-or-define-function)
-    ("\C-cv"    . sotlisp-find-or-define-variable)))
-
-
-;;; Commands
-(defun sotlisp-newline-and-parentheses ()
-  "`newline-and-indent' then insert a pair of parentheses."
-  (interactive)
-  (point)
-  (ignore-errors (expand-abbrev))
-  (newline-and-indent)
-  (insert "()")
-  (forward-char -1))
-
-(defun sotlisp-downlist-newline-and-parentheses ()
-  "`up-list', `newline-and-indent', then insert a parentheses pair."
-  (interactive)
-  (ignore-errors (expand-abbrev))
-  (up-list)
-  (newline-and-indent)
-  (insert "()")
-  (forward-char -1))
-
-(defun sotlisp--find-in-buffer (r s)
-  "Find the string (concat R (regexp-quote S)) somewhere in this buffer."
-  (let ((l (save-excursion
-             (goto-char (point-min))
-             (save-match-data
-               (when (search-forward-regexp (concat r (regexp-quote s) "\\_>")
-                                            nil :noerror)
-                 (match-beginning 0))))))
-    (when l
-      (push-mark)
-      (goto-char l)
-      l)))
-
-(defun sotlisp--beginning-of-defun ()
-  "`push-mark' and move above this defun."
-  (push-mark)
-  (beginning-of-defun)
-  (when (looking-back "^;;;###autoload\\s-*\n")
-    (forward-line -1)))
-
-(defun sotlisp--function-at-point ()
-  "Return name of `function-called-at-point'."
-  (if (save-excursion
-        (ignore-errors (forward-sexp -1)
-                       (looking-at-p "#'")))
-      (thing-at-point 'symbol)
-    (let ((fcap (function-called-at-point)))
-      (if fcap
-          (symbol-name fcap)
-        (thing-at-point 'symbol)))))
-
-(defun sotlisp-find-or-define-function (&optional prefix)
-  "If symbol under point is a defined function, go to it, otherwise define it.
-Essentially `find-function' on steroids.
-
-If you write in your code the name of a function you haven't
-defined yet, just place point on its name and hit 
\\[sotlisp-find-or-define-function]
-and a defun will be inserted with point inside it.  After that,
-you can just hit `pop-mark' to go back to where you were.
-With a PREFIX argument, creates a `defmacro' instead.
-
-If the function under point is already defined this just calls
-`find-function', with one exception:
-    if there's a defun (or equivalent) for this function in the
-    current buffer, we go to that even if it's not where the
-    global definition comes from (this is useful if you're
-    writing an Emacs package that also happens to be installed
-    through package.el).
-
-With a prefix argument, defines a `defmacro' instead of a `defun'."
-  (interactive "P")
-  (let ((name (sotlisp--function-at-point)))
-    (unless (and name (sotlisp--find-in-buffer "(def\\(un\\|macro\\|alias\\) " 
name))
-      (let ((name-s (intern-soft name)))
-        (if (fboundp name-s)
-            (find-function name-s)
-          (sotlisp--beginning-of-defun)
-          (insert "(def" (if prefix "macro" "un")
-                  " " name " (")
-          (save-excursion (insert ")\n  \"\"\n  )\n\n")))))))
-
-(defun sotlisp-find-or-define-variable (&optional prefix)
-  "If symbol under point is a defined variable, go to it, otherwise define it.
-Essentially `find-variable' on steroids.
-
-If you write in your code the name of a variable you haven't
-defined yet, place point on its name and hit 
\\[sotlisp-find-or-define-variable]
-and a `defcustom' will be created with point inside.  After that,
-you can just `pop-mark' to go back to where you were.  With a
-PREFIX argument, creates a `defvar' instead.
-
-If the variable under point is already defined this just calls
-`find-variable', with one exception:
-    if there's a defvar (or equivalent) for this variable in the
-    current buffer, we go to that even if it's not where the
-    global definition comes from (this is useful if you're
-    writing an Emacs package that also happens to be installed
-    through package.el).
-
-With a prefix argument, defines a `defvar' instead of a `defcustom'."
-  (interactive "P")
-  (let ((name (symbol-name (variable-at-point t))))
-    (unless (sotlisp--find-in-buffer "(def\\(custom\\|const\\|var\\) " name)
-      (unless (and (symbolp (variable-at-point))
-                   (ignore-errors (find-variable (variable-at-point)) t))
-        (let ((name (thing-at-point 'symbol)))
-          (sotlisp--beginning-of-defun)
-          (insert "(def" (if prefix "var" "custom")
-                  " " name " t")
-          (save-excursion
-            (insert "\n  \"\""
-                    (if prefix "" "\n  :type 'boolean")
-                    ")\n\n")))))))
-
-(provide 'sotlisp)
-;;; sotlisp.el ends here
-
+;;; sotlisp.el --- Write lisp at the speed of thought.  -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2014, 2015 Free Software Foundation, Inc.
+
+;; Author: Artur Malabarba  <address@hidden>
+;; Keywords: convenience, lisp
+;; Package-Requires: ((emacs "24.1"))
+;; Version: 0
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This defines a new global minor-mode `speed-of-thought-mode', which
+;; activates locally on any supported buffer.  Currently, only
+;; `emacs-lisp-mode' buffers are supported.
+;;
+;; The mode is quite simple, and is composed of two parts:
+;;
+;;; Abbrevs
+;;
+;; A large number of abbrevs which expand function
+;; initials to their name.  A few examples:
+;; 
+;; - wcb -> with-current-buffer
+;; - i -> insert
+;; - r -> require '
+;; - a -> and
+;; 
+;; However, these are defined in a way such that they ONLY expand in a
+;; place where you would use a function, so hitting SPC after "(r"
+;; expands to "(require '", but hitting SPC after "(delete-region r"
+;; will NOT expand the `r', because that's obviously not a function.
+;; Furtheromre, "#'r" will expand to "#'require" (note how it ommits
+;; that extra quote, since it would be useless here).
+;;
+;;; Commands
+;;
+;; It also defines 4 commands, which really fit into this "follow the
+;; thought-flow" way of writing.  The bindings are as follows, I
+;; understand these don't fully adhere to conventions, and I'd
+;; appreciate suggestions on better bindings.
+;; 
+;; - M-RET :: Break line, and insert "()" with point in the middle.
+;; - C-RET :: Do `forward-up-list', then do M-RET.
+;; 
+;; Hitting RET followed by a `(' was one of the most common key sequences
+;; for me while writing elisp, so giving it a quick-to-hit key was a
+;; significant improvement.
+;; 
+;; - C-c f :: Find function under point.  If it is not defined, create a
+;; definition for it below the current function and leave point inside.
+;; - C-c v :: Same, but for variable.
+;; 
+;; With these commands, you just write your code as you think of it.  Once
+;; you hit a "stop-point" of sorts in your tought flow, you hit `C-c f/v`
+;; on any undefined functions/variables, write their definitions, and hit
+;; `C-u C-SPC` to go back to the main function.
+;; 
+;;; Small Example
+;;
+;; With the above (assuming you use something like paredit or
+;; electric-pair-mode), if you write:
+;;
+;;   ( w t b M-RET i SPC text
+;; 
+;; You get
+;; 
+;;   (with-temp-buffer (insert text))
+
+
+;;; Code:
+
+;;; Predicates
+(defun sotlisp--auto-paired-p ()
+  "Non-nil if this buffer auto-inserts parentheses."
+  (or (bound-and-true-p electric-pair-mode)
+      (bound-and-true-p paredit-mode)
+      (bound-and-true-p smartparens-mode)))
+
+(defun sotlisp--function-form-p ()
+  "Non-nil if point is at the start of a sexp.
+Specially, avoids matching inside argument lists."
+  (and (eq (char-before) ?\()
+       (not (looking-back "(\\(defun\\s-+.*\\|lambda\\s-+\\)("))
+       (not (string-match (rx (syntax symbol)) (string last-command-event)))))
+
+(defun sotlisp--function-quote-p ()
+  "Non-nil if point is at a sharp-quote."
+  (looking-back "#'"))
+
+(defun sotlisp--function-p ()
+  "Non-nil if point is at reasonable place for a function name.
+Returns non-nil if, after moving backwards by a sexp, either
+`sotlisp--function-form-p' or `sotlisp--function-quote-p' return
+non-nil."
+  (save-excursion
+    (ignore-errors
+      (skip-chars-backward (rx alnum))
+      (or (sotlisp--function-form-p)
+          (sotlisp--function-quote-p)))))
+
+(defun sotlisp--whitespace-p ()
+  "Non-nil if current `self-insert'ed char is whitespace."
+  (ignore-errors
+    (string-match (rx space) (string last-command-event))))
+
+
+;;; Expansion logic
+(defvar sotlisp--needs-moving nil
+  "Will `sotlisp--move-to-$' move point after insertion?")
+
+(defun sotlisp--move-to-$ ()
+  "Move backwards until `$' and delete it.
+Point is left where the `$' char was.  Does nothing if variable
+`sotlisp-mode' is nil."
+  (when (bound-and-true-p speed-of-thought-mode)
+    (when sotlisp--needs-moving
+      (setq sotlisp--needs-moving nil)
+      (skip-chars-backward "^\\$")
+      (delete-char -1))))
+
+(add-hook 'post-command-hook #'sotlisp--move-to-$ 'append)
+
+(defun sotlisp--maybe-skip-closing-paren ()
+  "Move past `)' if variable `electric-pair-mode' is enabled."
+  (when (and (char-after ?\))
+             (sotlisp--auto-paired-p))
+    (forward-char 1)))
+
+(defvar sotlisp--function-table (make-hash-table :test #'equal)
+  "Table where function abbrev expansions are stored.")
+
+(defun sotlisp--expand-function ()
+  "Expand the function abbrev before point.
+See `sotlisp-define-function-abbrev'."
+  (let ((r (point)))
+    (skip-chars-backward (rx alnum))
+    (let* ((name (buffer-substring (point) r))
+           (expansion (gethash name sotlisp--function-table)))
+      (delete-region (point) r)
+      (if (sotlisp--function-quote-p)
+          ;; After #' use the simple expansion.
+          (insert (sotlisp--simplify-function-expansion expansion))
+        ;; Inside a form, use the full expansion.
+        (insert expansion)
+        (when (string-match "\\$" expansion)
+          (setq sotlisp--needs-moving t))))
+    ;; Inform `expand-abbrev' that `self-insert-command' should not
+    ;; trigger, by returning non-nil on SPC.
+    (when (sotlisp--whitespace-p)
+      ;; And maybe move out of closing paren if expansion ends with $.
+      (when (eq (char-before) ?$)
+        (delete-char -1)
+        (setq sotlisp--needs-moving nil)
+        (sotlisp--maybe-skip-closing-paren))
+      t)))
+
+(put 'sotlisp--expand-function 'no-self-insert t)
+
+(defun sotlisp--simplify-function-expansion (expansion)
+  "Take a substring of EXPANSION up to first space.
+The space char is not included.  Any \"$\" are also removed."
+  (replace-regexp-in-string
+   "\\$" ""
+   (substring expansion 0 (string-match " " expansion))))
+
+
+;;; Abbrev definitions
+(defconst sotlisp--default-function-abbrevs
+  '(
+    ("a" . "and ")
+    ("ah" . "add-hook '")
+    ("atl" . "add-to-list '")
+    ("bb" . "bury-buffer")
+    ("bc" . "forward-char -1")
+    ("bfn" . "buffer-file-name")
+    ("bl" . "buffer-list$")
+    ("bn" . "buffer-name")
+    ("bod" . "beginning-of-defun")
+    ("bol" . "forward-line 0$")
+    ("bp" . "boundp '")
+    ("bs" . "buffer-string$")
+    ("bsn" . "buffer-substring-no-properties")
+    ("bss" . "buffer-substring ")
+    ("bw" . "forward-word -1")
+    ("c" . "concat ")
+    ("ca" . "char-after$")
+    ("cb" . "current-buffer$")
+    ("cc" . "condition-case er\n$\n(error nil)")
+    ("ci" . "call-interactively ")
+    ("cip" . "called-interactively-p 'any")
+    ("csv" . "customize-save-variable '")
+    ("d" . "delete-char 1")
+    ("dc" . "delete-char 1")
+    ("dcu" . "defcustom $ t\n  \"\"\n  :type 'boolean")
+    ("df" . "defun $ ()\n  \"\"\n  ")
+    ("dfa" . "defface $ \n  '((t))\n  \"\"\n  ")
+    ("dfc" . "defcustom $ t\n  \"\"\n  :type 'boolean")
+    ("dff" . "defface $ \n  '((t))\n  \"\"\n  ")
+    ("dfv" . "defvar $ t\n  \"\"")
+    ("dk" . "define-key ")
+    ("dl" . "dolist (it $)")
+    ("dmp" . "derived-mode-p '")
+    ("dr" . "delete-region ")
+    ("dv" . "defvar $ t\n  \"\"")
+    ("e" . "error \"$\"")
+    ("efn" . "expand-file-name ")
+    ("eol" . "end-of-line")
+    ("f" . "format \"$\"")
+    ("fb" . "fboundp '")
+    ("fbp" . "fboundp '")
+    ("fc" . "forward-char 1")
+    ("ff" . "find-file ")
+    ("fl" . "forward-line 1")
+    ("fp" . "functionp ")
+    ("frp" . "file-readable-p ")
+    ("fs" . "forward-sexp 1")
+    ("fw" . "forward-word 1")
+    ("g" . "goto-char ")
+    ("gc" . "goto-char ")
+    ("gsk" . "global-set-key ")
+    ("i" . "insert ")
+    ("ie" . "ignore-errors ")
+    ("ii" . "interactive")
+    ("ir" . "indent-region ")
+    ("jcl" . "justify-current-line ")
+    ("jl" . "delete-indentation")
+    ("jos" . "just-one-space")
+    ("jr" . "json-read$")
+    ("jtr" . "jump-to-register ")
+    ("k" . "kbd \"$\"")
+    ("kb" . "kill-buffer")
+    ("kn" . "kill-new ")
+    ("l" . "lambda ($)")
+    ("la" . "looking-at \"$\"")
+    ("lap" . "looking-at-p \"$\"")
+    ("lb" . "looking-back \"$\"")
+    ("lbp" . "line-beginning-position")
+    ("lep" . "line-end-position")
+    ("let" . "let (($))")
+    ("lp" . "listp ")
+    ("m" . "message \"$%s\"")
+    ("mb" . "match-beginning 0")
+    ("me" . "match-end 0")
+    ("ms" . "match-string 0")
+    ("msn" . "match-string-no-properties 0")
+    ("msnp" . "match-string-no-properties 0")
+    ("msp" . "match-string-no-properties 0")
+    ("n" . "not ")
+    ("nai" . "newline-and-indent$")
+    ("nl" . "forward-line 1")
+    ("np" . "numberp ")
+    ("ntr" . "narrow-to-region ")
+    ("ow" . "other-window 1")
+    ("p" . "point$")
+    ("pa" . "point-max$")
+    ("pg" . "plist-get ")
+    ("pi" . "point-min$")
+    ("r" . "require '")
+    ("ra" . "use-region-p$")
+    ("rap" . "use-region-p$")
+    ("rb" . "region-beginning")
+    ("re" . "region-end")
+    ("rh" . "remove-hook '")
+    ("rm" . "replace-match \"$\"")
+    ("ro" . "regexp-opt ")
+    ("rq" . "regexp-quote ")
+    ("rris" . "replace-regexp-in-string ")
+    ("rrs" . "replace-regexp-in-string ")
+    ("rs" . "while (search-forward $ nil t)\n(replace-match \"\") nil t)")
+    ("rsb" . "re-search-backward $ nil 'noerror")
+    ("rsf" . "re-search-forward $ nil 'noerror")
+    ("s" . "setq ")
+    ("sb" . "search-backward $ nil 'noerror")
+    ("sbr" . "search-backward-regexp $ nil 'noerror")
+    ("scb" . "skip-chars-backward \"$\r\n[:blank:]\"")
+    ("scf" . "skip-chars-forward \"$\r\n[:blank:]\"")
+    ("se" . "save-excursion")
+    ("sf" . "search-forward $ nil 'noerror")
+    ("sfr" . "search-forward-regexp $ nil 'noerror")
+    ("sic" . "self-insert-command")
+    ("sl" . "string<")
+    ("sm" . "string-match \"$\"")
+    ("smd" . "save-match-data")
+    ("sn" . "symbol-name ")
+    ("sp" . "stringp ")
+    ("sq" . "string= ")
+    ("sr" . "save-restriction")
+    ("ss" . "substring ")
+    ("ssn" . "substring-no-properties ")
+    ("ssnp" . "substring-no-properties ")
+    ("stb" . "switch-to-buffer ")
+    ("sw" . "selected-window$")
+    ("syp" . "symbolp ")
+    ("tap" . "thing-at-point 'symbol")
+    ("u" . "unless ")
+    ("ul" . "up-list")
+    ("up" . "unwind-protect\n(progn $)")
+    ("urp" . "use-region-p$")
+    ("w" . "when ")
+    ("wcb" . "with-current-buffer ")
+    ("wf" . "write-file ")
+    ("wh" . "while ")
+    ("wl" . "window-list nil 'nominibuffer")
+    ("wtb" . "with-temp-buffer")
+    ("wtf" . "with-temp-file ")
+    )
+  "Alist of (ABBREV . EXPANSION) used by `sotlisp'.")
+
+(defun sotlisp-define-function-abbrev (name expansion)
+  "Define a function abbrev expanding NAME to EXPANSION.
+This abbrev will only be expanded in places where a function name is
+sensible.  Roughly, this is right after a `(' or a `#''.
+
+If EXPANSION is any string, it doesn't have to be the just the
+name of a function.  In particular:
+  - if it contains a `$', this char will not be inserted and
+    point will be moved to its position after expansion.
+  - if it contains a space, only a substring of it up to the
+first space is inserted when expanding after a `#'' (this is done
+by defining two different abbrevs).
+
+For instance, if one defines
+   (sotlisp-define-function-abbrev \"d\" \"delete-char 1\")
+
+then triggering `expand-abbrev' after \"d\" expands in the
+following way:
+   (d    => (delete-char 1
+   #'d   => #'delete-char"
+  (define-abbrev emacs-lisp-mode-abbrev-table
+    name t #'sotlisp--expand-function
+    ;; Don't override user abbrevs
+    :system t
+    ;; Only expand in function places.
+    :enable-function #'sotlisp--function-p)
+  (puthash name expansion sotlisp--function-table))
+
+(defun sotlisp-erase-all-abbrevs ()
+  "Undefine all abbrevs defined by `sotlisp'."
+  (interactive)
+  (maphash (lambda (x _) (define-abbrev emacs-lisp-mode-abbrev-table x nil))
+           sotlisp--function-table))
+
+(defun sotlisp-define-all-abbrevs ()
+  "Define all abbrevs in `sotlisp--default-function-abbrevs'."
+  (interactive)
+  (mapc (lambda (x) (sotlisp-define-function-abbrev (car x) (cdr x)))
+    sotlisp--default-function-abbrevs))
+
+
+;;; The global minor-mode
+(defvar speed-of-thought-turn-on-hook '(sotlisp-turn-on-everywhere)
+  "Hook run once when `speed-of-thought-mode' is enabled.
+Note that `speed-of-thought-mode' is global, so this is not run
+on every buffer.
+
+See `sotlisp-turn-on-everywhere' for an example of what a
+function in this hook should do.")
+
+(defvar speed-of-thought-turn-off-hook '(sotlisp-turn-off-everywhere)
+  "Hook run once when `speed-of-thought-mode' is disabled.
+Note that `speed-of-thought-mode' is global, so this is not run
+on every buffer.
+
+See `sotlisp-turn-on-everywhere' for an example of what a
+function in this hook should do.")
+
+;;;###autoload
+(define-minor-mode speed-of-thought-mode nil nil nil nil
+  :global t
+  (run-hooks (if speed-of-thought-mode
+                 'speed-of-thought-turn-on-hook
+               'speed-of-thought-turn-off-hook)))
+
+
+;;; The local minor-mode
+(defun sotlisp-turn-on-everywhere ()
+  "Call-once function to turn on sotlisp everywhere.
+Calls `sotlisp-mode' on all `emacs-lisp-mode' buffers, and sets
+up a hook and abbrevs."
+  (add-hook 'emacs-lisp-mode-hook #'sotlisp-mode)
+  (sotlisp-define-all-abbrevs)
+  (mapc (lambda (b)
+          (with-current-buffer b
+            (when (derived-mode-p 'emacs-lisp-mode)
+              (sotlisp-mode 1))))
+    (buffer-list)))
+
+(defun sotlisp-turn-off-everywhere ()
+  "Call-once function to turn off sotlisp everywhere.
+Removes `sotlisp-mode' from all `emacs-lisp-mode' buffers, and
+removes hooks and abbrevs."
+  (remove-hook 'emacs-lisp-mode-hook #'sotlisp-mode)
+  (sotlisp-erase-all-abbrevs)
+  (mapc (lambda (b)
+          (with-current-buffer b
+            (when (derived-mode-p 'emacs-lisp-mode)
+              (sotlisp-mode -1))))
+    (buffer-list)))
+
+(define-minor-mode sotlisp-mode nil nil " SoT"
+  '(([M-return] . sotlisp-newline-and-parentheses)
+    ([C-return] . sotlisp-downlist-newline-and-parentheses)
+    ("\C-cf"    . sotlisp-find-or-define-function)
+    ("\C-cv"    . sotlisp-find-or-define-variable)))
+
+
+;;; Commands
+(defun sotlisp-newline-and-parentheses ()
+  "`newline-and-indent' then insert a pair of parentheses."
+  (interactive)
+  (point)
+  (ignore-errors (expand-abbrev))
+  (newline-and-indent)
+  (insert "()")
+  (forward-char -1))
+
+(defun sotlisp-downlist-newline-and-parentheses ()
+  "`up-list', `newline-and-indent', then insert a parentheses pair."
+  (interactive)
+  (ignore-errors (expand-abbrev))
+  (up-list)
+  (newline-and-indent)
+  (insert "()")
+  (forward-char -1))
+
+(defun sotlisp--find-in-buffer (r s)
+  "Find the string (concat R (regexp-quote S)) somewhere in this buffer."
+  (let ((l (save-excursion
+             (goto-char (point-min))
+             (save-match-data
+               (when (search-forward-regexp (concat r (regexp-quote s) "\\_>")
+                                            nil :noerror)
+                 (match-beginning 0))))))
+    (when l
+      (push-mark)
+      (goto-char l)
+      l)))
+
+(defun sotlisp--beginning-of-defun ()
+  "`push-mark' and move above this defun."
+  (push-mark)
+  (beginning-of-defun)
+  (when (looking-back "^;;;###autoload\\s-*\n")
+    (forward-line -1)))
+
+(defun sotlisp--function-at-point ()
+  "Return name of `function-called-at-point'."
+  (if (save-excursion
+        (ignore-errors (forward-sexp -1)
+                       (looking-at-p "#'")))
+      (thing-at-point 'symbol)
+    (let ((fcap (function-called-at-point)))
+      (if fcap (symbol-name fcap)
+        (thing-at-point 'symbol)))))
+
+(defun sotlisp-find-or-define-function (&optional prefix)
+  "If symbol under point is a defined function, go to it, otherwise define it.
+Essentially `find-function' on steroids.
+
+If you write in your code the name of a function you haven't
+defined yet, just place point on its name and hit 
\\[sotlisp-find-or-define-function]
+and a defun will be inserted with point inside it.  After that,
+you can just hit `pop-mark' to go back to where you were.
+With a PREFIX argument, creates a `defmacro' instead.
+
+If the function under point is already defined this just calls
+`find-function', with one exception:
+    if there's a defun (or equivalent) for this function in the
+    current buffer, we go to that even if it's not where the
+    global definition comes from (this is useful if you're
+    writing an Emacs package that also happens to be installed
+    through package.el).
+
+With a prefix argument, defines a `defmacro' instead of a `defun'."
+  (interactive "P")
+  (let ((name (sotlisp--function-at-point)))
+    (unless (and name (sotlisp--find-in-buffer "(def\\(un\\|macro\\|alias\\) " 
name))
+      (let ((name-s (intern-soft name)))
+        (if (fboundp name-s)
+            (find-function name-s)
+          (sotlisp--beginning-of-defun)
+          (insert "(def" (if prefix "macro" "un")
+                  " " name " (")
+          (save-excursion (insert ")\n  \"\"\n  )\n\n")))))))
+
+(defun sotlisp-find-or-define-variable (&optional prefix)
+  "If symbol under point is a defined variable, go to it, otherwise define it.
+Essentially `find-variable' on steroids.
+
+If you write in your code the name of a variable you haven't
+defined yet, place point on its name and hit 
\\[sotlisp-find-or-define-variable]
+and a `defcustom' will be created with point inside.  After that,
+you can just `pop-mark' to go back to where you were.  With a
+PREFIX argument, creates a `defvar' instead.
+
+If the variable under point is already defined this just calls
+`find-variable', with one exception:
+    if there's a defvar (or equivalent) for this variable in the
+    current buffer, we go to that even if it's not where the
+    global definition comes from (this is useful if you're
+    writing an Emacs package that also happens to be installed
+    through package.el).
+
+With a prefix argument, defines a `defvar' instead of a `defcustom'."
+  (interactive "P")
+  (let ((name (symbol-name (variable-at-point t))))
+    (unless (sotlisp--find-in-buffer "(def\\(custom\\|const\\|var\\) " name)
+      (unless (and (symbolp (variable-at-point))
+                   (ignore-errors (find-variable (variable-at-point)) t))
+        (let ((name (thing-at-point 'symbol)))
+          (sotlisp--beginning-of-defun)
+          (insert "(def" (if prefix "var" "custom")
+                  " " name " t")
+          (save-excursion
+            (insert "\n  \"\""
+                    (if prefix "" "\n  :type 'boolean")
+                    ")\n\n")))))))
+
+(provide 'sotlisp)
+;;; sotlisp.el ends here
diff --git a/packages/test-simple/.gitignore b/packages/test-simple/.gitignore
new file mode 100644
index 0000000..0b38301
--- /dev/null
+++ b/packages/test-simple/.gitignore
@@ -0,0 +1,14 @@
+*elc
+*~
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache
+/config.log
+/config.status
+/configure
+/elc-stamp
+/install-sh
+/missing
+/script
+/README
diff --git a/packages/test-simple/.travis.yml b/packages/test-simple/.travis.yml
new file mode 100644
index 0000000..9280a20
--- /dev/null
+++ b/packages/test-simple/.travis.yml
@@ -0,0 +1,8 @@
+language: emacs
+
+install:
+  # Install emacs.
+  - "sudo apt-get install emacs23-nox"
+
+# run the tests
+script: /bin/sh ./autogen.sh && make check
diff --git a/packages/test-simple/AUTHORS b/packages/test-simple/AUTHORS
new file mode 100644
index 0000000..772a532
--- /dev/null
+++ b/packages/test-simple/AUTHORS
@@ -0,0 +1,2 @@
+Rocky Bernstein (address@hidden) adapted from Phil Hagelberg's behave.el
+
diff --git a/packages/test-simple/COPYING b/packages/test-simple/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/packages/test-simple/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/packages/test-simple/Carton b/packages/test-simple/Carton
new file mode 100644
index 0000000..b039f40
--- /dev/null
+++ b/packages/test-simple/Carton
@@ -0,0 +1,4 @@
+(source "melpa" "http://melpa.milkbox.net/packages/";)
+
+(package "test-simple" "0.2.1"
+        "Unit tests for GNU emacs that work interactively and in batch")
diff --git a/packages/test-simple/ChangeLog b/packages/test-simple/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/packages/test-simple/INSTALL b/packages/test-simple/INSTALL
new file mode 100644
index 0000000..20f7800
--- /dev/null
+++ b/packages/test-simple/INSTALL
@@ -0,0 +1,18 @@
+This package is now installable from inside Emacs and melpa. 
+
+We have an old-style GNU autoconf configuration as well and an install
+script to pick that up from git sources. For this, you will need:
+
+   * Emacs, of course. Version 23 or better
+   * _autoconf_ and _autoreconf_ to build the configure script. Usually 
_autoreconf_ comes with an "autoconf" package
+   * GNU Make -- or even better "remake":http//bashdb.sf.net/remake
+  
+If you are feeling lucky, you can try running the install script from the 
github repository:
+
+    $ bash < <( curl 
https://raw.github.com/rocky/emacs-test-simple/master/install-from-git.sh )
+
+Otherwise:
+
+   git clone http://github.com/rocky/emacs-test-simple
+   cd emacs-test-simple
+   ./configure && make && [sudo] make install
diff --git a/packages/test-simple/Makefile.am b/packages/test-simple/Makefile.am
new file mode 100644
index 0000000..a1c318c
--- /dev/null
+++ b/packages/test-simple/Makefile.am
@@ -0,0 +1,64 @@
+# Note: This makefile include remake-style target comments.
+# These comments before the targets start with #:
+# remake --tasks to shows the targets and the comments
+
+GIT2CL ?= git2cl
+RUBY   ?= ruby
+
+lisp_files := $(wildcard *.el)
+lisp_LISP = $(lisp_files)
+test_files := $(wildcard test/*.el)
+
+EXTRA_DIST = $(lisp_files) $(test_files) README THANKS README.md COPYING
+
+CHECK_FILES = $(notdir $(test_files:.el=.run))
+
+
+check: $(test-files)
+       $(MAKE) -C test check
+
+README: README.textile
+       ln -s README.md README
+
+PHONY=check check_copyrights clean dist distclean test check-short check-terse 
install-short
+
+if MAINTAINER_MODE
+
+ChangeLog:
+       git log --pretty --numstat --summary | $(GIT2CL) > $@
+
+ACLOCAL_AMFLAGS=-I .
+
+endif
+
+#: Run all tests
+test: check
+
+check-short:
+       $(MAKE) -C test check 2>&1  | ruby make-check-filter.rb
+
+#: Run all tests without and show just the failure lines
+check-terse:
+       $(MAKE) check 2>&1  | $(RUBY) make-check-filter.rb | grep failure
+
+#: Run "make install"
+install-short:
+       $(MAKE) install 2>&1  | $(RUBY) make-check-filter.rb
+
+CR_EXCEPTIONS=copyright_exceptions
+#: Check for GNU Copyrights.
+check_copyrights:
+       @echo "Compute exceptions >$(CR_EXCEPTIONS)~"
+       @export LANG=C;                                                 \
+       find . -name '.git' -prune -o -name '*.el' -print0 |            \
+           xargs -0 grep -L 'Free Software Foundation, Inc' |          \
+           grep -v '\(\.dir-locals\|.-\(pkg\|autoloads\)\)\.el$$';     \
+       find . -name '.git' -prune -o -name '*.el' -print |             \
+           while read f; do                                            \
+               fquoted="$$(echo $$f|tr '|' '_')";                      \
+               sed -n -e '/[Cc]opyright.*, *[1-9][-0-9]*,\?$$/N'       \
+                   -e '/Free Software Foundation/d'                    \
+                   -e "s|^\\(.*[Cc]opyright\\)|$$fquoted:\\1|p"        \
+                  "$$f";                                               \
+           done | sort >$(CR_EXCEPTIONS)~
+       diff -u "$(CR_EXCEPTIONS)" "$(CR_EXCEPTIONS)~"
diff --git a/packages/test-simple/NEWS b/packages/test-simple/NEWS
new file mode 100644
index 0000000..f35d826
--- /dev/null
+++ b/packages/test-simple/NEWS
@@ -0,0 +1,5 @@
+1.0
+Initial Melpa release
+
+0.2
+Initial Release
diff --git a/packages/test-simple/README.md b/packages/test-simple/README.md
new file mode 100644
index 0000000..7a473b0
--- /dev/null
+++ b/packages/test-simple/README.md
@@ -0,0 +1,71 @@
+[![Build 
Status](https://travis-ci.org/rocky/emacs-test-simple.png)](https://travis-ci.org/rocky/emacs-test-simple)
+
+*test-simple.el* is :
+
+* Simple -- no need for context macros, enclosing specifications, or required 
test tags. But if you want, you still can add custom assert failure messages or 
add notes before a group of tests.
+* Accomodates both interactive and non-interactive use:
+  * For interactive use one can use `eval-last-sexp`, `eval-region`, and 
`eval-buffer`
+  * For non-interactive use run as: `emacs --batch --no-site-file --no-splash 
--load <test-lisp-code.el>`
+
+I use this in my [Debugger front end](https://github.com/rocky/emacs-dbgr).
+
+Here is an example found in the [examples 
directory](https://github.com/rocky/emacs-test-simple/tree/master/test).
+
+In file `gcd.el`:
+
+    (defun gcd(a b)
+      "Greatest Common Divisor of A and B"
+      ;; Make a < b
+      (if (> a b)
+          (let ((c a))
+       (setq a b)
+       (setq b c)))
+      (cond
+       ((< a 0) nil)
+       ((or (= 0 (- b a)) (= a 1)) a)
+       (t (gcd (- b a) a))
+       )
+    )
+
+
+In file `test-gcd.el` in the same directory:
+
+    (require 'test-simple)
+    (test-simple-start) ;; Zero counters and start the stop watch.
+
+    ;; Use (load-file) below because we want to always to read the source.
+    ;; Also, we don't want no stinking compiled source.
+    (assert-t (load-file "./gcd.el")
+         "Can't load gcd.el - are you in the right directory?" )
+
+    (note "degenerate cases")
+
+    (assert-nil (gcd 5 -1) "using positive numbers")
+    (assert-nil (gcd -4 1) "using positive numbers, switched order")
+    (assert-raises error (gcd "a" 32)
+              "Passing a string value should raise an error")
+
+    (note "GCD computations")
+    (assert-equal 1 (gcd 3 5) "gcd(3,5)")
+    (assert-equal 8 (gcd 8 32) "gcd(8,32)")
+
+    (end-tests) ;; Stop the clock and print a summary
+
+Edit (with Emacs of course) `test-gcd.el` and run `M-x eval-current-buffer`
+
+You should see in buffer `*test-simple*`:
+
+    test-gcd.el
+    ......
+    0 failures in 6 assertions (0.002646 seconds)
+
+Now let's try from a command line:
+
+    $ emacs --batch --no-site-file --no-splash --load test-gcd.el
+    Loading /src/external-vcs/emacs-test-simple/example/gcd.el (source)...
+    *scratch*
+    ......
+    0 failures in 6 assertions (0.000723 seconds)
+
+*Author:*  Rocky Bernstein <address@hidden> <br>
+[![endorse](https://api.coderwall.com/rocky/endorsecount.png)](https://coderwall.com/rocky)
diff --git a/packages/test-simple/THANKS b/packages/test-simple/THANKS
new file mode 100644
index 0000000..4dae07d
--- /dev/null
+++ b/packages/test-simple/THANKS
@@ -0,0 +1 @@
+Lars Andersen (expez) - Getting this packaged and put on to Melpa.
diff --git a/packages/test-simple/autogen.sh b/packages/test-simple/autogen.sh
new file mode 100755
index 0000000..5f00302
--- /dev/null
+++ b/packages/test-simple/autogen.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+cp README.md README
+autoreconf -vi && \
+autoconf && {
+  echo "Running configure with --enable-maintainer-mode $@"
+  ./configure --enable-maintainer-mode $@
+}
diff --git a/packages/test-simple/common.mk b/packages/test-simple/common.mk
new file mode 100644
index 0000000..26b6325
--- /dev/null
+++ b/packages/test-simple/common.mk
@@ -0,0 +1,5 @@
+short:
+       $(MAKE) 2>&1 >/dev/null | ruby $(top_srcdir)/make-check-filter.rb
+
+%.short:
+       $(MAKE) $(@:.short=) 2>&1 >/dev/null
diff --git a/packages/test-simple/compute-lispdir.sh 
b/packages/test-simple/compute-lispdir.sh
new file mode 100755
index 0000000..dba43c9
--- /dev/null
+++ b/packages/test-simple/compute-lispdir.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Figures out a reasonable --prefix
+typeset -i rc=0
+typeset -i DEBUG=${DEBUG:-0}
+EMACS_PROG=${EMACS_PROG:-emacs}
+list=$($EMACS_PROG --batch --no-splash --eval '(message (substring (format 
"%s" load-path) 1 -1))' 2>&1)
+rc=$?
+if (( rc != 0 )) ; then
+    echo  >&2 "Something went running $EMACS_PROG"
+    exit $rc
+$cmd
+fi
+for dir in $list ; do
+    if [[ -d $dir ]] ; then
+       case $dir in
+           */emacs/site-lisp)
+               ((DEBUG)) && echo "site lisp: $dir"
+               echo "$dir"
+               exit 0
+               ;;
+       esac
+    fi
+done
+for dir in $list ; do
+    if [[ -d $dir ]] ; then
+       case $dir in
+           */emacs/2[34]\.[0-9]/site-lisp)
+               ((DEBUG)) && echo "versioned site lisp: $dir"
+               echo "$dir"
+               exit 0
+               ;;
+       esac
+    fi
+done
+for dir in $list ; do
+    if [[ -d $dir ]] ; then
+       case $dir in
+           */emacs/2[34]\.[0-9]/site-lisp)
+               ((DEBUG)) && echo "versioned site lisp: $dir"
+               echo "$dir"
+               exit 0
+               ;;
+       esac
+    fi
+done
+exit 0
diff --git a/packages/test-simple/configure.ac 
b/packages/test-simple/configure.ac
new file mode 100644
index 0000000..ae0cbee
--- /dev/null
+++ b/packages/test-simple/configure.ac
@@ -0,0 +1,44 @@
+dnl FIXME: pick up from test-simple.el
+AC_INIT(emacs-test-simple, 1.0,)
+AC_CONFIG_SRCDIR(test-simple.el)
+AM_INIT_AUTOMAKE([foreign])
+AM_MAINTAINER_MODE
+
+AC_PATH_PROG([EMACS], [emacs], [emacs])
+AC_MSG_NOTICE("Checking emacs version and prerequiste packages")
+$EMACS -batch -q -no-site-file -eval \
+  '(if (<= emacs-major-version 22)
+       (progn
+         (error "You need GNU Emacs 23 or better.")
+         (kill-emacs 1)
+       )
+   )'
+if test $? -ne 0 ; then
+    AC_MSG_ERROR([Can't continue until above error is corrected.])
+fi
+
+##################################################################
+# See if --with-lispdir was set. If not, set it to a reasonable default
+# based on where bash thinks bashdb is supposed to be installed.
+##################################################################
+
+AM_MISSING_PROG(GIT2CL, git2cl, $missing_dir)
+
+# Check whether --with-lispdir was given.
+if test "${with_lispdir+set}" = set -o "${prefix+set}" = set; then :
+else
+  my_lispdir=$(EMACS_PROG=$EMACS $SH_PROG $(dirname $0)/compute-lispdir.sh)
+  if test "${my_lispdir+set}" = set; then :
+    with_lispdir=$my_lispdir
+    echo "'compute-lispdir.sh' lispdir install directory override: 
'$with_lispdir'"
+  fi
+fi
+
+##
+## Find out where to install the debugger emacs lisp files
+##
+AM_PATH_LISPDIR
+AM_CONDITIONAL(INSTALL_EMACS_LISP, test "x$lispdir" != "x")
+
+AC_CONFIG_FILES([Makefile test/Makefile])
+AC_OUTPUT
diff --git a/packages/test-simple/copyright_exceptions 
b/packages/test-simple/copyright_exceptions
new file mode 100644
index 0000000..e69de29
diff --git a/packages/test-simple/elisp-comp b/packages/test-simple/elisp-comp
new file mode 100755
index 0000000..ecc6b15
--- /dev/null
+++ b/packages/test-simple/elisp-comp
@@ -0,0 +1,94 @@
+#!/bin/sh
+# Copyright (C) 1995, 2000, 2003, 2004, 2005, 2009, 2010 Free Software
+# Foundation, Inc.
+
+scriptversion=2010-02-06.18; # UTC
+
+# Franc,ois Pinard <address@hidden>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <address@hidden> or send patches to
+# <address@hidden>.
+
+case $1 in
+  '')
+     echo "$0: No files.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: elisp-comp [--help] [--version] FILES...
+
+This script byte-compiles all `.el' files listed as FILES using GNU
+Emacs, and put the resulting `.elc' files into the current directory,
+so disregarding the original directories used in `.el' arguments.
+
+This script manages in such a way that all Emacs LISP files to
+be compiled are made visible between themselves, in the event
+they require or load-library one another.
+
+Report bugs to <address@hidden>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "elisp-comp $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test -z "$EMACS" || test "$EMACS" = "t"; then
+  # Value of "t" means we are running in a shell under Emacs.
+  # Just assume Emacs is called "emacs".
+  EMACS=emacs
+fi
+
+tempdir=elc.$$
+
+# Cleanup the temporary directory on exit.
+trap 'ret=$?; rm -rf "$tempdir" && exit $ret' 0
+do_exit='(exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+
+mkdir $tempdir
+cp "$@" $tempdir
+
+(
+  cd $tempdir
+  echo "(setq load-path (cons nil load-path))" > script
+  $EMACS -batch -q -l script -f batch-byte-compile *.el || exit $?
+  mv *.elc ..
+) || exit $?
+
+(exit 0); exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/packages/test-simple/example/gcd.el 
b/packages/test-simple/example/gcd.el
new file mode 100644
index 0000000..ed587be
--- /dev/null
+++ b/packages/test-simple/example/gcd.el
@@ -0,0 +1,34 @@
+;;; test-simple.el --- Simple Unit Test Framework for Emacs Lisp
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+;; URL: http://github.com/rocky/emacs-test-simple
+;; Keywords: unit-test
+;; Version: 1.0
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+(defun gcd(a b)
+  "Greatest Common Divisor of A and B"
+  ;; Make a < b
+  (if (> a b)
+      (let ((c a))
+       (setq a b)
+       (setq b c)))
+  (cond
+   ((< a 0) nil)
+   ((or (= 0 (- b a)) (= a 1)) a)
+   (t (gcd (- b a) a))
+   )
+)
diff --git a/packages/test-simple/example/test-gcd.el 
b/packages/test-simple/example/test-gcd.el
new file mode 100644
index 0000000..8ffdce8
--- /dev/null
+++ b/packages/test-simple/example/test-gcd.el
@@ -0,0 +1,41 @@
+;;; test-simple.el --- Simple Unit Test Framework for Emacs Lisp
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+;; URL: http://github.com/rocky/emacs-test-simple
+;; Keywords: unit-test
+;; Version: 1.0
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+(require 'test-simple)
+
+(test-simple-start)
+
+(assert-t (load-file "./gcd.el")
+         "Can't load gcd.el - are you in the right directory?" )
+
+(note "degenereate cases")
+
+(assert-nil (gcd 5 -1) "using positive numbers")
+(assert-nil (gcd -4 1) "using positive numbers, switched order")
+
+(note "GCD computations")
+(assert-equal 1 (gcd 3 5) "gcd(3,5)")
+(assert-equal 8 (gcd 8 32) "gcd(8,32)")
+
+(assert-raises error (gcd "a" 32)
+              "Passing a string value should raise an error")
+
+(end-tests)
diff --git a/packages/test-simple/install-from-git.sh 
b/packages/test-simple/install-from-git.sh
new file mode 100755
index 0000000..6034983
--- /dev/null
+++ b/packages/test-simple/install-from-git.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# This installs all emcs-test-simple and its prerequisites. If you are lucky
+# you can just run this:
+#
+#   bash ./install-from-git.sh
+#
+# However we do provide for some customization...
+#
+# 1. GIT PROTOCOL
+# ===============
+#
+# If your "git clone" can't handle the "http" protocol, you might be
+# able to use the "git" protocol. To do this set the GIT_PROTOCOL
+# variable like this:
+#
+#     GIT_PROTOCOL=git sh ./install-from-git.sh
+#
+# 2. configure options (e.g --prefix)
+# ====================================
+
+# If you want to customize configuration parameters, for example,
+# choose where to install, you can pass configure options to this
+# script. For example:# can pass configure options.
+#
+#     sh ./install-from-git.sh --prefix=/tmp
+#
+# 3. TO "sudo" or not to "sudo"?
+# ==============================
+# If you are running as root on a *Nix-like box, then there's no problem.
+#
+# If you are not running as root, "sudo" might be invoked to install
+# code.  On systems that don't have a "sudo" command but need
+# filesystem permission, then you get by with setting SUDO_CMD to "su root-c"
+# For example:
+#
+#    SUDO_CMD='su root -c' sh ./install-from-git.sh
+#
+# If you have sufficient filesystem permission (which is often the
+# case on Windows or cygwin) then you might not need or want sudo. So
+# here, set SUDO_CMD to a blank:
+#
+#      SUDO_CMD=' ' sh ./install-from-git.sh
+#
+#
+# To finish here is an invocation using all 3 above options:
+#   GIT_PROTOCOL='git' SUDO_CMD=' ' sh ./install-from-git.sh --prefix=/tmp
+
+GIT_PROTOCOL=${GIT_PROTOCOL:-http}
+
+run_cmd() {
+    echo "--- Running command: $@"
+    $@
+    rc=$?
+    echo "--- $@ exit status is $?"
+    return $rc
+}
+
+if (( $(id -u) != 0)) ; then
+    if [[ -z "$SUDO_CMD" ]] ; then
+       need_sudo='sudo'
+       if which $need_sudo >/dev/null 2>&1 ; then
+           try_cmd=''
+       else
+           need_sudo='su root -c'
+           try_cmd='su'
+       fi
+    else
+       need_sudo="$SUDO_CMD"
+    fi
+else
+    need_sudo=''
+    try_cmd=''
+fi
+
+for program in git make $try_cmd ; do
+    if ! which $program >/dev/null 2>&1 ; then
+       echo "Cant find program $program in $PATH"
+       exit 1
+    fi
+done
+
+for pkg in emacs-test-simple ; do
+    echo '******************************************'
+    echo Trying to install ${pkg}...
+    echo '******************************************'
+    run_cmd git clone ${GIT_PROTOCOL}://github.com/rocky/${pkg}.git
+    (cd $pkg && \
+        run_cmd $SHELL ./autogen.sh && \
+       run_cmd ./configure $@ && \
+       run_cmd make && \
+       run_cmd make check && \
+        run_cmd $need_sudo make install
+    )
+done
diff --git a/packages/test-simple/make-check-filter.rb 
b/packages/test-simple/make-check-filter.rb
new file mode 100755
index 0000000..daee7c9
--- /dev/null
+++ b/packages/test-simple/make-check-filter.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+# Use this to cut out the crud from make check.
+# Use like this:
+#   make check 2>&1  | ruby ../make-check-filter.rb
+# See Makefile.am
+pats = ["^(?:Loading",
+        'make\[',
+        "Making check in",
+        '\(cd \.\.',
+        "make -C",
+        "Test-Unit",
+        "Fontifying",
+        '\s*$'
+       ].join('|') + ')'
+# puts pats
+skip_re = /#{pats}/
+
+while gets()
+  next if $_ =~ skip_re
+  puts $_
+end
diff --git a/packages/test-simple/test-simple.el 
b/packages/test-simple/test-simple.el
new file mode 100644
index 0000000..351a60b
--- /dev/null
+++ b/packages/test-simple/test-simple.el
@@ -0,0 +1,334 @@
+;;; test-simple.el --- Simple Unit Test Framework for Emacs Lisp
+;; Rewritten from Phil Hagelberg's behave.el by rocky
+
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; Author: Rocky Bernstein <address@hidden>
+;; URL: http://github.com/rocky/emacs-test-simple
+;; Keywords: unit-test
+;; Version: 1.1
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; test-simple.el is:
+;;
+;; * Simple. No need for
+;;   - context macros,
+;;   - enclosing specifications,
+;;   - required test tags.
+;;
+;;   But if you want, you still can enclose tests in a local scope,
+;;   add customized assert failure messages, or add summary messages
+;;   before a group of tests.
+;;
+;; * Accomodates both interactive and non-interactive use.
+;;    - For interactive use, one can use `eval-last-sexp', `eval-region',
+;;      and `eval-buffer'. One can `edebug' the code.
+;;    -  For non-interactive use, run:
+;;        emacs --batch --no-site-file --no-splash --load <test-lisp-code.el>
+;;
+;; Here is an example using gcd.el found in the examples directory.
+;;
+;;   (require 'test-simple)
+;;   (test-simple-start) ;; Zero counters and start the stop watch.
+;;
+;;   ;; Use (load-file) below because we want to always to read the source.
+;;   ;; Also, we don't want no stinking compiled source.
+;;   (assert-t (load-file "./gcd.el")
+;;           "Can't load gcd.el - are you in the right directory?" )
+;;
+;;   (note "degenerate cases")
+;;
+;;   (assert-nil (gcd 5 -1) "using positive numbers")
+;;   (assert-nil (gcd -4 1) "using positive numbers, switched order")
+;;   (assert-raises error (gcd "a" 32)
+;;                  "Passing a string value should raise an error")
+;;
+;;   (note "GCD computations")
+;;   (assert-equal 1 (gcd 3 5) "gcd(3,5)")
+;;   (assert-equal 8 (gcd 8 32) "gcd(8,32)")
+;;   (end-tests) ;; Stop the clock and print a summary
+;;
+;; Edit (with Emacs of course) test-gcd.el and run M-x eval-current-buffer
+;;
+;; You should see in buffer *test-simple*:
+;;
+;;    test-gcd.el
+;;    ......
+;;    0 failures in 6 assertions (0.002646 seconds)
+;;
+;; Now let us try from a command line:
+;;
+;;    $ emacs --batch --no-site-file --no-splash --load test-gcd.el
+;;    Loading /src/external-vcs/emacs-test-simple/example/gcd.el (source)...
+;;    *scratch*
+;;    ......
+;;    0 failures in 6 assertions (0.000723 seconds)
+
+;;; To do:
+
+;; Main issues: more expect predicates
+
+(require 'time-date)
+
+;;; Code:
+
+(eval-when-compile
+  (byte-compile-disable-warning 'cl-functions)
+  ;; Somehow disabling cl-functions causes the erroneous message:
+  ;;   Warning: the function `reduce' might not be defined at runtime.
+  ;; FIXME: isolate, fix and/or report back to Emacs developers a bug
+  ;; (byte-compile-disable-warning 'unresolved)
+  (require 'cl)
+  )
+(require 'cl)
+
+(defvar test-simple-debug-on-error nil
+  "If non-nil raise an error on the first failure.")
+
+(defvar test-simple-verbosity 0
+  "The greater the number the more verbose output.")
+
+(defstruct test-info
+  description                 ;; description of last group of tests
+  (assert-count 0)            ;; total number of assertions run
+  (failure-count 0)           ;; total number of failures seen
+  (start-time (current-time)) ;; Time run started
+  )
+
+(defvar test-simple-info (make-test-info)
+  "Variable to store testing information for a buffer.")
+
+(defun note (description &optional test-info)
+  "Adds a name to a group of tests."
+  (if (getenv "USE_TAP")
+    (test-simple-msg (format "# %s" description) 't)
+    (if (> test-simple-verbosity 0)
+       (test-simple-msg (concat "\n" description) 't))
+    (unless test-info
+      (setq test-info test-simple-info))
+    (setf (test-info-description test-info) description)
+    ))
+
+;;;###autoload
+(defmacro test-simple-start (&optional test-start-msg)
+  `(test-simple-clear nil
+                     (or ,test-start-msg
+                         (if (and (functionp '__FILE__) (__FILE__))
+                             (file-name-nondirectory (__FILE__))
+                           (buffer-name)))
+                     ))
+
+;;;###autoload
+(defun test-simple-clear (&optional test-info test-start-msg)
+  "Initializes and resets everything to run tests. You should run
+this before running any assertions. Running more than once clears
+out information from the previous run."
+
+  (interactive)
+
+  (unless test-info
+    (unless test-simple-info
+      (make-variable-buffer-local (defvar test-simple-info (make-test-info))))
+    (setq test-info test-simple-info))
+
+  (setf (test-info-description test-info) "none set")
+  (setf (test-info-start-time test-info) (current-time))
+  (setf (test-info-assert-count test-info) 0)
+  (setf (test-info-failure-count test-info) 0)
+
+  (with-current-buffer (get-buffer-create "*test-simple*")
+    (let ((old-read-only inhibit-read-only))
+      (setq inhibit-read-only 't)
+      (delete-region (point-min) (point-max))
+      (if test-start-msg (insert (format "%s\n" test-start-msg)))
+      (setq inhibit-read-only old-read-only)))
+  (unless noninteractive
+    (message "Test-Simple: test information cleared")))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Assertion tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defmacro assert-raises (error-condition body &optional fail-message test-info)
+  (let ((fail-message (or fail-message
+                         (format "assert-raises did not get expected %s"
+                                 error-condition))))
+    (list 'condition-case nil
+         (list 'progn body
+               (list 'assert-t nil fail-message test-info))
+         (list error-condition '(assert-t t)))))
+
+(defun assert-op (op expected actual &optional fail-message test-info)
+  "expectation is that ACTUAL should be equal to EXPECTED."
+  (unless test-info (setq test-info test-simple-info))
+  (incf (test-info-assert-count test-info))
+  (if (not (funcall op actual expected))
+      (let* ((fail-message
+             (if fail-message
+                 (format "Message: %s" fail-message)
+               ""))
+            (expect-message
+             (format "\n  Expected: %s\n  Got: %s" expected actual))
+            (test-info-mess
+             (if (boundp 'test-info)
+                 (test-info-description test-info)
+               "unset")))
+       (add-failure (format "assert-%s" op) test-info-mess
+                    (concat fail-message expect-message)))
+    (ok-msg fail-message)))
+
+(defun assert-equal (expected actual &optional fail-message test-info)
+  "expectation is that ACTUAL should be equal to EXPECTED."
+  (assert-op 'equal expected actual fail-message test-info))
+
+(defun assert-eq (expected actual &optional fail-message test-info)
+  "expectation is that ACTUAL should be EQ to EXPECTED."
+  (assert-op 'eql expected actual fail-message test-info))
+
+(defun assert-eql (expected actual &optional fail-message test-info)
+  "expectation is that ACTUAL should be EQL to EXPECTED."
+  (assert-op 'eql expected actual fail-message test-info))
+
+(defun assert-matches (expected-regexp actual &optional fail-message test-info)
+  "expectation is that ACTUAL should match EXPECTED-REGEXP."
+  (unless test-info (setq test-info test-simple-info))
+  (incf (test-info-assert-count test-info))
+  (if (not (string-match expected-regexp actual))
+      (let* ((fail-message
+             (if fail-message
+                 (format "\n\tMessage: %s" fail-message)
+               ""))
+            (expect-message
+             (format "\tExpected Regexp: %s\n\tGot:      %s"
+                     expected-regexp actual))
+            (test-info-mess
+             (if (boundp 'test-info)
+                 (test-info-description test-info)
+               "unset")))
+       (add-failure "assert-equal" test-info-mess
+                    (concat expect-message fail-message)))
+    (progn (test-simple-msg ".") t)))
+
+(defun assert-t (actual &optional fail-message test-info)
+  "expectation is that ACTUAL is not nil."
+  (assert-nil (not actual) fail-message test-info "assert-t"))
+
+(defun assert-nil (actual &optional fail-message test-info assert-type)
+  "expectation is that ACTUAL is nil. FAIL-MESSAGE is an optional
+additional message to be displayed. Since several assertions
+funnel down to this one, ASSERT-TYPE is an optional type."
+  (unless test-info (setq test-info test-simple-info))
+  (incf (test-info-assert-count test-info))
+  (if actual
+      (let* ((fail-message
+             (if fail-message
+                 (format "\n\tMessage: %s" fail-message)
+               ""))
+            (test-info-mess
+             (if (boundp 'test-simple-info)
+                 (test-info-description test-simple-info)
+               "unset")))
+       (add-failure "assert-nil" test-info-mess fail-message test-info))
+    (ok-msg fail-message)))
+
+(defun add-failure(type test-info-msg fail-msg &optional test-info)
+  (unless test-info (setq test-info test-simple-info))
+  (incf (test-info-failure-count test-info))
+  (let ((failure-msg
+        (format "\nDescription: %s, type %s\n%s" test-info-msg type fail-msg))
+       (old-read-only inhibit-read-only)
+       )
+    (save-excursion
+      (not-ok-msg fail-msg)
+      (test-simple-msg failure-msg 't)
+      (unless noninteractive
+       (if test-simple-debug-on-error
+           (signal 'test-simple-assert-failed failure-msg)
+         ;;(message failure-msg)
+         )))))
+
+(defun end-tests (&optional test-info)
+  "Give a tally of the tests run"
+  (interactive)
+  (unless test-info (setq test-info test-simple-info))
+  (test-simple-describe-failures test-info)
+  (if noninteractive
+      (progn
+       (switch-to-buffer "*test-simple*")
+       (message "%s" (buffer-substring (point-min) (point-max)))
+       )
+    (switch-to-buffer-other-window "*test-simple*")
+    ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Reporting
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun test-simple-msg(msg &optional newline)
+  (switch-to-buffer "*test-simple*")
+  (let ((old-read-only inhibit-read-only))
+    (setq inhibit-read-only 't)
+    (insert msg)
+    (if newline (insert "\n"))
+    (setq inhibit-read-only old-read-only)
+    (switch-to-buffer nil)
+  ))
+
+(defun ok-msg(fail-message &optional test-info)
+  (unless test-info (setq test-info test-simple-info))
+  (let ((msg (if (getenv "USE_TAP")
+                (if (equal fail-message "")
+                    (format "ok %d\n" (test-info-assert-count test-info))
+                  (format "ok %d - %s\n"
+                          (test-info-assert-count test-info)
+                          fail-message))
+              ".")))
+      (test-simple-msg msg))
+  't)
+
+(defun not-ok-msg(fail-message &optional test-info)
+  (unless test-info (setq test-info test-simple-info))
+  (let ((msg (if (getenv "USE_TAP")
+                (format "not ok %d\n" (test-info-assert-count test-info))
+              "F")))
+      (test-simple-msg msg))
+  nil)
+
+(defun test-simple-summary-line(info)
+  (let*
+      ((failures (test-info-failure-count info))
+       (asserts (test-info-assert-count info))
+       (problems (concat (number-to-string failures) " failure"
+                        (unless (= 1 failures) "s")))
+       (tests (concat (number-to-string asserts) " assertion"
+                     (unless (= 1 asserts) "s")))
+       (elapsed-time (time-since (test-info-start-time info)))
+       )
+    (if (getenv "USE_TAP")
+       (format "1..%d" asserts)
+      (format "\n%s in %s (%g seconds)" problems tests
+             (float-time elapsed-time))
+  )))
+
+(defun test-simple-describe-failures(&optional test-info)
+  (unless test-info (setq test-info test-simple-info))
+  (goto-char (point-max))
+  (test-simple-msg (test-simple-summary-line test-info)))
+
+(provide 'test-simple)
+;;; test-simple.el ends here
diff --git a/packages/test-simple/test/.gitignore 
b/packages/test-simple/test/.gitignore
new file mode 100644
index 0000000..b336cc7
--- /dev/null
+++ b/packages/test-simple/test/.gitignore
@@ -0,0 +1,2 @@
+/Makefile
+/Makefile.in
diff --git a/packages/test-simple/test/Makefile.am 
b/packages/test-simple/test/Makefile.am
new file mode 100644
index 0000000..cd86850
--- /dev/null
+++ b/packages/test-simple/test/Makefile.am
@@ -0,0 +1,29 @@
+include $(top_srcdir)/common.mk
+
+PHONY=check test all
+EXTRA_DIST=gcd.py gcd.rb
+
+all: 
+
+#: same thing as "check"
+test: check
+
+test_files := $(wildcard test-*.el)
+
+CHECK_FILES = $(notdir $(test_files:.el=.run))
+
+#: Run all tests
+check: $(CHECK_FILES)
+
+#: Run all tests with minimum verbosity
+check-short:
+       $(MAKE) check 2>&1  | ruby ../make-check-filter.rb
+
+test-%.run:
+       (cd $(top_srcdir)/test && $(EMACS) --batch --no-site-file --no-splash 
--load $(@:.run=.el))
+
+# Whatever it is you want to do, it should be forwarded to the 
+# to top-level directories
+%: 
+       $(MAKE) -C .. $@
+
diff --git a/packages/test-simple/test/test-basic.el 
b/packages/test-simple/test/test-basic.el
new file mode 100644
index 0000000..f14a385
--- /dev/null
+++ b/packages/test-simple/test/test-basic.el
@@ -0,0 +1,29 @@
+;;; test-simple.el --- Simple Unit Test Framework for Emacs Lisp
+;; Copyright (C) 2015 Free Software Foundation, Inc
+;; Author: Rocky Bernstein <address@hidden>
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+(require 'cl)
+(load-file "../test-simple.el")
+(test-simple-start "test-simple.el")
+
+(note "basic-tests")
+(assert-t (memq 'test-simple features) "'test-simple provided")
+
+(assert-nil nil "assert-nil failure test")
+(assert-nil nil "Knights if ni")
+(assert-equal 5 (+ 1 4) "assert-equal")
+(assert-raises error (error "you should not see this") "assert-raises")
+
+(end-tests)
diff --git a/packages/test-simple/test/test-fns.el 
b/packages/test-simple/test/test-fns.el
new file mode 100644
index 0000000..bd340f0
--- /dev/null
+++ b/packages/test-simple/test/test-fns.el
@@ -0,0 +1,39 @@
+;;; test-simple.el --- Simple Unit Test Framework for Emacs Lisp
+;; Copyright (C) 2015 Free Software Foundation, Inc
+;; Author: Rocky Bernstein <address@hidden>
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+(require 'cl)
+(load-file "../test-simple.el")
+(test-simple-clear)
+
+(setq test-info (make-test-info))
+(test-simple-clear test-info)
+
+(note "Initializing test information")
+(assert-equal 0 (test-info-assert-count test-info) "Count zeroed")
+(assert-equal 0 (test-info-failure-count test-info) "Failure zeroed")
+
+(note "Summary information")
+(assert-matches "0 failures in 0 assertions" (test-simple-summary-line 
test-info)
+               "initial summary")
+(incf (test-info-assert-count test-info))
+(incf (test-info-failure-count test-info))
+(assert-matches "1 failure in 1 assertion" (test-simple-summary-line test-info)
+               "handling singular correctly")
+(incf (test-info-assert-count test-info))
+(assert-matches "1 failure in 2 assertions" (test-simple-summary-line 
test-info)
+               "back to plural for two assertions")
+
+(end-tests)
diff --git a/packages/test-simple/test/test-no-clear.el 
b/packages/test-simple/test/test-no-clear.el
new file mode 100644
index 0000000..45822bd
--- /dev/null
+++ b/packages/test-simple/test/test-no-clear.el
@@ -0,0 +1,27 @@
+;;; test-simple.el --- Simple Unit Test Framework for Emacs Lisp
+;; Copyright (C) 2015 Free Software Foundation, Inc
+;; Author: Rocky Bernstein <address@hidden>
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see
+;; <http://www.gnu.org/licenses/>.
+(require 'cl)
+(load-file "../test-simple.el")
+;; We don't do this or test-simple-start
+;; (test-simple-clear)
+
+(note "no-test-start")
+(assert-t (memq 'test-simple features) "'test-simple provided")
+
+(assert-nil nil)
+
+(end-tests)
diff --git a/packages/timerfunctions/timerfunctions.el 
b/packages/timerfunctions/timerfunctions.el
new file mode 100644
index 0000000..f8b1a57
--- /dev/null
+++ b/packages/timerfunctions/timerfunctions.el
@@ -0,0 +1,458 @@
+;;; timerfunctions.el --- Enhanced versions of some timer.el functions
+
+;; Copyright (C) 2000-2002, 2015  Free Software Foundation, Inc.
+
+;; Time-stamp: <2015-03-02 12:23:21 deego>
+;; Emacs Lisp Archive entry
+;; Filename: timerfunctions.el
+;; Author: Dave Goel <address@hidden>
+;; Version: 1.4.2
+;; Created: 2000/11/20
+;; Author's homepage: http://gnufans.net/~deego
+
+;; This file is NOT (yet) part of GNU Emacs.
+
+;; This is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; For latest version:
+;; Gives me a "Not found"!
+;;(defconst timerfunctions-home-page
+;;  "http://gnufans.net/~deego/emacspub/timerfunctions";)
+
+;;; Commentary:
+
+;; See also: midnight.el (part of Emacs), timer.el
+
+;;; Code:
+
+(defvar timerfunctions-version "1.4.2")
+
+
+;;; New features:
+(defconst timerfunctions-new-features
+  "New since last posting: Changed the syntax of `tf-with-timeout' and
+provided a `tf-with-timeout-check'.")
+
+(defun timerfunctions-new-features ()
+  "Provides electric help from variable `timerfunctions-new-features'."
+  (interactive)
+  (with-electric-help
+   (lambda () (insert timerfunctions-new-features) nil) "*doc*"))
+
+
+(defconst timerfunctions-introduction
+  "timerfunctions.el contains some 'enhanced' versions of a few timer.el
+functions.  It is also used by vel.el, idledo.el etc.
+
+ Suppose you want Emacs to run an action every REDOSECS for
+ _as_long_as Emacs remains idle.  `tf-run-with-idle-timer' allows that.
+
+ `tf-with-timeout' is a generalized with-timeout where you can inhibit
+ breaks within parts of the body that you want.
+
+ QUICKSTART:
+ Place this file somewhere in your load-path, and add the
+ following to your ~/.emacs: (load \"timerfunctions.el\")
+"
+)
+
+;;;###autoload
+(defun timerfunctions-introduction ()
+  "Provides electric help from variable `timerfunctions-introduction'."
+  (interactive)
+  (with-electric-help
+   '(lambda () (insert timerfunctions-introduction) nil) "*doc*"))
+
+;;; Real Code:
+
+
+;;;###autoload
+(defun tf-time-difference (timeplus timesub)
+  "Return the time in seconds elaspsed from TIMESUB to TIMEPLUS.
+
+Conceptually:  \(- TIMEPLUS TIMESUB \)."
+  (+ (* (expt 2 16) (- (car timeplus) (car timesub)))
+     (- (cadr timeplus) (cadr timesub)))
+)
+
+
+;;;###autoload
+(defun tf-run-with-idle-timer  (secs repeat redosecs redorepeat includeruntime 
function &rest args)
+  "Similar to `run-with-idle-timer', except that provides more options.
+
+Args are SECS, REPEAT, REDOSECS, REDOREPEAT, INCLUDERUNTIME,
+FUNCTION and &rest ARGS.
+
+Similar to `run-with-idle-timer', but provides more options.
+Suppose you want Emacs to run an action every REDOSECS for as
+long as Emacs remains idle.  Emacs' `run-with-idle-timer' will
+perform the action exactly once every time Emacs goes idle.  This
+funciton, on the other hand, will allow
+you to keep performing an action as long as Emacs remains idle.
+
+SECS is the number of seconds to wait once Emacs has first gone
+idle. It can really be any expression whose at runtime yields a
+number.  Note that the way `run-with-idle-timer' is defined, SECS will
+unfortunately be evalled immediately after you call this function, but
+redosecs will be *every* time Emacs *remains* idle..yay..
+
+If REDOREPEAT is non-nil, the action is repeated as long Emacs remains
+idle.  REDOSECS is the number of additional seconds (after the action
+has been done) to wait if Emacs remains idle before performing the
+action again.  Again, redosecs does not have to be a number, it can be
+any expression whose eval yields to a number...
+
+If INCLUDERUNTIME is non-nil, REDOSECS is the number of
+additional seconds to wait after the action has been invoked (not
+finished).
+
+If REPEAT is nonnil, the entire cycle is repeated every time Emacs
+next goes idle.. (as in the default `run-with-idle-timer'."
+  (apply 'run-with-idle-timer
+        (eval secs) repeat 'tf-run-while-idle
+        redosecs redorepeat includeruntime
+        function args)
+  )
+
+
+(defun tf-run-while-idle (redosecs redorepeat includeruntime function &rest 
args)
+  "A simplified version of `tf-run-with-idle-timer'.
+
+Runs FUNCTION with ARGS and optionally repeats if emacs remains idle.
+Probably is of no use unless used in programs.
+ If REDOREPEAT is non-nil, the function is repeated periodically every
+REDOSECS as long as emacs remains idle. By default, emacs waits
+REDOSECS *after* the function is done executing to repeat.  If you want
+the execution-time to count towards REDOSECS, make INCLUDERUNTIME
+non-nil.
+SECS and REDOSECS can be any expressions that eval at runtime to
+numbers. In particular, of course, they can simply be numbers."
+  (if (not includeruntime)
+      (progn
+       (apply function args)
+       (if redorepeat
+           (while (sit-for (eval redosecs))
+             (apply function args))))
+    (progn
+      (let ((before-time (current-time)))
+       (apply function args)
+       (if redorepeat
+           (while (sit-for (-
+                            (eval redosecs)
+                            (tf-time-difference (current-time)
+                                                before-time)))
+             (setq before-time (current-time))
+             (apply function args))))))
+  )
+
+
+;;;====================================================
+;;;TESTS FOLLOW
+(defun tf-test-display-time-internal ()
+  "A test function."
+  (interactive)
+  (let ((thisbuffer (buffer-name)))
+    (switch-to-buffer-other-window "*scratch*")
+    (goto-char (point-max))
+    (insert (concat "\n" (format "%S" (cadr (current-time)))))
+    (recenter)
+    (switch-to-buffer-other-window thisbuffer))
+)
+
+
+(defun tf-test-idle-timer ()
+  "A test function.
+
+Run this and watch Play around with the options.  If you run it,
+you may have to exit your Emacs session to restore normal Emacs,
+unless you clean things up carefully!"
+
+  (interactive)
+  (tf-run-with-idle-timer
+  1 t 3 t nil 'tf-test-display-time-internal)
+)
+
+
+
+
+
+(defun tf-test-timeout ()
+  "Bad count should be zero."
+  (interactive)
+  (let ((inhi nil) (goodcount 0) (badcount 0) (ctr 0) (a 1) (b 2)
+       (mytag nil)
+       (myvar nil)
+       )
+    (loop
+     for ctr from 0 to 10 do
+     (message "ctr=%S" ctr)
+     (tf-with-timeout 'inhi 'mytah 'myvar
+      (0.3 nil)
+      (loop for i from 0 to 100000 do
+           (message "ctr=%S, i=%S" ctr i)
+           (setq inhi t)
+           (setq a (random 100))
+           (sleep-for 0.1)
+           (setq b a)
+           (setq inhi nil)
+           (sleep-for 0.02)
+           ))
+     (if (equal b a) (incf goodcount) (incf badcount)))
+    (message "Goodcount: %S; badcount: %S" goodcount badcount)))
+
+
+
+(defun tf-test-timeout-complex ()
+  "Should return a value of 20000 for a."
+
+  (interactive)
+  (let ((inhi t) (goodcount 0) (badcount 0) (ctr 0) (a 1) (b 2)
+       (mytag nil)
+       (myvar nil)
+       )
+    (setq a 0)
+    (message "ctr=%S" ctr)
+    (tf-with-timeout
+     'inhi 'mytag 'myvar
+     (0.1 nil)
+     (loop for i from 0 to 10000 do
+          (message "first loop. ctr=%S, i=%S, " ctr i)
+          (incf a))
+     (message "initial loop ends here.")
+     ;; no throw here because loop prohibited.
+     (tf-with-timeout-check 'inhi 'mytag 'myvar)
+     ;; this shouldn't help either
+     (sit-for 0.3)
+
+     (loop for i from 0 to 10000 do
+          (message "second loop.  i=%S" i)
+          (incf a))
+     (message "second loop ends here.")
+     (setq inhi nil)
+     ;; this should throw.
+     (tf-with-timeout-check 'inhi 'mytag 'myvar)
+     ;; this should NOT be needed.
+     ;;(sit-for 0.2)
+     ;; this loop should never take place.
+     (loop for i from 0 to 1000 do
+          (message "third loop, i=%S" i)
+          (incf a))
+     (message "third loop ends here."))
+    (message "%S" a)
+    a))
+
+
+
+(defvar tf-internal-var-recenter 1)
+
+(defun tf-test-internal-recenter-toggle ()
+  "A test function."
+  (interactive)
+  (recenter 1)
+  (setq tf-internal-var-recenter (- 0 tf-internal-var-recenter)))
+
+(defun tf-test-example-timer-recenter ()
+  "An example timer.
+Changes the screen display every 3 seconds, thus ensuring that you
+don't time out of ssh sessions."
+  (interactive)
+  (tf-run-with-idle-timer 3 t 3 t nil 'tf-test-internal-recenter-toggle))
+
+
+
+
+(defun tf-todo-wait-until-idle (&optional secs)
+  "This function is not functional yet.
+
+Waits until idle.  Arguments are SECS.
+Will help run processes in background.  This function will NOT create
+a timer.  Will simply use `sit-for'."
+  (if (null secs)
+      (setq secs 1))
+  (while (not (sit-for secs))
+    (sit-for 1))
+  (message "tf-todo-wait-until-idle DONE WAITING!")
+)
+
+
+;;;Tue Jan 23 17:38:44 2001
+;; FIXME: Use `with-demoted-errors' instead.
+(defmacro tf-ignore-errors (&rest body)
+ "Ignore errors in BODY, but loudly."
+ (let ((err (gensym)))
+   (list 'condition-case err (cons 'progn body)
+        (list 'error
+              (list 'message
+                    (list 'concat
+                          "IGNORED ERROR: "
+                          (list 'error-message-string err)))))
+   ))
+
+
+
+
+(defvar tf-with-timeout-repeat-sec 0.01
+  "Interval between checks for inhibitedness.
+
+If the initial timeout fails because of inhibitedness, we shall
+check every `tf-with-timeout-repeat-sec' seconds to see if we are
+uninhibited, yet.  This variable is customizable.")
+
+
+(defun tf-with-timeout-handler-internal (tag timedoutvar inhibitp)
+  "Internal function.
+Arguments are TAG, TIMEDOUTVAR, and INHIBITP."
+  (set timedoutvar t)
+  ;;(tf-with-timeout-check tag timedoutvar inhibitp)
+  ;; which is equivalent to:
+  (unless (eval inhibitp)
+    (tf-ignore-errors (throw tag 'timeout)))
+  )
+
+(defun tf-with-timeout-check (inhibitp tag timedoutvar)
+  "Internal function.
+Check whether timeout has actually reached.
+We need this step because this function might be called by the
+user as well.  Arguments are INHIBITP, TAG and TIMEDOUTVAR."
+  (when (eval timedoutvar)
+    (unless (eval inhibitp)
+      (tf-ignore-errors (throw tag 'timeout)))))
+
+
+
+(defvar tf-tag-tmpvar nil)
+
+(defmacro tf-catch (tag &rest body)
+  "Catch a TAG in BODY."
+  `(let
+       ;; unquote the tag here..
+       ((,(cadr tag) 'tf-catch))
+     (catch ,tag
+       ,@body)))
+
+(defmacro tf-throw (tag value)
+  "Throw a TAG with value VALUE."
+  `(when (eql (eval ,tag) 'tf-catch)
+     (throw ,tag value)))
+
+
+;;;###autoload
+(defmacro tf-with-timeout (inhibitp timertag timedoutvar tlist &rest body)
+  "Like `with-timeout' but with support for unbreakable code.
+
+Provides ability to inhibit timeout during parts of the body.
+Note that most of the time, you may not need this functionality
+at all unless you want to be very 'clean' about things---you
+could get by with the regular with-timeout and not using
+sit-for's in the body.  Or with the regular with-timeout and
+using unwind-protect.
+
+
+A judicious use of `unwind-protect' may seem to alleviate the
+need for this function. This function, however, provides
+additional flexibility in that the inhibitedness can be altered
+at run-time depending on various conditions.
+
+
+Run BODY, but if it doesn't finish in SECONDS seconds, give up.
+If we give up, we run the TIMEOUT-FORMS which are contained in TLIST
+and return the value of the last one.
+The call should look like:
+ (tf-with-timeout quoted-expr (SECONDS TIMEOUT-FORMS...) BODY...)
+
+The timeout is checked whenever Emacs waits for some kind of external
+event \(such as keyboard input, input from subprocesses, or a certain time);
+if the program loops without waiting in any way, the timeout will not
+be detected.  Furthermore:
+
+During the execution of the body, we SHALL NOT time out when INHIBITP
+evals to non-nil.  Thus, for example, you might initially setq a
+variable my-var as nil, supply inhibitp as 'my-var, and then you may
+setq my-var to t or nil within the body of tf-with-timeout to enable
+or disable timeout.  The best use of this functionality is to setq
+inhibitp to t when during parts of loops where you do not want the
+body broken within certain parts of the loop.  (Of course, if that
+part of the loop does not contain any sit-for's or read's then you
+don't have to worry about this in the first place..)
+
+
+Again, Do not forget to bind my-var to some value before attempting to use this
+tf-with-timeout :)
+
+Here's an example:
+
+
+ (let ((myinhibit t))
+  (tf-with-timeout 'myinhibit 'mytag 'mytimedoutvar
+                  (2 2)
+                  (setq a nil)
+                  (setq b nil)
+                  (sit-for 4)
+                  (setq a 4)
+                  (setq myinhibit nil)
+                  (sit-for 2)
+                  (setq b 5)
+                  ))
+
+
+The above example requests a timeout within 2 seconds.  However, the
+timeout can takes place only when myinhibit is set to nil,
+which becomes true after about 4 seconds.  Thus, after the execution of the
+body, a has the value 4, but b has the value nil.
+
+See `tf-test-timeout' for another example.
+
+Important Note: If the body of a loop tends to stay in a timeout
+inhibited region for most of the time, then make sure that the timeout
+enabled region atleast spans about 0.02 seconds.. thus, use (sleep-for
+0.02) if needed.. this is because we check every 0.01 seconds if an
+uninhibited timeout condition has been satisfied.
+
+But perhaps you do not want to include (sleep-for 0.02) because that
+wastes precious cpu time.  Simple, don't include it, just after a long
+inhibited body, you can include a timeout check within the body
+instead of (sleep-for 0.02):
+ (tf-with-timeout-check 'mytag 'mytimedoutvar 'myinhibitp)
+
+Moreover, if that is the main check you rely on, you it perhaps makes
+sense to increase the value of tf-with-timeout-repeat-sec, so that
+your cpu cycles are not wasted every 0.01 sec.  See the doc of that
+variable for more.
+
+TIMERTAG should be a quoted symbol, also we WILL set that symbol to t
+during the execution of these forms.
+
+TIMEDOUTVAR is the variable that times out."
+  (let ((seconds (car tlist))
+       (timeout-forms (cdr tlist)))
+    `(let (
+          ;;(with-timeout-tag (cons nil nil))
+          with-timeout-value with-timeout-timer)
+       (set ,timedoutvar nil)
+       (if (catch ,timertag
+            (progn
+              (setq with-timeout-timer
+                    (run-with-timer ,seconds tf-with-timeout-repeat-sec
+                                    'tf-with-timeout-handler-internal
+                                    ,timertag ,timedoutvar
+                                    ,inhibitp))
+              (setq with-timeout-value (progn ,@body))
+              nil))
+          (progn ,@timeout-forms)
+        (cancel-timer with-timeout-timer)
+        with-timeout-value))))
+
+
+(provide 'timerfunctions)
+;;; timerfunctions.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]