diff --git a/API.txt b/API.txt
index e0441d620515fd484f4583a03486a2296756005c..b698b79867e3876cce3f20a6e345100bd558c31b 100644
--- a/API.txt
+++ b/API.txt
@@ -3,6 +3,9 @@ Current API Version: 2.0.8
 Please note that the API version is an internal number and does not match release numbers. It is entirely possible that releases will not increase the API version number, and increasing this number too often would burden contrib module maintainers who need to keep up with API changes.
 
 This file contains a log of changes to the API.
+API Version 2.0.9
+Changed import permissions to use the new 'use ctools import' permission.
+
 API Version 2.0.8
   Introduce ctools_class_add().
   Introduce ctools_class_remove().
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
deleted file mode 100644
index c5bd5e6dc1ba959868e664b8cab49b3a4dd0e906..0000000000000000000000000000000000000000
--- a/CHANGELOG.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-Current API VERSION: 2.0. See API.txt for more information.
-
-ctools 7.x-1.x-dev
-==================
-#1008120: "New custom content" shows empty form if custom content panes module is not enabled.
-#999302 by troky: Fix jump menu. Apparently this wasn't actually committed the last time it was committed.
-#1065976 by tekante and David_Rothstein: Reset plugin static cache during module enable to prevent stale data from harming export ui.
-#1016510 by EclipseGC: Make the taxonomy system page functional.
-
-ctools 7.x-1.x-alpha2 (05-Jan-2011)
-===================================
-
-#911396 by alex_b: Prevent notices in export UI.
-#919768 by mikey_p: Allow url options to be sent to ctools_ajax_command_url().
-#358953 by cedarm: Allow term context to return lowercase, spaces to dashes versions of terms.
-#931434 by EclipseGc: Argument plugin for node revision ID.
-#910656: CTools AJAX sample wizard demo "domesticated" checkbox value not stored.
-#922442 by EugenMayer, neclimdul and voxpelli: Make sure ctools_include can handle '' or NULL directory.
-#919956 by traviss359: Correct example in wizard advanced help.
-#942968: Fix taxonomy term access rule with tag term vocabs.
-#840344: node add argument had crufty code causing notices.
-#944462 by longhairedgit: Invalid character in regex causes rare notice.
-#938778 by dereine: Fix profile content type for D7 updates.
-Add detach event to modal close so that wysiwyg can detach the editor.
-Variant titles showing up as blank if more than one variant on a page.
-#940016: token support was not yet updated for D7.
-#940446: Skip validation on back and cancel buttons in all wizards.
-#954492: Redirect not always working in wizard.inc
-#955348: Lack of redirect on "Update" button in Page Manager causing data loss sometimes.
-#941778: Update and save button should not appear in the "Add variant" path.
-#955070 by EclipseGc: Update ctools internal page tokens to work properly on content all content.
-#956890 by EclipseGc: Update views_content to not use views dependency since that is gone.
-#954728 by EclipseGc: Update node template page function name to not collide with new hook_node_view().
-#946534 by EclipseGc: Add support for field content on all entitities.
-#952586 by EclipseGc: Fix node_author content type.
-#959206: If a context is not set when rendering content, attempt to guess the context (fixes Views panes where "From context" was added but pane was never edited.)
-#961654 by benshell: drupal_alter() only supports 4 arguments.
-#911362 by alex_b: Facilitate plugin cache resets for tests.
-#945360 by naxoc: node_tag_new() not updated to D7.
-#953804 by EclipseGc: Fix node comment rendering.
-#953542 by EclipseGc: Fix node rendering.
-#953776 by EclipseGc: Fix node link rendering.
-#954772 by EclipseGc: Fix node build mode selection in node content type.
-#954762 by EclipseGc: Fix comment forbidden theme call.
-#954894 by EclipseGc: Fix breadcrumb content type.
-#955180 by EclipseGc: Fix page primary navigation type.
-#957190 by EclipseGc: Fix page secondary navigation type.
-#957194 by EclipseGc: Remove mission content type, since D7 no longer has a site mission.
-#957348 by EclipseGc: Fix search form URL path.
-#952586 by andypost: Use format_username for displaying unlinked usernames.
-#963800 by benshell: Fix query to fetch custom block title.
-#983496 by Amitaibu: Fix term argument to use proper load function.
-#989484 by Amitaibu: Fix notice in views plugin.
-#982496: Fix token context.
-#995026: Fix export UI during enable/disable which would throw notices and not properly set/unset menu items.
-#998870 by Amitaibu: Fix notice when content has no icon by using function already designed for that.
-#983576 by Amitaibu: Node view fallback task showed white screen.
-#1004644 by pillarsdotnet: Update a missed theme() call to D7.
-#1006162 by aspilicious: .info file cleanup.
-#998312 by dereine: Support the expanded/hidden options that Views did for dependent.js
-#955030: Remove no longer supported footer message content type.
-Fix broken query in term context config.
-#992022 by pcambra: Fix node autocomplete.
-#946302 by BerdArt and arywyr: Fix PHP 5.3 reference error.
-#980528 by das-peter: Notice fix with entity settings.
-#999302 by troky: ctools_jump_menu() needed updating to new form parameters.
-#964174: stylizer plugin theme delegation was in the wrong place, causing errors.
-#991658 by burlap: Fully load the "user" context for the logged in user because not all fields are in $user.
-#1014866 by das-peter: Smarter title panes, notice fix on access plugin descriptions.
-#1015662 by troky: plugin .info files were not using correct filepaths.
-#941780 by EclipseGc: Restore the "No blocks" functionality.
-#951048 by EclipseGc: Tighter entity integration so that new entities are automatic contexts and relationships.
-#941800 by me and aspilicious: Use Drupal 7 #machine_name automation on page manager pages and all export_ui defaults.
-Disabled exportables and pages not properly greyed out.
-#969208 by me and benshell: Get user_view and user profile working.
-#941796: Recategorize blocks
-
-ctools 7.x-1.x-alpha1
-=====================
-
-Changelog reset for 7.x
-Basic conversion done during sprint.
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..abdd913e9f3eb25bafc2cadff5689a3f78fcdf56
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,78 @@
+CONTENTS OF THIS FILE
+---------------------
+
+ * Introduction
+ * Requirements
+ * Recommended Modules
+ * Installation
+ * Configuration
+
+
+INTRODUCTION
+------------
+
+The Chaos tool suite (ctools) module is primarily a set of APIs and tools to
+improve the developer experience. It also contains a module called the Page
+Manager whose job is to manage pages. In particular it manages panel pages, but
+as it grows it will be able to manage far more than just Panels.
+
+The Chaos Tool Suite (ctools) is a series of tools that makes code readily
+available for developers and creates libraries for other modules to use. Modules
+that use ctools include Views and Panels.
+
+End users will use ctools as underlying user interface libraries when operating
+Views and Panels modules and will not need to explore further (ctools is geared
+more toward developer usage). Developers will use the module differently and
+work more with the tools provided.
+
+For the moment, it includes the following tools:
+
+ * Plugins -- tools to make it easy for modules to let other modules implement
+   plugins from .inc files.
+ * Exportables -- tools to make it easier for modules to have objects that live
+   in database or live in code, such as 'default views'.
+ * AJAX responder -- tools to make it easier for the server to handle AJAX
+   requests and tell the client what to do with them.
+ * Form tools -- tools to make it easier for forms to deal with AJAX.
+ * Object caching -- tool to make it easier to edit an object across multiple
+   page requests and cache the editing work.
+ * Contexts -- the notion of wrapping objects in a unified wrapper and providing
+   an API to create and accept these contexts as input.
+ * Modal dialog -- tool to make it simple to put a form in a modal dialog.
+ * Dependent -- a simple form widget to make form items appear and disappear
+   based upon the selections in another item.
+ * Content -- pluggable content types used as panes in Panels and other modules
+   like Dashboard.
+ * Form wizard -- an API to make multi-step forms much easier.
+ * CSS tools -- tools to cache and sanitize CSS easily to make user-input CSS
+   safe.
+
+ * For a full description of the module visit:
+   https://www.drupal.org/project/ctools
+
+ * To submit bug reports and feature suggestions, or to track changes visit:
+   https://www.drupal.org/project/issues/ctools
+
+
+REQUIREMENTS
+------------
+
+This module requires no modules outside of Drupal core.
+
+
+RECOMMENDED MODULES
+-------------------
+
+The Advanced help module provides extended documentation. Once enabled,
+navigate to Administration > Advanced Help and select the Chaos tools link to
+view documentation.
+
+ * Advanced help - https://www.drupal.org/project/advanced_help
+
+
+INSTALLATION
+------------
+
+ * Install the Chaos tool suite module as you would normally install a
+   contributed Drupal module. Visit https://www.drupal.org/node/895232 for
+   further information.
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 844ecce42ad4cff3ccb01a86ad83aa8ec656cd74..2fbfa4f748a0b75f0cf77116c6862b59d58c294f 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -60,4 +60,4 @@ Upgrading from ctools-6.x-1.x to ctools-7.x-2.x:
 
     For all of these forms, the separate settings #trees in the form are now
     gone, so form ids may be adjusted. Also, these are now all real forms
-    using CTools form wizard instead of fake subforms as previously.
\ No newline at end of file
+    using CTools form wizard instead of fake subforms as previously.
diff --git a/bulk_export/bulk_export.module b/bulk_export/bulk_export.module
index afb15b9e575c229798d28bb9f373ef7006cdb33d..1050caa60622e157a3e4e9b18b9d2cb2537abcfb 100644
--- a/bulk_export/bulk_export.module
+++ b/bulk_export/bulk_export.module
@@ -137,7 +137,7 @@ function bulk_export_export($cli = FALSE, $options = array()) {
       // Add hook_ctools_plugin_api at the top of the module code, if there is any.
       if ($api_code) {
         foreach ($api_code as $api_hook => $text) {
-          $api =  "\n/**\n";
+          $api = "\n/**\n";
           $api .= " * Implements hook_$api_hook().\n";
           $api .= " */\n";
           $api .= "function {$module_name}_$api_hook(\$module, \$api) {\n";
@@ -148,7 +148,7 @@ function bulk_export_export($cli = FALSE, $options = array()) {
       }
 
       if ($module_code) {
-        $module =  "<?php\n\n";
+        $module = "<?php\n\n";
         $module .= "/**\n";
         $module .= " * @file\n";
         $module .= " * Bulk export of objects generated by Bulk export module.\n";
@@ -193,7 +193,6 @@ function bulk_export_export($cli = FALSE, $options = array()) {
 
 /**
  * FAPI definition for the bulk exporter form.
- *
  */
 function bulk_export_export_form($form, &$form_state) {
 
diff --git a/css/button.css b/css/button.css
index 15e484be3cb6676643f113f470ae6278d1e9d116..de214080a46cd8675ef0b60965e9719270d87322 100644
--- a/css/button.css
+++ b/css/button.css
@@ -1,4 +1,3 @@
-
 .ctools-button-processed {
   border-style: solid;
   border-width: 1px;
@@ -17,8 +16,8 @@
 
 .ctools-no-js .ctools-content ul,
 .ctools-button-processed .ctools-content ul {
-  list-style-image: none;
-  list-style-type: none;
+  list-style: none none;
+  margin-left: 0;
 }
 
 .ctools-button-processed li {
diff --git a/css/collapsible-div.css b/css/collapsible-div.css
index ff648138faed79fb607cae21cd76663eb3029fcb..5366a0a87dd49a0c70c718d055be3c22513edb27 100644
--- a/css/collapsible-div.css
+++ b/css/collapsible-div.css
@@ -1,12 +1,9 @@
-
 .ctools-collapsible-container .ctools-toggle {
   float: left;
   width: 21px;
   height: 21px;
   cursor: pointer;
-  background-position: 7px 7px;
-  background-repeat: no-repeat;
-  background-image: url(../images/collapsible-expanded.png);
+  background: url(../images/collapsible-expanded.png) no-repeat 7px 7px;
 }
 
 .ctools-collapsible-container .ctools-collapsible-handle {
diff --git a/css/ctools.css b/css/ctools.css
index 7372988df8a07c921a717b57c5e26bb27618f817..66dcd59fd7162fdc4ab49e6e6bcb48091588a8e6 100644
--- a/css/ctools.css
+++ b/css/ctools.css
@@ -5,8 +5,8 @@
 }
 
 .ctools-owns-lock {
-  background: #FFFFDD none repeat scroll 0 0;
-  border: 1px solid #F0C020;
+  background: #ffffdd none repeat scroll 0 0;
+  border: 1px solid #f0c020;
   padding: 1em;
 }
 
diff --git a/css/dropbutton.css b/css/dropbutton.css
index 5e3ea242d00283a0a3a252add97f24dabc00744f..486ac3edaa0c63a08124524dda08cad54fcc5d57 100644
--- a/css/dropbutton.css
+++ b/css/dropbutton.css
@@ -1,4 +1,3 @@
-
 .ctools-dropbutton-processed {
   padding-right: 18px;
   position: relative;
@@ -20,7 +19,6 @@
   height: auto;
   position: absolute;
   right: 0;
-  text-indent: -9999px; /* LTR */
   top: 0;
   width: 17px;
 }
@@ -51,6 +49,7 @@
   right: 6px;
   position: absolute;
   top: 0.75em;
+  white-space: nowrap;
 }
 
 .ctools-dropbutton-processed.open .ctools-twisty {
diff --git a/css/dropdown.css b/css/dropdown.css
index bb50f3f44131bb5b7300209ee6f75a772a0f3324..d63bb7b26b2b2a13f7e1e7e87a94481c24895347 100644
--- a/css/dropdown.css
+++ b/css/dropdown.css
@@ -49,14 +49,14 @@ html.js div.ctools-dropdown div.ctools-dropdown-container {
 html.js div.ctools-dropdown div.ctools-dropdown-container ul li li a {
   padding-left: 25px;
   width: 150px;
-  color: #027AC6;
+  color: #027ac6;
 }
 
 html.js div.ctools-dropdown div.ctools-dropdown-container ul li a {
   text-decoration: none;
   padding-left: 5px;
   width: 170px;
-  color: #027AC6;
+  color: #027ac6;
 }
 
 html.js div.ctools-dropdown div.ctools-dropdown-container ul li span {
@@ -69,5 +69,5 @@ html.js div.ctools-dropdown div.ctools-dropdown-container ul li span.text {
 }
 
 html.js .ctools-dropdown-hover {
-  background-color: #ECECEC;
+  background-color: #ececec;
 }
diff --git a/css/modal-rtl.css b/css/modal-rtl.css
new file mode 100644
index 0000000000000000000000000000000000000000..5231b9fe1aa0b9cd6156442a5b49fd98fe3a5b15
--- /dev/null
+++ b/css/modal-rtl.css
@@ -0,0 +1,60 @@
+div.ctools-modal-content {
+  text-align: right;
+}
+
+div.ctools-modal-content .modal-header {
+  background-color: #2385c2;
+  padding: 0 1em 0 .25em;
+}
+
+div.ctools-modal-content a.close {
+  color: white;
+  float: left;
+}
+
+/** modal forms CSS **/
+div.ctools-modal-content .form-item label {
+  float: right;
+}
+
+div.ctools-modal-content .form-item .description {
+  clear: right;
+}
+
+div.ctools-modal-content .form-item .description .tips {
+  margin-left: 0;
+  margin-right: 2em;
+}
+
+div.ctools-modal-content fieldset,
+div.ctools-modal-content .form-radios,
+div.ctools-modal-content .form-checkboxes {
+  clear: right;
+}
+
+div.ctools-modal-content .resizable-textarea {
+  margin-left: 5em;
+  margin-right: 15em;
+}
+
+div.ctools-modal-content .container-inline .form-item {
+  margin-right: 0;
+  margin-left: 2em;
+}
+
+div.ctools-modal-content label.hidden-options {
+  background-position: left;
+  padding-right: 0;
+  padding-left: 12px;
+}
+
+div.ctools-modal-content label.expanded-options {
+  background-position: left;
+  padding-right: 0;
+  padding-left: 16px;
+}
+
+div.ctools-modal-content .dependent-options {
+  padding-left: 0;
+  padding-right: 30px;
+}
diff --git a/css/modal.css b/css/modal.css
index def374be3ef74b24886edece6d6c62711b138f4d..0045ecc99781575a5373decfd6dcc04bc9874717 100644
--- a/css/modal.css
+++ b/css/modal.css
@@ -79,7 +79,7 @@ div.ctools-modal-content .no-float .form-item * {
   float: none;
 }
 
-div.ctools-modal-content .modal-form .no-float label  {
+div.ctools-modal-content .modal-form .no-float label {
   width: auto;
 }
 
diff --git a/css/stylizer.css b/css/stylizer.css
index a16ec789bfd960ab98508bb59cb6f62ac899fd1a..fc8dcb2eeeb85fdfa9d79e3efe04e6fe8623d8b2 100644
--- a/css/stylizer.css
+++ b/css/stylizer.css
@@ -1,4 +1,3 @@
-
 /* Farbtastic placement */
 .color-form {
   max-width: 50em;
@@ -32,7 +31,8 @@
   clear: left; /* LTR */
   width: 14em;
 }
-.color-form .form-text, .color-form .form-select {
+.color-form .form-text,
+.color-form .form-select {
   float: left; /* LTR */
 }
 .color-form .form-text {
@@ -84,7 +84,7 @@
   cursor: default;
 }
 
-.ctools-style-icons .form-item  {
+.ctools-style-icons .form-item {
   width: 100px;
   float: left;
   margin: 0 3px !important;
diff --git a/css/wizard.css b/css/wizard.css
index d42a2db061239c11c160cb07196124c3065151d3..ab80def361e6190114faf48c1b3ff94030a38f5e 100644
--- a/css/wizard.css
+++ b/css/wizard.css
@@ -1,4 +1,3 @@
-
 .wizard-trail {
   font-size: 120%;
 }
diff --git a/ctools.api.php b/ctools.api.php
index a7ab78395a8acca71b53cfd495b407855cdb7ffd..0948e8798adf1814a497985d6ab767f1cc831545 100644
--- a/ctools.api.php
+++ b/ctools.api.php
@@ -17,9 +17,9 @@
  * Inform CTools about plugin types.
  *
  * @return array
- *  An array of plugin types, keyed by the type name.
- *  See the advanced help topic 'plugins-creating' for details of the array
- *  properties.
+ *   An array of plugin types, keyed by the type name.
+ *   See the advanced help topic 'plugins-creating' for details of the array
+ *   properties.
  */
 function hook_ctools_plugin_type() {
   $plugins['my_type'] = array(
@@ -30,6 +30,8 @@ function hook_ctools_plugin_type() {
 }
 
 /**
+ * Tells CTools where to find module-defined plugins.
+ *
  * This hook is used to inform the CTools plugin system about the location of a
  * directory that should be searched for files containing plugins of a
  * particular type. CTools invokes this same hook for all plugins, using the
@@ -65,6 +67,7 @@ function hook_ctools_plugin_type() {
  *   directory location is being requested.
  * @param string $plugin_type
  *   The name of the plugin type for which a base directory is being requested.
+ *
  * @return string
  *   The path where CTools' plugin system should search for plugin files,
  *   relative to your module's root. Omit leading and trailing slashes.
@@ -94,7 +97,7 @@ function hook_ctools_plugin_directory($owner, $plugin_type) {
     // Yes, this is exactly like Form 2 - just a different reasoning for it.
     return "plugins/$plugin_type";
   }
-  // Finally, if nothing matches, it's safe to return nothing at all (or NULL).
+  // Finally, if nothing matches, it's safe to return nothing at all (== NULL).
 }
 
 /**
@@ -103,12 +106,12 @@ function hook_ctools_plugin_directory($owner, $plugin_type) {
  * This hook is useful for altering flags or other information that will be
  * used or possibly overriden by the process hook if defined.
  *
- * @param $plugin
+ * @param array $plugin
  *   An associative array defining a plugin.
- * @param $info
+ * @param array $info
  *   An associative array of plugin type info.
  */
-function hook_ctools_plugin_pre_alter(&$plugin, &$info) {
+function hook_ctools_plugin_pre_alter(array &$plugin, array &$info) {
   // Override a function defined by the plugin.
   if ($info['type'] == 'my_type') {
     $plugin['my_flag'] = 'new_value';
@@ -121,12 +124,12 @@ function hook_ctools_plugin_pre_alter(&$plugin, &$info) {
  * This hook is useful for overriding the final values for a plugin after it
  * has been processed.
  *
- * @param $plugin
+ * @param array $plugin
  *   An associative array defining a plugin.
- * @param $info
+ * @param array $info
  *   An associative array of plugin type info.
  */
-function hook_ctools_plugin_post_alter(&$plugin, &$info) {
+function hook_ctools_plugin_post_alter(array &$plugin, array &$info) {
   // Override a function defined by the plugin.
   if ($info['type'] == 'my_type') {
     $plugin['my_function'] = 'new_function';
@@ -143,7 +146,7 @@ function hook_ctools_plugin_post_alter(&$plugin, &$info) {
  *   An array of informations about the implementors of a certain api.
  *   The key of this array are the module names/theme names.
  */
-function hook_ctools_api_hook_alter(&$list) {
+function hook_ctools_api_hook_alter(array &$list) {
   // Alter the path of the node implementation.
   $list['node']['path'] = drupal_get_path('module', 'node');
 }
@@ -151,30 +154,55 @@ function hook_ctools_api_hook_alter(&$list) {
 /**
  * Alter the available functions to be used in ctools math expression api.
  *
- * One usecase would be to create your own function in your module and
+ * One use case would be to create your own function in your module and
  * allow to use it in the math expression api.
  *
- * @param $functions
- *    An array which has the functions as value.
+ * @param array $functions
+ *   An array which has the functions as value.
+ * @param array $context
+ *   An array containing an item 'final' whose value is a reference to the
+ *   definitions for multiple-arg functions. Use this to add in functions that
+ *   require more than one arg.
  */
-function hook_ctools_math_expression_functions_alter(&$functions) {
-  // Allow to convert from degrees to radiant.
+function hook_ctools_math_expression_functions_alter(array &$functions, array $context) {
+  // Allow to convert from degrees to radians.
   $functions[] = 'deg2rad';
+
+  $multiarg = $context['final'];
+  $multiarg['pow'] = array(
+    'function' => 'pow',
+    'arguments' => 2,
+  );
+}
+
+/**
+ * Alter the available functions to be used in ctools math expression api.
+ *
+ * One usecase would be to create your own function in your module and
+ * allow to use it in the math expression api.
+ *
+ * @param array $constants
+ *   An array of name:value pairs, one for each named constant. Values added
+ *   to this array become read-only variables with the value assigned here.
+ */
+function hook_ctools_math_expression_constants_alter(array &$constants) {
+  // Add the speed of light as constant 'c':
+  $constants['c'] = 299792458;
 }
 
 /**
  * Alter everything.
  *
- * @param $info
+ * @param array $info
  *   An associative array containing the following keys:
  *   - content: The rendered content.
  *   - title: The content's title.
  *   - no_blocks: A boolean to decide if blocks should be displayed.
- * @param $page
+ * @param bool $page
  *   If TRUE then this renderer owns the page and can use theme('page')
  *   for no blocks; if false, output is returned regardless of any no
  *   blocks settings.
- * @param $context
+ * @param array $context
  *   An associative array containing the following keys:
  *   - args: The raw arguments behind the contexts.
  *   - contexts: The context objects in use.
@@ -182,7 +210,7 @@ function hook_ctools_math_expression_functions_alter(&$functions) {
  *   - subtask: The subtask object in use.
  *   - handler: The handler object in use.
  */
-function hook_ctools_render_alter(&$info, &$page, &$context) {
+function hook_ctools_render_alter(array &$info, &$page, array &$context) {
   if ($context['handler']->name == 'my_handler') {
     ctools_add_css('my_module.theme', 'my_module');
   }
@@ -199,7 +227,13 @@ function hook_ctools_render_alter(&$info, &$page, &$context) {
  * or categories or to rename content on specific sites.
  */
 function hook_ctools_content_subtype_alter($subtype, $plugin) {
-  $subtype['render last'] = TRUE;
+  // Force a particular subtype of a particular plugin to render last.
+  if ($plugin['module'] === 'some_plugin_module'
+    && $plugin['name'] === 'some_plugin_name'
+    && $subtype['subtype_id'] === 'my_subtype_id'
+  ) {
+    $subtype['render last'] = TRUE;
+  }
 }
 
 /**
@@ -212,7 +246,7 @@ function hook_ctools_content_subtype_alter($subtype, $plugin) {
  * @param string $plugin_id
  *   The plugin ID, in the format NAME:KEY.
  */
-function hook_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
+function hook_ctools_entity_context_alter(array &$plugin, array &$entity, $plugin_id) {
   ctools_include('context');
   switch ($plugin_id) {
     case 'entity_id:taxonomy_term':
@@ -225,6 +259,28 @@ function hook_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
   }
 }
 
+/**
+ * Alter the conversion of context items by ctools context plugin convert()s.
+ *
+ * @param ctools_context $context
+ *   The current context plugin object. If this implemented a 'convert'
+ *   function, the value passed in has been processed by that function.
+ * @param string $converter
+ *   A string associated with the plugin type, identifying the operation.
+ * @param string $value
+ *   The value being converted; this is the only return from the function.
+ * @param array $converter_options
+ *   Array of key-value pairs to pass to a converter function from higher
+ *   levels.
+ *
+ * @see ctools_context_convert_context()
+ */
+function hook_ctools_context_converter_alter(ctools_context $context, $converter, &$value, array $converter_options) {
+  if ($converter === 'mystring') {
+    $value = 'fixed';
+  }
+}
+
 /**
  * Alter the definition of entity context plugins.
  *
@@ -233,7 +289,7 @@ function hook_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
  *
  * @see hook_ctools_entity_context_alter()
  */
-function hook_ctools_entity_contexts_alter(&$plugins) {
+function hook_ctools_entity_contexts_alter(array &$plugins) {
   $plugins['entity_id:taxonomy_term']['no ui'] = TRUE;
 }
 
@@ -245,7 +301,7 @@ function hook_ctools_entity_contexts_alter(&$plugins) {
  *
  * @see ctools_cleanstring()
  */
-function hook_ctools_cleanstring_alter(&$settings) {
+function hook_ctools_cleanstring_alter(array &$settings) {
   // Convert all strings to lower case.
   $settings['lower case'] = TRUE;
 }
@@ -258,11 +314,27 @@ function hook_ctools_cleanstring_alter(&$settings) {
  *
  * @see ctools_cleanstring()
  */
-function hook_ctools_cleanstring_CLEAN_ID_alter(&$settings) {
+function hook_ctools_cleanstring_CLEAN_ID_alter(array &$settings) {
   // Convert all strings to lower case.
   $settings['lower case'] = TRUE;
 }
 
+/**
+ * Let other modules modify the context handler before it is rendered.
+ *
+ * @param object $handler
+ *   A handler for a current task and subtask.
+ * @param array $contexts
+ *   An associative array of contexts.
+ * @param array $args
+ *   An array for current args.
+ *
+ * @see ctools_context_handler_pre_render()
+ */
+function ctools_context_handler_pre_render($handler, array $contexts, array $args) {
+  $handler->conf['css_id'] = 'my-id';
+}
+
 /**
  * @} End of "addtogroup hooks".
  */
diff --git a/ctools.info b/ctools.info
index b2c54ad9f0f8b65d4877162a843ba5615080ee66..cacd137c4ae7f233486a7ccad107ef5b19c5809a 100644
--- a/ctools.info
+++ b/ctools.info
@@ -3,5 +3,18 @@ description = A library of helpful tools by Merlin of Chaos.
 core = 7.x
 package = Chaos tool suite
 files[] = includes/context.inc
+files[] = includes/css-cache.inc
 files[] = includes/math-expr.inc
 files[] = includes/stylizer.inc
+
+; Tests.
+files[] = tests/context.test
+files[] = tests/css.test
+files[] = tests/css_cache.test
+files[] = tests/ctools.plugins.test
+files[] = tests/ctools.test
+files[] = tests/math_expression.test
+files[] = tests/math_expression_stack.test
+files[] = tests/object_cache.test
+files[] = tests/object_cache_unit.test
+files[] = tests/page_tokens.test
diff --git a/ctools.install b/ctools.install
index 63677fcffe9a6800cc4890975d7d409f90368664..d50bc9f8f16dcc2e6275fbe1ad72774e09e9346a 100644
--- a/ctools.install
+++ b/ctools.install
@@ -12,24 +12,25 @@
 function ctools_requirements($phase) {
   $requirements = array();
   if ($phase == 'runtime') {
+    $t = get_t();
     $requirements['ctools_css_cache'] = array(
-      'title' => t('CTools CSS Cache'),
+      'title' => $t('CTools CSS Cache'),
       'severity' => REQUIREMENT_OK,
-      'value' => t('Exists'),
+      'value' => $t('Exists'),
     );
 
     $path = 'public://ctools/css';
     if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
-      $requirements['ctools_css_cache']['description'] = t('The CTools CSS cache directory, %path could not be created due to a misconfigured files directory. Please ensure that the files directory is correctly configured and that the webserver has permission to create directories.', array('%path' => file_uri_target($path)));
+      $requirements['ctools_css_cache']['description'] = $t('The CTools CSS cache directory, %path could not be created due to a misconfigured files directory. Please ensure that the files directory is correctly configured and that the webserver has permission to create directories.', array('%path' => file_uri_target($path)));
       $requirements['ctools_css_cache']['severity'] = REQUIREMENT_ERROR;
-      $requirements['ctools_css_cache']['value'] = t('Unable to create');
+      $requirements['ctools_css_cache']['value'] = $t('Unable to create');
     }
 
     if (!function_exists('error_get_last')) {
-      $requirements['ctools_php_52']['title'] = t('CTools PHP requirements');
-      $requirements['ctools_php_52']['description'] = t('CTools requires certain features only available in PHP 5.2.0 or higher.');
+      $requirements['ctools_php_52']['title'] = $t('CTools PHP requirements');
+      $requirements['ctools_php_52']['description'] = $t('CTools requires certain features only available in PHP 5.2.0 or higher.');
       $requirements['ctools_php_52']['severity'] = REQUIREMENT_WARNING;
-      $requirements['ctools_php_52']['value'] = t('PHP !version', array('!version' => phpversion()));
+      $requirements['ctools_php_52']['value'] = $t('PHP !version', array('!version' => phpversion()));
     }
   }
 
@@ -40,7 +41,31 @@ function ctools_requirements($phase) {
  * Implements hook_schema().
  */
 function ctools_schema() {
-  return ctools_schema_2();
+  return ctools_schema_4();
+}
+
+/**
+ * Version 4 of the CTools schema.
+ */
+function ctools_schema_4() {
+  $schema = ctools_schema_3();
+
+  // Removed due to alternative database configuration issues.
+  // @see https://www.drupal.org/project/ctools/issues/2941920
+
+  return $schema;
+}
+
+/**
+ * Version 3 of the CTools schema.
+ */
+function ctools_schema_3() {
+  $schema = ctools_schema_2();
+
+  // Update the 'obj' field to be 128 bytes long:
+  $schema['ctools_object_cache']['fields']['obj']['length'] = 128;
+
+  return $schema;
 }
 
 /**
@@ -49,7 +74,7 @@ function ctools_schema() {
 function ctools_schema_2() {
   $schema = ctools_schema_1();
 
-  // update the 'name' field to be 128 bytes long:
+  // Update the 'name' field to be 128 bytes long:
   $schema['ctools_object_cache']['fields']['name']['length'] = 128;
 
   // Update the 'data' field to be type 'blob'.
@@ -83,10 +108,10 @@ function ctools_schema_2() {
         'serialize' => TRUE,
       ),
       'filter' => array(
-         'type' => 'int',
-         'size' => 'tiny',
-         'description' => 'Whether or not this CSS needs to be filtered.',
-       ),
+        'type' => 'int',
+        'size' => 'tiny',
+        'description' => 'Whether or not this CSS needs to be filtered.',
+      ),
     ),
     'primary key' => array('cid'),
   );
@@ -141,6 +166,21 @@ function ctools_schema_1() {
   return $schema;
 }
 
+/**
+ * Implements hook_install().
+ */
+function ctools_install() {
+  // Activate our custom cache handler for the CSS cache.
+  variable_set('cache_class_cache_ctools_css', 'CToolsCssCache');
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function ctools_uninstall() {
+  variable_del('cache_class_cache_ctools_css');
+}
+
 /**
  * Enlarge the ctools_object_cache.name column to prevent truncation and weird
  * errors.
@@ -170,7 +210,7 @@ function ctools_update_6003() {
   if ($result) {
     db_delete('system')->condition('name', 'panels_views')->execute();
     module_enable(array('views_content'), TRUE);
- }
+  }
 }
 
 /**
@@ -189,7 +229,7 @@ function ctools_update_6005() {
 }
 
 /**
- * ctools_custom_content table was originally here, but is now moved to
+ * The ctools_custom_content table was originally here, but is now moved to
  * its own module.
  */
 function ctools_update_6007() {
@@ -203,17 +243,57 @@ function ctools_update_6007() {
 }
 
 /**
- * ctools_object_cache needs to be defined as a blob.
+ * The ctools_object_cache needs to be defined as a blob.
  */
 function ctools_update_6008() {
   db_delete('ctools_object_cache')
     ->execute();
 
   db_change_field('ctools_object_cache', 'data', 'data', array(
-      'type' => 'blob',
-      'size' => 'big',
-      'description' => 'Serialized data being stored.',
-      'serialize' => TRUE,
-    )
+    'type' => 'blob',
+    'size' => 'big',
+    'description' => 'Serialized data being stored.',
+    'serialize' => TRUE,
+  )
   );
 }
+
+/**
+ * Enable the custom CSS cache handler.
+ */
+function ctools_update_7000() {
+  variable_set('cache_class_cache_ctools_css', 'CToolsCssCache');
+}
+
+/**
+ * Increase the length of the ctools_object_cache.obj column.
+ */
+function ctools_update_7001() {
+  db_change_field('ctools_object_cache', 'obj', 'obj', array(
+    'type' => 'varchar',
+    'length' => '128',
+    'not null' => TRUE,
+    'description' => 'The type of the object this cache is attached to; this essentially represents the owner so that several sub-systems can use this cache.',
+  ));
+}
+
+/**
+ * Increase the length of the ctools_object_cache.name column to 255.
+ */
+function ctools_update_7002() {
+  // Removed due to alternative database configuration issues.
+  // @see https://www.drupal.org/project/ctools/issues/2941920
+}
+
+/**
+ * Revert the length of the ctools_object_cache.name column back to 128.
+ */
+function ctools_update_7003() {
+  db_delete('ctools_object_cache')->execute();
+  db_change_field('ctools_object_cache', 'name', 'name', array(
+    'type' => 'varchar',
+    'length' => '128',
+    'not null' => TRUE,
+    'description' => 'The name of the object this cache is attached to.',
+  ));
+}
diff --git a/ctools.module b/ctools.module
index 0ce445716f4d3d3af77da1776317b80f8441184a..f1d40c3778657eca2a5324fec457681637d3ec41 100644
--- a/ctools.module
+++ b/ctools.module
@@ -9,7 +9,24 @@
  * must be implemented in the module file.
  */
 
-define('CTOOLS_API_VERSION', '2.0.7');
+define('CTOOLS_API_VERSION', '2.0.9');
+
+/**
+ * The current working ctools version.
+ *
+ * In a release, it should be 7.x-1.x, which should match what drush make will
+ * create. In a dev format, it should be 7.x-1.(x+1)-dev, which will allow
+ * modules depending on new features in ctools to depend on ctools > 7.x-1.x.
+ *
+ * To define a specific version of CTools as a dependency for another module,
+ * simply include a dependency line in that module's info file, e.g.:
+ *   ; Requires CTools v7.x-1.4 or newer.
+ *   dependencies[] = ctools (>=1.4)
+ *
+ * @deprecated in CTools 1.15 and will be removed before CTools 2.0.0.
+ *   Use the version provided by the drupal.org packaging system.
+ */
+define('CTOOLS_MODULE_VERSION', '7.x-1.13');
 
 /**
  * Test the CTools API version.
@@ -61,6 +78,9 @@ define('CTOOLS_API_VERSION', '2.0.7');
  *   The minimum version of CTools necessary for your software to run with it.
  * @param $maximum
  *   The maximum version of CTools allowed for your software to run with it.
+ *
+ * @return bool
+ *   TRUE if the running ctools is usable, FALSE otherwise.
  */
 function ctools_api_version($minimum, $maximum = NULL) {
   if (version_compare(CTOOLS_API_VERSION, $minimum, '<')) {
@@ -75,8 +95,7 @@ function ctools_api_version($minimum, $maximum = NULL) {
 }
 
 // -----------------------------------------------------------------------
-// General utility functions
-
+// General utility functions.
 /**
  * Include .inc files as necessary.
  *
@@ -104,6 +123,7 @@ function ctools_api_version($minimum, $maximum = NULL) {
  * @param $dir
  *   Optional subdirectory containing the include file.
  */
+
 function ctools_include($file, $module = 'ctools', $dir = 'includes') {
   static $used = array();
 
@@ -133,8 +153,8 @@ function ctools_form_include(&$form_state, $file, $module = 'ctools', $dir = 'in
 /**
  * Add an arbitrary path to the $form_state so it can work with form cache.
  *
- * module_load_include uses an unfortunately annoying syntax to work, making it
- * difficult to translate the more simple $path + $file syntax.
+ * The module_load_include() function uses an unfortunately annoying syntax to
+ * work, making it difficult to translate the more simple $path + $file syntax.
  */
 function ctools_form_include_file(&$form_state, $filename) {
   if (!isset($form_state['build_info']['args'])) {
@@ -158,6 +178,9 @@ function ctools_form_include_file(&$form_state, $filename) {
  *   Optional module containing the include.
  * @param $dir
  *   Optional subdirectory containing the include file.
+ *
+ * @return string
+ *   A string containing the appropriate path from drupal root.
  */
 function ctools_image_path($image, $module = 'ctools', $dir = 'images') {
   return drupal_get_path('module', $module) . "/$dir/" . $image;
@@ -197,6 +220,9 @@ function ctools_add_css($file, $module = 'ctools', $dir = 'css') {
  *   Optional module containing the include.
  * @param $dir
  *   Optional subdirectory containing the include file.
+ *
+ * @return string
+ *   A string containing the appropriate path from drupal root.
  */
 function ctools_attach_css($file, $module = 'ctools', $dir = 'css') {
   return drupal_get_path('module', $module) . "/$dir/$file.css";
@@ -235,6 +261,9 @@ function ctools_add_js($file, $module = 'ctools', $dir = 'js') {
  *   Optional module containing the include.
  * @param $dir
  *   Optional subdirectory containing the include file.
+ *
+ * @return string
+ *   A string containing the appropriate path from drupal root.
  */
 function ctools_attach_js($file, $module = 'ctools', $dir = 'js') {
   return drupal_get_path('module', $module) . "/$dir/$file.js";
@@ -253,16 +282,29 @@ function ctools_get_roles() {
   return user_roles();
 }
 
-/*
- * Break x,y,z and x+y+z into an array. Numeric only.
+/**
+ * Parse integer sequences of the form "x,y,z" or "x+y+z" into separate values.
+ *
+ * A string with integers separated by comma (,) is reported as an 'and' set;
+ * separation by a plus sign (+) or a space ( ) is an 'or' set. The meaning
+ * of this is up to the caller. Negative or fractional numbers are not
+ * recognised.
+ *
+ * Additional space characters within or around the sequence are not allowed.
  *
  * @param $str
  *   The string to parse.
  *
- * @return $object
- *   An object containing
- *   - operator: Either 'and' or 'or'
- *   - value: An array of numeric values.
+ * @return object
+ *   An object containing the properties:
+ *
+ *   - operator: Either 'and' or 'or' when there are multiple matched values.
+ *   Absent when invalid_input is TRUE or there is only one value.
+ *   - value: An array of integers (never strings) from $str. An empty array is
+ *   returned if the input is empty. A single integer input is returned
+ *   as a single value, but no 'operator' is defined.
+ *   - invalid_input: TRUE if input could not be parsed and the values array
+ *   will contain just -1. This property is otherwise absent.
  */
 function ctools_break_phrase($str) {
   $object = new stdClass();
@@ -272,7 +314,7 @@ function ctools_break_phrase($str) {
     $object->operator = 'or';
     $object->value = preg_split('/[+ ]/', $str);
   }
-  else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str)) {
+  elseif (preg_match('/^([0-9]+,)*[0-9]+$/', $str)) {
     $object->operator = 'and';
     $object->value = explode(',', $str);
   }
@@ -290,7 +332,7 @@ function ctools_break_phrase($str) {
 
   // Doubly ensure that all values are numeric only.
   foreach ($object->value as $id => $value) {
-    $object->value[$id] = intval($value);
+    $object->value[$id] = (int) $value;
   }
 
   return $object;
@@ -300,23 +342,29 @@ function ctools_break_phrase($str) {
  * Set a token/value pair to be replaced later in the request, specifically in
  * ctools_page_token_processing().
  *
- * @param $token
+ * @param string $token
  *   The token to be replaced later, during page rendering.  This should
- *    ideally be a string inside of an HTML comment, so that if there is
- *    no replacement, the token will not render on the page.
- * @param $type
+ *   ideally be a string inside of an HTML comment, so that if there is
+ *   no replacement, the token will not render on the page.
+ *   If $token is NULL, the token set is not changed, but is still
+ *   returned.
+ * @param string $type
  *   The type of the token. Can be either 'variable', which will pull data
- *   directly from the page variables
- * @param $argument
- *   If $type == 'variable' then argument should be the key to fetch from
- *   the $variables. If $type == 'callback' then it should either be the
- *   callback, or an array that will be sent to call_user_func_array().
+ *   directly from the page variables, or 'callback', which causes a function
+ *   to be called to calculate the value. No other values are supported.
+ * @param string|array $argument
+ *   For $type of:
+ *   - 'variable': argument should be the key to fetch from the $variables.
+ *   - 'callback': then it should either be the callback function name as a
+ *     string, or an array that will be sent to call_user_func_array(). Argument
+ *     arrays must not use array keys (i.e. $a[0] is the first and $a[1] the
+ *     second element, etc.)
  *
- * @return
+ * @return array
  *   A array of token/variable names to be replaced.
  */
 function ctools_set_page_token($token = NULL, $type = NULL, $argument = NULL) {
-  static $tokens = array();
+  $tokens = &drupal_static('ctools_set_page_token', array());
 
   if (isset($token)) {
     $tokens[$token] = array($type, $argument);
@@ -325,13 +373,32 @@ function ctools_set_page_token($token = NULL, $type = NULL, $argument = NULL) {
 }
 
 /**
- * Easily set a token from the page variables.
+ * Reset the defined page tokens within this request.
+ *
+ * Introduced for simpletest purposes. Normally not needed.
+ */
+function ctools_reset_page_tokens() {
+  drupal_static_reset('ctools_set_page_token');
+}
+
+/**
+ * Set a replacement token from the containing element's children during #post_render.
  *
  * This function can be used like this:
- * $token = ctools_set_variable_token('tabs');
+ *   $token = ctools_set_variable_token('tabs');
  *
- * $token will then be a simple replacement for the 'tabs' about of the
- * variables available in the page template.
+ * The token "<!-- ctools-page-tabs -->" would then be replaced by the value of
+ * this element's (sibling) render array key 'tabs' during post-render (or be
+ * deleted if there was no such key by that point).
+ *
+ * @param string $token
+ *   The token string for the page callback, e.g. 'title'.
+ *
+ * @return string
+ *   The constructed token.
+ *
+ * @see ctools_set_callback_token()
+ * @see ctools_page_token_processing()
  */
 function ctools_set_variable_token($token) {
   $string = '<!-- ctools-page-' . $token . ' -->';
@@ -340,10 +407,45 @@ function ctools_set_variable_token($token) {
 }
 
 /**
- * Easily set a token from the page variables.
+ * Set a replacement token from the value of a function during #post_render.
  *
  * This function can be used like this:
- * $token = ctools_set_variable_token('id', 'mymodule_myfunction');
+ *   $token = ctools_set_callback_token('id', 'mymodule_myfunction');
+ *
+ * Or this (from its use in ctools_page_title_content_type_render):
+ *   $token = ctools_set_callback_token('title', array(
+ *       'ctools_page_title_content_type_token', $conf['markup'], $conf['id'], $conf['class']
+ *     )
+ *   );
+ *
+ * The token (e.g: "<!-- ctools-page-id-1b7f84d1c8851290cc342631ac663053 -->")
+ * would then be replaced during post-render by the return value of:
+ *
+ *   ctools_page_title_content_type_token($value_markup, $value_id, $value_class);
+ *
+ * @param string $token
+ *   The token string for the page callback, e.g. 'title'.
+ *
+ * @param string|array $callback
+ *   For callback functions that require no args, the name of the function as a
+ *   string; otherwise an array of two or more elements: the function name
+ *   followed by one or more function arguments.
+ *
+ *   NB: the value of $callback must be a procedural (non-class) function that
+ *   passes the php function_exists() check.
+ *
+ *   The callback function itself will be called with args dependent
+ *   on $callback. If:
+ *    - $callback is a string, the function is called with a reference to the
+ *      render array;
+ *    - $callback is an array, the function is called with $callback merged
+ *      with an array containing a reference to the render array.
+ *
+ * @return string
+ *   The constructed token.
+ *
+ * @see ctools_set_variable_token()
+ * @see ctools_page_token_processing()
  */
 function ctools_set_callback_token($token, $callback) {
   // If the callback uses arguments they are considered in the token.
@@ -370,14 +472,14 @@ function ctools_set_no_blocks($blocks = FALSE) {
 /**
  * Wrapper function to create UUIDs via ctools, falls back on UUID module
  * if it is enabled. This code is a copy of uuid.inc from the uuid module.
+ *
  * @see http://php.net/uniqid#65879
  */
-
 function ctools_uuid_generate() {
   if (!module_exists('uuid')) {
     ctools_include('uuid');
 
-    $callback = drupal_static(__FUNCTION__);
+    $callback = &drupal_static(__FUNCTION__);
 
     if (empty($callback)) {
       if (function_exists('uuid_create') && !function_exists('uuid_make')) {
@@ -399,6 +501,7 @@ function ctools_uuid_generate() {
 
 /**
  * Check that a string appears to be in the format of a UUID.
+ *
  * @see http://drupal.org/project/uuid
  *
  * @param $uuid
@@ -454,6 +557,8 @@ function ctools_class_add($classes, $hook = 'html') {
  */
 function ctools_class_remove($classes, $hook = 'html') {
   if (!is_array($classes)) {
+    // @todo Consider using explode(' ', $classes);
+    // @todo Consider checking that $classes is a string before adding.
     $classes = array($classes);
   }
 
@@ -466,12 +571,35 @@ function ctools_class_remove($classes, $hook = 'html') {
   }
 }
 
-// -----------------------------------------------------------------------
-// Drupal core hooks
+/**
+ * Reset the storage used for ctools_class_add and ctools_class_remove.
+ *
+ * @see ctools_class_add()
+ * @see ctools_class_remove()
+ */
+function ctools_class_reset() {
+  drupal_static_reset('ctools_process_classes');
+}
 
+/**
+ * Return the classes for the body (added by ctools_class_add).
+ *
+ * @return array
+ *   A copy of the array of classes to add to the body tag. If none have been
+ *   added, this will be an empty array.
+ *
+ * @see ctools_class_add()
+ */
+function ctools_get_classes() {
+  return drupal_static('ctools_process_classes', array());
+}
+
+// -----------------------------------------------------------------------
+// Drupal core hooks.
 /**
  * Implement hook_init to keep our global CSS at the ready.
  */
+
 function ctools_init() {
   ctools_add_css('ctools');
   // If we are sure that CTools' AJAX is in use, change the error handling.
@@ -490,7 +618,7 @@ function ctools_init() {
  * Shutdown handler used during ajax operations to help catch fatal errors.
  */
 function ctools_shutdown_handler() {
-  if (function_exists('error_get_last') AND ($error = error_get_last())) {
+  if (function_exists('error_get_last') && ($error = error_get_last())) {
     switch ($error['type']) {
       case E_ERROR:
       case E_CORE_ERROR:
@@ -536,6 +664,19 @@ function ctools_menu() {
   return $items;
 }
 
+/**
+ * Implements hook_permission().
+ */
+function ctools_permission() {
+  return array(
+    'use ctools import' => array(
+      'title' => t('Use CTools importer'),
+      'description' => t('The import functionality allows users to execute arbitrary PHP code, so extreme caution must be taken.'),
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
 /**
  * Implementation of hook_cron. Clean up old caches.
  */
@@ -546,24 +687,16 @@ function ctools_cron() {
 }
 
 /**
- * Ensure the CTools CSS cache is flushed whenever hook_flush_caches is invoked.
+ * Implements hook_flush_caches().
  */
 function ctools_flush_caches() {
-  // Do not actually flush caches if running on cron. Drupal uses this hook
-  // in an inconsistent fashion and it does not necessarily mean to *flush*
-  // caches when running from cron. Instead it's just getting a list of cache
-  // tables and may not do any flushing.
-  if (!empty($GLOBALS['locks']['cron'])) {
-    return;
-  }
-
-  ctools_include('css');
-  ctools_css_flush_caches();
+  // Only return the CSS cache bin if it has been activated, to avoid
+  // drupal_flush_all_caches() from trying to truncate a non-existing table.
+  return variable_get('cache_class_cache_ctools_css', FALSE) ? array('cache_ctools_css') : array();
 }
 
 /**
  * Implements hook_element_info_alter().
- *
  */
 function ctools_element_info_alter(&$type) {
   ctools_include('dependent');
@@ -593,17 +726,41 @@ function ctools_file_download($filepath) {
  * class-based plugins.
  */
 function ctools_registry_files_alter(&$files, $indexed_modules) {
+  if (drupal_get_bootstrap_phase() < DRUPAL_BOOTSTRAP_FULL) {
+    return;
+  }  
   ctools_include('registry');
   return _ctools_registry_files_alter($files, $indexed_modules);
 }
 
 // -----------------------------------------------------------------------
-// CTools hook implementations.
+// FAPI hooks that must be in the .module file.
+/**
+ * Alter the comment form to get a little more control over it.
+ */
+
+function ctools_form_comment_form_alter(&$form, &$form_state) {
+  if (!empty($form_state['ctools comment alter'])) {
+    // Force the form to post back to wherever we are.
+    $form['#action'] = url($_GET['q'], array('fragment' => 'comment-form'));
+    if (empty($form['#submit'])) {
+      $form['#submit'] = array('comment_form_submit');
+    }
+    $form['#submit'][] = 'ctools_node_comment_form_submit';
+  }
+}
 
+function ctools_node_comment_form_submit(&$form, &$form_state) {
+  $form_state['redirect'][0] = $_GET['q'];
+}
+
+// -----------------------------------------------------------------------
+// CTools hook implementations.
 /**
  * Implementation of hook_ctools_plugin_directory() to let the system know
  * where all our own plugins are.
  */
+
 function ctools_ctools_plugin_directory($owner, $plugin_type) {
   if ($owner == 'ctools') {
     return 'plugins/' . $plugin_type;
@@ -624,11 +781,11 @@ function ctools_ctools_plugin_type() {
 
 // -----------------------------------------------------------------------
 // Drupal theme preprocess hooks that must be in the .module file.
-
 /**
  * A theme preprocess function to automatically allow panels-based node
  * templates based upon input when the panel was configured.
  */
+
 function ctools_preprocess_node(&$vars) {
   // The 'ctools_template_identifier' attribute of the node is added when the pane is
   // rendered.
@@ -638,7 +795,25 @@ function ctools_preprocess_node(&$vars) {
   }
 }
 
+/**
+ * Implements hook_page_alter().
+ *
+ * Last ditch attempt to remove sidebar regions if the "no blocks"
+ * functionality has been activated.
+ *
+ * @see ctools_block_list_alter()
+ */
 function ctools_page_alter(&$page) {
+  $check = drupal_static('ctools_set_no_blocks', TRUE);
+  if (!$check) {
+    foreach ($page as $region_id => $region) {
+      // @todo -- possibly we can set configuration for this so that users can
+      // specify which blocks will not get rendered.
+      if (strpos($region_id, 'sidebar') !== FALSE) {
+        unset($page[$region_id]);
+      }
+    }
+  }
   $page['#post_render'][] = 'ctools_page_token_processing';
 }
 
@@ -656,6 +831,7 @@ function ctools_page_token_processing($children, $elements) {
         case 'variable':
           $tokens[$token] = isset($elements[$argument]) ? $elements[$argument] : '';
           break;
+
         case 'callback':
           if (is_string($argument) && function_exists($argument)) {
             $tokens[$token] = $argument($elements);
@@ -684,7 +860,7 @@ function ctools_process(&$variables, $hook) {
     return;
   }
 
-  $classes = drupal_static('ctools_process_classes', array());
+  $classes = ctools_get_classes();
 
   // Process the classses to add.
   if (!empty($classes[$hook]['add'])) {
@@ -705,7 +881,6 @@ function ctools_process(&$variables, $hook) {
 
 // -----------------------------------------------------------------------
 // Menu callbacks that must be in the .module file.
-
 /**
  * Determine if the current user has access via a plugin.
  *
@@ -729,14 +904,16 @@ function ctools_process(&$variables, $hook) {
  * @return
  *   TRUE if access is granted, false if otherwise.
  */
+
 function ctools_access_menu($access) {
+  $func_args = func_get_args();
   // Short circuit everything if there are no access tests.
   if (empty($access['plugins'])) {
     return TRUE;
   }
 
   $contexts = array();
-  foreach (func_get_args() as $arg) {
+  foreach ($func_args as $arg) {
     if (is_object($arg) && get_class($arg) == 'ctools_context') {
       $contexts[$arg->id] = $arg;
     }
@@ -757,7 +934,7 @@ function ctools_access_menu($access) {
  *   An indexed array of zero or more permission strings to be checked by
  *   user_access().
  *
- * @return
+ * @return bool
  *   Iff all checks pass will this function return TRUE. If an invalid argument
  *   is passed (e.g., not a string), this function errs on the safe said and
  *   returns FALSE.
@@ -786,6 +963,15 @@ function ctools_js_load($js) {
   return 0;
 }
 
+/**
+ * Provides the default value for %ctools_js.
+ *
+ * This allows drupal_valid_path() to work with %ctools_js.
+ */
+function ctools_js_to_arg($arg) {
+  return empty($arg) || $arg == '%' ? 'nojs' : $arg;
+}
+
 /**
  * Menu _load hook.
  *
@@ -810,7 +996,6 @@ function ctools_export_ui_load($item_name, $plugin_name) {
 
 // -----------------------------------------------------------------------
 // Caching callbacks on behalf of export-ui.
-
 /**
  * Menu access callback for various tasks of export-ui.
  */
@@ -854,7 +1039,7 @@ function ctools_export_ui_ctools_access_get($argument) {
 }
 
 /**
- * Callback for access control ajax form on behalf of export ui
+ * Callback for access control ajax form on behalf of export ui.
  *
  * Returns the cached access config and contexts used.
  * Note that this is assuming that access will be in $item->access -- if it
@@ -887,8 +1072,9 @@ function ctools_menu_local_tasks_alter(&$data, $router_item, $root_path) {
 }
 
 /**
- * Implement hook_block_list_alter() to potentially remove blocks.
+ * Implements hook_block_list_alter().
  *
+ * Used to potentially remove blocks.
  * This exists in order to replicate Drupal 6's "no blocks" functionality.
  */
 function ctools_block_list_alter(&$blocks) {
@@ -905,11 +1091,25 @@ function ctools_block_list_alter(&$blocks) {
 }
 
 /**
- * Implement hook_modules_enabled to clear static caches for detecting new plugins
+ * Implements hook_modules_enabled().
+ *
+ * Clear caches for detecting new plugins.
  */
 function ctools_modules_enabled($modules) {
   ctools_include('plugins');
   ctools_get_plugins_reset();
+  cache_clear_all('ctools_plugin_files:', 'cache', TRUE);
+}
+
+/**
+ * Implements hook_modules_disabled().
+ *
+ * Clear caches for removing disabled plugins.
+ */
+function ctools_modules_disabled($modules) {
+  ctools_include('plugins');
+  ctools_get_plugins_reset();
+  cache_clear_all('ctools_plugin_files:', 'cache', TRUE);
 }
 
 /**
@@ -937,6 +1137,7 @@ function ctools_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
     case 'entity_id:taxonomy_term':
       $plugin['no ui'] = TRUE;
       break;
+
     case 'entity:user':
       $plugin = ctools_get_context('user');
       unset($plugin['no ui']);
@@ -956,3 +1157,53 @@ function ctools_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
     }
   }
 }
+
+/**
+ * Implements hook_field_create_field().
+ */
+function ctools_field_create_field($field) {
+  ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_create_instance().
+ */
+function ctools_field_create_instance($instance) {
+  ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_delete_field().
+ */
+function ctools_field_delete_field($field) {
+  ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_delete_instance().
+ */
+function ctools_field_delete_instance($instance) {
+  ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_update_field().
+ */
+function ctools_field_update_field($field, $prior_field, $has_data) {
+  ctools_flush_field_caches();
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function ctools_field_update_instance($instance, $prior_instance) {
+  ctools_flush_field_caches();
+}
+
+/**
+ * Clear field related caches.
+ */
+function ctools_flush_field_caches() {
+  // Clear caches of 'Entity field' content type plugin.
+  cache_clear_all('ctools_entity_field_content_type_content_types', 'cache');
+}
diff --git a/ctools_access_ruleset/ctools_access_ruleset.install b/ctools_access_ruleset/ctools_access_ruleset.install
index 3f0087725a01f236b0132aa6092966e7d002825d..70afb3c6970e21f7dc460e5ac2d2e637cd38b868 100644
--- a/ctools_access_ruleset/ctools_access_ruleset.install
+++ b/ctools_access_ruleset/ctools_access_ruleset.install
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Schema for customizable access rulesets.
  */
diff --git a/ctools_access_ruleset/ctools_access_ruleset.module b/ctools_access_ruleset/ctools_access_ruleset.module
index fb39f37917574e57b41933d96b11327488e3d113..47a5d874d70e4fdbb94c31f59b6a6ba32b0151f5 100644
--- a/ctools_access_ruleset/ctools_access_ruleset.module
+++ b/ctools_access_ruleset/ctools_access_ruleset.module
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * ctools_access_ruleset module
+ * The ctools_access_ruleset module.
  *
  * This module allows styles to be created and managed on behalf of modules
  * that implement styles.
@@ -30,7 +30,7 @@ function ctools_access_ruleset_permission() {
  */
 function ctools_access_ruleset_ctools_plugin_directory($module, $plugin) {
   // Most of this module is implemented as an export ui plugin, and the
-  // rest is in ctools/includes/ctools_access_ruleset.inc
+  // rest is in ctools/includes/ctools_access_ruleset.inc.
   if ($module == 'ctools' && ($plugin == 'export_ui' || $plugin == 'access')) {
     return 'plugins/' . $plugin;
   }
@@ -47,7 +47,7 @@ function ctools_access_ruleset_panels_dashboard_blocks(&$vars) {
     'description' => t('Custom rulesets are combinations of access plugins you can use for access control, selection criteria and pane visibility.'),
   );
 
-   // Load all mini panels and their displays.
+  // Load all mini panels and their displays.
   ctools_include('export');
   $items = ctools_export_crud_load_all('ctools_access_ruleset');
   $count = 0;
diff --git a/ctools_access_ruleset/plugins/access/ruleset.inc b/ctools_access_ruleset/plugins/access/ruleset.inc
index f8abea6df74b42a97ff069748b446ab6e72d2b87..95f32c37fbafd4e175f0c99cde9f98cc8c5ecfa1 100644
--- a/ctools_access_ruleset/plugins/access/ruleset.inc
+++ b/ctools_access_ruleset/plugins/access/ruleset.inc
@@ -35,7 +35,7 @@ function ctools_ruleset_ctools_access_merge_plugin($plugin, $parent, $item) {
     $plugin['required context'] = array();
     foreach ($item->requiredcontexts as $context) {
       $info = ctools_get_context($context['name']);
-      // TODO: allow an optional setting
+      // TODO: allow an optional setting.
       $plugin['required context'][] = new ctools_context_required($context['identifier'], $info['context name']);
     }
   }
@@ -72,7 +72,7 @@ function ctools_ruleset_ctools_access_get_children($plugin, $parent) {
 }
 
 /**
- * Settings form for the 'by ruleset' access plugin
+ * Settings form for the 'by ruleset' access plugin.
  */
 function ctools_ruleset_ctools_access_settings(&$form, &$form_state, $conf) {
   if (!empty($form_state['plugin']['ruleset']->admin_description)) {
@@ -106,4 +106,3 @@ function ctools_ruleset_ctools_access_summary($conf, $context, $plugin) {
     return check_plain($plugin['ruleset']->admin_title);
   }
 }
-
diff --git a/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc b/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc
index d2a1c605644bdf94421002248e03393438f75e7d..2589ac38fe5e95109fa65b90474d3102be9c3f61 100644
--- a/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc
+++ b/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 $plugin = array(
   'schema' => 'ctools_access_ruleset',
   'access' => 'administer ctools access ruleset',
@@ -26,4 +30,3 @@ $plugin = array(
     ),
   ),
 );
-
diff --git a/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php b/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php
index b18146455310a4b6123df8a859ad4a704358e2a2..c9f8c20f63864bdc428188fc04187d3af1822950 100644
--- a/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php
+++ b/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php
@@ -2,7 +2,7 @@
 
 class ctools_access_ruleset_ui extends ctools_export_ui {
 
-  function edit_form_context(&$form, &$form_state) {
+  public function edit_form_context(&$form, &$form_state) {
     ctools_include('context-admin');
     ctools_context_admin_includes();
     ctools_add_css('ruleset');
@@ -27,7 +27,7 @@ class ctools_access_ruleset_ui extends ctools_export_ui {
     ctools_context_add_relationship_form($module, $form, $form_state, $form['right']['relationships_table'], $form_state['item'], $name);
   }
 
-  function edit_form_rules(&$form, &$form_state) {
+  public function edit_form_rules(&$form, &$form_state) {
     // The 'access' UI passes everything via $form_state, unlike the 'context' UI.
     // The main difference is that one is about 3 years newer than the other.
     ctools_include('context');
@@ -43,11 +43,12 @@ class ctools_access_ruleset_ui extends ctools_export_ui {
     $form = ctools_access_admin_form($form, $form_state);
   }
 
-  function edit_form_rules_submit(&$form, &$form_state) {
+  public function edit_form_rules_submit(&$form, &$form_state) {
     $form_state['item']->access['logic'] = $form_state['values']['logic'];
   }
 
-  function edit_form_submit(&$form, &$form_state) {
+  public function edit_form_submit(&$form, &$form_state) {
     parent::edit_form_submit($form, $form_state);
   }
+
 }
diff --git a/ctools_ajax_sample/css/ctools-ajax-sample.css b/ctools_ajax_sample/css/ctools-ajax-sample.css
index 8df17de5fc25c449a3d5a4fba09bf2407478a252..c312e9913157d7db6289a5dc6386460fe8136378 100644
--- a/ctools_ajax_sample/css/ctools-ajax-sample.css
+++ b/ctools_ajax_sample/css/ctools-ajax-sample.css
@@ -1,52 +1,52 @@
 div.ctools-sample-modal-content {
-	background:none;
-	border:0;
-	color:#000000;
-	margin:0;
-	padding:0;
-	text-align:left;
+  background: none;
+  border: 0;
+  color: #000;
+  margin: 0;
+  padding: 0;
+  text-align: left;
 }
-div.ctools-sample-modal-content .modal-scroll{
-	overflow:hidden;
-	overflow-y:auto;
+div.ctools-sample-modal-content .modal-scroll {
+  overflow: hidden;
+  overflow-y: auto;
 }
 div.ctools-sample-modal-content #popups-overlay {
-  background-color:transparent;
+  background-color: transparent;
 }
 div.ctools-sample-modal-content #popups-loading {
-  width:248px;
-  position:absolute;
-  display:none;
-  opacity:1;
+  width: 248px;
+  position: absolute;
+  display: none;
+  opacity: 1;
   -moz-border-radius: 8px;
   -webkit-border-radius: 8px;
-  z-index:99;
+  z-index: 99;
 }
 div.ctools-sample-modal-content #popups-loading span.popups-loading-message {
-  background:#FFF url(../images/loading-large.gif) no-repeat 8px center;
-  display:block;
-  color:#444444;
-  font-family:Arial;
-  font-size:22px;
-  font-weight:bold;
-  height:36px;
-  line-height:36px;
-  padding:0 40px;
+  background: #fff url(../images/loading-large.gif) no-repeat 8px center;
+  display: block;
+  color: #444;
+  font-family: Arial, serif;
+  font-size: 22px;
+  font-weight: bold;
+  height: 36px;
+  line-height: 36px;
+  padding: 0 40px;
 }
 div.ctools-sample-modal-content #popups-loading table,
 div.ctools-sample-modal-content .popups-box table {
-	margin:0px;
+  margin: 0;
 }
 div.ctools-sample-modal-content #popups-loading tbody,
 div.ctools-sample-modal-content .popups-box tbody {
-	border:none;
+  border: none;
 }
 div.ctools-sample-modal-content .popups-box tr {
-	background-color:transparent;
+  background-color: transparent;
 }
 div.ctools-sample-modal-content td.popups-border {
   background: url(../images/popups-border.png);
-  background-color:transparent;
+  background-color: transparent;
   border: none;
 }
 div.ctools-sample-modal-content td.popups-tl,
@@ -54,79 +54,94 @@ div.ctools-sample-modal-content td.popups-tr,
 div.ctools-sample-modal-content td.popups-bl,
 div.ctools-sample-modal-content td.popups-br {
   background-repeat: no-repeat;
-  height:10px;
-  padding:0px;
+  height: 10px;
+  padding: 0;
+}
+div.ctools-sample-modal-content td.popups-tl {
+  background-position: 0 0;
 }
-div.ctools-sample-modal-content td.popups-tl { background-position: 0px 0px; }
 div.ctools-sample-modal-content td.popups-t,
 div.ctools-sample-modal-content td.popups-b {
-  background-position: 0px -40px;
+  background-position: 0 -40px;
   background-repeat: repeat-x;
 }
-div.ctools-sample-modal-content td.popups-tr { background-position: 0px -10px; width: 10px; }
+div.ctools-sample-modal-content td.popups-tr {
+  background-position: 0 -10px;
+  width: 10px;
+}
 div.ctools-sample-modal-content td.popups-cl,
 div.ctools-sample-modal-content td.popups-cr {
   background-position: -10px 0;
   background-repeat: repeat-y;
-  width:10px;
+  width: 10px;
 }
 div.ctools-sample-modal-content td.popups-cl,
 div.ctools-sample-modal-content td.popups-cr,
-div.ctools-sample-modal-content td.popups-c { padding:0; border: none; }
-div.ctools-sample-modal-content td.popups-c { background:#fff; }
-div.ctools-sample-modal-content td.popups-bl { background-position: 0px -20px; }
-div.ctools-sample-modal-content td.popups-br { background-position: 0px -30px; width: 10px; }
+div.ctools-sample-modal-content td.popups-c {
+  padding: 0;
+  border: none;
+}
+div.ctools-sample-modal-content td.popups-c {
+  background: #fff;
+}
+div.ctools-sample-modal-content td.popups-bl {
+  background-position: 0 -20px;
+}
+div.ctools-sample-modal-content td.popups-br {
+  background-position: 0 -30px;
+  width: 10px;
+}
 
 div.ctools-sample-modal-content .popups-box,
 div.ctools-sample-modal-content #popups-loading {
-  border: 0px solid #454545;
-  opacity:1;
-  overflow:hidden;
-  padding:0;
-  background-color:transparent;
+  border: 0 solid #454545;
+  opacity: 1;
+  overflow: hidden;
+  padding: 0;
+  background-color: transparent;
 }
 div.ctools-sample-modal-content .popups-container {
-  overflow:hidden;
-  height:100%;
-  background-color:#fff;
+  overflow: hidden;
+  height: 100%;
+  background-color: #fff;
 }
 div.ctools-sample-modal-content div.popups-title {
-  -moz-border-radius-topleft: 0px;
-  -webkit-border-radius-topleft: 0px;
-  margin-bottom:0px;
-  background-color:#ff7200;
-  border:1px solid #ce5c00;
-  padding:4px 10px 5px;
-  color:white;
-  font-size:1em;
-  font-weight:bold;
+  -moz-border-radius-topleft: 0;
+  -webkit-border-radius-topleft: 0;
+  margin-bottom: 0;
+  background-color: #ff7200;
+  border: 1px solid #ce5c00;
+  padding: 4px 10px 5px;
+  color: white;
+  font-size: 1em;
+  font-weight: bold;
 }
 div.ctools-sample-modal-content .popups-body {
-  background-color:#fff;
-  padding:8px;
+  background-color: #fff;
+  padding: 8px;
 }
 div.ctools-sample-modal-content .popups-box .popups-buttons,
 div.ctools-sample-modal-content .popups-box .popups-footer {
-  background-color:#fff;
+  background-color: #fff;
 }
 div.ctools-sample-modal-content .popups-title a.close {
   color: #fff;
-  text-decoration:none;
+  text-decoration: none;
 }
 div.ctools-sample-modal-content .popups-close {
-	font-size:120%;
-	float:right;
-	text-align:right;
+  font-size: 120%;
+  float: right;
+  text-align: right;
 }
 div.ctools-sample-modal-content .modal-loading-wrapper {
-	width:220px;
-	height:19px;
-	margin:0 auto;
-	margin-top:2%;
+  width: 220px;
+  height: 19px;
+  margin: 0 auto;
+  margin-top: 2%;
 }
 
-div.ctools-sample-modal-content tbody{
-	border:none;
+div.ctools-sample-modal-content tbody {
+  border: none;
 }
 
 div.ctools-sample-modal-content .modal-content .modal-throbber-wrapper img {
diff --git a/ctools_ajax_sample/ctools_ajax_sample.install b/ctools_ajax_sample/ctools_ajax_sample.install
index 04325dbf418b23d2d5d2ead9498fea9763c853bf..e0fdfc6f9c0f1b14f5d22d1b0fc1ab6c80355853 100644
--- a/ctools_ajax_sample/ctools_ajax_sample.install
+++ b/ctools_ajax_sample/ctools_ajax_sample.install
@@ -1,18 +1,18 @@
 <?php
 
 /**
- * @file 
+ * @file
  */
 
 /**
- * Implementation of hook_install() 
+ * Implementation of hook_install()
  */
 function ctools_ajax_sample_install() {
 
 }
 
 /**
- * Implementation of hook_uninstall() 
+ * Implementation of hook_uninstall()
  */
 function ctools_ajax_sample_uninstall() {
 
diff --git a/ctools_ajax_sample/ctools_ajax_sample.module b/ctools_ajax_sample/ctools_ajax_sample.module
index 2a30c2a5638f87db7e3bc826b81679e7384e6571..c022fdb616076ede83ba7a1d588e53fa27cfc883 100644
--- a/ctools_ajax_sample/ctools_ajax_sample.module
+++ b/ctools_ajax_sample/ctools_ajax_sample.module
@@ -8,16 +8,16 @@
 
 // ---------------------------------------------------------------------------
 // Drupal hooks.
-
 /**
- *  Implementation of hook_menu()
+ * Implementation of hook_menu()
  */
+
 function ctools_ajax_sample_menu() {
   $items['ctools_ajax_sample'] = array(
-      'title' => 'Chaos Tools AJAX Demo',
-      'page callback' => 'ctools_ajax_sample_page',
-      'access callback' => TRUE,
-      'type' => MENU_NORMAL_ITEM,
+    'title' => 'Chaos Tools AJAX Demo',
+    'page callback' => 'ctools_ajax_sample_page',
+    'access callback' => TRUE,
+    'type' => MENU_NORMAL_ITEM,
   );
   $items['ctools_ajax_sample/simple_form'] = array(
     'title' => 'Simple Form',
@@ -26,39 +26,39 @@ function ctools_ajax_sample_menu() {
     'type' => MENU_CALLBACK,
   );
   $items['ctools_ajax_sample/%ctools_js/hello'] = array(
-      'title' => 'Hello World',
-      'page callback' => 'ctools_ajax_sample_hello',
-      'page arguments' => array(1),
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+    'title' => 'Hello World',
+    'page callback' => 'ctools_ajax_sample_hello',
+    'page arguments' => array(1),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
   );
   $items['ctools_ajax_sample/%ctools_js/tablenix/%'] = array(
-      'title' => 'Hello World',
-      'page callback' => 'ctools_ajax_sample_tablenix',
-      'page arguments' => array(1, 3),
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+    'title' => 'Hello World',
+    'page callback' => 'ctools_ajax_sample_tablenix',
+    'page arguments' => array(1, 3),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
   );
   $items['ctools_ajax_sample/%ctools_js/login'] = array(
-      'title' => 'Login',
-      'page callback' => 'ctools_ajax_sample_login',
-      'page arguments' => array(1),
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+    'title' => 'Login',
+    'page callback' => 'ctools_ajax_sample_login',
+    'page arguments' => array(1),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
   );
   $items['ctools_ajax_sample/%ctools_js/animal'] = array(
-      'title' => 'Animal',
-      'page callback' => 'ctools_ajax_sample_animal',
-      'page arguments' => array(1),
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+    'title' => 'Animal',
+    'page callback' => 'ctools_ajax_sample_animal',
+    'page arguments' => array(1),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
   );
   $items['ctools_ajax_sample/%ctools_js/login/%'] = array(
-      'title' => 'Post-Login Action',
-      'page callback' => 'ctools_ajax_sample_login_success',
-      'page arguments' => array(1, 3),
-      'access callback' => TRUE,
-      'type' => MENU_CALLBACK,
+    'title' => 'Post-Login Action',
+    'page callback' => 'ctools_ajax_sample_login_success',
+    'page arguments' => array(1, 3),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
   );
   $items['ctools_ajax_sample/jumped'] = array(
     'title' => 'Successful Jumping',
@@ -104,11 +104,11 @@ function ctools_ajax_sample_theme() {
 }
 
 // ---------------------------------------------------------------------------
-// Page callbacks
-
+// Page callbacks.
 /**
  * Page callback to display links and render a container for AJAX stuff.
  */
+
 function ctools_ajax_sample_page() {
   global $user;
 
@@ -156,14 +156,14 @@ function ctools_ajax_sample_page() {
 
     // The extra class points to the info in ctools-sample-style which we added
     // to the settings, prefixed with 'ctools-modal'.
-    $links[] = ctools_modal_text_button(t('Modal Login (custom style)'), 'ctools_ajax_sample/nojs/login', t('Login via modal'),  'ctools-modal-ctools-sample-style');
+    $links[] = ctools_modal_text_button(t('Modal Login (custom style)'), 'ctools_ajax_sample/nojs/login', t('Login via modal'), 'ctools-modal-ctools-sample-style');
   }
 
   // Four ways to do our animal picking wizard.
   $button_form = ctools_ajax_sample_ajax_button_form();
   $links[] = l(t('Wizard (no modal)'), 'ctools_ajax_sample/nojs/animal');
   $links[] = ctools_modal_text_button(t('Wizard (default modal)'), 'ctools_ajax_sample/nojs/animal', t('Pick an animal'));
-  $links[] = ctools_modal_text_button(t('Wizard (custom modal)'), 'ctools_ajax_sample/nojs/animal', t('Pick an animal'),  'ctools-modal-ctools-sample-style');
+  $links[] = ctools_modal_text_button(t('Wizard (custom modal)'), 'ctools_ajax_sample/nojs/animal', t('Pick an animal'), 'ctools-modal-ctools-sample-style');
   $links[] = drupal_render($button_form);
 
   $links[] = ctools_ajax_text_button(t('Hello world!'), "ctools_ajax_sample/nojs/hello", t('Replace text with "hello world"'));
@@ -176,9 +176,9 @@ function ctools_ajax_sample_page() {
   // Create a table that we can have data removed from via AJAX.
   $header = array(t('Row'), t('Content'), t('Actions'));
   $rows = array();
-  for($i = 1; $i < 11; $i++) {
+  for ($i = 1; $i < 11; $i++) {
     $rows[] = array(
-      'class' => array('ajax-sample-row-'. $i),
+      'class' => array('ajax-sample-row-' . $i),
       'data' => array(
         $i,
         md5($i),
@@ -187,12 +187,12 @@ function ctools_ajax_sample_page() {
     );
   }
 
-  $output .= theme('table', array('header' => $header, 'rows' => $rows, array('class' => array('ajax-sample-table'))));
+  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('ajax-sample-table'))));
 
-  // Show examples of ctools javascript widgets
-  $output .= '<h2>'. t('CTools Javascript Widgets') .'</h2>';
+  // Show examples of ctools javascript widgets.
+  $output .= '<h2>' . t('CTools Javascript Widgets') . '</h2>';
 
-  // Create a drop down menu
+  // Create a drop down menu.
   $links = array();
   $links[] = array('title' => t('Link 1'), 'href' => $_GET['q']);
   $links[] = array('title' => t('Link 2'), 'href' => $_GET['q']);
@@ -201,16 +201,16 @@ function ctools_ajax_sample_page() {
   $output .= '<h3>' . t('Drop Down Menu') . '</h3>';
   $output .= theme('ctools_dropdown', array('title' => t('Click to Drop Down'), 'links' => $links));
 
-  // Create a collapsible div
+  // Create a collapsible div.
   $handle = t('Click to Collapse');
   $content = 'Nulla ligula ante, aliquam at adipiscing egestas, varius vel arcu. Etiam laoreet elementum mi vel consequat. Etiam scelerisque lorem vel neque consequat quis bibendum libero congue. Nulla facilisi. Mauris a elit a leo feugiat porta. Phasellus placerat cursus est vitae elementum.';
-  $output .= '<h3>'. t('Collapsible Div') .'</h3>';
+  $output .= '<h3>' . t('Collapsible Div') . '</h3>';
   $output .= theme('ctools_collapsible', array('handle' => $handle, 'content' => $content, 'collapsed' => FALSE));
 
-  // Create a jump menu
+  // Create a jump menu.
   ctools_include('jump-menu');
   $form = drupal_get_form('ctools_ajax_sample_jump_menu_form');
-  $output .= '<h3>'. t('Jump Menu') .'</h3>';
+  $output .= '<h3>' . t('Jump Menu') . '</h3>';
   $output .= drupal_render($form);
 
   return array('markup' => array('#markup' => $output));
@@ -225,7 +225,8 @@ function ctools_ajax_sample_hello($js = NULL) {
     ctools_include('ajax');
     $commands = array();
     $commands[] = ajax_command_html('#ctools-sample', $output);
-    print ajax_render($commands); // this function exits.
+    // This function exits.
+    print ajax_render($commands);
     exit;
   }
   else {
@@ -234,7 +235,7 @@ function ctools_ajax_sample_hello($js = NULL) {
 }
 
 /**
- *  Nix a row from a table and restripe.
+ * Nix a row from a table and restripe.
  */
 function ctools_ajax_sample_tablenix($js, $row) {
   if (!$js) {
@@ -272,7 +273,7 @@ function ctools_ajax_sample_login($js = NULL) {
     $output = array();
     $inplace = ctools_ajax_text_button(t('remain here'), 'ctools_ajax_sample/nojs/login/inplace', t('Go to your account'));
     $account = ctools_ajax_text_button(t('your account'), 'ctools_ajax_sample/nojs/login/user', t('Go to your account'));
-    $output[] = ctools_modal_command_display(t('Login Success'), '<div class="modal-message">Login successful. You can now choose whether to '. $inplace .', or go to '. $account.'.</div>');
+    $output[] = ctools_modal_command_display(t('Login Success'), '<div class="modal-message">Login successful. You can now choose whether to ' . $inplace . ', or go to ' . $account . '.</div>');
   }
   print ajax_render($output);
   exit;
@@ -283,7 +284,7 @@ function ctools_ajax_sample_login($js = NULL) {
  */
 function ctools_ajax_sample_login_success($js, $action) {
   if (!$js) {
-    // we should never be here out of ajax context
+    // We should never be here out of ajax context.
     return MENU_NOT_FOUND;
   }
 
@@ -291,11 +292,11 @@ function ctools_ajax_sample_login_success($js, $action) {
   ctools_add_js('ajax-responder');
   $commands = array();
   if ($action == 'inplace') {
-    // stay here
+    // Stay here.
     $commands[] = ctools_ajax_command_reload();
   }
   else {
-    // bounce bounce
+    // Bounce bounce.
     $commands[] = ctools_ajax_command_redirect('user');
   }
   print ajax_render($commands);
@@ -318,18 +319,18 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
     'show back' => TRUE,
     'show cancel' => TRUE,
     'show return' => FALSE,
-    'next callback' =>  'ctools_ajax_sample_wizard_next',
+    'next callback' => 'ctools_ajax_sample_wizard_next',
     'finish callback' => 'ctools_ajax_sample_wizard_finish',
     'cancel callback' => 'ctools_ajax_sample_wizard_cancel',
-   // this controls order, as well as form labels
+   // This controls order, as well as form labels.
     'order' => array(
       'start' => t('Choose animal'),
     ),
-   // here we map a step to a form id.
+   // Here we map a step to a form id.
     'forms' => array(
-      // e.g. this for the step at wombat/create
+      // e.g. this for the step at wombat/create.
       'start' => array(
-        'form id' => 'ctools_ajax_sample_start'
+        'form id' => 'ctools_ajax_sample_start',
       ),
     ),
   );
@@ -341,7 +342,6 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
   // in creation.
   //
   // We skip all this here by just using an id of 1.
-
   $object_id = 1;
 
   if (empty($step)) {
@@ -406,7 +406,7 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
       $commands[] = ajax_command_html('#ctools-sample', $animal);
       $commands[] = ctools_modal_command_dismiss();
     }
-    else if (!empty($form_state['cancel'])) {
+    elseif (!empty($form_state['cancel'])) {
       // If cancelling, return to the activity.
       $commands[] = ctools_modal_command_dismiss();
     }
@@ -420,7 +420,7 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
     if ($output === FALSE || !empty($form_state['complete'])) {
       return $animal;
     }
-    else if (!empty($form_state['cancel'])) {
+    elseif (!empty($form_state['cancel'])) {
       drupal_goto('ctools_ajax_sample');
     }
     else {
@@ -430,11 +430,11 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
 }
 
 // ---------------------------------------------------------------------------
-// Themes
-
+// Themes.
 /**
  * Theme function for main rendered output.
  */
+
 function theme_ctools_ajax_sample_container($vars) {
   $output = '<div id="ctools-sample">';
   $output .= $vars['content'];
@@ -445,7 +445,6 @@ function theme_ctools_ajax_sample_container($vars) {
 
 // ---------------------------------------------------------------------------
 // Stuff needed for our little wizard.
-
 /**
  * Get a list of our animals and associated forms.
  *
@@ -453,6 +452,7 @@ function theme_ctools_ajax_sample_container($vars) {
  * which is often how it will work in the real world. If using CTools, what
  * you would probably really have, here, is a set of plugins for each animal.
  */
+
 function ctools_ajax_sample_animals() {
   return array(
     'sheep' => array(
@@ -478,10 +478,10 @@ function ctools_ajax_sample_animals() {
 
 // ---------------------------------------------------------------------------
 // Wizard caching helpers.
-
 /**
  * Store our little cache so that we can retain data from form to form.
  */
+
 function ctools_ajax_sample_cache_set($id, $object) {
   ctools_include('object-cache');
   ctools_object_cache_set('ctools_ajax_sample', $id, $object);
@@ -495,7 +495,7 @@ function ctools_ajax_sample_cache_get($id) {
   $object = ctools_object_cache_get('ctools_ajax_sample', $id);
   if (!$object) {
     // Create a default object.
-    $object = new stdClass;
+    $object = new stdClass();
     $object->type = 'unknown';
     $object->name = '';
   }
@@ -513,18 +513,18 @@ function ctools_ajax_sample_cache_clear($id) {
 
 // ---------------------------------------------------------------------------
 // Wizard in-between helpers; what to do between or after forms.
-
 /**
  * Handle the 'next' click on the add/edit pane form wizard.
  *
  * All we need to do is store the updated pane in the cache.
  */
+
 function ctools_ajax_sample_wizard_next(&$form_state) {
   ctools_ajax_sample_cache_set($form_state['object_id'], $form_state['object']);
 }
 
 /**
- * Handle the 'finish' click on teh add/edit pane form wizard.
+ * Handle the 'finish' click on the add/edit pane form wizard.
  *
  * All we need to do is set a flag so the return can handle adding
  * the pane.
@@ -542,10 +542,10 @@ function ctools_ajax_sample_wizard_cancel(&$form_state) {
 
 // ---------------------------------------------------------------------------
 // Wizard forms for our simple info collection wizard.
-
 /**
  * Wizard start form. Choose an animal.
  */
+
 function ctools_ajax_sample_start($form, &$form_state) {
   $form_state['title'] = t('Choose animal');
 
@@ -713,7 +713,7 @@ function ctools_ajax_sample_show_raptor($object) {
 }
 
 /**
- * Helper function to provide a sample jump menu form
+ * Helper function to provide a sample jump menu form.
  */
 function ctools_ajax_sample_jump_menu_form() {
   $url = url('ctools_ajax_sample/jumped');
@@ -723,7 +723,7 @@ function ctools_ajax_sample_jump_menu_form() {
 }
 
 /**
- * Provide a message to the user that the jump menu worked
+ * Provide a message to the user that the jump menu worked.
  */
 function ctools_ajax_sample_jump_menu_page() {
   $return_link = l(t('Return to the examples page.'), 'ctools_ajax_sample');
@@ -732,7 +732,7 @@ function ctools_ajax_sample_jump_menu_page() {
 }
 
 /**
- * Provide a form for an example ajax modal button
+ * Provide a form for an example ajax modal button.
  */
 function ctools_ajax_sample_ajax_button_form() {
   $form = array();
diff --git a/ctools_custom_content/ctools_custom_content.install b/ctools_custom_content/ctools_custom_content.install
index b4512f2a4cd5c839650ff6b45405e61728b3be8c..dcf87e734374f79bcde60070b01c37e330652ddf 100644
--- a/ctools_custom_content/ctools_custom_content.install
+++ b/ctools_custom_content/ctools_custom_content.install
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Schema for CTools custom content.
  */
diff --git a/ctools_custom_content/ctools_custom_content.module b/ctools_custom_content/ctools_custom_content.module
index 3e316a9188d51dc7c18c8f7b2f26fd4f0d6e8eca..3060fa604e68e8c3ca63671bde65074474910472 100644
--- a/ctools_custom_content/ctools_custom_content.module
+++ b/ctools_custom_content/ctools_custom_content.module
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * ctools_custom_content module
+ * The ctools_custom_content module.
  *
  * This module allows styles to be created and managed on behalf of modules
  * that implement styles.
@@ -30,7 +30,7 @@ function ctools_custom_content_permission() {
  */
 function ctools_custom_content_ctools_plugin_directory($module, $plugin) {
   // Most of this module is implemented as an export ui plugin, and the
-  // rest is in ctools/includes/ctools_custom_content.inc
+  // rest is in ctools/includes/ctools_custom_content.inc.
   if ($module == 'ctools' && $plugin == 'export_ui') {
     return 'plugins/' . $plugin;
   }
@@ -41,7 +41,7 @@ function ctools_custom_content_ctools_plugin_directory($module, $plugin) {
  */
 function ctools_custom_content_get_pane_links_alter(&$links, $pane, $content_type) {
   if ($pane->type == 'custom') {
-    if(!isset($pane->configuration['name'])) {
+    if (!isset($pane->configuration['name'])) {
       $name_of_pane = $pane->subtype;
     }
     else {
@@ -80,7 +80,7 @@ function ctools_custom_content_panels_dashboard_blocks(&$vars) {
     'description' => t('Custom content panes are basic HTML you enter that can be reused in all of your panels.'),
   );
 
-   // Load all mini panels and their displays.
+  // Load all mini panels and their displays.
   ctools_include('export');
   $items = ctools_export_crud_load_all('ctools_custom_content');
   $count = 0;
diff --git a/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc b/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc
index 467dc5804af5c81dd3bd1dc44401fd60e1d53bb3..c7933bcb38eecf856fd91be25d131c4e6fac62b2 100644
--- a/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc
+++ b/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 $plugin = array(
   'schema' => 'ctools_custom_content',
   'access' => 'administer custom content',
@@ -17,4 +21,3 @@ $plugin = array(
 
   'handler' => 'ctools_custom_content_ui',
 );
-
diff --git a/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php b/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
index 56fe4b21485665b6550e87a8b4a0d5b55bd3006f..e56f7a7ec58f87c809490cc20b3fb4bc436045fb 100644
--- a/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
+++ b/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
@@ -2,7 +2,7 @@
 
 class ctools_custom_content_ui extends ctools_export_ui {
 
-  function edit_form(&$form, &$form_state) {
+  public function edit_form(&$form, &$form_state) {
     // Correct for an error that came in because filter format changed.
     if (is_array($form_state['item']->settings['body'])) {
       $form_state['item']->settings['format'] = $form_state['item']->settings['body']['format'];
@@ -23,6 +23,22 @@ class ctools_custom_content_ui extends ctools_export_ui {
       '#title' => t('Title'),
     );
 
+    $form['title_heading'] = array(
+      '#title' => t('Title heading'),
+      '#type' => 'select',
+      '#default_value' => isset($form_state['item']->settings['title_heading']) ? $form_state['item']->settings['title_heading'] : 'h2',
+      '#options' => array(
+        'h1' => t('h1'),
+        'h2' => t('h2'),
+        'h3' => t('h3'),
+        'h4' => t('h4'),
+        'h5' => t('h5'),
+        'h6' => t('h6'),
+        'div' => t('div'),
+        'span' => t('span'),
+      ),
+    );
+
     $form['body'] = array(
       '#type' => 'text_format',
       '#title' => t('Body'),
@@ -38,17 +54,18 @@ class ctools_custom_content_ui extends ctools_export_ui {
     );
   }
 
-  function edit_form_submit(&$form, &$form_state) {
+  public function edit_form_submit(&$form, &$form_state) {
     parent::edit_form_submit($form, $form_state);
 
     // Since items in our settings are not in the schema, we have to do these manually:
     $form_state['item']->settings['title'] = $form_state['values']['title'];
+    $form_state['item']->settings['title_heading'] = $form_state['values']['title_heading'];
     $form_state['item']->settings['body'] = $form_state['values']['body']['value'];
     $form_state['item']->settings['format'] = $form_state['values']['body']['format'];
     $form_state['item']->settings['substitute'] = $form_state['values']['substitute'];
   }
 
-  function list_form(&$form, &$form_state) {
+  public function list_form(&$form, &$form_state) {
     parent::list_form($form, $form_state);
 
     $options = array('all' => t('- All -'));
@@ -65,7 +82,7 @@ class ctools_custom_content_ui extends ctools_export_ui {
     );
   }
 
-  function list_filter($form_state, $item) {
+  public function list_filter($form_state, $item) {
     if ($form_state['values']['category'] != 'all' && $form_state['values']['category'] != $item->category) {
       return TRUE;
     }
@@ -73,7 +90,7 @@ class ctools_custom_content_ui extends ctools_export_ui {
     return parent::list_filter($form_state, $item);
   }
 
-  function list_sort_options() {
+  public function list_sort_options() {
     return array(
       'disabled' => t('Enabled, title'),
       'title' => t('Title'),
@@ -83,21 +100,25 @@ class ctools_custom_content_ui extends ctools_export_ui {
     );
   }
 
-  function list_build_row($item, &$form_state, $operations) {
-    // Set up sorting
+  public function list_build_row($item, &$form_state, $operations) {
+    // Set up sorting.
     switch ($form_state['values']['order']) {
       case 'disabled':
         $this->sorts[$item->name] = empty($item->disabled) . $item->admin_title;
         break;
+
       case 'title':
         $this->sorts[$item->name] = $item->admin_title;
         break;
+
       case 'name':
         $this->sorts[$item->name] = $item->name;
         break;
+
       case 'category':
         $this->sorts[$item->name] = $item->category;
         break;
+
       case 'storage':
         $this->sorts[$item->name] = $item->type . $item->admin_title;
         break;
@@ -117,7 +138,7 @@ class ctools_custom_content_ui extends ctools_export_ui {
     );
   }
 
-  function list_table_header() {
+  public function list_table_header() {
     return array(
       array('data' => t('Name'), 'class' => array('ctools-export-ui-name')),
       array('data' => t('Title'), 'class' => array('ctools-export-ui-title')),
diff --git a/ctools_plugin_example/README.txt b/ctools_plugin_example/README.txt
index 42edcdc9025c3c28d542fde5e07e4b77fdeee618..2f9b0fffa56243d514885834fbca34524fa9f450 100644
--- a/ctools_plugin_example/README.txt
+++ b/ctools_plugin_example/README.txt
@@ -11,4 +11,4 @@ There are a number of ways to profit from this:
 2. There is a sample panel. You can access it at /ctools_plugin_example/xxxx
    to see how it works.
    
-3. There is Advanced Help at admin/advanced_help/ctools_plugin_example.
\ No newline at end of file
+3. There is Advanced Help at admin/advanced_help/ctools_plugin_example.
diff --git a/ctools_plugin_example/ctools_plugin_example.module b/ctools_plugin_example/ctools_plugin_example.module
index 01d533826e4f8bffc4ea06bc68892fcf283de6ee..a9a6080b9054b04a98b5a828335cf180d00add36 100644
--- a/ctools_plugin_example/ctools_plugin_example.module
+++ b/ctools_plugin_example/ctools_plugin_example.module
@@ -1,9 +1,8 @@
 <?php
 
-/*
+/**
  * @file
- *
- * Working sample module to demonstrate CTools 3 plugins
+ * Working sample module to demonstrate CTools 3 plugins.
  *
  * This sample module is only intended to demonstrate how external modules can
  * provide ctools plugins. There is no useful functionality, and it's only
@@ -25,7 +24,7 @@
  */
 
 /**
- * Implements hook_menu
+ * Implements hook_menu.
  */
 function ctools_plugin_example_menu() {
   $items = array();
@@ -58,7 +57,7 @@ function ctools_plugin_example_ctools_plugin_directory($module, $plugin) {
  * Implement hook_ctools_plugin_api().
  *
  * If you do this, CTools will pick up default panels pages in
- * <modulename>.pages_default.inc
+ * <modulename>.pages_default.inc.
  */
 function ctools_plugin_example_ctools_plugin_api($module, $api) {
   // @todo -- this example should explain how to put it in a different file.
@@ -71,7 +70,8 @@ function ctools_plugin_example_ctools_plugin_api($module, $api) {
 }
 
 /**
- * Just provide an explanation page for the admin section
+ * Just provide an explanation page for the admin section.
+ *
  * @return unknown_type
  */
 function ctools_plugin_example_explanation_page() {
diff --git a/ctools_plugin_example/ctools_plugin_example.pages_default.inc b/ctools_plugin_example/ctools_plugin_example.pages_default.inc
index 10a76193826443f20dce69dd6b5a0275033223cd..ed3ffd776eadbf9b6e1719b41eefe454361171e2 100644
--- a/ctools_plugin_example/ctools_plugin_example.pages_default.inc
+++ b/ctools_plugin_example/ctools_plugin_example.pages_default.inc
@@ -6,7 +6,7 @@
  */
 
 /**
- * Default panels pages for CTools Plugin Example
+ * Default panels pages for CTools Plugin Example.
  *
  * To pick up this file, your module needs to implement
  * hook_ctools_plugin_api() - See ctools_plugin_example_ctools_plugin_api() in
@@ -23,12 +23,10 @@
  * @return
  *   Array of pages, normally exported from Panels.
  */
-
 function ctools_plugin_example_default_page_manager_pages() {
 
-  // begin exported panel.
-
-  $page = new stdClass;
+  // Begin exported panel.
+  $page = new stdClass();
   $page->disabled = FALSE; /* Edit this to true to make a default page disabled initially */
   $page->api_version = 1;
   $page->name = 'ctools_plugin_example';
@@ -37,31 +35,31 @@ function ctools_plugin_example_default_page_manager_pages() {
   $page->admin_description = 'This panel provides no functionality to a working Drupal system. It\'s intended to display the various sample plugins provided by the CTools Plugin Example module. ';
   $page->path = 'ctools_plugin_example/%sc';
   $page->access = array(
-  'logic' => 'and',
+    'logic' => 'and',
   );
   $page->menu = array(
-  'type' => 'normal',
-  'title' => 'CTools plugin example',
-  'name' => 'navigation',
-  'weight' => '0',
-  'parent' => array(
-    'type' => 'none',
-    'title' => '',
+    'type' => 'normal',
+    'title' => 'CTools plugin example',
     'name' => 'navigation',
     'weight' => '0',
-  ),
+    'parent' => array(
+      'type' => 'none',
+      'title' => '',
+      'name' => 'navigation',
+      'weight' => '0',
+    ),
   );
   $page->arguments = array(
-  'sc' => array(
-    'id' => 2,
-    'identifier' => 'simplecontext-arg',
-    'name' => 'simplecontext_arg',
-    'settings' => array(),
-  ),
+    'sc' => array(
+      'id' => 2,
+      'identifier' => 'simplecontext-arg',
+      'name' => 'simplecontext_arg',
+      'settings' => array(),
+    ),
   );
   $page->conf = array();
   $page->default_handlers = array();
-  $handler = new stdClass;
+  $handler = new stdClass();
   $handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
   $handler->api_version = 1;
   $handler->name = 'page_ctools_panel_context';
@@ -70,44 +68,45 @@ function ctools_plugin_example_default_page_manager_pages() {
   $handler->handler = 'panel_context';
   $handler->weight = 0;
   $handler->conf = array(
-  'title' => 'Panel',
-  'no_blocks' => FALSE,
-  'css_id' => '',
-  'css' => '',
-  'contexts' => array(
-    '0' => array(
-      'name' => 'simplecontext',
-      'id' => 1,
-      'identifier' => 'Configured simplecontext (not from argument)',
-      'keyword' => 'configured_simplecontext',
-      'context_settings' => array(
-        'sample_simplecontext_setting' => 'default simplecontext setting',
-  ),
-  ),
-  ),
-  'relationships' => array(
-    '0' => array(
-      'context' => 'argument_simplecontext_arg_2',
-      'name' => 'relcontext_from_simplecontext',
-      'id' => 1,
-      'identifier' => 'Relcontext from simplecontext (from relationship)',
-      'keyword' => 'relcontext',
-  ),
-  ),
-  'access' => array(
-    'logic' => 'and',
-  ),
+    'title' => 'Panel',
+    'no_blocks' => FALSE,
+    'css_id' => '',
+    'css' => '',
+    'contexts' => array(
+      '0' => array(
+        'name' => 'simplecontext',
+        'id' => 1,
+        'identifier' => 'Configured simplecontext (not from argument)',
+        'keyword' => 'configured_simplecontext',
+        'context_settings' => array(
+          'sample_simplecontext_setting' => 'default simplecontext setting',
+        ),
+      ),
+    ),
+    'relationships' => array(
+      '0' => array(
+        'context' => 'argument_simplecontext_arg_2',
+        'name' => 'relcontext_from_simplecontext',
+        'id' => 1,
+        'identifier' => 'Relcontext from simplecontext (from relationship)',
+        'keyword' => 'relcontext',
+      ),
+    ),
+    'access' => array(
+      'logic' => 'and',
+    ),
+    'pipeline' => 'standard',
   );
-  $display = new panels_display;
+  $display = new panels_display();
   $display->layout = 'threecol_33_34_33_stacked';
   $display->layout_settings = array();
   $display->panel_settings = array(
-  'style' => 'rounded_corners',
-  'style_settings' => array(
-    'default' => array(
-      'corner_location' => 'pane',
-  ),
-  ),
+    'style' => 'rounded_corners',
+    'style_settings' => array(
+      'default' => array(
+        'corner_location' => 'pane',
+      ),
+    ),
   );
   $display->cache = array();
   $display->title = 'CTools plugin example panel';
@@ -115,7 +114,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $display->title_pane = 1;
   $display->content = array();
   $display->panels = array();
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-1';
   $pane->panel = 'left';
   $pane->type = 'no_context_content_type';
@@ -135,7 +134,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 0;
   $display->content['new-1'] = $pane;
   $display->panels['left'][0] = 'new-1';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-2';
   $pane->panel = 'left';
   $pane->type = 'custom';
@@ -148,15 +147,15 @@ function ctools_plugin_example_default_page_manager_pages() {
         'settings' => array(
           'greater_than' => '1',
           'arg_length' => '4',
-  ),
+        ),
         'context' => 'argument_simplecontext_arg_2',
-  ),
-  ),
+      ),
+    ),
   );
   $pane->configuration = array(
     'title' => 'Long Arg Visibility Block',
     'body' => 'This block will be here when the argument is longer than configured arg length. It uses the \'arg_length\' access plugin to test against the length of the argument used for Simplecontext.',
-    'format' => '1',
+    'format' => 'filtered_html',
     'substitute' => 1,
   );
   $pane->cache = array();
@@ -166,7 +165,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 1;
   $display->content['new-2'] = $pane;
   $display->panels['left'][1] = 'new-2';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-3';
   $pane->panel = 'left';
   $pane->type = 'custom';
@@ -179,15 +178,15 @@ function ctools_plugin_example_default_page_manager_pages() {
         'settings' => array(
           'greater_than' => '0',
           'arg_length' => '4',
-  ),
+        ),
         'context' => 'argument_simplecontext_arg_2',
-  ),
-  ),
+      ),
+    ),
   );
   $pane->configuration = array(
     'title' => 'Short Arg Visibility',
     'body' => 'This block appears when the simplecontext argument is <i>less than</i> the configured length.',
-    'format' => '1',
+    'format' => 'filtered_html',
     'substitute' => 1,
   );
   $pane->cache = array();
@@ -197,7 +196,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 2;
   $display->content['new-3'] = $pane;
   $display->panels['left'][2] = 'new-3';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-4';
   $pane->panel = 'middle';
   $pane->type = 'simplecontext_content_type';
@@ -241,7 +240,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 0;
   $display->content['new-4'] = $pane;
   $display->panels['middle'][0] = 'new-4';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-5';
   $pane->panel = 'middle';
   $pane->type = 'simplecontext_content_type';
@@ -285,7 +284,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 1;
   $display->content['new-5'] = $pane;
   $display->panels['middle'][1] = 'new-5';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-6';
   $pane->panel = 'middle';
   $pane->type = 'custom';
@@ -299,7 +298,7 @@ function ctools_plugin_example_default_page_manager_pages() {
     item1 is %sc:item1
     item2 is %sc:item2
     description is %sc:description',
-    'format' => '1',
+    'format' => 'filtered_html',
     'substitute' => 1,
   );
   $pane->cache = array();
@@ -309,7 +308,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 2;
   $display->content['new-6'] = $pane;
   $display->panels['middle'][2] = 'new-6';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-7';
   $pane->panel = 'right';
   $pane->type = 'relcontext_content_type';
@@ -353,7 +352,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->position = 0;
   $display->content['new-7'] = $pane;
   $display->panels['right'][0] = 'new-7';
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-8';
   $pane->panel = 'top';
   $pane->type = 'custom';
@@ -365,7 +364,7 @@ function ctools_plugin_example_default_page_manager_pages() {
     'body' => 'The CTools Plugin Example module (and this panel page) are just here to demonstrate how to build CTools plugins.
 
             ',
-    'format' => '2',
+    'format' => 'full_html',
     'substitute' => 1,
   );
   $pane->cache = array();
@@ -378,12 +377,11 @@ function ctools_plugin_example_default_page_manager_pages() {
   $handler->conf['display'] = $display;
   $page->default_handlers[$handler->name] = $handler;
 
-  // end of exported panel.
+  // End of exported panel.
   $pages['ctools_plugin_example_demo_page'] = $page;
 
-  // begin exported panel
-
-  $page = new stdClass;
+  // Begin exported panel.
+  $page = new stdClass();
   $page->disabled = FALSE; /* Edit this to true to make a default page disabled initially */
   $page->api_version = 1;
   $page->name = 'ctools_plugin_example_base';
@@ -396,7 +394,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $page->arguments = array();
   $page->conf = array();
   $page->default_handlers = array();
-  $handler = new stdClass;
+  $handler = new stdClass();
   $handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
   $handler->api_version = 1;
   $handler->name = 'page_ctools_plugin_example_base_panel_context';
@@ -405,14 +403,15 @@ function ctools_plugin_example_default_page_manager_pages() {
   $handler->handler = 'panel_context';
   $handler->weight = 0;
   $handler->conf = array(
-  'title' => 'Panel',
-  'no_blocks' => FALSE,
-  'css_id' => '',
-  'css' => '',
-  'contexts' => array(),
-  'relationships' => array(),
+    'title' => 'Panel',
+    'no_blocks' => FALSE,
+    'css_id' => '',
+    'css' => '',
+    'contexts' => array(),
+    'relationships' => array(),
+    'pipeline' => 'standard',
   );
-  $display = new panels_display;
+  $display = new panels_display();
   $display->layout = 'onecol';
   $display->layout_settings = array();
   $display->panel_settings = array();
@@ -421,7 +420,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $display->hide_title = FALSE;
   $display->content = array();
   $display->panels = array();
-  $pane = new stdClass;
+  $pane = new stdClass();
   $pane->pid = 'new-1';
   $pane->panel = 'middle';
   $pane->type = 'custom';
@@ -431,7 +430,7 @@ function ctools_plugin_example_default_page_manager_pages() {
   $pane->configuration = array(
     'title' => 'Use this page with an argument',
     'body' => 'This demo page works if you use an argument, like <a href="ctools_plugin_example/xxxxx">ctools_plugin_example/xxxxx</a>.',
-    'format' => '1',
+    'format' => 'filtered_html',
     'substitute' => NULL,
   );
   $pane->cache = array();
@@ -443,9 +442,8 @@ function ctools_plugin_example_default_page_manager_pages() {
   $display->panels['middle'][0] = 'new-1';
   $handler->conf['display'] = $display;
   $page->default_handlers[$handler->name] = $handler;
-  // end exported panel.
-
+  // End exported panel.
   $pages['base_page'] = $page;
 
   return $pages;
-}
\ No newline at end of file
+}
diff --git a/ctools_plugin_example/plugins/access/arg_length.inc b/ctools_plugin_example/plugins/access/arg_length.inc
index 2a09eea127d6f75d8f9ef7bffcc96f95fbd49e16..3b5d8636201ff182497e9049106430b1b2898710 100644
--- a/ctools_plugin_example/plugins/access/arg_length.inc
+++ b/ctools_plugin_example/plugins/access/arg_length.inc
@@ -59,7 +59,8 @@ function ctools_plugin_example_arg_length_ctools_access_check($conf, $context) {
  */
 function ctools_plugin_example_arg_length_ctools_access_summary($conf, $context) {
   return t('Simpletext argument must be !comp @length characters',
-    array('!comp' => $conf['greater_than'] ? 'greater than' : 'less than or equal to',
-      '@length' => $conf['arg_length']));
+    array(
+      '!comp' => $conf['greater_than'] ? 'greater than' : 'less than or equal to',
+      '@length' => $conf['arg_length'],
+    ));
 }
-
diff --git a/ctools_plugin_example/plugins/access/example_role.inc b/ctools_plugin_example/plugins/access/example_role.inc
index bbe364c153d8865e85378a391924b416be82b4b6..75721e8b83242302a273b8cebebb0c1d46657965 100644
--- a/ctools_plugin_example/plugins/access/example_role.inc
+++ b/ctools_plugin_example/plugins/access/example_role.inc
@@ -4,7 +4,7 @@
  * @file
  * Plugin to provide access control based upon role membership.
  * This is directly from the ctools module, but serves as a good
- * example of an access plugin
+ * example of an access plugin.
  */
 
 /**
@@ -73,4 +73,3 @@ function ctools_plugin_example_example_role_ctools_access_summary($conf, $contex
   }
   return format_plural(count($names), '@identifier must have role "@roles"', '@identifier can be one of "@roles"', array('@roles' => implode(', ', $names), '@identifier' => $context->identifier));
 }
-
diff --git a/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc b/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc
index 51c7c601c99984998f961cff50d6ba749a4beae7..7fb732c600b23f3352085b65cbad05d47cdaec63 100644
--- a/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc
+++ b/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Sample plugin to provide an argument handler for a simplecontext.
  *
  * Given any argument to the page, simplecontext will get it
@@ -18,14 +17,12 @@
  */
 $plugin = array(
   'title' => t("Simplecontext arg"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'simplecontext',
   'description' => t('Creates a "simplecontext" from the arg.'),
   'context' => 'simplecontext_arg_context',
-  // 'settings form' => 'simplecontext_arg_settings_form',
-
   // placeholder_form is used in panels preview, for example, so we can
-  // preview without getting the arg from a URL
+  // preview without getting the arg from a URL.
   'placeholder form' => array(
     '#type' => 'textfield',
     '#description' => t('Enter the simplecontext arg'),
diff --git a/ctools_plugin_example/plugins/content_types/no_context_content_type.inc b/ctools_plugin_example/plugins/content_types/no_context_content_type.inc
index 3c02ab84fac4cdd0516313f454213ccd96b8495c..48ce0f5ccf047a01236e1d9f65d863ca70c53d26 100644
--- a/ctools_plugin_example/plugins/content_types/no_context_content_type.inc
+++ b/ctools_plugin_example/plugins/content_types/no_context_content_type.inc
@@ -5,7 +5,6 @@
  * "No context" sample content type. It operates with no context at all. It would
  * be basically the same as a 'custom content' block, but it's not even that
  * sophisticated.
- *
  */
 
 /**
@@ -33,7 +32,7 @@ $plugin = array(
   'icon' => 'icon_example.png',
   'category' => array(t('CTools Examples'), -9),
 
-  // this example does not provide 'admin info', which would populate the
+  // This example does not provide 'admin info', which would populate the
   // panels builder page preview.
 );
 
@@ -56,7 +55,7 @@ function no_context_content_type_render($subtype, $conf, $args, $context) {
   $ctools_help = theme('advanced_help_topic', array('module' => 'ctools', 'topic' => 'plugins', 'type' => 'title'));
   $ctools_plugin_example_help = theme('advanced_help_topic', array('module' => 'ctools_plugin_example', 'topic' => 'Chaos-Tools--CTools--Plugin-Examples', 'type' => 'title'));
 
-  // The title actually used in rendering
+  // The title actually used in rendering.
   $block->title = check_plain("No-context content type");
   $block->content = t("
   <div>Welcome to the CTools Plugin Example demonstration content type.
@@ -84,7 +83,6 @@ function no_context_content_type_render($subtype, $conf, $args, $context) {
  * Note that if we had not provided an entry for this in hook_content_types,
  * this could have had the default name
  * ctools_plugin_example_no_context_content_type_edit_form.
- *
  */
 function no_context_content_type_edit_form($form, &$form_state) {
   $conf = $form_state['conf'];
diff --git a/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc b/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc
index bf54dce6433483ce1adfcb84bf42196e6dc8ac29..ced6411715326c4464a6f4c44e4c203672474669 100644
--- a/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc
+++ b/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc
@@ -1,6 +1,5 @@
 <?php
 
-
 /**
  * @file
  * Content type that displays the relcontext context type.
@@ -27,9 +26,8 @@ $plugin = array(
   'category' => array(t('CTools Examples'), -9),
   'edit form' => 'relcontext_edit_form',
 
-  // this example does not provide 'admin info', which would populate the
+  // This example does not provide 'admin info', which would populate the
   // panels builder page preview.
-
 );
 
 /**
@@ -60,7 +58,7 @@ function relcontext_content_type_render($subtype, $conf, $args, $context) {
     In our case, the configuration form (\$conf) has just one field, 'config_item_1;
     and it's configured with:
     ");
-    if (!empty($conf)) {
+  if (!empty($conf)) {
     $block->content .= '<div style="border: 1px solid red;">' . var_export($conf['config_item_1'], TRUE) . '</div>';
   }
   if (!empty($context)) {
@@ -77,7 +75,6 @@ function relcontext_content_type_render($subtype, $conf, $args, $context) {
 /**
  * 'Edit' callback for the content type.
  * This example just returns a form.
- *
  */
 function relcontext_edit_form($form, &$form_state) {
   $conf = $form_state['conf'];
diff --git a/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc b/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc
index a308683c5e959508ada8966cb7de55480f465915..e34fa18e0ae82453f4d117a87c9afbb3bdc04bd4 100644
--- a/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc
+++ b/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc
@@ -1,6 +1,5 @@
 <?php
 
-
 /**
  * @file
  * Sample ctools content type that takes advantage of context.
@@ -9,7 +8,6 @@
  * ctools content type can access and use context. Note that the simplecontext
  * can be either configured manually into a panel or it can be retrieved via
  * an argument.
- *
  */
 
 /**
@@ -31,7 +29,7 @@ $plugin = array(
   'edit form' => 'simplecontext_content_type_edit_form',
   'admin title' => 'ctools_plugin_example_simplecontext_content_type_admin_title',
 
-  // presents a block which is used in the preview of the data.
+  // Presents a block which is used in the preview of the data.
   // Pn Panels this is the preview pane shown on the panels building page.
   'admin info' => 'ctools_plugin_example_simplecontext_content_type_admin_info',
   'category' => array(t('CTools Examples'), -9),
@@ -103,7 +101,6 @@ function simplecontext_content_type_render($subtype, $conf, $args, $context) {
 /**
  * 'Edit' callback for the content type.
  * This example just returns a form.
- *
  */
 function simplecontext_content_type_edit_form($form, &$form_state) {
   $conf = $form_state['conf'];
diff --git a/ctools_plugin_example/plugins/contexts/relcontext.inc b/ctools_plugin_example/plugins/contexts/relcontext.inc
index 0c7ef113556a150a45208c71a150b4df575ace64..61e25db0337167697a7eacc7a035b240bcb05d39 100644
--- a/ctools_plugin_example/plugins/contexts/relcontext.inc
+++ b/ctools_plugin_example/plugins/contexts/relcontext.inc
@@ -80,4 +80,3 @@ function relcontext_settings_form($conf, $external = FALSE) {
   );
   return $form;
 }
-
diff --git a/ctools_plugin_example/plugins/contexts/simplecontext.inc b/ctools_plugin_example/plugins/contexts/simplecontext.inc
index e19a84229617740ce8a4dd422aa4f0b4787799c8..0ee4658d0f716c31ab6b59260ff2a5bbe8567d03 100644
--- a/ctools_plugin_example/plugins/contexts/simplecontext.inc
+++ b/ctools_plugin_example/plugins/contexts/simplecontext.inc
@@ -1,10 +1,8 @@
 <?php
 
-
 /**
  * @file
  * Sample ctools context type plugin that shows how to create a context from an arg.
- *
  */
 
 /**
@@ -14,7 +12,8 @@
 $plugin = array(
   'title' => t("Simplecontext"),
   'description' => t('A single "simplecontext" context, or data element.'),
-  'context' => 'ctools_plugin_example_context_create_simplecontext',  // func to create context
+// Func to create context.
+  'context' => 'ctools_plugin_example_context_create_simplecontext',
   'context name' => 'simplecontext',
   'settings form' => 'simplecontext_settings_form',
   'keyword' => 'simplecontext',
@@ -69,7 +68,7 @@ function ctools_plugin_example_context_create_simplecontext($empty, $data = NULL
     // This is used for keyword.
     $context->title = $data;
     $context->argument = $data;
-    // Make up a bogus context
+    // Make up a bogus context.
     $context->data = new stdClass();
     $context->data->item1 = t("Item1");
     $context->data->item2 = t("Item2");
@@ -102,8 +101,6 @@ function simplecontext_settings_form($conf, $external = FALSE) {
   return $form;
 }
 
-
-
 /**
  * Provide a list of sub-keywords.
  *
@@ -125,10 +122,11 @@ function simplecontext_convert($context, $type) {
   switch ($type) {
     case 'item1':
       return $context->data->item1;
+
     case 'item2':
       return $context->data->item2;
+
     case 'description':
       return $context->data->description;
   }
 }
-
diff --git a/ctools_plugin_example/plugins/panels.pages.inc b/ctools_plugin_example/plugins/panels.pages.inc
index d3022af7fc194a91224bc7663d7d91e0530f62a7..25422cfa64006b717bfb747116ed757a686b304a 100644
--- a/ctools_plugin_example/plugins/panels.pages.inc
+++ b/ctools_plugin_example/plugins/panels.pages.inc
@@ -19,24 +19,24 @@ function ctools_plugin_example_default_panel_pages() {
   $page->load_flags = 1;
   $page->css_id = '';
   $page->arguments = array(
-  0 =>
+    0 =>
   array(
-      'name' => 'simplecontext_arg',
-      'id' => 1,
-      'default' => '404',
-      'title' => '',
-      'identifier' => 'Simplecontext arg',
-      'keyword' => 'simplecontext',
+    'name' => 'simplecontext_arg',
+    'id' => 1,
+    'default' => '404',
+    'title' => '',
+    'identifier' => 'Simplecontext arg',
+    'keyword' => 'simplecontext',
   ),
   );
   $page->relationships = array(
-  0 =>
+    0 =>
   array(
-      'context' => 'argument_simplecontext_arg_1',
-      'name' => 'relcontext_from_simplecontext',
-      'id' => 1,
-      'identifier' => 'Relcontext from Simplecontext',
-      'keyword' => 'relcontext',
+    'context' => 'argument_simplecontext_arg_1',
+    'name' => 'relcontext_from_simplecontext',
+    'id' => 1,
+    'identifier' => 'Relcontext from Simplecontext',
+    'keyword' => 'relcontext',
   ),
   );
   $page->no_blocks = '0';
@@ -58,14 +58,14 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->subtype = 'custom';
   $pane->access = array();
   $pane->configuration = array(
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'title' => '"No Context Item"',
-      'body' => 'The "no context item" content type is here to demonstrate that you can create a content_type that does not require a context. This is probably the same as just creating a custom php block on the fly, and might serve the same purpose.',
-      'format' => '1',
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'title' => '"No Context Item"',
+    'body' => 'The "no context item" content type is here to demonstrate that you can create a content_type that does not require a context. This is probably the same as just creating a custom php block on the fly, and might serve the same purpose.',
+    'format' => '1',
   );
   $pane->cache = array();
   $display->content['new-1'] = $pane;
@@ -78,14 +78,14 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->subtype = 'description';
   $pane->access = array();
   $pane->configuration = array(
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'item1' => 'one',
-      'item2' => 'two',
-      'item3' => 'three',
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'item1' => 'one',
+    'item2' => 'two',
+    'item3' => 'three',
   );
   $pane->cache = array();
   $display->content['new-2'] = $pane;
@@ -98,16 +98,16 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->subtype = 'custom';
   $pane->access = array();
   $pane->configuration = array(
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'title' => 'Simplecontext',
-      'body' => 'The "Simplecontext" content and content type demonstrate a very basic context and how to display it.
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'title' => 'Simplecontext',
+    'body' => 'The "Simplecontext" content and content type demonstrate a very basic context and how to display it.
 
     Simplecontext includes configuration, so it can get info from the config. It can also get its information to run from a simplecontext context, generated either from an arg to the panels page or via explicitly adding a context to the page.',
-      'format' => '1',
+    'format' => '1',
   );
   $pane->cache = array();
   $display->content['new-3'] = $pane;
@@ -119,17 +119,17 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->shown = '1';
   $pane->subtype = 'description';
   $pane->access = array(
-  0 => '2',
-  1 => '4',
+    0 => '2',
+    1 => '4',
   );
   $pane->configuration = array(
-      'context' => 'argument_simplecontext_arg_1',
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'config_item_1' => 'simplecontext called from arg',
+    'context' => 'argument_simplecontext_arg_1',
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'config_item_1' => 'simplecontext called from arg',
   );
   $pane->cache = array();
   $display->content['new-4'] = $pane;
@@ -142,14 +142,14 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->subtype = 'custom';
   $pane->access = array();
   $pane->configuration = array(
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'title' => 'Relcontext',
-      'body' => 'The relcontext content_type gets its data from a relcontext, which is an example of a relationship. This panel should be run with an argument like "/xxx", which allows the simplecontext to get its context, and then the relcontext is configured in this panel to get (create) its data from the simplecontext.',
-      'format' => '1',
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'title' => 'Relcontext',
+    'body' => 'The relcontext content_type gets its data from a relcontext, which is an example of a relationship. This panel should be run with an argument like "/xxx", which allows the simplecontext to get its context, and then the relcontext is configured in this panel to get (create) its data from the simplecontext.',
+    'format' => '1',
   );
   $pane->cache = array();
   $display->content['new-5'] = $pane;
@@ -162,13 +162,13 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->subtype = 'description';
   $pane->access = array();
   $pane->configuration = array(
-      'context' => 'relationship_relcontext_from_simplecontext_1',
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'config_item_1' => 'default1',
+    'context' => 'relationship_relcontext_from_simplecontext_1',
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'config_item_1' => 'default1',
   );
   $pane->cache = array();
   $display->content['new-6'] = $pane;
@@ -181,13 +181,13 @@ function ctools_plugin_example_default_panel_pages() {
   $pane->subtype = 'custom_php';
   $pane->access = array();
   $pane->configuration = array(
-      'style' => 'default',
-      'override_title' => 0,
-      'override_title_text' => '',
-      'css_id' => '',
-      'css_class' => '',
-      'title' => '',
-      'body' => '$arg = arg(1);
+    'style' => 'default',
+    'override_title' => 0,
+    'override_title_text' => '',
+    'css_id' => '',
+    'css_class' => '',
+    'title' => '',
+    'body' => '$arg = arg(1);
     $arg0 = arg(0);
     if (!$arg) {
     $block->content = <<<END
@@ -209,6 +209,5 @@ END;
   $page->displays = array();
   $pages['ctools_plugin_example'] = $page;
 
-
   return $pages;
 }
diff --git a/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc b/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc
index 6224621042338ee1c60bc760c4d4eaa4068c4a19..31d7b00b3fbc3fc60998b9cc0d11f2f2bfc6ab2b 100644
--- a/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc
+++ b/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc
@@ -1,9 +1,7 @@
 <?php
 
-
 /**
  * @file
- *
  * Sample relationship plugin.
  *
  * We take a simplecontext, look in it for what we need to make a relcontext, and make it.
@@ -26,14 +24,13 @@ $plugin = array(
 /**
  * Return a new context based on an existing context.
  */
-function ctools_relcontext_from_simplecontext_context($context = NULL, $conf) {
+function ctools_relcontext_from_simplecontext_context($context, $conf) {
   // If unset it wants a generic, unfilled context, which is just NULL.
   if (empty($context->data)) {
     return ctools_context_create_empty('relcontext', NULL);
   }
 
   // You should do error-checking here.
-
   // Create the new context from some element of the parent context.
   // In this case, we'll pass in the whole context so it can be used to
   // create the relcontext.
@@ -47,4 +44,3 @@ function ctools_relcontext_from_simplecontext_settings_form($conf) {
   // We won't configure it in this case.
   return array();
 }
-
diff --git a/drush/ctools.drush.inc b/drush/ctools.drush.inc
index 1862dbe9480fb63940c5f5fee2db8837d2d64f22..34fd4d3a571de8ed720bb39269ff28f445e3021a 100644
--- a/drush/ctools.drush.inc
+++ b/drush/ctools.drush.inc
@@ -64,7 +64,7 @@ function ctools_drush_command() {
       'machine names' => 'Space separated list of exportables you want to view.',
     ),
     'options' => array(
-      'indent' => 'The string to use for indentation when dispalying the exportable export code. Defaults to \'\'.',
+      'indent' => 'The string to use for indentation when displaying the exportable export code. Defaults to \'\'.',
       'no-colour' => 'Remove any colour formatting from export string output. Ideal if you are sending the output of this command to a file.',
       'module' => $module_text,
       'all' => $all_text,
@@ -140,13 +140,14 @@ function ctools_drush_help($section) {
   switch ($section) {
     case 'meta:ctools:title':
       return dt('CTools commands');
+
     case 'meta:entity:summary':
       return dt('CTools drush commands.');
   }
 }
 
 /**
- * Drush callback: export
+ * Drush callback: export.
  */
 function ctools_drush_export($module = 'foo') {
   $error = FALSE;
@@ -338,7 +339,7 @@ function _ctools_drush_selection_screen(array $tables = array()) {
       $build[$table_choice]['count'] = count($multi_select);
       $selections[$table_choice] = array();
       foreach ($multi_select as $key) {
-         $selections[$table_choice][$key] = $key;
+        $selections[$table_choice][$key] = $key;
       }
     }
   }
@@ -445,11 +446,13 @@ function ctools_drush_export_info() {
     }
   }
 }
+
 /**
  * Drush callback: Acts as the hub for all op commands to keep
  * all arg handling etc in one place.
  */
 function ctools_drush_export_op_command() {
+  $args = func_get_args();
   // Get all info for the current drush command.
   $command = drush_get_command();
   $op = '';
@@ -457,17 +460,20 @@ function ctools_drush_export_op_command() {
   switch ($command['command']) {
     case 'ctools-export-view':
       $op = 'view';
-    break;
+      break;
+
     case 'ctools-export-revert':
       // Revert is same as deleting. As any objects in the db are deleted.
       $op = 'delete';
-    break;
+      break;
+
     case 'ctools-export-enable':
       $op = 'enable';
-    break;
+      break;
+
     case 'ctools-export-disable':
       $op = 'disable';
-    break;
+      break;
   }
 
   if (!$op) {
@@ -475,7 +481,7 @@ function ctools_drush_export_op_command() {
   }
 
   if (drush_get_option('all', FALSE)) {
-    $info = _ctools_drush_export_info('', TRUE);
+    $info = _ctools_drush_export_info(array(), TRUE);
     $exportable_info = $info['exportables'];
 
     $all = drush_confirm(dt('Are you sure you would like to !op all exportables on the system?',
@@ -490,7 +496,6 @@ function ctools_drush_export_op_command() {
     }
   }
   else {
-    $args = func_get_args();
     // Table name should always be first arg...
     $table_name = array_shift($args);
     // Any additional args are assumed to be exportable names.
@@ -512,7 +517,6 @@ function ctools_drush_export_op_command() {
  * @param $op
  * @param $table_name
  * @param $exportables
- *
  */
 function ctools_drush_export_op($op = '', $table_name = '', $exportables = NULL) {
   $objects = ctools_export_crud_load_multiple($table_name, array_keys($exportables));
@@ -538,7 +542,7 @@ function ctools_drush_export_op($op = '', $table_name = '', $exportables = NULL)
  * @param $object_names
  *
  * @return
- *    Array of exportable objects (filtered if necessary, by name etc..) or FALSE if not.
+ *   Array of exportable objects (filtered if necessary, by name etc..) or FALSE if not.
  */
 function _ctools_drush_export_op_command_logic($op = '', $table_name = NULL, array $object_names = array()) {
   if (!$table_name) {
@@ -644,7 +648,7 @@ function _ctools_drush_export_info(array $table_names = array(), $load = FALSE)
   return array('exportables' => $exportables, 'schemas' => $schemas);
 }
 
-/*
+/**
  * View a single object.
  *
  * @param $table_name
@@ -662,7 +666,7 @@ function _ctools_drush_export_view($table_name, $object) {
   }
 }
 
-/*
+/**
  * Revert a single object.
  *
  * @param $table_name
@@ -681,7 +685,7 @@ function _ctools_drush_export_delete($table_name, $object) {
   }
 }
 
-/*
+/**
  * Enable a single object.
  *
  * @param $table_name
@@ -701,7 +705,7 @@ function _ctools_drush_export_enable($table_name, $object) {
   }
 }
 
-/*
+/**
  * Disable a single object.
  *
  * @param $table_name
@@ -723,9 +727,9 @@ function _ctools_drush_export_disable($table_name, $object) {
 /**
  * Filter a nested array of exportables by export module.
  *
- * @param $exportables array
+ * @param array $exportables
  *   Passed by reference. A nested array of exportables, keyed by table name.
- * @param $export_module string
+ * @param string $export_module
  *   The name of the export module providing the exportable.
  */
 function _ctools_drush_export_module_filter($exportables, $export_module) {
@@ -778,7 +782,7 @@ function _ctools_drush_object_is_disabled($object) {
 /**
  * Determine if an object is enabled.
  *
- * @see _ctools_drush_object_is_disabled.
+ * @see _ctools_drush_object_is_disabled()
  */
 function _ctools_drush_object_is_enabled($object) {
   return (empty($object->disabled)) ? TRUE : FALSE;
@@ -835,7 +839,7 @@ function _ctools_drush_object_is_not_code_only($object) {
  *   Array of exportables to count.
  *
  * @return
- *    Array of count data containing the following:
+ *   Array of count data containing the following:
  *     'total' - A total count of all exportables.
  *     'exportables' - An array of exportable counts per table.
  */
@@ -867,26 +871,32 @@ function _ctools_drush_filter_exportables($exportables, $filter) {
       // Show enabled exportables only.
       case 'enabled':
         $eval = '_ctools_drush_object_is_disabled';
-      break;
+        break;
+
       // Show disabled exportables only.
       case 'disabled':
         $eval = '_ctools_drush_object_is_enabled';
-      break;
+        break;
+
       // Show overridden exportables only.
       case 'overridden':
         $eval = '_ctools_drush_object_is_not_overridden';
-      break;
+        break;
+
       // Show database only exportables.
       case 'database':
         $eval = '_ctools_drush_object_is_not_db_only';
-      break;
+        break;
+
       // Show code only exportables.
       case 'code':
         $eval = '_ctools_drush_object_is_not_code_only';
-      break;
+        break;
+
       // Do nothing.
       case 'all':
         break;
+
       default:
         drush_log(dt('Invalid filter option. Available options are: enabled, disabled, overridden, database, and code.'), 'error');
         return;
@@ -983,33 +993,42 @@ class shellColours {
     'light_gray' => '47',
   );
 
+  /**
+   * shellColours constructor.
+   */
   private function __construct() {}
 
-  // Returns coloured string
+  /**
+   * Returns coloured string.
+   */
   public static function getColouredOutput($string, $foreground_colour = NULL, $background_colour = NULL) {
     $coloured_string = "";
 
-    // Check if given foreground colour found
+    // Check if given foreground colour found.
     if ($foreground_colour) {
       $coloured_string .= "\033[" . self::$foreground_colours[$foreground_colour] . "m";
     }
-    // Check if given background colour found
+    // Check if given background colour found.
     if ($background_colour) {
       $coloured_string .= "\033[" . self::$background_colours[$background_colour] . "m";
     }
 
-    // Add string and end colouring
-    $coloured_string .=  $string . "\033[0m";
+    // Add string and end colouring.
+    $coloured_string .= $string . "\033[0m";
 
     return $coloured_string;
   }
 
-  // Returns all foreground colour names
+  /**
+   * Returns all foreground colour names.
+   */
   public static function getForegroundColours() {
     return array_keys(self::$foreground_colours);
   }
 
-  // Returns all background colour names
+  /**
+   * Returns all background colour names.
+   */
   public static function getBackgroundColours() {
     return array_keys(self::$background_colours);
   }
diff --git a/help/export.html b/help/export.html
index ce24cad9fd022f9252ab32054fdaf94ce57f3e59..573c98a68c6c87d0606c5aa064f9da0cbcd7a857 100644
--- a/help/export.html
+++ b/help/export.html
@@ -154,7 +154,7 @@ function mymodule_schema() {
 <dd>Bulk export callback to provide a list of exportable objects to be chosen for bulk exporting. Defaults to $module . '_' . $table . '_list' if the function exists. If it is not, a default listing function will be provided that will make a best effort to list the titles. See ctools_export_default_list().</dd>
 
 <dt>to hook code callback</dt>
-<dd>Function used to generate an export for the bulk export process. This is only necessary if the export is more complicated than simply listing the fields. Defaults to $module . '_' . $table . '_to_hook_code'.</dt>
+<dd>Function used to generate an export for the bulk export process. This is only necessary if the export is more complicated than simply listing the fields. Defaults to $module . '_' . $table . '_to_hook_code'.</dd>
 
 <dt>boolean</dt>
 <dd>Explicitly indicate if a table field contains a boolean or not. The Schema API does not model the
diff --git a/help/modal.html b/help/modal.html
index ea823a0deab7c06d8cbea694188f29fb9fb5d884..761fd2e32c02890a538212f7b41ad93e54c3a60a 100644
--- a/help/modal.html
+++ b/help/modal.html
@@ -82,7 +82,7 @@ function ctools_modal_text_button($text, $dest, $alt, $class = '') {
     <li> <strong>modalSize</strong>: an array of data to control the sizing of the modal. It can contain:
   <ul>
   <li> <strong>type</strong>: Either <em>fixed</em> or <em>scale</em>. If fixed, the modal will always be a fixed size. If <em>scale</em> the modal will scale to a percentage of the browser window. <em>Default: scale</em>.
-<li> <strong>width</strong>: If </em>fixed</em> the width in pixels. If <em>scale</em> the percentage of the screen expressed as a number less than zero. (For 80 percent, use .8, for example). <em>Default: .8</em></li>
+<li> <strong>width</strong>: If <em>fixed</em> the width in pixels. If <em>scale</em> the percentage of the screen expressed as a number less than zero. (For 80 percent, use .8, for example). <em>Default: .8</em></li>
 <li> <strong>height</strong>: If <em>fixed</em> the height in pixels. If <em>scale</em> the percentage of the screen expressed as a number less than zero. (For 80 percent, use .8, for example). <em>Default: .8</em></li>
 <li> <strong>addWidth</strong>: Any additional width to add to the modal in pixels. Only useful if the type is scale. <em>Default: 0</em></li>
 <li> <strong>addHeight</strong>: Any additional height to add to the modal in pixels. Only useful if the type is scale. <em>Default: 0</em></li>
@@ -168,7 +168,7 @@ function ctools_ajax_sample_login($js) {
 <pre>
 function ctools_ajax_hello_world($js) {
   $title = t('Greetings');
-  $output = '&lt;p&gt;' . t('Hello world') . ''&lt;/p&gt;';
+  $output = '&lt;p&gt;' . t('Hello world') . '&lt;/p&gt;';
   if ($js) {
     ctools_modal_render($title, $output);
   }
diff --git a/help/plugins-creating.html b/help/plugins-creating.html
index 23237058e5c5c803a5c45e457297f1dd54f4a7e7..6d5b35f615231af560ee0a4e420b026e6fd70015 100644
--- a/help/plugins-creating.html
+++ b/help/plugins-creating.html
@@ -26,7 +26,7 @@ The following information can be specified for each plugin type:
 <dd>If 'cache' is TRUE, then this value specifies the cache table where the cached plugin information will be stored.</dd>
 <dt>classes</dt>
 <dd><em>Defaults to:</em> <strong>array()</strong></dd>
-<dd>An array of <em>class identifiers</em>(i.e. plugin array keys) which a plugin of this type uses to provide classes to the CTools autoloader. For example, if <strong>classes</strong> is set to array('class'), then CTools will search each <strong>$plugin['class']</strong> for a class to autoload. Depending of the plugin structure, a <em>class identifier</em> may be either:</dd>
+<dd>An array of <em>class identifiers</em>(i.e. plugin array keys) which a plugin of this type uses to provide classes to the CTools autoloader. For example, if <strong>classes</strong> is set to array('class'), then CTools will search each <strong>$plugin['class']</strong> for a class to autoload. Depending of the plugin structure, a <em>class identifier</em> may be either:
 <dl>
 <dt>- a file name:</dt>
 <dd>the file which holds the class with the name structure as: <em>[filename].[class].php</em></dd>
@@ -35,6 +35,7 @@ The following information can be specified for each plugin type:
 <dd>if the class is in the same file as the $plugin</dd>
 <dd>the plugin <em>.inc</em> file can have a different name than the <em>class identifier</em></dd>
 </dl>
+<dd>
 <dt>defaults</dt>
 <dd><em>Defaults to:</em> <strong>array()</strong></dd>
 <dd>An array of defaults that should be added to each plugin; this can be used to ensure that every plugin has the basic data necessary. These defaults will not ovewrite data supplied by the plugin. This could also be a function name, in which case the callback will be used to provide defaults. NOTE, however, that the callback-based approach is deprecated as it is redundant with the 'process' callback, and as such will be removed in later versions. Consequently, you should only use the array form for maximum cross-version compatibility.</dd>
diff --git a/includes/action-links.theme.inc b/includes/action-links.theme.inc
index 3a2398a1fd35416c07a946a1d03d89c5d5dedab1..f53f59c84183de5944fe65861dccade5a67ca448 100644
--- a/includes/action-links.theme.inc
+++ b/includes/action-links.theme.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Theme function for wrapping menu local actions.
@@ -30,4 +31,4 @@ function theme_ctools_menu_local_actions_wrapper($variables) {
   }
 
   return '<ul class="action-links">' . $links . '</ul>';
-}
\ No newline at end of file
+}
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 96f5068f3010cab75585656c0d33f96caf333085..4d72d0c6b3989a1c71f8de4fb9dc6026c081c2a3 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -1,6 +1,10 @@
 <?php
 
-// Set this so we can tell that the file has been included at some point.
+/**
+ * @file
+ * Set this so we can tell that the file has been included at some point.
+ */
+
 define('CTOOLS_AJAX_INCLUDED', 1);
 
 /**
@@ -85,17 +89,17 @@ function ctools_ajax_icon_text_button($text, $image, $dest, $alt, $class = '', $
  * @param $name
  *   The name or key: of the data attached to this selector.
  * @param $value
- *  The value of the data.
+ *   The value of the data.
  */
 function ctools_ajax_command_attr($selector, $name, $value) {
   ctools_add_js('ajax-responder');
   return array(
-     'command' => 'attr',
-     'selector' => $selector,
-     'name' => $name,
-     'value' => $value,
-   );
- }
+    'command' => 'attr',
+    'selector' => $selector,
+    'name' => $name,
+    'value' => $value,
+  );
+}
 
 /**
  * Force a client-side redirect.
@@ -154,4 +158,3 @@ function ctools_ajax_render_error($error = '') {
   print ajax_render($commands);
   exit;
 }
-
diff --git a/includes/cache.inc b/includes/cache.inc
index 3918683b02a16083088b4952366ae046089ce870..cace8002ecbc693fcbdc382adabeac843d2a772e 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Plugins to handle cache-indirection.
  *
  * Simple plugin management to allow clients to more tightly control where
@@ -52,7 +51,6 @@
  * @param string $mechanism
  *   A string containing the plugin name, and an optional data element to
  *   send to the plugin separated by two colons.
- *
  * @param string $key
  *   The key used to identify the cache.
  *
@@ -70,7 +68,6 @@ function ctools_cache_get($mechanism, $key) {
  * @param string $mechanism
  *   A string containing the plugin name, and an optional data element to
  *   send to the plugin separated by two colons.
- *
  * @param string $key
  *   The key used to identify the cache.
  *
@@ -88,7 +85,6 @@ function ctools_cache_set($mechanism, $key, $object) {
  * @param string $mechanism
  *   A string containing the plugin name, and an optional data element to
  *   send to the plugin separated by two colons.
- *
  * @param string $key
  *   The key used to identify the cache.
  */
@@ -108,13 +104,10 @@ function ctools_cache_clear($mechanism, $key) {
  * @param string $mechanism
  *   A string containing the plugin name, and an optional data element to
  *   send to the plugin separated by two colons.
- *
  * @param string $key
  *   The key used to identify the cache.
- *
  * @param string $op
  *   The operation to call, such as 'break' or 'finalize'.
- *
  * @param mixed $object
  *   The cache data being operated on, in case it is necessary. This is
  *   optional so no references should be used.
@@ -150,7 +143,7 @@ function ctools_cache_operation($mechanism, $key, $op, $object = NULL) {
  */
 function ctools_cache_find_plugin($mechanism) {
   if (strpos($mechanism, '::') !== FALSE) {
-    // use explode(2) to ensure that the data can contain double
+    // Use explode(2) to ensure that the data can contain double
     // colons, just in case.
     list($name, $data) = explode('::', $mechanism, 2);
   }
diff --git a/includes/cleanstring.inc b/includes/cleanstring.inc
index 56b3e36f47857654ec9f9972c0b458d7c67e65d3..11ffceff6c58cc30ced90c445e5a4e24ca375665 100644
--- a/includes/cleanstring.inc
+++ b/includes/cleanstring.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id $
 
 /**
  * @file
@@ -21,7 +20,7 @@
 /**
  * Matches Unicode character classes.
  *
- * See: http://www.unicode.org/Public/UNIDATA/UCD.html#General_Category_Values
+ * See: http://www.unicode.org/Public/UNIDATA/UCD.html#General_Category_Values.
  *
  * The index only contains the following character classes:
  *   Lu  Letter, Uppercase
@@ -129,13 +128,13 @@ function ctools_cleanstring($string, $settings = array()) {
     $output = transliteration_get($output);
   }
 
-  // Reduce to the subset of ASCII96 letters and numbers
+  // Reduce to the subset of ASCII96 letters and numbers.
   if ($settings['reduce ascii']) {
     $pattern = '/[^a-zA-Z0-9\/]+/';
     $output = preg_replace($pattern, $settings['separator'], $output);
   }
 
-  // Get rid of words that are on the ignore list
+  // Get rid of words that are on the ignore list.
   if (!empty($settings['ignore words'])) {
     $ignore_re = '\b' . preg_replace('/,/', '\b|\b', $settings['ignore words']) . '\b';
 
@@ -159,14 +158,14 @@ function ctools_cleanstring($string, $settings = array()) {
     else {
       $seppattern = '\\' . $settings['separator'];
     }
-    // Trim any leading or trailing separators (note the need to
+    // Trim any leading or trailing separators (note the need to.
     $output = preg_replace("/^$seppattern+|$seppattern+$/", '', $output);
 
-    // Replace multiple separators with a single one
+    // Replace multiple separators with a single one.
     $output = preg_replace("/$seppattern+/", $settings['separator'], $output);
   }
 
-  // Enforce the maximum component length
+  // Enforce the maximum component length.
   if (!empty($settings['max length'])) {
     $output = ctools_cleanstring_truncate($output, $settings['max length'], $settings['separator']);
   }
@@ -188,12 +187,14 @@ function ctools_cleanstring($string, $settings = array()) {
  *   A string which contains the word boundary such as - or _.
  *
  * @return
- *  The string truncated below the maxlength.
+ *   The string truncated below the maxlength.
  */
 function ctools_cleanstring_truncate($string, $length, $separator) {
   if (drupal_strlen($string) > $length) {
-    $string = drupal_substr($string, 0, $length + 1); // leave one more character
-    if ($last_break = strrpos($string, $separator)) { // space exists AND is not on position 0
+    // Leave one more character.
+    $string = drupal_substr($string, 0, $length + 1);
+    // Space exists AND is not on position 0.
+    if ($last_break = strrpos($string, $separator)) {
       $string = substr($string, 0, $last_break);
     }
     else {
diff --git a/includes/collapsible.theme.inc b/includes/collapsible.theme.inc
index f7bbbb376f59ffd2ded7e88f6ae1db4a1d9bb0fb..81df4bccd2aacdaa15fa1afa6c53cc609eb00f3f 100644
--- a/includes/collapsible.theme.inc
+++ b/includes/collapsible.theme.inc
@@ -30,8 +30,8 @@ function ctools_collapsible_theme(&$items) {
  *   Text to put in the handle/title area of the div.
  * @param $content
  *   Text to put in the content area of the div, this is what will get
- *   collapsed
- * @param $collapsed = FALSE
+ *   collapsed.
+ * @param $collapsed
  *   If true, this div will start out collapsed.
  */
 function theme_ctools_collapsible($vars) {
@@ -56,8 +56,8 @@ function theme_ctools_collapsible($vars) {
  *   Text to put in the handle/title area of the div.
  * @param $content
  *   Text to put in the content area of the div, this is what will get
- *   collapsed
- * @param $collapsed = FALSE
+ *   collapsed.
+ * @param $collapsed
  *   If true, this div will start out collapsed.
  */
 function theme_ctools_collapsible_remembered($vars) {
@@ -76,4 +76,3 @@ function theme_ctools_collapsible_remembered($vars) {
 
   return $output;
 }
-
diff --git a/includes/content.inc b/includes/content.inc
index e0e5534f10e879d18eb422c070952f02266819f5..49c356502686899996a7ac3e366362075b64d80b 100644
--- a/includes/content.inc
+++ b/includes/content.inc
@@ -86,7 +86,7 @@ function ctools_content_process(&$plugin, $info) {
 /**
  * Fetch metadata on a specific content_type plugin.
  *
- * @param $content type
+ * @param mixed $content
  *   Name of a panel content type.
  *
  * @return
@@ -146,7 +146,7 @@ function ctools_content_get_subtypes($type) {
     if (is_array($function)) {
       $subtypes = $function;
     }
-    else if (function_exists($function)) {
+    elseif (function_exists($function)) {
       // Cast to array to prevent errors from non-array returns.
       $subtypes = (array) $function($plugin);
     }
@@ -155,6 +155,11 @@ function ctools_content_get_subtypes($type) {
   // Walk through the subtypes and ensure minimal settings are
   // retained.
   foreach ($subtypes as $id => $subtype) {
+    // Ensure that the 'subtype_id' value exists.
+    if (!isset($subtype['subtype_id'])) {
+      $subtypes[$id]['subtype_id'] = $id;
+    }
+
     // Use exact name since this is a modify by reference.
     ctools_content_prepare_subtype($subtypes[$id], $plugin);
   }
@@ -202,6 +207,13 @@ function ctools_content_get_subtype($type, $subtype_id) {
   }
 
   if ($subtype) {
+    // Ensure that the 'subtype_id' value exists. This is also done in
+    // ctools_content_get_subtypes(), but it wouldn't be called if the plugin
+    // provides the subtype through its own function.
+    if (!isset($subtype['subtype_id'])) {
+      $subtype['subtype_id'] = $subtype_id;
+    }
+
     ctools_content_prepare_subtype($subtype, $plugin);
   }
   return $subtype;
@@ -217,6 +229,7 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
     }
   }
 
+  // Trigger hook_ctools_content_subtype_alter().
   drupal_alter('ctools_content_subtype', $subtype, $plugin);
 }
 
@@ -241,9 +254,10 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
  *   Any incoming content, if this display is a wrapper.
  *
  * @return
- *   The content as rendered by the plugin. This content should be an array
- *   with the following possible keys:
+ *   The content as rendered by the plugin, or NULL.
+ *   This content should be an object with the following possible properties:
  *   - title: The safe to render title of the content.
+ *   - title_heading: The title heading.
  *   - content: The safe to render HTML content.
  *   - links: An array of links associated with the content suitable for
  *     theme('links').
@@ -293,21 +307,22 @@ function ctools_content_render($type, $subtype, $conf, $keywords = array(), $arg
       $content->subtype = $subtype;
     }
 
-    // Override the title if configured to
+    // Override the title if configured to.
     if (!empty($conf['override_title'])) {
       // Give previous title as an available substitution here.
       $keywords['%title'] = empty($content->title) ? '' : $content->title;
       $content->original_title = $keywords['%title'];
       $content->title = $conf['override_title_text'];
+      $content->title_heading = isset($conf['override_title_heading']) ? $conf['override_title_heading'] : 'h2';
     }
 
     if (!empty($content->title)) {
-      // Perform substitutions
+      // Perform substitutions.
       if (!empty($keywords) || !empty($context)) {
         $content->title = ctools_context_keyword_substitute($content->title, $keywords, $context);
       }
 
-      // Sterilize the title
+      // Sterilize the title.
       $content->title = filter_xss_admin($content->title);
 
       // If a link is specified, populate.
@@ -318,7 +333,7 @@ function ctools_content_render($type, $subtype, $conf, $keywords = array(), $arg
         else {
           $url = $content->title_link;
         }
-        // set defaults so we don't bring up notices
+        // Set defaults so we don't bring up notices.
         $url += array('href' => '', 'attributes' => array(), 'query' => array(), 'fragment' => '', 'absolute' => NULL, 'html' => TRUE);
         $content->title = l($content->title, $url['href'], $url);
       }
@@ -339,7 +354,16 @@ function ctools_content_editable($type, $subtype, $conf) {
     return FALSE;
   }
 
-  if ($function = ctools_plugin_get_function($subtype, 'check editable')) {
+  $function = FALSE;
+
+  if (!empty($subtype['check editable'])) {
+    $function = ctools_plugin_get_function($subtype, 'check editable');
+  }
+  elseif (!empty($type['check editable'])) {
+    $function = ctools_plugin_get_function($type, 'check editable');
+  }
+
+  if ($function) {
     return $function($type, $subtype, $conf);
   }
 
@@ -362,7 +386,7 @@ function ctools_content_admin_title($type, $subtype, $conf, $context = NULL) {
   if (is_array($type)) {
     $plugin = $type;
   }
-  else if (is_string($type)) {
+  elseif (is_string($type)) {
     $plugin = ctools_get_content_type($type);
   }
   else {
@@ -380,10 +404,10 @@ function ctools_content_admin_title($type, $subtype, $conf, $context = NULL) {
 
     return $function($subtype, $conf, $pane_context);
   }
-  else if (isset($plugin['admin title'])) {
+  elseif (isset($plugin['admin title'])) {
     return $plugin['admin title'];
   }
-  else if (isset($plugin['title'])) {
+  elseif (isset($plugin['title'])) {
     return $plugin['title'];
   }
 }
@@ -418,7 +442,7 @@ function ctools_content_get_defaults($plugin, $subtype) {
   if (isset($plugin['defaults'])) {
     $defaults = $plugin['defaults'];
   }
-  else if (isset($subtype['defaults'])) {
+  elseif (isset($subtype['defaults'])) {
     $defaults = $subtype['defaults'];
   }
   if (isset($defaults)) {
@@ -427,7 +451,7 @@ function ctools_content_get_defaults($plugin, $subtype) {
         return $return;
       }
     }
-    else if (is_array($defaults)) {
+    elseif (is_array($defaults)) {
       return $defaults;
     }
   }
@@ -461,7 +485,7 @@ function ctools_content_admin_info($type, $subtype, $conf, $context = NULL) {
 
   if (empty($output) || !is_object($output)) {
     $output = new stdClass();
-    // replace the _ with " " for a better output
+    // Replace the _ with " " for a better output.
     $subtype = check_plain(str_replace("_", " ", $subtype));
     $output->title = $subtype;
     $output->content = t('No info available.');
@@ -470,7 +494,7 @@ function ctools_content_admin_info($type, $subtype, $conf, $context = NULL) {
 }
 
 /**
- * Add the default FAPI elements to the content type configuration form
+ * Add the default FAPI elements to the content type configuration form.
  */
 function ctools_content_configure_form_defaults($form, &$form_state) {
   $plugin = $form_state['plugin'];
@@ -504,8 +528,26 @@ function ctools_content_configure_form_defaults($form, &$form_state) {
       '#size' => 35,
       '#id' => 'override-title-textfield',
       '#dependency' => array('override-title-checkbox' => array(1)),
-      '#dependency_type' => 'disable',
+      '#dependency_type' => 'hidden',
     );
+    $form['override_title_heading'] = array(
+      '#type' => 'select',
+      '#default_value' => isset($conf['override_title_heading']) ? $conf['override_title_heading'] : 'h2',
+      '#options' => array(
+        'h1' => t('h1'),
+        'h2' => t('h2'),
+        'h3' => t('h3'),
+        'h4' => t('h4'),
+        'h5' => t('h5'),
+        'h6' => t('h6'),
+        'div' => t('div'),
+        'span' => t('span'),
+      ),
+      '#id' => 'override-title-heading',
+      '#dependency' => array('override-title-checkbox' => array(1)),
+      '#dependency_type' => 'hidden',
+    );
+
     $form['aligner_stop'] = array(
       '#markup' => '</div>',
     );
@@ -536,6 +578,7 @@ function ctools_content_configure_form_defaults_submit(&$form, &$form_state) {
   if (isset($form_state['values']['override_title'])) {
     $form_state['conf']['override_title'] = $form_state['values']['override_title'];
     $form_state['conf']['override_title_text'] = $form_state['values']['override_title_text'];
+    $form_state['conf']['override_title_heading'] = $form_state['values']['override_title_heading'];
   }
 }
 
@@ -568,7 +611,7 @@ function ctools_content_form($op, $form_info, &$form_state, $plugin, $subtype_na
     if (!empty($subtype['add form'])) {
       _ctools_content_create_form_info($form_info, $subtype['add form'], $subtype, $subtype, $op);
     }
-    else if (!empty($plugin['add form'])) {
+    elseif (!empty($plugin['add form'])) {
       _ctools_content_create_form_info($form_info, $plugin['add form'], $plugin, $subtype, $op);
     }
   }
@@ -578,7 +621,7 @@ function ctools_content_form($op, $form_info, &$form_state, $plugin, $subtype_na
     if (!empty($subtype['edit form'])) {
       _ctools_content_create_form_info($form_info, $subtype['edit form'], $subtype, $subtype, $op);
     }
-    else if (!empty($plugin['edit form'])) {
+    elseif (!empty($plugin['edit form'])) {
       _ctools_content_create_form_info($form_info, $plugin['edit form'], $plugin, $subtype, $op);
     }
   }
@@ -597,7 +640,7 @@ function _ctools_content_create_form_info(&$form_info, $info, $plugin, $subtype,
     if (empty($subtype['title'])) {
       $title = t('Configure');
     }
-    else if ($op == 'add') {
+    elseif ($op == 'add') {
       $title = t('Configure new !subtype_title', array('!subtype_title' => $subtype['title']));
     }
     else {
@@ -612,7 +655,7 @@ function _ctools_content_create_form_info(&$form_info, $info, $plugin, $subtype,
       ),
     );
   }
-  else if (is_array($info)) {
+  elseif (is_array($info)) {
     $form_info['order'] = array();
     $form_info['forms'] = array();
     $count = 0;
@@ -663,7 +706,7 @@ function ctools_content_get_available_types($contexts = NULL, $has_content = FAL
 
   foreach ($plugins as $id => $plugin) {
     foreach (ctools_content_get_subtypes($plugin) as $subtype_id => $subtype) {
-      // exclude items that require content if we're saying we don't
+      // Exclude items that require content if we're saying we don't
       // provide it.
       if (!empty($subtype['requires content']) && !$has_content) {
         continue;
@@ -703,7 +746,6 @@ function ctools_content_get_available_types($contexts = NULL, $has_content = FAL
  * Get an array of all content types that can be fed into the
  * display editor for the add content list, regardless of
  * availability.
- *
  */
 function ctools_content_get_all_types() {
   $plugins = ctools_get_content_types();
diff --git a/includes/content.menu.inc b/includes/content.menu.inc
index c14c36836aadbddf1786f7899020627a2cb63434..64d44b0bf87db2cb182871b4b9fd5e4ba5358e39 100644
--- a/includes/content.menu.inc
+++ b/includes/content.menu.inc
@@ -23,10 +23,14 @@ function ctools_content_menu(&$items) {
 /**
  * Helper function for autocompletion of entity titles.
  */
-function ctools_content_autocomplete_entity($type, $string = '') {
+function ctools_content_autocomplete_entity($entity_type, $string = '') {
   if ($string != '') {
-    global $user;
-    $entity_info = entity_get_info($type);
+    $entity_info = entity_get_info($entity_type);
+
+    if (!module_exists('entity')) {
+      module_load_include('inc', 'ctools', 'includes/entity-access');
+      _ctools_entity_access($entity_info, $entity_type);
+    }
 
     // We must query all ids, because if every one of the 10 don't have access
     // the user may never be able to autocomplete a node title.
@@ -39,78 +43,77 @@ function ctools_content_autocomplete_entity($type, $string = '') {
     // If an ID match was found, use that ID rather than the whole string.
     if ($match) {
       $entity_id = $preg_matches[1];
-      $entity = entity_load($type, array($entity_id));
-
-      // Format results in an array so later we could add attributes to the
-      // autocomplete text that is returned.
-      $results = array($entity_id => array(
-        'label' => $entity[$entity_id]->$entity_info['entity keys']['label'],
-      ));
+      $results = _ctools_getReferencableEntities($entity_type, $entity_info, $entity_id, '=', 1);
     }
     else {
-      $results = _ctools_getReferencableEntities($type, $entity_info, $string, 'LIKE', 10);
-    }
-    foreach($results as $entity_id => $result) {
-      if (!$entity_info['entity keys']['label']) {
-         $matches["[id: $entity_id]"] = '<span class="autocomplete_title">' . $entity_id . '</span>';
-      }
-      else {
-        $matches[$result['label'] . " [id: $entity_id]"] = '<span class="autocomplete_title">' . check_plain($result['label']) . '</span>';
+      // We cannot find results if the entity doesn't have a label to search.
+      if (!isset($entity_info['entity keys']['label'])) {
+        drupal_json_output(array("[id: NULL]" => '<span class="autocomplete_title">' . t('Entity Type !entity_type does not support autocomplete search.', array('!entity_type' => $entity_type)) . '</span>'));
+        return;
       }
+      $results = _ctools_getReferencableEntities($entity_type, $entity_info, $string, 'LIKE', 10);
+    }
+    foreach ($results as $entity_id => $result) {
+      $matches[$result['label'] . " [id: $entity_id]"] = '<span class="autocomplete_title">' . check_plain($result['label']) . '</span>';
+      $matches[$result['label'] . " [id: $entity_id]"] .= isset($result['bundle']) ? ' <span class="autocomplete_bundle">(' . check_plain($result['bundle']) . ')</span>' : '';
     }
 
     drupal_json_output($matches);
   }
 }
 
-/*
- * Use well known/tested entity reference code to build our search query
- * From EntityReference_SelectionHandler_Generic class
+/**
+ * Use EntityReference_SelectionHandler_Generic class to build our search query.
  */
 function _ctools_buildQuery($entity_type, $entity_info, $match = NULL, $match_operator = 'CONTAINS') {
   $base_table = $entity_info['base table'];
-    $query = db_select($base_table)
-      ->fields($base_table, array($entity_info['entity keys']['id']));
+  $label_key = $entity_info['entity keys']['label'];
+  $query = db_select($base_table)
+    ->fields($base_table, array($entity_info['entity keys']['id']));
 
-    if (isset($match)) {
-      if (isset($entity_info['entity keys']['label'])) {
-        $query->condition($base_table .'.'. $entity_info['entity keys']['label'], '%' . $match . '%' , $match_operator);
-      }
-    }
-
-    // Add a label to the query, if the label exists
-    if (isset($entity_info['entity keys']['label'])) {
-      $query->fields($base_table, array($entity_info['entity keys']['label']));
-    }
-
-    // Add a generic entity access tag to the query.
-    $query->addTag('ctools');
-
-    if($entity_type == 'comment') {
-      // Adding the 'comment_access' tag is sadly insufficient for comments: core
-      // requires us to also know about the concept of 'published' and
-      // 'unpublished'.
-      if (!user_access('administer comments')) {
-        $query->condition('comment.status', COMMENT_PUBLISHED);
-      }
-      // Join to a node if the user does not have node access bypass permissions
-      // to obey node published permissions
-      if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
-        $node_alias = $query->innerJoin('node', 'n', '%alias.nid = comment.nid');
-        $query->condition($node_alias . '.status', NODE_PUBLISHED);
-      }
-      $query->addTag('node_access');
+  if (isset($match)) {
+    if (isset($label_key)) {
+      $query->condition($base_table . '.' . $label_key, '%' . $match . '%', $match_operator);
     }
+    // This should never happen, but double check just in case.
     else {
-      $query->addTag($entity_type . '_access');
+      return array();
+    }
+  }
+  // Add a generic entity access tag to the query.
+  $query->addTag('ctools');
+
+  // We have to perform two checks. First check is a query alter (with tags)
+  // in an attempt to only return results that have access. However, this is
+  // not full-proof since entities many not implement hook_access query tag.
+  // This is why we have a second check after entity load, before we display
+  // the label of an entity.
+  if ($entity_type == 'comment') {
+    // Adding the 'comment_access' tag is sadly insufficient for comments: core

+    // requires us to also know about the concept of 'published' and

+    // 'unpublished'.
+    if (!user_access('administer comments')) {
+      $query->condition('comment.status', COMMENT_PUBLISHED);
     }
 
-    // Add the sort option.
-    if(isset($entity_info['entity keys']['label'])) {
-      $query->orderBy($base_table .'.'. $entity_info['entity keys']['label'], 'ASC');
+    // Join to a node if the user does not have node access bypass permissions

+    // to obey node published permissions.
+    if (!user_access('bypass node access')) {
+      $node_alias = $query->innerJoin('node', 'n', '%alias.nid = comment.nid');
+      $query->condition($node_alias . '.status', NODE_PUBLISHED);
     }
+    $query->addTag('node_access');
+  }
+  else {
+    $query->addTag($entity_type . '_access');
+  }
+
+  // Add the sort option.
+  if (isset($label_key)) {
+    $query->orderBy($base_table . '.' . $label_key, 'ASC');
+  }
 
-    return $query;
+  return $query;
 }
 
 /**
@@ -118,22 +121,58 @@ function _ctools_buildQuery($entity_type, $entity_info, $match = NULL, $match_op
  * Entity Reference module.
  */
 function _ctools_getReferencableEntities($entity_type, $entity_info, $match = NULL, $match_operator = 'LIKE', $limit = 0) {
+  global $user;
+  $account = $user;
   $options = array();
-
-  $query = _ctools_buildQuery($entity_type, $entity_info, $match, $match_operator);
-  if ($limit > 0) {
-    $query->range(0, $limit);
+  // We're an entity ID, return the id.
+  if (is_numeric($match) && $match_operator == '=') {
+    if ($entity = array_shift(entity_load($entity_type, array($match)))) {
+      if (isset($entity_info['access callback']) && function_exists($entity_info['access callback'])) {
+        if ($entity_info['access callback']('view', $entity, $account, $entity_type)) {
+          $label = entity_label($entity_type, $entity);
+          return array(
+            $match => array(
+              'label' => !empty($label) ? $label : $entity->{$entity_info['entity keys']['id']},
+              'bundle' => !empty($entity_info['entity keys']['bundle']) ? check_plain($entity->{$entity_info['entity keys']['bundle']}) : NULL,
+            ),
+          );
+        }
+      }
+    }
+    // If you don't have access, or an access callback or a valid entity, just
+    // Return back the Entity ID.
+    return array(
+      $match => array(
+        'label' => $match,
+        'bundle' => NULL,
+      ),
+    );
   }
 
-  $results = $query->execute();
+  // We have matches, build a query to fetch the result.
+  if ($query = _ctools_buildQuery($entity_type, $entity_info, $match, $match_operator)) {
+    if ($limit > 0) {
+      $query->range(0, $limit);
+    }
 
-  if (!empty($results)) {
-    foreach ($results as $record) {
-      $options[$record->{$entity_info['entity keys']['id']}] = array(
-        'label' => isset($entity_info['entity keys']['label']) ? check_plain($record->{$entity_info['entity keys']['label']}) : $record->{$entity_info['entity keys']['id']},
-      );
+    $results = $query->execute();
+
+    if (!empty($results)) {
+      foreach ($results as $record) {
+        $entities = entity_load($entity_type, array($record->{$entity_info['entity keys']['id']}));
+        $entity = array_shift($entities);
+        if (isset($entity_info['access callback']) && function_exists($entity_info['access callback'])) {
+          if ($entity_info['access callback']('view', $entity, $account, $entity_type)) {
+            $label = entity_label($entity_type, $entity);
+            $options[$record->{$entity_info['entity keys']['id']}] = array(
+              'label' => !empty($label) ? $label : $entity->{$entity_info['entity keys']['id']},
+              'bundle' => !empty($entity_info['entity keys']['bundle']) ? check_plain($entity->{$entity_info['entity keys']['bundle']}) : NULL,
+            );
+          }
+        }
+      }
     }
+    return $options;
   }
-
-  return $options;
-}
\ No newline at end of file
+  return array();
+}
diff --git a/includes/content.plugin-type.inc b/includes/content.plugin-type.inc
index a0debc3e5ee779060d40442dc2891e46889d3b3a..0364a927a4fda5dfb8f1b8fdba7fa6e498b0384d 100644
--- a/includes/content.plugin-type.inc
+++ b/includes/content.plugin-type.inc
@@ -14,4 +14,4 @@ function ctools_content_plugin_type(&$items) {
       'path' => drupal_get_path('module', 'ctools') . '/includes',
     ),
   );
-}
\ No newline at end of file
+}
diff --git a/includes/context-access-admin.inc b/includes/context-access-admin.inc
index 76643cf62c76dc4a92ed5a42a406d977f5291188..d8c4f3b144c0a61799fa836cae46ffadfc3b5d31 100644
--- a/includes/context-access-admin.inc
+++ b/includes/context-access-admin.inc
@@ -245,10 +245,10 @@ function ctools_access_admin_form_submit($form, &$form_state) {
 
 // --------------------------------------------------------------------------
 // AJAX menu entry points.
-
 /**
  * AJAX callback to add a new access test to the list.
  */
+
 function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
   ctools_include('ajax');
   ctools_include('modal');
@@ -263,7 +263,7 @@ function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
     ctools_ajax_render_error();
   }
 
-  // Separate the fragment into 'module' and 'argument'
+  // Separate the fragment into 'module' and 'argument'.
   if (strpos($fragment, '-') === FALSE) {
     $module = $fragment;
     $argument = NULL;
@@ -279,7 +279,7 @@ function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
 
   list($access, $contexts) = $function($argument);
 
-  // Make sure we have the logged in user context
+  // Make sure we have the logged in user context.
   if (!isset($contexts['logged-in-user'])) {
     $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
   }
@@ -306,6 +306,9 @@ function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
   );
 
   $output = ctools_modal_form_wrapper('ctools_access_ajax_edit_item', $form_state);
+  $access = $form_state['access'];
+  $access['plugins'][$id] = $form_state['test'];
+
   if (!isset($output[0])) {
     $function = $module . '_ctools_access_set';
     if (function_exists($function)) {
@@ -333,7 +336,7 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
     ctools_ajax_render_error();
   }
 
-  // Separate the fragment into 'module' and 'argument'
+  // Separate the fragment into 'module' and 'argument'.
   if (strpos($fragment, '-') === FALSE) {
     $module = $fragment;
     $argument = NULL;
@@ -353,7 +356,7 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
     ctools_ajax_render_error();
   }
 
-  // Make sure we have the logged in user context
+  // Make sure we have the logged in user context.
   if (!isset($contexts['logged-in-user'])) {
     $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
   }
@@ -367,12 +370,14 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
     'contexts' => $contexts,
     'title' => t('Edit criteria'),
     'ajax' => TRUE,
-    'ajax' => TRUE,
     'modal' => TRUE,
     'modal return' => TRUE,
   );
 
   $output = ctools_modal_form_wrapper('ctools_access_ajax_edit_item', $form_state);
+  $access = $form_state['access'];
+  $access['plugins'][$id] = $form_state['test'];
+
   if (!isset($output[0])) {
     $function = $module . '_ctools_access_set';
     if (function_exists($function)) {
@@ -452,7 +457,7 @@ function ctools_access_ajax_delete($fragment = NULL, $id = NULL) {
     ajax_render_error();
   }
 
-  // Separate the fragment into 'module' and 'argument'
+  // Separate the fragment into 'module' and 'argument'.
   if (strpos($fragment, '-') === FALSE) {
     $module = $fragment;
     $argument = NULL;
@@ -472,7 +477,7 @@ function ctools_access_ajax_delete($fragment = NULL, $id = NULL) {
     unset($access['plugins'][$id]);
   }
 
-  // re-cache
+  // re-cache.
   $function = $module . '_ctools_access_set';
   if (function_exists($function)) {
     $function($argument, $access);
diff --git a/includes/context-admin.inc b/includes/context-admin.inc
index c774bf41d7de117bd7ebf7b7ba463ee45afcc7cc..533c89f553a33be7dfaa4e1fe6c89a7e26584518 100644
--- a/includes/context-admin.inc
+++ b/includes/context-admin.inc
@@ -376,11 +376,11 @@ function ctools_context_ajax_item_add($mechanism = NULL, $type = NULL, $cache_ke
     'path' => "ctools/context/ajax/add/$mechanism/$type/$cache_key/$name/%step",
     'show cancel' => TRUE,
     'default form' => 'ctools_edit_context_form_defaults',
-    'auto caching' => TRUE,
+    'auto cache' => TRUE,
     'cache mechanism' => $mechanism,
     'cache key' => $cache_key,
     // This is stating what the cache will be referred to in $form_state
-    'cache storage' => 'object',
+    'cache location' => 'object',
   );
 
   if ($type == 'requiredcontext') {
@@ -395,7 +395,7 @@ function ctools_context_ajax_item_add($mechanism = NULL, $type = NULL, $cache_ke
   if (!empty($form_state['cancel'])) {
     $output = array(ctools_modal_command_dismiss());
   }
-  else if (!empty($form_state['complete'])) {
+  elseif (!empty($form_state['complete'])) {
     // Successful submit -- move temporary data to location.
 
     // Create a reference to the place our context lives. Since this is fairly
@@ -416,13 +416,14 @@ function ctools_context_ajax_item_add($mechanism = NULL, $type = NULL, $cache_ke
     ctools_cache_operation($mechanism, $cache_key, 'finalize', $object);
 
     // Very irritating way to update the form for our contexts.
-    $arg_form_state = array(
+    $arg_form_state = form_state_defaults() + array(
       'values' => array(),
-      'programmed' => FALSE,
       'process_input' => FALSE,
       'complete form' => array(),
     );
 
+    $rel_form_state = $arg_form_state;
+
     $arg_form = array(
       '#post' => array(),
       '#programmed' => FALSE,
@@ -469,7 +470,7 @@ function ctools_context_ajax_item_add($mechanism = NULL, $type = NULL, $cache_ke
     $output = array();
     if (!empty($available_relationships)) {
       ctools_context_add_item_table_buttons('relationship', $mechanism, $rel_form, $available_relationships);
-      $rel_form = form_builder('dummy_form_id', $rel_form, $arg_form_state);
+      $rel_form = form_builder('dummy_form_id', $rel_form, $rel_form_state);
       $output[] = ajax_command_replace('div#ctools-relationships-table div.buttons', drupal_render($rel_form));
     }
 
@@ -560,11 +561,11 @@ function ctools_context_ajax_item_edit($mechanism = NULL, $type = NULL, $cache_k
     'path' => "ctools/context/ajax/configure/$mechanism/$type/$cache_key/$position/%step",
     'show cancel' => TRUE,
     'default form' => 'ctools_edit_context_form_defaults',
-    'auto caching' => TRUE,
+    'auto cache' => TRUE,
     'cache mechanism' => $mechanism,
     'cache key' => $cache_key,
     // This is stating what the cache will be referred to in $form_state
-    'cache storage' => 'object',
+    'cache location' => 'object',
   );
 
   if ($type == 'requiredcontext') {
@@ -579,7 +580,7 @@ function ctools_context_ajax_item_edit($mechanism = NULL, $type = NULL, $cache_k
   if (!empty($form_state['cancel'])) {
     $output = array(ctools_modal_command_dismiss());
   }
-  else if (!empty($form_state['complete'])) {
+  elseif (!empty($form_state['complete'])) {
     // successful submit
     $ref[$position] = $conf;
     if (isset($object->temporary)) {
@@ -591,8 +592,16 @@ function ctools_context_ajax_item_edit($mechanism = NULL, $type = NULL, $cache_k
     $output = array();
     $output[] = ctools_modal_command_dismiss();
 
+    $arg_form_state = form_state_defaults() + array(
+      'values' => array(),
+      'process_input' => FALSE,
+      'complete form' => array(),
+    );
+
     $arg_form = array(
       '#post' => array(),
+      '#parents' => array(),
+      '#array_parents' => array(),
       '#programmed' => FALSE,
       '#tree' => FALSE,
     );
@@ -648,7 +657,7 @@ function ctools_context_get_defaults($plugin_definition, $object, $type) {
   if (isset($plugin_definition['defaults'])) {
     $defaults = $plugin_definition['defaults'];
   }
-  else if (isset($subtype['defaults'])) {
+  elseif (isset($subtype['defaults'])) {
     $defaults = $subtype['defaults'];
   }
 
@@ -658,7 +667,7 @@ function ctools_context_get_defaults($plugin_definition, $object, $type) {
         $conf += $settings;
       }
     }
-    else if (is_array($defaults)) {
+    elseif (is_array($defaults)) {
       $conf += $defaults;
     }
   }
@@ -727,6 +736,15 @@ function ctools_edit_context_form_defaults($form, &$form_state) {
     '#default_value' => $conf['keyword'],
   );
 
+  if ($type_info['key'] == 'requiredcontexts') {
+    $form['optional'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Context is optional'),
+      '#default_value' => !empty($form_state['conf']['optional']),
+      '#description' => t('This context need not be present for the component to function.'),
+    );
+  }
+
   $form['#submit'][] = 'ctools_edit_context_form_defaults_submit';
 
   return $form;
@@ -743,6 +761,9 @@ function ctools_edit_context_form_defaults_submit(&$form, &$form_state) {
     $form_state['conf']['default'] = $form_state['values']['default'];
     $form_state['conf']['title'] = $form_state['values']['title'];
   }
+  if ($form_state['type info']['key'] == 'requiredcontexts') {
+    $form_state['conf']['optional'] = $form_state['values']['optional'];
+  }
 
   $form_state['conf']['identifier'] = $form_state['values']['identifier'];
   $form_state['conf']['keyword'] = $form_state['values']['keyword'];
diff --git a/includes/context-task-handler.inc b/includes/context-task-handler.inc
index 21ceea5dc37166b9fe7ad34bfd5a23ec12521baa..ed4acad0811299de0ab46a8a3373673305061019 100644
--- a/includes/context-task-handler.inc
+++ b/includes/context-task-handler.inc
@@ -4,9 +4,9 @@
  * @file
  * Support for creating 'context' type task handlers.
  *
- * Context task handlers expect the task to provide 0 or more contexts. The
- * task handler should use those contexts as selection rules, as well as
- * rendering with them.
+ * Context task handlers expect the task to provide 0 or more contexts. The task
+ * handler should use those contexts as selection rules, as well as rendering
+ * with them.
  *
  * The functions and forms in this file should be common to every context type
  * task handler made.
@@ -31,6 +31,7 @@
  *   If TRUE then this renderer owns the page and can use theme('page')
  *   for no blocks; if false, output is returned regardless of any no
  *   blocks settings.
+ *
  * @return
  *   Either the output or NULL if there was output, FALSE if no handler
  *   accepted the task. If $page is FALSE then the $info block is returned instead.
@@ -84,7 +85,7 @@ function ctools_context_handler_get_render_handler($task, $subtask, $handlers, $
  */
 function ctools_context_handler_default_test($handler, $base_contexts, $args) {
   ctools_include('context');
-  // Add my contexts
+  // Add my contexts.
   $contexts = ctools_context_handler_get_handler_contexts($base_contexts, $handler);
 
   // Test.
@@ -128,7 +129,7 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
     'contexts' => $contexts,
     'task' => $task,
     'subtask' => $subtask,
-    'handler' => $handler
+    'handler' => $handler,
   );
   drupal_alter('ctools_render', $info, $page, $context);
 
@@ -141,12 +142,15 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
     switch ($info['response code']) {
       case 403:
         return MENU_ACCESS_DENIED;
+
       case 404:
         return MENU_NOT_FOUND;
+
       case 410:
         drupal_add_http_header('Status', '410 Gone');
         drupal_exit();
         break;
+
       case 301:
       case 302:
       case 303:
@@ -162,7 +166,7 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
           'fragment' => $info['fragment'],
         );
         drupal_goto($info['destination'], $options, $info['response code']);
-      // @todo -- should other response codes be supported here?
+        // @todo -- should other response codes be supported here?
     }
   }
 
@@ -222,7 +226,7 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
 }
 
 /**
- * Default function to provide contextual link for a task as defined by the handler.
+ * Provides contextual link for a task as defined by the handler.
  *
  * This provides a simple link to th main content operation and is suitable
  * for most normal handlers. Setting 'contextual link' to a function overrides
@@ -241,7 +245,7 @@ function ctools_task_handler_default_contextual_link($handler, $plugin, $context
     if (is_array($plugin['tab operation'])) {
       $trail = $plugin['tab operation'];
     }
-    else if (function_exists($plugin['tab operation'])) {
+    elseif (function_exists($plugin['tab operation'])) {
       $trail = $plugin['tab operation']($handler, $contexts, $args);
     }
   }
@@ -251,7 +255,8 @@ function ctools_task_handler_default_contextual_link($handler, $plugin, $context
     'href' => $path,
     'title' => $title,
     'query' => drupal_get_destination(),
-  ));
+  ),
+  );
 
   return $links;
 }
@@ -259,17 +264,22 @@ function ctools_task_handler_default_contextual_link($handler, $plugin, $context
 /**
  * Called to execute actions that should happen before a handler is rendered.
  */
-function ctools_context_handler_pre_render($handler, $contexts, $args) { }
+function ctools_context_handler_pre_render($handler, $contexts, $args) {
+  foreach (module_implements('ctools_context_handler_pre_render') as $module) {
+    $function = $module . '_ctools_context_handler_pre_render';
+    $function($handler, $contexts, $args);
+  }
+}
 
 /**
  * Compare arguments to contexts for selection purposes.
  *
- * @param $handler
+ * @param object $handler
  *   The handler in question.
- * @param $contexts
+ * @param object $contexts
  *   The context objects provided by the task.
  *
- * @return
+ * @return bool
  *   TRUE if these contexts match the selection rules. NULL or FALSE
  *   otherwise.
  */
@@ -288,12 +298,15 @@ function ctools_context_handler_select($handler, $contexts) {
  * These summary strings are used to communicate to the user what
  * arguments the task handlers are selecting.
  *
- * @param $task
+ * @param object $task
  *   The loaded task plugin.
- * @param $subtask
+ * @param object $subtask
  *   The subtask id.
- * @param $handler
+ * @param object $handler
  *   The handler to be checked.
+ *
+ * @return array
+ *   Returns array of summary strings for arguments selected by task handlers.
  */
 function ctools_context_handler_summary($task, $subtask, $handler) {
   if (empty($handler->conf['access']['plugins'])) {
@@ -320,7 +333,6 @@ function ctools_context_handler_summary($task, $subtask, $handler) {
 // the task handler, for example) but sometimes we need them separately
 // (when a task has contexts loaded and is trying out the task handlers,
 // for example). Therefore there are two paths we can take to getting contexts.
-
 /**
  * Load the contexts for a task, using arguments.
  *
@@ -368,7 +380,7 @@ function ctools_context_handler_get_all_contexts($task, $subtask, $handler) {
  * expects things in a certain, kind of clunky format.
  */
 function ctools_context_handler_get_handler_object($handler) {
-  $object = new stdClass;
+  $object = new stdClass();
   $object->name = $handler->name;
   $object->contexts = isset($handler->conf['contexts']) ? $handler->conf['contexts'] : array();
   $object->relationships = isset($handler->conf['relationships']) ? $handler->conf['relationships'] : array();
@@ -382,7 +394,7 @@ function ctools_context_handler_get_handler_object($handler) {
  * arguments from the task.
  */
 function ctools_context_handler_get_task_object($task, $subtask, $handler) {
-  $object = new stdClass;
+  $object = new stdClass();
   $object->name = !empty($handler->name) ? $handler->name : 'temp';
   $object->base_contexts = ctools_context_handler_get_base_contexts($task, $subtask, TRUE);
   $object->arguments = ctools_context_handler_get_task_arguments($task, $subtask);
@@ -456,7 +468,7 @@ function ctools_context_handler_edit_criteria($form, &$form_state) {
   ctools_modal_add_plugin_js(ctools_get_access_plugins());
   ctools_include('context-access-admin');
   $form_state['module'] = (isset($form_state['module'])) ? $form_state['module'] : 'page_manager_task_handler';
-  // Encode a bunch of info into the argument so we can get our cache later
+  // Encode a bunch of info into the argument so we can get our cache later.
   $form_state['callback argument'] = $form_state['task_name'] . '*' . $form_state['handler']->name;
   $form_state['access'] = $form_state['handler']->conf['access'];
   $form_state['no buttons'] = TRUE;
@@ -472,7 +484,7 @@ function ctools_context_handler_edit_criteria($form, &$form_state) {
 }
 
 /**
- * Submit handler for rules selection
+ * Submit handler for rules selection.
  */
 function ctools_context_handler_edit_criteria_submit(&$form, &$form_state) {
   $form_state['handler']->conf['access']['logic'] = $form_state['values']['logic'];
@@ -537,4 +549,3 @@ function ctools_context_handler_edit_context_submit(&$form, &$form_state) {
     unset($form_state['page']->context_cache[$cache_name]);
   }
 }
-
diff --git a/includes/context.inc b/includes/context.inc
index 3b75c0ff46919e40d793c7b98a8198de63bb7403..6c136698b7246338c99cdf180649e1f5e7f6695c 100644
--- a/includes/context.inc
+++ b/includes/context.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Contains code related to the ctools system of 'context'.
  *
  * Context, originally from Panels, is a method of packaging objects into
@@ -28,28 +27,104 @@
  * of the context is important.
  */
 class ctools_context {
-  var $type = NULL;
-  var $data = NULL;
-  // The title of this object.
-  var $title = '';
-  // The title of the page if this object exists
-  var $page_title = '';
-  // The identifier (in the UI) of this object
-  var $identifier = '';
-  var $argument = NULL;
-  var $keyword = '';
-  var $original_argument = NULL;
-  var $restrictions = array();
-  var $empty = FALSE;
-
-  function ctools_context($type = 'none', $data = NULL) {
-    $this->type  = $type;
-    $this->data  = $data;
+  /**
+   * @var string|array
+   *   A string naming this specific context type. The values 'any' and 'none'
+   *   are special:
+   *    - 'any': used in is_type() to match any other type.
+   *    - 'none': used to signal the type is not defined.
+   */
+  public $type;
+
+  /**
+   * @var mixed
+   *   The data payload for this context object.
+   */
+  public $data;
+
+  /**
+   * @var string
+   *   The title of this object.
+   */
+  public $title;
+
+  /**
+   * @var string
+   *   The title of the page if this object exists
+   */
+  public $page_title;
+
+  /**
+   * @var string
+   *   The identifier (in the UI) of this object.
+   */
+  public $identifier;
+
+  /**
+   * @var
+   */
+  public $argument;
+
+  /**
+   * @var string
+   */
+  public $keyword;
+
+  /**
+   * @var
+   */
+  public $original_argument;
+
+  /**
+   * @var array
+   */
+  public $restrictions;
+
+  /**
+   * @var bool
+   */
+  public $empty;
+
+  /**
+   * The ctools_context constructor.
+   *
+   * @param string $type
+   *   The type name of this context. Should be unique. Use the machine_name
+   *   conventions: lowercase, short, underscores and no spaces.
+   * @param mixed $data
+   *   The data payload, if required for this context.
+   */
+  public function __construct($type = 'none', $data = NULL) {
+    $this->type = $type;
+    $this->data = $data;
     $this->title = t('Unknown context');
+    $this->page_title = '';
+    $this->identifier = '';
+    $this->keyword = '';
+    $this->restrictions = array();
+    $this->empty = FALSE;
+    // Other vars are NULL.
   }
 
-  function is_type($type) {
-    if ($type == 'any' || $this->type == 'any') {
+  /**
+   * Determine whether this object is of type @var $type .
+   *
+   * Both the internal value ($this->type) and the supplied value ($type) can
+   * be a string or an array of strings, and if one or both are arrays the match
+   * succeeds if at least one common element is found.
+   *
+   * Type names
+   *
+   * @param string|array $type
+   *   'type' can be:
+   *    - 'any' to match all types (this is true of the internal value too).
+   *    - an array of type name strings, when more than one type is acceptable.
+   *
+   * @return bool
+   *   True if the type matches, False otherwise.
+   */
+  public function is_type($type) {
+    if ($type === 'any' || $this->type === 'any') {
       return TRUE;
     }
 
@@ -58,32 +133,71 @@ class ctools_context {
     return (bool) array_intersect($a, $b);
   }
 
-  function get_argument() {
+  /**
+   * Return the argument.
+   *
+   * @return mixed
+   *   The value of $argument.
+   */
+  public function get_argument() {
     return $this->argument;
   }
 
-  function get_original_argument() {
+  /**
+   * Return the value of argument (or arg) variable as it was passed in.
+   *
+   * For example see ctools_plugin_load_function() and ctools_terms_context().
+   *
+   * @return mixed
+   *   The original arg value.
+   */
+  public function get_original_argument() {
     if (!is_null($this->original_argument)) {
       return $this->original_argument;
     }
     return $this->argument;
   }
 
-  function get_keyword() {
+  /**
+   * Return the keyword.
+   *
+   * @return mixed
+   *   The value of $keyword.
+   */
+  public function get_keyword() {
     return $this->keyword;
   }
 
-  function get_identifier() {
+  /**
+   * Return the identifier.
+   *
+   * @return mixed
+   *   The value of $identifier.
+   */
+  public function get_identifier() {
     return $this->identifier;
   }
 
-  function get_title() {
+  /**
+   * Return the title.
+   *
+   * @return mixed
+   *   The value of $title.
+   */
+  public function get_title() {
     return $this->title;
   }
 
-  function get_page_title() {
+  /**
+   * Return the page title.
+   *
+   * @return mixed
+   *   The value of $page_title.
+   */
+  public function get_page_title() {
     return $this->page_title;
   }
+
 }
 
 /**
@@ -91,39 +205,57 @@ class ctools_context {
  * match a required context type.
  */
 class ctools_context_required {
-  var $keywords = '';
+  /**
+   * @var array
+   *   Keyword strings associated with the context.
+   */
+  public $keywords;
 
   /**
    * If set, the title will be used in the selector to identify
    * the context. This is very useful when multiple contexts
    * are required to inform the user will be used for what.
    */
-  var $title = NULL;
+  public $title;
 
   /**
    * Test to see if this context is required.
    */
-  var $required = TRUE;
+  public $required = TRUE;
 
   /**
    * If TRUE, skip the check in ctools_context_required::select()
    * for contexts whose names may have changed.
    */
-  var $skip_name_check = FALSE;
+  public $skip_name_check = FALSE;
 
   /**
+   * The ctools_context_required constructor.
    *
-   * @param $title
-   *   The first parameter should be the 'title' of the context for use
-   *   in UYI selectors when multiple contexts qualify.
-   * @param ...
+   * Note: Constructor accepts a variable number of arguments, with optional
+   * type-dependent args at the end of the list and one required argument,
+   * the title. Note in particular that skip_name_check MUST be passed in as
+   * a boolean (and not, for example, as an integer).
+   *
+   * @param string $title
+   *   The title of the context for use in UI selectors when multiple contexts
+   *   qualify.
+   * @param string $keywords
    *   One or more keywords to use for matching which contexts are allowed.
+   * @param array $restrictions
+   *   Array of context restrictions.
+   * @param bool $skip_name_check
+   *   If True, skip the check in select() for contexts whose names may have
+   *   changed.
    */
-  function ctools_context_required($title) {
+  public function __construct($title) {
+    // If it was possible, using variadic syntax this should be:
+    // __construct($title, string ...$keywords, array $restrictions = NULL, bool $skip = NULL)
+    // but that form isn't allowed.
     $args = func_get_args();
     $this->title = array_shift($args);
 
-    // If we have a boolean value at the end for $skip_name_check, store it
+    // If we have a boolean value at the end for $skip_name_check, store it.
     if (is_bool(end($args))) {
       $this->skip_name_check = array_pop($args);
     }
@@ -133,20 +265,44 @@ class ctools_context_required {
       $this->restrictions = array_pop($args);
     }
 
-    if (count($args) == 1) {
+    if (count($args) === 1) {
       $args = array_shift($args);
     }
     $this->keywords = $args;
   }
 
-  function filter($contexts) {
+  /**
+   * Filter the contexts to determine which apply in the current environment.
+   *
+   * A context passes the filter if:
+   *  - the context matches 'type' of the required keywords (uses
+   *    ctools_context::is_type(), so includes 'any' matches, etc).
+   *  - AND if restrictions are present, there are some common elements between
+   *    the requirement and the context.
+   *
+   * @param array $contexts
+   *   An array of ctools_context objects (or something which will cast to an
+   *   array of them). The contexts to apply the filter on.
+   *
+   * @return array
+   *   An array of context objects, keyed with the same keys used for $contexts,
+   *   which pass the filter.
+   *
+   * @see ctools_context::is_type()
+   */
+  public function filter($contexts) {
     $result = array();
 
-    // See which of these contexts are valid
+    /**
+     * See which of these contexts are valid.
+     * @var ctools_context $context
+     */
     foreach ((array) $contexts as $cid => $context) {
       if ($context->is_type($this->keywords)) {
+
         // Compare to see if our contexts were met.
         if (!empty($this->restrictions) && !empty($context->restrictions)) {
+
           foreach ($this->restrictions as $key => $values) {
             // If we have a restriction, the context must either not have that
             // restriction listed, which means we simply don't know what it is,
@@ -155,11 +311,16 @@ class ctools_context_required {
             if (!is_array($values)) {
               $values = array($values);
             }
-            if (!empty($context->restrictions[$key]) && !array_intersect($values, $context->restrictions[$key])) {
+
+            if (!empty($context->restrictions[$key])
+              && !array_intersect($values, $context->restrictions[$key])
+            ) {
+              // Break out to check next context; this one fails the filter.
               continue 2;
             }
           }
         }
+        // This context passes the filter.
         $result[$cid] = $context;
       }
     }
@@ -167,16 +328,43 @@ class ctools_context_required {
     return $result;
   }
 
-  function select($contexts, $context) {
+  /**
+   * Select one context from the list of contexts, accounting for changed IDs.
+   *
+   * Fundamentally, this returns $contexts[$context] or FALSE if that does not
+   * exist. Additional logic accounts for changes in context names and dealing
+   * with a $contexts parameter that is not an array.
+   *
+   * If we had requested a $context but that $context doesn't exist in our
+   * context list, there is a good chance that what happened is the context
+   * IDs changed. Look for another context that satisfies our requirements,
+   * unless $skip_name_check is set.
+   *
+   * @param ctools_context|array $contexts
+   *   A context, or an array of ctools_context.
+   * @param string $context
+   *   A context ID.
+   *
+   * @return bool|ctools_context
+   *   The matching ctools_context, or False if no such context was found.
+   */
+  public function select($contexts, $context) {
+    // Easier to deal with a standalone object as a 1-element array of objects.
     if (!is_array($contexts)) {
-      $contexts = array($contexts);
+      if (is_object($contexts) && $contexts instanceof ctools_context) {
+        $contexts = array($contexts->id => $contexts);
+      }
+      else {
+        $contexts = array($contexts);
+      }
     }
 
-    // If we had requested a $context but that $context doesn't exist
-    // in our context list, there is a good chance that what happened
-    // is our context IDs changed. See if there's another context
-    // that satisfies our requirements.
-    if (!$this->skip_name_check && !empty($context) && !isset($contexts[$context])) {
+    // If we had requested a $context but that $context doesn't exist in our
+    // context list, there is a good chance that what happened is the context
+    // IDs changed. Check for another context that satisfies our requirements.
+    if (!$this->skip_name_check
+      && !empty($context) && !isset($contexts[$context])
+    ) {
       $choices = $this->filter($contexts);
 
       // If we got a hit, take the first one that matches.
@@ -191,6 +379,7 @@ class ctools_context_required {
     }
     return $contexts[$context];
   }
+
 }
 
 /**
@@ -198,28 +387,73 @@ class ctools_context_required {
  * can produce empty contexts to use as placeholders.
  */
 class ctools_context_optional extends ctools_context_required {
-  var $required = FALSE;
-  function ctools_context_optional() {
-    $args = func_get_args();
-    call_user_func_array(array($this, 'ctools_context_required'), $args);
-  }
 
   /**
-   * Add the 'empty' context which is possible for optional
+   * {@inheritdoc}
    */
-  function add_empty(&$contexts) {
+  public $required = FALSE;
+
+  /**
+   * Add the 'empty' context to the existing set.
+   *
+   * @param array &$contexts
+   *   An array of ctools_context objects.
+   */
+  public function add_empty(&$contexts) {
     $context = new ctools_context('any');
-    $context->title      = t('No context');
+    $context->title = t('No context');
     $context->identifier = t('No context');
-    $contexts = array_merge(array('empty' => $context), $contexts);
+    $contexts['empty'] = $context;
   }
 
-  function filter($contexts) {
+  /**
+   * Filter the contexts to determine which apply in the current environment.
+   *
+   * As for ctools_context_required, but we add the empty context to those
+   * passed in so the check is optional (i.e. if nothing else matches, the
+   * empty context will, and so there will always be at least one matched).
+   *
+   * @param array $contexts
+   *   An array of ctools_context objects (or something which will cast to an
+   *   array of them). The contexts to apply the filter on.
+   *
+   * @return array
+   *   An array of context objects, keyed with the same keys used for $contexts,
+   *   which pass the filter.
+   *
+   * @see ctools_context::is_type()
+   */
+  public function filter($contexts) {
+    /**
+     * @todo We are assuming here that $contexts is actually an array, whereas
+     * ctools_context_required::filter only requires $contexts is convertible
+     * to an array.
+     */
     $this->add_empty($contexts);
     return parent::filter($contexts);
   }
 
-  function select($contexts, $context) {
+  /**
+   * Select and return one context from the list of applicable contexts.
+   *
+   * Fundamentally, this returns $contexts[$context] or the empty context if
+   * that does not exist.
+   *
+   * @param array $contexts
+   *   The applicable contexts to check.
+   * @param string $context
+   *   The context id to check for.
+   *
+   * @return bool|ctools_context
+   *   The matching ctools_context, or False if no such context was found.
+   *
+   * @see ctools_context_required::select()
+   */
+  public function select($contexts, $context) {
+    /**
+     * @todo We are assuming here that $contexts is actually an array, whereas
+     * ctools_context_required::select permits ctools_context objects as well.
+     */
     $this->add_empty($contexts);
     if (empty($context)) {
       return $contexts['empty'];
@@ -229,11 +463,12 @@ class ctools_context_optional extends ctools_context_required {
 
     // Don't flip out if it can't find the context; this is optional, put
     // in an empty.
-    if ($result == FALSE) {
+    if ($result === FALSE) {
       $result = $contexts['empty'];
     }
     return $result;
   }
+
 }
 
 /**
@@ -248,20 +483,20 @@ class ctools_context_optional extends ctools_context_required {
  * Since multiple contexts can be required, this function will accept either
  * an array of all required contexts, or just a single required context object.
  *
- * @param $contexts
+ * @param array $contexts
  *   A keyed array of all available contexts.
- * @param $required
- *   A ctools_context_required or ctools_context_optional object, or an array
- *   of such objects.
+ * @param array|ctools_context_required|ctools_context_optional $required
+ *   A *_required or *_optional object, or an array of such objects, which
+ *   define the selection condition.
  *
- * @return
+ * @return array
  *   A keyed array of contexts that match the filter.
  */
 function ctools_context_filter($contexts, $required) {
   if (is_array($required)) {
     $result = array();
-    foreach ($required as $r) {
-      $result = array_merge($result, _ctools_context_filter($contexts, $r));
+    foreach ($required as $item) {
+      $result = array_merge($result, _ctools_context_filter($contexts, $item));
     }
     return $result;
   }
@@ -269,6 +504,21 @@ function ctools_context_filter($contexts, $required) {
   return _ctools_context_filter($contexts, $required);
 }
 
+/**
+ * Helper function for ctools_context_filter().
+ *
+ * Used to transform the required context during the merge into the final array.
+ *
+ * @internal This function DOES NOT form part of the CTools API.
+ *
+ * @param array $contexts
+ *   A keyed array of all available contexts.
+ * @param ctools_context_required|ctools_context_optional $required
+ *   A ctools_context_required or ctools_context_optional object, although if
+ *   given something else will return an empty array.
+ *
+ * @return array
+ */
 function _ctools_context_filter($contexts, $required) {
   $result = array();
 
@@ -288,12 +538,17 @@ function _ctools_context_filter($contexts, $required) {
  * If an array of required contexts is provided, one selector will be
  * provided for each context.
  *
- * @param $contexts
+ * @param array $contexts
  *   A keyed array of all available contexts.
- * @param $required
+ * @param array|ctools_context_required|ctools_context_optional $required
  *   The required context object or array of objects.
+ * @param array|string $default
+ *   The default value for the select object, suitable for a #default_value
+ *   render key. Where $required is an array, this is an array keyed by the
+ *   same key values as $required for all keys where an empty string is not a
+ *   suitable default. Otherwise it is just the default value.
  *
- * @return
+ * @return array
  *   A form element, or NULL if there are no contexts that satisfy the
  *   requirements.
  */
@@ -301,8 +556,10 @@ function ctools_context_selector($contexts, $required, $default) {
   if (is_array($required)) {
     $result = array('#tree' => TRUE);
     $count = 1;
-    foreach ($required as $id => $r) {
-      $result[] = _ctools_context_selector($contexts, $r, isset($default[$id]) ? $default[$id] : '', $count++);
+    foreach ($required as $id => $item) {
+      $result[] = _ctools_context_selector(
+        $contexts, $item, isset($default[$id]) ? $default[$id] : '', $count++
+      );
     }
     return $result;
   }
@@ -310,6 +567,27 @@ function ctools_context_selector($contexts, $required, $default) {
   return _ctools_context_selector($contexts, $required, $default);
 }
 
+/**
+ * Helper function for ctools_context_selector().
+ *
+ * @internal This function DOES NOT form part of the CTools API. Use the API
+ * function ctools_context_selector() instead.
+ *
+ * @param array $contexts
+ *   A keyed array of all available contexts.
+ * @param ctools_context_required|ctools_context_optional $required
+ *   The required context object.
+ * @param $default
+ *   The default value for the select object, suitable for a #default_value
+ *   render key.
+ * @param int $num
+ *   If supplied and non-zero, the title of the select form element will be
+ *   "Context $num", otherwise it will be "Context".
+ *
+ * @return array
+ *   A form element, or NULL if there are no contexts that satisfy the
+ *   requirements.
+ */
 function _ctools_context_selector($contexts, $required, $default, $num = 0) {
   $filtered = ctools_context_filter($contexts, $required);
   $count = count($filtered);
@@ -328,13 +606,15 @@ function _ctools_context_selector($contexts, $required, $default, $num = 0) {
       $title = $num ? t('Context %count', array('%count' => $num)) : t('Context');
     }
 
-    return array(
+    $form = array(
       '#type' => 'select',
       '#options' => $options,
       '#title' => $title,
       '#default_value' => $default,
     );
   }
+
+  return $form;
 }
 
 /**
@@ -351,8 +631,8 @@ function _ctools_context_selector($contexts, $required, $default, $num = 0) {
  * @param $required
  *   The required context object or array of objects.
  *
- * @return
- *   TRUE if there are enough contexts, FALSE if there are not.
+ * @return bool
+ *   True if there are enough contexts, otherwise False.
  */
 function ctools_context_match_requirements($contexts, $required) {
   if (!is_array($required)) {
@@ -385,8 +665,13 @@ function ctools_context_match_requirements($contexts, $required) {
  *   A keyed array of all available contexts.
  * @param $required
  *   The required context object or array of objects.
+ * @param array|string $default
+ *   The default value for the select object, suitable for a #default_value
+ *   render key. Where $required is an array, this is an array keyed by the
+ *   same key values as $required for all keys where an empty string is not a
+ *   suitable default. Otherwise it is just the default value.
  *
- * @return
+ * @return array
  *   A form element, or NULL if there are no contexts that satisfy the
  *   requirements.
  */
@@ -394,8 +679,11 @@ function ctools_context_converter_selector($contexts, $required, $default) {
   if (is_array($required)) {
     $result = array('#tree' => TRUE);
     $count = 1;
-    foreach ($required as $id => $r) {
-      $result[] = _ctools_context_converter_selector($contexts, $r, isset($default[$id]) ? $default[$id] : '', $count++);
+    foreach ($required as $id => $dependency) {
+      $default_id = isset($default[$id]) ? $default[$id] : '';
+      $result[] = _ctools_context_converter_selector(
+        $contexts, $dependency, $default_id, $count++
+      );
     }
     return $result;
   }
@@ -403,17 +691,36 @@ function ctools_context_converter_selector($contexts, $required, $default) {
   return _ctools_context_converter_selector($contexts, $required, $default);
 }
 
+/**
+ * Helper function for ctools_context_converter_selector().
+ *
+ * @internal This function DOES NOT form part of the CTools API. Use the API
+ * function ctools_context_converter_selector() instead.
+ *
+ * @param array $contexts
+ *   A keyed array of all available contexts.
+ * @param ctools_context $required
+ *   The required context object.
+ * @param $default
+ *   The default value for the select object, suitable for a #default_value
+ *   render key.
+ * @param int $num
+ *   If supplied and non-zero, the title of the select form element will be
+ *   "Context $num", otherwise it will be "Context".
+ *
+ * @return array|null
+ *   A form element, or NULL if there are no contexts that satisfy the
+ *   requirements.
+ */
 function _ctools_context_converter_selector($contexts, $required, $default, $num = 0) {
   $filtered = ctools_context_filter($contexts, $required);
   $count = count($filtered);
 
-  $form = array();
-
   if ($count > 1) {
     // If there's more than one to choose from, create a select widget.
     $options = array();
     foreach ($filtered as $cid => $context) {
-      if ($context->type == 'any') {
+      if ($context->type === 'any') {
         $options[''] = t('No context');
         continue;
       }
@@ -443,10 +750,22 @@ function _ctools_context_converter_selector($contexts, $required, $default, $num
       '#default_value' => $default,
     );
   }
+  else {
+    // Not enough choices to need a selector, so don't make one.
+    return NULL;
+  }
 }
 
 /**
  * Get a list of converters available for a given context.
+ *
+ * @param string $cid
+ *   A context ID.
+ * @param ctools_context $context
+ *   The context for which converters are needed.
+ *
+ * @return array
+ *   A list of context converters.
  */
 function ctools_context_get_converters($cid, $context) {
   if (empty($context->plugin)) {
@@ -458,6 +777,17 @@ function ctools_context_get_converters($cid, $context) {
 
 /**
  * Get a list of converters available for a given context.
+ *
+ * @internal This function DOES NOT form part of the CTools API. Use the API
+ * function ctools_context_get_converters() instead.
+ *
+ * @param string $id
+ *   A context ID.
+ * @param string $plugin_name
+ *   The name of the context plugin.
+ *
+ * @return array
+ *   A list of context converters.
  */
 function _ctools_context_get_converters($id, $plugin_name) {
   $plugin = ctools_get_context($plugin_name);
@@ -469,7 +799,7 @@ function _ctools_context_get_converters($id, $plugin_name) {
   if (is_array($plugin['convert list'])) {
     $converters = $plugin['convert list'];
   }
-  else if ($function = ctools_plugin_get_function($plugin, 'convert list')) {
+  elseif ($function = ctools_plugin_get_function($plugin, 'convert list')) {
     $converters = (array) $function($plugin);
   }
 
@@ -489,7 +819,13 @@ function _ctools_context_get_converters($id, $plugin_name) {
 }
 
 /**
- * Get a list of all contexts + converters available.
+ * Get a list of all contexts converters available.
+ *
+ * For all contexts returned by ctools_get_contexts(), return the converter
+ * for all contexts that have one.
+ *
+ * @return array
+ *   A list of context converters, keyed by the title of the converter.
  */
 function ctools_context_get_all_converters() {
   $contexts = ctools_get_contexts();
@@ -509,21 +845,24 @@ function ctools_context_get_all_converters() {
 /**
  * Let the context convert an argument based upon the converter that was given.
  *
- * @param $context
- *   The context object
- * @param $converter
- *   The converter to use, which should be a string provided by the converter list.
- * @param $converter_options
- *   A n array of options to pass on to the generation function. For contexts
+ * @param ctools_context $context
+ *   The context object.
+ * @param string $converter
+ *   The type of converter to use, which should be a string provided by the
+ *   converter list function.
+ * @param array $converter_options
+ *   An array of options to pass on to the generation function. For contexts
  *   that use token module, of particular use is 'sanitize' => FALSE which can
  *   get raw tokens. This should ONLY be used in values that will later be
  *   treated as unsafe user input since these values are by themselves unsafe.
  *   It is particularly useful to get raw values from Field API.
+ *
+ * @return string|null
  */
 function ctools_context_convert_context($context, $converter, $converter_options = array()) {
   // Contexts without plugins might be optional placeholders.
   if (empty($context->plugin)) {
-    return;
+    return NULL;
   }
 
   $value = $context->argument;
@@ -544,22 +883,35 @@ function ctools_context_convert_context($context, $converter, $converter_options
  * Choose a context or contexts based upon the selection made via
  * ctools_context_filter.
  *
- * @param $contexts
- *   A keyed array of all available contexts
- * @param $required
- *   The required context object provided by the plugin
+ * @param array $contexts
+ *   A keyed array of all available contexts.
+ * @param array|ctools_context_required $required
+ *   The required context object(s) provided by the plugin.
  * @param $context
- *   The selection made using ctools_context_selector
+ *   The selection made using ctools_context_selector().
+ *
+ * @return ctools_context|array|false
+ *   Returns FALSE if $required is not an object, or array of objects, or
+ *   the value of $required->select() for the context, or an array of those (if
+ *   passed an array in $required).
  */
 function ctools_context_select($contexts, $required, $context) {
   if (is_array($required)) {
+
+    /**
+     * @var array $required
+     *   Array of required context objects.
+     * @var ctools_context_required $item
+     *   A required context object.
+     */
     $result = array();
-    foreach ($required as $id => $r) {
+    foreach ($required as $id => $item) {
+      // @todo What's the difference between the following and "empty($item)" ?
       if (empty($required[$id])) {
         continue;
       }
 
-      if (($result[] = _ctools_context_select($contexts, $r, $context[$id])) === FALSE) {
+      if (($result[] = _ctools_context_select($contexts, $item, $context[$id])) === FALSE) {
         return FALSE;
       }
     }
@@ -569,6 +921,22 @@ function ctools_context_select($contexts, $required, $context) {
   return _ctools_context_select($contexts, $required, $context);
 }
 
+/**
+ * Helper function for calling the required context object's selection function.
+ *
+ * This function DOES NOT form part of the CTools API.
+ *
+ * @param array $contexts
+ *   A keyed array of all available contexts.
+ * @param ctools_context_required $required
+ *   The required context object provided by the plugin.
+ * @param $context
+ *   The selection made using ctools_context_selector().
+ *
+ * @return ctools_context|bool
+ *   FALSE if the $required is not an object. A ctools_context object if one
+ *   matched.
+ */
 function _ctools_context_select($contexts, $required, $context) {
   if (!is_object($required)) {
     return FALSE;
@@ -580,16 +948,14 @@ function _ctools_context_select($contexts, $required, $context) {
 /**
  * Create a new context object.
  *
- * @param $type
+ * @param string $type
  *   The type of context to create; this loads a plugin.
- * @param $data
+ * @param mixed $data
  *   The data to put into the context.
- * @param $empty
- *   Whether or not this context is specifically empty.
  * @param $conf
  *   A configuration structure if this context was created via UI.
  *
- * @return
+ * @return ctools_context
  *   A $context or NULL if one could not be created.
  */
 function ctools_context_create($type, $data = NULL, $conf = FALSE) {
@@ -612,7 +978,7 @@ function ctools_context_create($type, $data = NULL, $conf = FALSE) {
  * @param $type
  *   The type of context to create; this loads a plugin.
  *
- * @return
+ * @return ctools_context
  *   A $context or NULL if one could not be created.
  */
 function ctools_context_create_empty($type) {
@@ -629,8 +995,21 @@ function ctools_context_create_empty($type) {
 
 /**
  * Perform keyword and context substitutions.
+ *
+ * @param string $string
+ *   The string in which to replace keywords.
+ * @param array $keywords
+ *   Array of keyword-replacement pairs.
+ * @param array $contexts
+ *
+ * @param array $converter_options
+ *   Options to pass on to ctools_context_convert_context(), defaults to an
+ *   empty array.
+ *
+ * @return string
+ *   The returned string, with substitutions performed.
  */
-function ctools_context_keyword_substitute($string, $keywords, $contexts, $converter_options = array()) {
+function ctools_context_keyword_substitute($string, $keywords, $contexts, array $converter_options = array()) {
   // Ensure a default keyword exists:
   $keywords['%%'] = '%';
 
@@ -653,7 +1032,7 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
 
       // If the keyword is already set by something passed in, don't try to
       // overwrite it.
-      if (!empty($keywords['%' . $keyword])) {
+      if (array_key_exists('%' . $keyword, $keywords)) {
         continue;
       }
 
@@ -673,14 +1052,21 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
         }
       }
 
-      if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
-        $keywords['%' . $keyword] = '';
-      }
-      else if (!empty($converter)) {
-        $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+      if (!isset($context_keywords[$context])) {
+        $keywords['%' . $keyword] = '%' . $keyword;
       }
       else {
-        $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+        if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
+          $keywords['%' . $keyword] = '';
+        }
+        else {
+          if (!empty($converter)) {
+            $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+          }
+          else {
+            $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+          }
+        }
       }
     }
   }
@@ -688,18 +1074,22 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
 }
 
 /**
- * Determine a unique context ID for a context
+ * Determine a unique context ID for a context.
  *
  * Often contexts of many different types will be placed into a list. This
  * ensures that even though contexts of multiple types may share IDs, they
  * are unique in the final list.
  */
 function ctools_context_id($context, $type = 'context') {
-  if (!$context['id']) {
+  // If not set, FALSE or empty.
+  if (!isset($context['id']) || !$context['id']) {
     $context['id'] = 1;
   }
 
-  return $type . '_' . $context['name'] . '_' . $context['id'];
+  // @todo is '' the appropriate default value?
+  $name = isset($context['name']) ? $context['name'] : '';
+
+  return $type . '_' . $name . '_' . $context['id'];
 }
 
 /**
@@ -707,42 +1097,46 @@ function ctools_context_id($context, $type = 'context') {
  *
  * This finds the next id available for the named object.
  *
- * @param $objects
- *   A list of context descriptor objects, i.e, arguments, relationships, contexts, etc.
- * @param $name
+ * @param array $objects
+ *   A list of context descriptor objects, i.e, arguments, relationships,
+ *   contexts, etc.
+ * @param string $name
  *   The name being used.
+ *
+ * @return int
+ *   The next integer id available.
  */
 function ctools_context_next_id($objects, $name) {
   $id = 0;
-  // Figure out which instance of this argument we're creating
+  // Figure out which instance of this argument we're creating.
   if (!$objects) {
     return $id + 1;
   }
 
   foreach ($objects as $object) {
-    if (isset($object['name']) && $object['name'] == $name) {
-      if ($object['id'] > $id) {
-        $id = $object['id'];
+    if (isset($object['name']) && $object['name'] === $name) {
+      if (isset($object['id']) && $object['id'] > $id) {
+        $id = (int) $object['id'];
       }
+      // @todo If obj has no 'id', should we increment local id? $id = $id + 1;
     }
   }
 
   return $id + 1;
 }
 
-
 // ---------------------------------------------------------------------------
 // Functions related to contexts from arguments.
-
 /**
- * Fetch metadata on a specific argument plugin.
+ * Fetch metadata for a specific argument plugin.
  *
  * @param $argument
  *   Name of an argument plugin.
  *
- * @return
+ * @return array
  *   An array with information about the requested argument plugin.
  */
+
 function ctools_get_argument($argument) {
   ctools_include('plugins');
   return ctools_get_plugins('ctools', 'arguments', $argument);
@@ -751,7 +1145,7 @@ function ctools_get_argument($argument) {
 /**
  * Fetch metadata for all argument plugins.
  *
- * @return
+ * @return array
  *   An array of arrays with information about all available argument plugins.
  */
 function ctools_get_arguments() {
@@ -771,22 +1165,23 @@ function ctools_get_arguments() {
  *   - keyword: The keyword used for this argument for substitutions.
  *
  * @param $arg
- *   The actual argument received. This is expected to be a string from a URL but
- *   this does not have to be the only source of arguments.
+ *   The actual argument received. This is expected to be a string from a URL
+ *   but this does not have to be the only source of arguments.
  * @param $empty
  *   If true, the $arg will not be used to load the context. Instead, an empty
  *   placeholder context will be loaded.
  *
- * @return
+ * @return ctools_context
  *   A context object if one can be loaded.
  */
 function ctools_context_get_context_from_argument($argument, $arg, $empty = FALSE) {
   ctools_include('plugins');
   if (empty($argument['name'])) {
-    return;
+    return NULL;
   }
 
-  if ($function = ctools_plugin_load_function('ctools', 'arguments', $argument['name'], 'context')) {
+  $function = ctools_plugin_load_function('ctools', 'arguments', $argument['name'], 'context');
+  if ($function) {
     // Backward compatibility: Merge old style settings into new style:
     if (!empty($argument['settings'])) {
       $argument += $argument['settings'];
@@ -798,8 +1193,8 @@ function ctools_context_get_context_from_argument($argument, $arg, $empty = FALS
     if (is_object($context)) {
       $context->identifier = $argument['identifier'];
       $context->page_title = isset($argument['title']) ? $argument['title'] : '';
-      $context->keyword    = $argument['keyword'];
-      $context->id         = ctools_context_id($argument, 'argument');
+      $context->keyword = $argument['keyword'];
+      $context->id = ctools_context_id($argument, 'argument');
       $context->original_argument = $arg;
 
       if (!empty($context->empty)) {
@@ -815,6 +1210,12 @@ function ctools_context_get_context_from_argument($argument, $arg, $empty = FALS
 
 /**
  * Retrieve a list of empty contexts for all arguments.
+ *
+ * @param array $arguments
+ *
+ * @return array
+ *
+ * @see ctools_context_get_context_from_arguments()
  */
 function ctools_context_get_placeholders_from_argument($arguments) {
   $contexts = array();
@@ -830,19 +1231,21 @@ function ctools_context_get_placeholders_from_argument($arguments) {
 /**
  * Load the contexts for a given list of arguments.
  *
- * @param $arguments
+ * @param array $arguments
  *   The array of argument definitions.
- * @param &$contexts
+ * @param array &$contexts
  *   The array of existing contexts. New contexts will be added to this array.
- * @param $args
+ * @param array $args
  *   The arguments to load.
  *
- * @return
- *   FALSE if an argument wants to 404.
+ * @return bool
+ *   TRUE if all is well, FALSE if an argument wants to 404.
+ *
+ * @see ctools_context_get_context_from_argument()
  */
 function ctools_context_get_context_from_arguments($arguments, &$contexts, $args) {
   foreach ($arguments as $argument) {
-    // pull the argument off the list.
+    // Pull the argument off the list.
     $arg = array_shift($args);
     $id = ctools_context_id($argument, 'argument');
 
@@ -857,7 +1260,10 @@ function ctools_context_get_context_from_arguments($arguments, &$contexts, $args
       $context = $contexts[$id];
     }
 
-    if ((empty($context) || empty($context->data)) && !empty($argument['default']) && $argument['default'] == '404') {
+    if ((empty($context) || empty($context->data))
+      && !empty($argument['default'])
+      && $argument['default'] === '404'
+    ) {
       return FALSE;
     }
   }
@@ -866,16 +1272,18 @@ function ctools_context_get_context_from_arguments($arguments, &$contexts, $args
 
 // ---------------------------------------------------------------------------
 // Functions related to contexts from relationships.
-
 /**
- * Fetch metadata on a specific relationship plugin.
+ * Fetch plugin metadata for a specific relationship plugin.
  *
- * @param $content type
+ * @param $relationship
  *   Name of a panel content type.
  *
- * @return
+ * @return array
  *   An array with information about the requested relationship.
+ *
+ * @see ctools_get_relationships()
  */
+
 function ctools_get_relationship($relationship) {
   ctools_include('plugins');
   return ctools_get_plugins('ctools', 'relationships', $relationship);
@@ -884,8 +1292,10 @@ function ctools_get_relationship($relationship) {
 /**
  * Fetch metadata for all relationship plugins.
  *
- * @return
+ * @return array
  *   An array of arrays with information about all available relationships.
+ *
+ * @see ctools_get_relationship()
  */
 function ctools_get_relationships() {
   ctools_include('plugins');
@@ -893,8 +1303,9 @@ function ctools_get_relationships() {
 }
 
 /**
+ * Return a context from a relationship.
  *
- * @param $relationship
+ * @param array $relationship
  *   The configuration of a relationship. It must contain the following data:
  *   - name: The name of the relationship plugin being used.
  *   - relationship_settings: The configuration based upon the plugin forms.
@@ -902,18 +1313,21 @@ function ctools_get_relationships() {
  *     defined by the UI.
  *   - keyword: The keyword used for this relationship for substitutions.
  *
- * @param $source_context
+ * @param ctools_context $source_context
  *   The context this relationship is based upon.
- *
- * @param $placeholders
+ * @param bool $placeholders
  *   If TRUE, placeholders are acceptable.
  *
- * @return
- *   A context object if one can be loaded.
+ * @return ctools_context|null
+ *   A context object if one can be loaded, otherwise NULL.
+ *
+ * @see ctools_context_get_relevant_relationships()
+ * @see ctools_context_get_context_from_relationships()
  */
 function ctools_context_get_context_from_relationship($relationship, $source_context, $placeholders = FALSE) {
   ctools_include('plugins');
-  if ($function = ctools_plugin_load_function('ctools', 'relationships', $relationship['name'], 'context')) {
+  $function = ctools_plugin_load_function('ctools', 'relationships', $relationship['name'], 'context');
+  if ($function) {
     // Backward compatibility: Merge old style settings into new style:
     if (!empty($relationship['relationship_settings'])) {
       $relationship += $relationship['relationship_settings'];
@@ -924,7 +1338,7 @@ function ctools_context_get_context_from_relationship($relationship, $source_con
     if ($context) {
       $context->identifier = $relationship['identifier'];
       $context->page_title = isset($relationship['title']) ? $relationship['title'] : '';
-      $context->keyword    = $relationship['keyword'];
+      $context->keyword = $relationship['keyword'];
       if (!empty($context->empty)) {
         $context->placeholder = array(
           'type' => 'relationship',
@@ -934,6 +1348,7 @@ function ctools_context_get_context_from_relationship($relationship, $source_con
       return $context;
     }
   }
+  return NULL;
 }
 
 /**
@@ -947,18 +1362,24 @@ function ctools_context_get_context_from_relationship($relationship, $source_con
  * @param $contexts
  *   An array of contexts used to figure out which relationships are relevant.
  *
- * @return
+ * @return array
  *   An array of relationship keys that are relevant for the given set of
  *   contexts.
+ *
+ * @see ctools_context_filter()
+ * @see ctools_context_get_context_from_relationship()
+ * @see ctools_context_get_context_from_relationships()
  */
 function ctools_context_get_relevant_relationships($contexts) {
   $relevant = array();
   $relationships = ctools_get_relationships();
 
-  // Go through each relationship
+  // Go through each relationship.
   foreach ($relationships as $rid => $relationship) {
     // For each relationship, see if there is a context that satisfies it.
-    if (empty($relationship['no ui']) && ctools_context_filter($contexts, $relationship['required context'])) {
+    if (empty($relationship['no ui'])
+      && ctools_context_filter($contexts, $relationship['required context'])
+    ) {
       $relevant[$rid] = $relationship['title'];
     }
   }
@@ -967,7 +1388,7 @@ function ctools_context_get_relevant_relationships($contexts) {
 }
 
 /**
- * Fetch all active relationships
+ * Fetch all active relationships.
  *
  * @param $relationships
  *   An keyed array of relationship data including:
@@ -982,10 +1403,11 @@ function ctools_context_get_relevant_relationships($contexts) {
  *
  * @param $placeholders
  *   If TRUE, placeholders are acceptable.
+ *
+ * @see ctools_context_get_context_from_relationship()
+ * @see ctools_context_get_relevant_relationships()
  */
 function ctools_context_get_context_from_relationships($relationships, &$contexts, $placeholders = FALSE) {
-  $return = array();
-
   foreach ($relationships as $rdata) {
     if (!isset($rdata['context'])) {
       continue;
@@ -994,16 +1416,12 @@ function ctools_context_get_context_from_relationships($relationships, &$context
     if (is_array($rdata['context'])) {
       $rcontexts = array();
       foreach ($rdata['context'] as $cid) {
-        if (empty($contexts[$cid])) {
-          continue 2;
+        if (!empty($contexts[$cid])) {
+          $rcontexts[] = $contexts[$cid];
         }
-        $rcontexts[] = $contexts[$cid];
       }
     }
-    else {
-      if (empty($contexts[$rdata['context']])) {
-        continue;
-      }
+    elseif (!empty($contexts[$rdata['context']])) {
       $rcontexts = $contexts[$rdata['context']];
     }
 
@@ -1016,16 +1434,16 @@ function ctools_context_get_context_from_relationships($relationships, &$context
 
 // ---------------------------------------------------------------------------
 // Functions related to loading contexts from simple context definitions.
-
 /**
  * Fetch metadata on a specific context plugin.
  *
- * @param $context
+ * @param string $context
  *   Name of a context.
  *
- * @return
+ * @return array
  *   An array with information about the requested panel context.
  */
+
 function ctools_get_context($context) {
   static $gate = array();
   ctools_include('plugins');
@@ -1049,7 +1467,7 @@ function ctools_get_context($context) {
 /**
  * Fetch metadata for all context plugins.
  *
- * @return
+ * @return array
  *   An array of arrays with information about all available panel contexts.
  */
 function ctools_get_contexts() {
@@ -1058,27 +1476,38 @@ function ctools_get_contexts() {
 }
 
 /**
+ * Return a context object from a context definition array.
  *
- * @param $context
+ * The input $context contains the information needed to identify and invoke
+ * the context plugin and create the plugin context from that.
+ *
+ * @param array $context
  *   The configuration of a context. It must contain the following data:
  *   - name: The name of the context plugin being used.
  *   - context_settings: The configuration based upon the plugin forms.
  *   - identifier: The human readable identifier for this context, usually
  *     defined by the UI.
  *   - keyword: The keyword used for this context for substitutions.
- * @param $type
+ * @param string $type
  *   This is either 'context' which indicates the context will be loaded
- *   from data in the settings, or 'required_context' which means the
+ *   from data in the settings, or 'requiredcontext' which means the
  *   context must be acquired from an external source. This is the method
  *   used to pass pure contexts from one system to another.
+ * @param mixed $argument
+ *   Optional information passed to the plugin context via the arg defined in
+ *   the plugin's "placeholder name" field.
  *
- * @return
+ * @return ctools_context|null
  *   A context object if one can be loaded.
+ *
+ * @see ctools_get_context()
+ * @see ctools_plugin_get_function()
  */
 function ctools_context_get_context_from_context($context, $type = 'context', $argument = NULL) {
   ctools_include('plugins');
   $plugin = ctools_get_context($context['name']);
-  if ($function = ctools_plugin_get_function($plugin, 'context')) {
+  $function = ctools_plugin_get_function($plugin, 'context');
+  if ($function) {
     // Backward compatibility: Merge old style settings into new style:
     if (!empty($context['context_settings'])) {
       $context += $context['context_settings'];
@@ -1093,7 +1522,7 @@ function ctools_context_get_context_from_context($context, $type = 'context', $a
     if ($return) {
       $return->identifier = $context['identifier'];
       $return->page_title = isset($context['title']) ? $context['title'] : '';
-      $return->keyword    = $context['keyword'];
+      $return->keyword = $context['keyword'];
 
       if (!empty($context->empty)) {
         $context->placeholder = array(
@@ -1105,6 +1534,8 @@ function ctools_context_get_context_from_context($context, $type = 'context', $a
       return $return;
     }
   }
+
+  return NULL;
 }
 
 /**
@@ -1118,7 +1549,10 @@ function ctools_context_get_context_from_context($context, $type = 'context', $a
  *   Either 'context' or 'requiredcontext', which indicates whether the contexts
  *   are loaded from internal data or copied from an external source.
  * @param $placeholders
- *   If true, placeholders are acceptable.
+ *   If True, placeholders are acceptable.
+ *
+ * @return array
+ *   Array of contexts, keyed by context ID.
  */
 function ctools_context_get_context_from_contexts($contexts, $type = 'context', $placeholders = FALSE) {
   $return = array();
@@ -1137,17 +1571,20 @@ function ctools_context_get_context_from_contexts($contexts, $type = 'context',
 /**
  * Match up external contexts to our required contexts.
  *
- * This function is used to create a list of contexts with proper
- * IDs based upon a list of required contexts.
+ * This function is used to create a list of contexts with proper IDs based
+ * upon a list of required contexts.
  *
- * These contexts passed in should match the numeric positions of the
- * required contexts. The caller must ensure this has already happened
- * correctly as this function will not detect errors here.
+ * These contexts passed in should match the numeric positions of the required
+ * contexts. The caller must ensure this has already happened correctly as this
+ * function will not detect errors here.
  *
  * @param $required
  *   A list of required contexts as defined by the UI.
  * @param $contexts
  *   A list of matching contexts as passed in from the calling system.
+ *
+ * @return array
+ *   Array of contexts, keyed by context ID.
  */
 function ctools_context_match_required_contexts($required, $contexts) {
   $return = array();
@@ -1156,10 +1593,10 @@ function ctools_context_match_required_contexts($required, $contexts) {
   }
 
   foreach ($required as $r) {
-    $context = clone(array_shift($contexts));
+    $context = clone array_shift($contexts);
     $context->identifier = $r['identifier'];
     $context->page_title = isset($r['title']) ? $r['title'] : '';
-    $context->keyword    = $r['keyword'];
+    $context->keyword = $r['keyword'];
     $return[ctools_context_id($r, 'requiredcontext')] = $context;
   }
 
@@ -1171,31 +1608,35 @@ function ctools_context_match_required_contexts($required, $contexts) {
  *
  * Not all of the types need to be supported by this object.
  *
- * This function is not used to load contexts from external data, but may
- * be used to load internal contexts and relationships. Otherwise it can also
- * be used to generate a full set of placeholders for UI purposes.
+ * This function is not used to load contexts from external data, but may be
+ * used to load internal contexts and relationships. Otherwise it can also be
+ * used to generate a full set of placeholders for UI purposes.
  *
- * @param $object
+ * @param object $object
  *   An object that contains some or all of the following variables:
  *
- * - requiredcontexts: A list of UI configured contexts that are required
- *   from an external source. Since these require external data, they will
- *   only be added if $placeholders is set to TRUE, and empty contexts will
- *   be created.
- * - arguments: A list of UI configured arguments that will create contexts.
- *   Since these require external data, they will only be added if $placeholders
- *   is set to TRUE.
- * - contexts: A list of UI configured contexts that have no external source,
- *   and are essentially hardcoded. For example, these might configure a
- *   particular node or a particular taxonomy term.
- * - relationships: A list of UI configured contexts to be derived from other
- *   contexts that already exist from other sources. For example, these might
- *   be used to get a user object from a node via the node author relationship.
- * @param $placeholders
- *   If TRUE, this will generate placeholder objects for types this function
+ *   - requiredcontexts: A list of UI configured contexts that are required
+ *     from an external source. Since these require external data, they will
+ *     only be added if $placeholders is set to TRUE, and empty contexts will
+ *     be created.
+ *   - arguments: A list of UI configured arguments that will create contexts.
+ *     As these require external data, they will only be added if $placeholders
+ *     is set to TRUE.
+ *   - contexts: A list of UI configured contexts that have no external source,
+ *     and are essentially hardcoded. For example, these might configure a
+ *     particular node or a particular taxonomy term.
+ *   - relationships: A list of UI configured contexts to be derived from other
+ *     contexts that already exist from other sources. For example, these might
+ *     be used to get a user object from a node via the node author
+ *     relationship.
+ * @param bool $placeholders
+ *   If True, this will generate placeholder objects for any types this function
  *   cannot load.
- * @param $contexts
+ * @param array $contexts
  *   An array of pre-existing contexts that will be part of the return value.
+ *
+ * @return array
+ *   Merged output of all results of ctools_context_get_context_from_contexts().
  */
 function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts = array()) {
   if (!empty($object->base_contexts)) {
@@ -1219,7 +1660,7 @@ function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts =
     $contexts += ctools_context_get_context_from_contexts($object->contexts, 'context', $placeholders);
   }
 
-  // add contexts from relationships
+  // Add contexts from relationships.
   if (!empty($object->relationships) && is_array($object->relationships)) {
     ctools_context_get_context_from_relationships($object->relationships, $contexts, $placeholders);
   }
@@ -1238,7 +1679,7 @@ function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts =
 function ctools_context_get_form($contexts) {
   if (!empty($contexts)) {
     foreach ($contexts as $id => $context) {
-      // if a form shows its id as being a 'required context' that means the
+      // If a form shows its id as being a 'required context' that means the
       // the context is external to this display and does not count.
       if (!empty($context->form_id) && substr($id, 0, 15) != 'requiredcontext') {
         return $context;
@@ -1257,7 +1698,7 @@ function ctools_context_get_form($contexts) {
  *   The arguments. These will be acquired from $form_state['values'] and the
  *   keys must match the context IDs.
  *
- * @return
+ * @return array
  *   A new $contexts array containing the replaced contexts. Not all contexts
  *   may be replaced if, for example, an argument was unable to be converted
  *   into a context.
@@ -1276,12 +1717,14 @@ function ctools_context_replace_placeholders($contexts, $arguments) {
           $new_context = ctools_context_get_context_from_relationship($relationship, $contexts[$relationship['context']]);
         }
         break;
+
       case 'argument':
         if (isset($arguments[$cid]) && $arguments[$cid] !== '') {
           $argument = $context->placeholder['conf'];
           $new_context = ctools_context_get_context_from_argument($argument, $arguments[$cid]);
         }
         break;
+
       case 'context':
         if (!empty($arguments[$cid])) {
           $context_info = $context->placeholder['conf'];
@@ -1330,32 +1773,37 @@ function ctools_context_replace_form(&$form, $contexts) {
       if (is_array($plugin['placeholder form'])) {
         $form[$cid] = $plugin['placeholder form'];
       }
-      else if (function_exists($plugin['placeholder form'])) {
-        $widget = $plugin['placeholder form']($info);
-        if ($widget) {
-          $form[$cid] = $widget;
+      else {
+        if (function_exists($plugin['placeholder form'])) {
+          $widget = $plugin['placeholder form']($info);
+          if ($widget) {
+            $form[$cid] = $widget;
+          }
         }
       }
 
       if (!empty($form[$cid])) {
-        $form[$cid]['#title'] = t('@identifier (@keyword)', array('@keyword' => '%' . $context->keyword, '@identifier' => $context->identifier));
+        $form[$cid]['#title'] = t('@identifier (@keyword)', array(
+          '@keyword' => '%' . $context->keyword,
+          '@identifier' => $context->identifier,
+        ));
       }
     }
   }
 }
 
 // ---------------------------------------------------------------------------
-// Functions related to loading access control plugins
-
+// Functions related to loading access control plugins.
 /**
  * Fetch metadata on a specific access control plugin.
  *
  * @param $name
  *   Name of a plugin.
  *
- * @return
+ * @return array
  *   An array with information about the requested access control plugin.
  */
+
 function ctools_get_access_plugin($name) {
   ctools_include('plugins');
   return ctools_get_plugins('ctools', 'access', $name);
@@ -1364,7 +1812,7 @@ function ctools_get_access_plugin($name) {
 /**
  * Fetch metadata for all access control plugins.
  *
- * @return
+ * @return array
  *   An array of arrays with information about all available access control plugins.
  */
 function ctools_get_access_plugins() {
@@ -1376,8 +1824,14 @@ function ctools_get_access_plugins() {
  * Fetch a list of access plugins that are available for a given list of
  * contexts.
  *
- * if 'logged-in-user' is not in the list of contexts, it will be added as
+ * If 'logged-in-user' is not in the list of contexts, it will be added as
  * this is required.
+ *
+ * @param array $contexts
+ *   Array of ctools_context objects with which to select access plugins.
+ *
+ * @return array
+ *   Array of applicable access plugins. Can be empty.
  */
 function ctools_get_relevant_access_plugins($contexts) {
   if (!isset($contexts['logged-in-user'])) {
@@ -1387,7 +1841,9 @@ function ctools_get_relevant_access_plugins($contexts) {
   $all_plugins = ctools_get_access_plugins();
   $plugins = array();
   foreach ($all_plugins as $id => $plugin) {
-    if (!empty($plugin['required context']) && !ctools_context_match_requirements($contexts, $plugin['required context'])) {
+    if (!empty($plugin['required context'])
+      && !ctools_context_match_requirements($contexts, $plugin['required context'])
+    ) {
       continue;
     }
     $plugins[$id] = $plugin;
@@ -1402,14 +1858,17 @@ function ctools_get_relevant_access_plugins($contexts) {
 function ctools_access_get_loggedin_context() {
   $context = ctools_context_create('entity:user', array('type' => 'current'), TRUE);
   $context->identifier = t('Logged in user');
-  $context->keyword    = 'viewer';
-  $context->id         = 0;
+  $context->keyword = 'viewer';
+  $context->id = 0;
 
   return $context;
 }
 
 /**
  * Get a summary of an access plugin's settings.
+ *
+ * @return string
+ *   The summary text.
  */
 function ctools_access_summary($plugin, $contexts, $test) {
   if (!isset($contexts['logged-in-user'])) {
@@ -1419,8 +1878,9 @@ function ctools_access_summary($plugin, $contexts, $test) {
   $description = '';
   if ($function = ctools_plugin_get_function($plugin, 'summary')) {
     $required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
-    $context          = isset($test['context']) ? $test['context'] : array();
-    $description      = $function($test['settings'], ctools_context_select($contexts, $required_context, $context), $plugin);
+    $context = isset($test['context']) ? $test['context'] : array();
+    $selected_context = ctools_context_select($contexts, $required_context, $context);
+    $description = $function($test['settings'], $selected_context, $plugin);
   }
 
   if (!empty($test['not'])) {
@@ -1432,10 +1892,23 @@ function ctools_access_summary($plugin, $contexts, $test) {
 
 /**
  * Get a summary of a group of access plugin's settings.
+ *
+ * @param $access
+ *   An array of settings theoretically set by the user, including the array
+ *   of plugins to check:
+ *    - 'plugins': the array of plugin metadata info to check
+ *    - 'logic': (optional) either 'and' or 'or', indicating how to combine
+ *      restrictions. Defaults to 'or'.
+ * @param array $contexts
+ *   An array of zero or more contexts that may be used to determine if
+ *   the user has access.
+ *
+ * @return string
+ *   The summary text. Can be NULL if there are no plugins defined.
  */
 function ctools_access_group_summary($access, $contexts) {
-  if (empty($access['plugins'])) {
-    return;
+  if (empty($access['plugins']) || !is_array($access['plugins'])) {
+    return NULL;
   }
 
   $descriptions = array();
@@ -1444,21 +1917,29 @@ function ctools_access_group_summary($access, $contexts) {
     $descriptions[] = ctools_access_summary($plugin, $contexts, $test);
   }
 
-  $separator = (isset($access['logic']) && $access['logic'] == 'and') ? t(', and ') : t(', or ');
+  $separator =
+    (isset($access['logic']) && $access['logic'] === 'and')
+      ? t(', and ') : t(', or ');
   return implode($separator, $descriptions);
 }
 
 /**
- * Determine if the current user has access via  plugin.
+ * Determine if the current user has access via a plugin.
  *
- * @param $settings
- *   An array of settings theoretically set by the user.
- * @param $contexts
+ * @param array $settings
+ *   An array of settings theoretically set by the user, including the array
+ *   of plugins to check:
+ *    - 'plugins': the array of plugin metadata info to check
+ *    - 'logic': (optional) either 'and' or 'or', indicating how to combine
+ *      restrictions. The 'or' case is not fully implemented and returns the
+ *      input contexts unchanged.
+ *
+ * @param array $contexts
  *   An array of zero or more contexts that may be used to determine if
  *   the user has access.
  *
- * @return
- *   TRUE if access is granted, false if otherwise.
+ * @return bool
+ *   TRUE if access is granted, FALSE if otherwise.
  */
 function ctools_access($settings, $contexts = array()) {
   if (empty($settings['plugins'])) {
@@ -1497,15 +1978,15 @@ function ctools_access($settings, $contexts = array()) {
       // Pass if 'or' and this rule passed.
       return TRUE;
     }
-    else if (!$pass && $settings['logic'] == 'and') {
-      // Fail if 'and' and htis rule failed.
+    elseif (!$pass && $settings['logic'] == 'and') {
+      // Fail if 'and' and this rule failed.
       return FALSE;
     }
   }
 
   // Return TRUE if logic was and, meaning all rules passed.
   // Return FALSE if logic was or, meaning no rule passed.
-  return $settings['logic'] == 'and';
+  return ($settings['logic'] === 'and');
 }
 
 /**
@@ -1514,7 +1995,7 @@ function ctools_access($settings, $contexts = array()) {
  * @param $plugin
  *   The access plugin being used.
  *
- * @return
+ * @return array
  *   A default configured test that should be placed in $access['plugins'];
  */
 function ctools_access_new_test($plugin) {
@@ -1536,7 +2017,6 @@ function ctools_access_new_test($plugin) {
     }
   }
 
-
   $default = NULL;
   if (isset($plugin['default'])) {
     $default = $plugin['default'];
@@ -1550,7 +2030,7 @@ function ctools_access_new_test($plugin) {
     if (is_array($default)) {
       $test['settings'] = $default;
     }
-    else if (function_exists($default)) {
+    elseif (function_exists($default)) {
       $test['settings'] = $default();
     }
     else {
@@ -1564,11 +2044,23 @@ function ctools_access_new_test($plugin) {
 /**
  * Apply restrictions to contexts based upon the access control configured.
  *
- * These restrictions allow the UI to not show content that may not
- * be relevant to all types of a particular context.
+ * These restrictions allow the UI to not show content that may not be relevant
+ * to all types of a particular context.
+ *
+ * @param array $settings
+ *   Array of keys specifying the settings:
+ *    - 'plugins': the array of plugin metadata info to check. If not set, or
+ *      not an array, the function returns with no action.
+ *    - 'logic': (optional) either 'and' or 'or', indicating how to combine
+ *      restrictions. Defaults to 'and'.
+ *      The 'or' case is not fully implemented and returns with no action if
+ *      there is more than one plugin.
+ *
+ * @param array $contexts
+ *   Array of available contexts.
  */
 function ctools_access_add_restrictions($settings, $contexts) {
-  if (empty($settings['plugins'])) {
+  if (empty($settings['plugins']) || !is_array($settings['plugins'])) {
     return;
   }
 
@@ -1577,17 +2069,23 @@ function ctools_access_add_restrictions($settings, $contexts) {
   }
 
   // We're not going to try to figure out restrictions on the or.
-  if ($settings['logic'] == 'or' && count($settings['plugins']) > 1) {
+  if ($settings['logic'] === 'or' && count($settings['plugins']) > 1) {
     return;
   }
 
   foreach ($settings['plugins'] as $test) {
     $plugin = ctools_get_access_plugin($test['name']);
-    if ($plugin && $function = ctools_plugin_get_function($plugin, 'restrictions')) {
+    // $plugin is 'array()' on error.
+    if ($plugin
+      && $function = ctools_plugin_get_function($plugin, 'restrictions')
+    ) {
       $required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
       $context = isset($test['context']) ? $test['context'] : array();
       $contexts = ctools_context_select($contexts, $required_context, $context);
-      $function($test['settings'], $contexts);
+
+      if ($contexts !== FALSE) {
+        $function($test['settings'], $contexts);
+      }
     }
   }
 }
diff --git a/includes/context.menu.inc b/includes/context.menu.inc
index ee227cb74699e12434f2ab21a39b858e904eb3e0..798d167ce746bf106eb9d56eee2fdf0216852f15 100644
--- a/includes/context.menu.inc
+++ b/includes/context.menu.inc
@@ -25,7 +25,7 @@ function ctools_context_menu(&$items) {
     'page callback' => 'ctools_context_ajax_item_delete',
   ) + $base;
 
-  // For the access system
+  // For the access system.
   $base['file'] = 'includes/context-access-admin.inc';
   $items['ctools/context/ajax/access/add'] = array(
     'page callback' => 'ctools_access_ajax_add',
diff --git a/includes/context.theme.inc b/includes/context.theme.inc
index 8f660b8c004afce38ea18ad8cc3f48cd7ec39d97..d0d866f78556ba7df3ec300a170c005244a97bb9 100644
--- a/includes/context.theme.inc
+++ b/includes/context.theme.inc
@@ -19,7 +19,6 @@ function ctools_context_theme(&$theme) {
   );
   $theme['ctools_context_item_form'] = array(
     'render element' => 'form',
-//    'variables' => array('form' => NULL),
     'file' => 'includes/context.theme.inc',
   );
   $theme['ctools_context_item_row'] = array(
@@ -27,7 +26,7 @@ function ctools_context_theme(&$theme) {
     'file' => 'includes/context.theme.inc',
   );
 
-  // For the access plugin
+  // For the access plugin.
   $theme['ctools_access_admin_add'] = array(
     'render element' => 'form',
     'file' => 'includes/context-access-admin.inc',
@@ -62,10 +61,10 @@ function theme_ctools_context_item_row($vars) {
 function theme_ctools_context_item_form($vars) {
   $form = $vars['form'];
 
-  $output = '';
-  $type   = $form['#ctools_context_type'];
-  $module = $form['#ctools_context_module'];
-  $cache_key   = $form['#cache_key'];
+  $output    = '';
+  $type      = $form['#ctools_context_type'];
+  $module    = $form['#ctools_context_module'];
+  $cache_key = $form['#cache_key'];
 
   $type_info = ctools_context_info($type);
 
@@ -104,17 +103,17 @@ function theme_ctools_context_item_form($vars) {
 
   if (!empty($form['buttons'])) {
     // Display the add context item.
-    $row   = array();
-    $row[] = array('data' => render($form['buttons'][$type]['item']), 'class' => array('title'));
-    $row[] = array('data' => render($form['buttons'][$type]['add']), 'class' => array('add'), 'width' => "60%");
-    $output .= '<div class="buttons">';
-    $output .= render($form['buttons'][$type]);
-    $theme_vars = array();
-    $theme_vars['header'] = array();
-    $theme_vars['rows'] = array($row);
+    $row                      = array();
+    $row[]                    = array('data' => render($form['buttons'][$type]['item']), 'class' => array('title'));
+    $row[]                    = array('data' => render($form['buttons'][$type]['add']), 'class' => array('add'), 'width' => "60%");
+    $output                  .= '<div class="buttons">';
+    $output                  .= render($form['buttons'][$type]);
+    $theme_vars               = array();
+    $theme_vars['header']     = array();
+    $theme_vars['rows']       = array($row);
     $theme_vars['attributes'] = array('id' => $type . '-add-table');
-    $output .= theme('table', $theme_vars);
-    $output .= '</div>';
+    $output                  .= theme('table', $theme_vars);
+    $output                  .= '</div>';
   }
   if (!empty($form['description'])) {
     $output .= render($form['description']);
@@ -139,7 +138,7 @@ function theme_ctools_context_list($vars) {
   $description = (!empty($vars['description'])) ? $vars['description'] : NULL;
   $titles = array();
   $output = '';
-  $count  = 1;
+  $count = 1;
 
   $contexts = ctools_context_load_contexts($object);
 
@@ -209,7 +208,7 @@ function theme_ctools_context_list($vars) {
     }
   }
 
-  // And relationships
+  // And relationships.
   if (!empty($object->relationships)) {
     foreach ($object->relationships as $relationship) {
       $output .= '<tr>';
@@ -253,15 +252,15 @@ function theme_ctools_context_list($vars) {
 }
 
 /**
- * ctools_context_list() but not in a table format because tabledrag
- * won't let us have tables within tables and still drag.
+ * The ctools_context_list() function but not in a table format because
+ * tabledrag won't let us have tables within tables and still drag.
  */
 function theme_ctools_context_list_no_table($vars) {
   $object = $vars['object'];
   ctools_add_css('context');
   $titles = array();
   $output = '';
-  $count  = 1;
+  $count = 1;
   // Describe 'built in' contexts.
   if (!empty($object->base_contexts)) {
     foreach ($object->base_contexts as $id => $context) {
@@ -312,7 +311,7 @@ function theme_ctools_context_list_no_table($vars) {
       $count++;
     }
   }
-  // And relationships
+  // And relationships.
   if (!empty($object->relationships)) {
     foreach ($object->relationships as $relationship) {
       $output .= '<div class="ctools-context-holder clearfix">';
@@ -341,4 +340,3 @@ function theme_ctools_context_list_no_table($vars) {
 
   return $output;
 }
-
diff --git a/includes/css-cache.inc b/includes/css-cache.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d88160b5b88b569b54a8e29fa4742567be9d2d79
--- /dev/null
+++ b/includes/css-cache.inc
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Custom cache implementation for the CTools CSS cache.
+ */
+
+class CToolsCssCache implements DrupalCacheInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clear($cid = NULL, $wildcard = FALSE) {
+    // Only clear the caches if the wildcard is set, this ensures that the cache
+    // is only cleared when the full caches are cleared manually (eg by invoking
+    // drupal_flush_all_caches()), and not on a cron run.
+    // @see drupal_flush_all_caches()
+    // @see system_cron()
+    if ($wildcard) {
+      ctools_include('css');
+      ctools_css_flush_caches();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid) {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = CACHE_PERMANENT) {
+  }
+
+}
diff --git a/includes/css.inc b/includes/css.inc
index 9813a8720ae51e203a6373dd37c1cd5838bcb379..83fe1c34ca3e57bf8c9b4943472c7622ba5c6755 100644
--- a/includes/css.inc
+++ b/includes/css.inc
@@ -1,6 +1,6 @@
 <?php
 
-/*
+/**
  * @file
  * CSS filtering functions. Contains a disassembler, filter, compressor, and
  * decompressor.
@@ -149,11 +149,11 @@ function ctools_css_clear($id) {
  *
  * @param $css
  *   A chunk of well-formed CSS text to cache.
- * @param $filter
+ * @param bool $filter
  *   If TRUE the css will be filtered. If FALSE the text will be cached
  *   as-is.
  *
- * @return $filename
+ * @return string
  *   The filename the CSS will be cached in.
  */
 function ctools_css_cache($css, $filter = TRUE) {
@@ -164,7 +164,6 @@ function ctools_css_cache($css, $filter = TRUE) {
   // Create the css/ within the files folder.
   $path = 'public://ctools/css';
   if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
-//  if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
     drupal_set_message(t('Unable to create CTools CSS cache directory. Check the permissions on your files directory.'), 'error');
     return;
   }
@@ -172,10 +171,12 @@ function ctools_css_cache($css, $filter = TRUE) {
   // @todo Is this slow? Does it matter if it is?
   $filename = $path . '/' . md5($css) . '.css';
 
-  // This will do renames if the file already exists, ensuring we don't
-  // accidentally overwrite other files who share the same md5. Yes this
-  // is a very miniscule chance but it's safe.
-  $filename = file_unmanaged_save_data($css, $filename);
+  // Generally md5 is considered unique enough to sign file downloads.
+  // So this replaces already existing files based on the assumption that two
+  // files with the same hash are identical content wise.
+  // If we rename, the cache folder can potentially fill up with thousands of
+  // files with the same content.
+  $filename = file_unmanaged_save_data($css, $filename, FILE_EXISTS_REPLACE);
 
   return $filename;
 }
@@ -211,7 +212,7 @@ function ctools_css_filter($css, $compressed = TRUE) {
  *   An array of css data, as produced by @see ctools_css_disassemble()
  *   disassembler and the @see ctools_css_filter_css_data() filter.
  *
- * @return string $css
+ * @return string
  *   css optimized for human viewing.
  */
 function ctools_css_assemble($css_data) {
@@ -241,7 +242,7 @@ function ctools_css_assemble($css_data) {
  *   An array of css data, as produced by @see ctools_css_disassemble()
  *   disassembler and the @see ctools_css_filter_css_data() filter.
  *
- * @return string $css
+ * @return string
  *   css optimized for use.
  */
 function ctools_css_compress($css_data) {
@@ -277,7 +278,7 @@ function ctools_css_compress($css_data) {
  * @param string $css
  *   A string containing the css to be disassembled.
  *
- * @return array $disassembled_css
+ * @return array
  *   An array of disassembled, slightly cleaned-up/formatted css statements.
  */
 function ctools_css_disassemble($css) {
@@ -383,7 +384,6 @@ function _ctools_css_disassemble_declaration($declaration) {
  *   An array of disassembled, filtered CSS.
  */
 function ctools_css_filter_css_data($css, $allowed_properties = array(), $allowed_values = array(), $allowed_values_regex = '', $disallowed_values_regex = '') {
-//function ctools_css_filter_css_data($css, &$filtered = NULL, $allowed_properties = array(), $allowed_values = array(), $allowed_values_regex = '', $disallowed_values_regex = '') {
   // Retrieve the default list of allowed properties if none is provided.
   $allowed_properties = !empty($allowed_properties) ? $allowed_properties : ctools_css_filter_default_allowed_properties();
   // Retrieve the default list of allowed values if none is provided.
@@ -391,19 +391,18 @@ function ctools_css_filter_css_data($css, $allowed_properties = array(), $allowe
   // Define allowed values regex if none is provided.
   $allowed_values_regex = !empty($allowed_values_regex) ? $allowed_values_regex : '/(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)/';
   // Define disallowed url() value contents, if none is provided.
-  // $disallowed_values_regex = !empty($disallowed_values_regex) ? $disallowed_values_regex : '/[url|expression]\s*\(\s*[^\s)]+?\s*\)\s*/';
   $disallowed_values_regex = !empty($disallowed_values_regex) ? $disallowed_values_regex : '/(url|expression)/';
 
   foreach ($css as $selector_str => $declaration) {
     foreach ($declaration as $property => $value) {
       if (!in_array($property, $allowed_properties)) {
-        // $filtered['properties'][$selector_str][$property] = $value;
+        // $filtered['properties'][$selector_str][$property] = $value;.
         unset($css[$selector_str][$property]);
         continue;
       }
       $value = str_replace('!important', '', $value);
       if (preg_match($disallowed_values_regex, $value) || !(in_array($value, $allowed_values) || preg_match($allowed_values_regex, $value))) {
-        // $filtered['values'][$selector_str][$property] = $value;
+        // $filtered['values'][$selector_str][$property] = $value;.
         unset($css[$selector_str][$property]);
         continue;
       }
diff --git a/includes/dependent.inc b/includes/dependent.inc
index 74de919716ea788bdb05dda376cbf7f152be0f66..20c25ded895a0eb3006d85698a22e159ca6223c1 100644
--- a/includes/dependent.inc
+++ b/includes/dependent.inc
@@ -44,7 +44,7 @@
  *
  * A fuller example, that hides the menu title when no menu is selected:
  * @code
- *function ctools_dependent_example() {
+ * function ctools_dependent_example() {
  *  $form = array();
  *  $form['menu'] = array(
  *    '#type' => 'fieldset',
@@ -72,12 +72,12 @@
  *   );
  *
  *  return system_settings_form($form);
- *}
+ * }
  * @endcode
  *
  * An example for hiding checkboxes using #prefix and #suffix:
  * @code
- *function ctools_dependent_example_checkbox() {
+ * function ctools_dependent_example_checkbox() {
  *  $form = array();
  *  $form['object'] = array(
  *    '#type' => 'fieldset',
@@ -111,7 +111,7 @@
  *   );
  *
  *  return system_settings_form($form);
- *}
+ * }
  * @endcode
  *
  * Deprecated:
@@ -125,7 +125,6 @@
 
 /**
  * Process callback to add dependency to form items.
- *
  */
 function ctools_dependent_process($element, &$form_state, &$form) {
   return $element;
diff --git a/includes/dropbutton.theme.inc b/includes/dropbutton.theme.inc
index fcdd5a37a7f9506a6059441b2cd936108a368062..4b95ef0dfb65ed9130c0ff836241a340d577f1ac 100644
--- a/includes/dropbutton.theme.inc
+++ b/includes/dropbutton.theme.inc
@@ -75,7 +75,7 @@ function theme_links__ctools_dropbutton($vars) {
   if (!empty($vars['links'])) {
     $is_drop_button = (count($vars['links']) > 1);
 
-    // Add needed files
+    // Add needed files.
     if ($is_drop_button) {
       ctools_add_js('dropbutton');
       ctools_add_css('dropbutton');
@@ -86,7 +86,7 @@ function theme_links__ctools_dropbutton($vars) {
     static $id = 0;
     $id++;
 
-    // Wrapping div
+    // Wrapping div.
     $class = 'ctools-no-js';
     $class .= ($is_drop_button) ? ' ctools-dropbutton' : '';
     $class .= ' ctools-button';
@@ -98,21 +98,22 @@ function theme_links__ctools_dropbutton($vars) {
 
     $output .= '<div class="' . $class . '" id="ctools-button-' . $id . '">';
 
-    // Add a twisty if this is a dropbutton
+    // Add a twisty if this is a dropbutton.
     if ($is_drop_button) {
       $vars['title'] = ($vars['title'] ? check_plain($vars['title']) : t('open'));
 
       $output .= '<div class="ctools-link">';
       if ($vars['image']) {
-        $output .= '<a href="#" class="ctools-twisty ctools-image">' . $vars['title'] . '</a>';
+        $output .= '<a href="#" class="ctools-twisty ctools-image"><span class="element-invisible">' . $vars['title'] . '</span></a>';
       }
       else {
-        $output .= '<a href="#" class="ctools-twisty ctools-text">' . $vars['title'] . '</a>';
+        $output .= '<a href="#" class="ctools-twisty ctools-text"><span class="element-invisible">' . $vars['title'] . '</span></a>';
       }
-      $output .= '</div>'; // ctools-link
+      // ctools-link.
+      $output .= '</div>';
     }
 
-    // The button content
+    // The button content.
     $output .= '<div class="ctools-content">';
 
     // Check for attributes. theme_links expects an array().
@@ -132,12 +133,11 @@ function theme_links__ctools_dropbutton($vars) {
 
     // Call theme_links to render the list of links.
     $output .= theme_links(array('links' => $vars['links'], 'attributes' => $vars['attributes'], 'heading' => ''));
-    $output .= '</div>'; // ctools-content
-    $output .= '</div>'; // ctools-dropbutton
+    $output .= '</div>'; // ctools-content.
+    $output .= '</div>'; // ctools-dropbutton.
     return $output;
   }
   else {
     return '';
   }
 }
-
diff --git a/includes/dropdown.theme.inc b/includes/dropdown.theme.inc
index 7e748f5e9c5b7226365708d7475b98aedd926955..b7636874fff7d0f5bee9825707906f1aad06999c 100644
--- a/includes/dropdown.theme.inc
+++ b/includes/dropdown.theme.inc
@@ -44,20 +44,21 @@ function ctools_dropdown_theme(&$items) {
 /**
  * Create a dropdown menu.
  *
- * @param $title
- *   The text to place in the clickable area to activate the dropdown.
- * @param $links
- *   A list of links to provide within the dropdown, suitable for use
- *   in via Drupal's theme('links').
- * @param $image
- *   If true, the dropdown link is an image and will not get extra decorations
- *   that a text dropdown link will.
- * @param $class
- *   An optional class to add to the dropdown's container div to allow you
- *   to style a single dropdown however you like without interfering with
- *   other dropdowns.
+ * @param array $variables
+ *   An associative array containing:
+ *   - title: The text to place in the clickable area to activate the dropdown.
+ *   - links: A list of links to provide within the dropdown, suitable for use
+ *     in via Drupal's theme('links').
+ *   - image: If true, the dropdown link is an image and will not get extra
+ *     decorations that a text dropdown link will.
+ *   - class: An optional class to add to the dropdown's container div to allow
+ *     you to style a single dropdown however you like without interfering with
+ *     other dropdowns.
+ *
+ * @return string
+ *   Returns HTML for a language configuration form.
  */
-function theme_ctools_dropdown($vars) { 
+function theme_ctools_dropdown($vars) {
   // Provide a unique identifier for every dropdown on the page.
   static $id = 0;
   $id++;
@@ -67,9 +68,7 @@ function theme_ctools_dropdown($vars) {
   ctools_add_js('dropdown');
   ctools_add_css('dropdown');
 
-  $output = '';
-
-  $output .= '<div class="' . $class . '" id="ctools-dropdown-' . $id . '">';
+  $output = '<div class="' . $class . '" id="ctools-dropdown-' . $id . '">';
   $output .= '<div class="ctools-dropdown-link-wrapper">';
   if ($vars['image']) {
     $output .= '<a href="#" class="ctools-dropdown-link ctools-dropdown-image-link">' . $vars['title'] . '</a>';
@@ -77,14 +76,13 @@ function theme_ctools_dropdown($vars) {
   else {
     $output .= '<a href="#" class="ctools-dropdown-link ctools-dropdown-text-link">' . check_plain($vars['title']) . '</a>';
   }
-
-  $output .= '</div>'; // wrapper
+  $output .= '</div>';
   $output .= '<div class="ctools-dropdown-container-wrapper">';
   $output .= '<div class="ctools-dropdown-container">';
   $output .= theme_links(array('links' => $vars['links'], 'attributes' => array(), 'heading' => ''));
-  $output .= '</div>'; // container
-  $output .= '</div>'; // container wrapper
-  $output .= '</div>'; // dropdown
+  $output .= '</div>';
+  $output .= '</div>';
+  $output .= '</div>';
+
   return $output;
 }
-
diff --git a/includes/entity-access.inc b/includes/entity-access.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8140f51a63311f4b24d62757a011398645471163
--- /dev/null
+++ b/includes/entity-access.inc
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * @file
+ * Provides various callbacks for the whole core module integration.
+ * This is a copy of Entity API's functionality for use when Entity API isn't
+ * Enabled, and only works on view functions.
+ */
+
+/**
+ * Core hack to include entity api-esque 'access callback' functions to core
+ * entities without needing to rely on entity api.
+ * Exception: We don't touch file entity. You must have entity API enabled to
+ * view files.
+ */
+function _ctools_entity_access(&$entity_info, $entity_type) {
+  // If the access callback is already set, don't change anything.
+  if (isset($entity_info['access callback'])) {
+    return;
+  }
+
+  switch ($entity_type) {
+    case 'node':
+      // Sad panda, we don't use Entity API, lets manually add access callbacks.
+      $entity_info['access callback'] = 'ctools_metadata_no_hook_node_access';
+      break;
+
+    case 'user':
+      $entity_info['access callback'] = 'ctools_metadata_user_access';
+      break;
+
+    case 'comment':
+      if (module_exists('comment')) {
+        $entity_info['access callback'] = 'ctools_metadata_comment_access';
+      }
+      break;
+
+    case 'taxonomy_term':
+      if (module_exists('taxonomy')) {
+        $entity_info['access callback'] = 'ctools_metadata_taxonomy_access';
+      }
+      break;
+
+    case 'taxonomy_vocabulary':
+      if (module_exists('taxonomy')) {
+        $entity_info['access callback'] = 'ctools_metadata_taxonomy_access';
+      }
+      break;
+  }
+}
+
+/**
+ * Access callback for the node entity.
+ *
+ * This function does not implement hook_node_access(), thus it may not be
+ * called ctools_metadata_node_access().
+ *
+ * @see entity_access()
+ *
+ * @param $op
+ *   The operation being performed. One of 'view', 'update', 'create' or
+ *   'delete'.
+ * @param $node
+ *   A node to check access for. Must be a node object. Must have nid,
+ *   except in the case of 'create' operations.
+ * @param $account
+ *   The user to check for. Leave it to NULL to check for the global user.
+ *
+ * @throws EntityMalformedException
+ *
+ * @return bool
+ *   TRUE if access is allowed, FALSE otherwise.
+ */
+function ctools_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
+  // First deal with the case where a $node is provided.
+  if (isset($node)) {
+    // If a non-default revision is given, incorporate revision access.
+    $default_revision = node_load($node->nid);
+    if ($node->vid !== $default_revision->vid) {
+      return _node_revision_access($node, $op, $account);
+    }
+    else {
+      return node_access($op, $node, $account);
+    }
+  }
+  // No node is provided. Check for access to all nodes.
+  if (user_access('bypass node access', $account)) {
+    return TRUE;
+  }
+  if (!user_access('access content', $account)) {
+    return FALSE;
+  }
+  if ($op == 'view' && node_access_view_all_nodes($account)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the user entity.
+ */
+function ctools_metadata_user_access($op, $entity, $account , $entity_type) {
+  $account = isset($account) ? $account : $GLOBALS['user'];
+  // Grant access to the users own user account and to the anonymous one.
+  if (isset($entity) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
+    return TRUE;
+  }
+  if (user_access('administer users', $account) || user_access('access user profiles', $account) && $op == 'view' && $entity->status) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the comment entity.
+ */
+function ctools_metadata_comment_access($op, $entity = NULL, $account = NULL) {
+  // When determining access to a comment, if comment has an associated node,
+  // the user must be able to view the node in order to access the comment.
+  if (isset($entity->nid)) {
+    if (!node_access('view', node_load($entity->nid), $account)) {
+      return FALSE;
+    }
+  }
+
+  // Comment administrators are allowed to perform all operations on all
+  // comments.
+  if (user_access('administer comments', $account)) {
+    return TRUE;
+  }
+
+  // Unpublished comments can never be accessed by non-admins.
+  if (isset($entity->status) && $entity->status == COMMENT_NOT_PUBLISHED) {
+    return FALSE;
+  }
+
+  if (user_access('access comments', $account) && $op == 'view') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the taxonomy entities.
+ */
+function ctools_metadata_taxonomy_access($op, $entity, $account, $entity_type) {
+
+  if ($entity_type == 'taxonomy_vocabulary') {
+    return user_access('administer taxonomy', $account);
+  }
+  if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') {
+    return TRUE;
+  }
+  return FALSE;
+}
diff --git a/includes/export-ui.inc b/includes/export-ui.inc
index 16e57d6ed4b0a94318002c88d553c3740e93fd28..1158ac8f626935aff4888ede5ad82fc1f71d5dcd 100644
--- a/includes/export-ui.inc
+++ b/includes/export-ui.inc
@@ -81,7 +81,6 @@ function ctools_export_ui_process(&$plugin, $info) {
   // Add some default fields that appear often in exports
   // If these use different keys they can easily be specified in the
   // $plugin.
-
   if (empty($plugin['export']['admin_title']) && !empty($schema['fields']['admin_title'])) {
     $plugin['export']['admin_title'] = 'admin_title';
   }
@@ -297,7 +296,6 @@ function ctools_export_ui_process(&$plugin, $info) {
   );
 
   // Define strings.
-
   // For all strings, %title may be filled in at a later time via str_replace
   // since we do not know the title now.
   $plugin['strings'] += array(
@@ -335,7 +333,7 @@ function ctools_export_ui_process(&$plugin, $info) {
 
   $plugin['strings']['confirmation']['delete'] += array(
     'question' => t('Are you sure you want to delete %title?'),
-    'information' => t('This action will permanently remove this item from your database..'),
+    'information' => t('This action will permanently remove this item from your database.'),
     'success' => t('The item has been deleted.'),
   );
 
@@ -414,6 +412,7 @@ function ctools_export_ui_plugin_base_path($plugin) {
  *   The id in the menu items from the plugin.
  * @param $export_key
  *   The export key of the item being edited, if it exists.
+ *
  * @return
  *   The menu path to the plugin's list.
  */
@@ -429,12 +428,11 @@ function ctools_export_ui_plugin_menu_path($plugin, $item_id, $export_key = NULL
  * Helper function to include CTools plugins and get an export-ui exportable.
  *
  * @param $plugin_name
- *   The plugin that should be laoded.
+ *   The plugin that should be loaded.
  */
 function ctools_get_export_ui($plugin_name) {
   ctools_include('plugins');
   return ctools_get_plugins('ctools', 'export_ui', $plugin_name);
-
 }
 
 /**
@@ -456,20 +454,22 @@ function ctools_export_ui_switcher_page($plugin_name, $op) {
   $args = func_get_args();
   $js = !empty($_REQUEST['js']);
 
-  // Load the $plugin information
+  // Load the $plugin information.
   $plugin = ctools_get_export_ui($plugin_name);
-  $handler = ctools_export_ui_get_handler($plugin);
-
-  if ($handler) {
-    $method = $op . '_page';
-    if (method_exists($handler, $method)) {
-      // replace the first two arguments:
-      $args[0] = $js;
-      $args[1] = $_POST;
-      return call_user_func_array(array($handler, $method), $args);
-    }
+  if (!$plugin) {
+    return t('Configuration error. No plugin found: %plugin_name.', array('%plugin_name' => $plugin_name));
   }
-  else {
+
+  $handler = ctools_export_ui_get_handler($plugin);
+  if (!$handler) {
     return t('Configuration error. No handler found.');
   }
+
+  $method = $op . '_page';
+  if (method_exists($handler, $method)) {
+    // Replace the first two arguments:
+    $args[0] = $js;
+    $args[1] = $_POST;
+    return call_user_func_array(array($handler, $method), $args);
+  }
 }
diff --git a/includes/export-ui.menu.inc b/includes/export-ui.menu.inc
index d27bf157a1c4e0078e9e7053807bc4cd92fb5941..0fda8c25693174818f2f742508236e128ef2438c 100644
--- a/includes/export-ui.menu.inc
+++ b/includes/export-ui.menu.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Delegated implementation of hook_menu().
  */
diff --git a/includes/export-ui.plugin-type.inc b/includes/export-ui.plugin-type.inc
index f1a7510955517c7cc0c66bfbb8d831d0918224a0..baa79f3748e0510146d64e313327be48957e7635 100644
--- a/includes/export-ui.plugin-type.inc
+++ b/includes/export-ui.plugin-type.inc
@@ -17,4 +17,4 @@ function ctools_export_ui_plugin_type(&$items) {
     ),
     'classes' => array('handler'),
   );
-}
\ No newline at end of file
+}
diff --git a/includes/export.inc b/includes/export.inc
index 0b85c2ef9422c482f1a7eb119f2bf5aff62a03b8..efc356efb0a919471762d5f0e3ca9c05d1e5b27d 100644
--- a/includes/export.inc
+++ b/includes/export.inc
@@ -4,7 +4,7 @@
  * @file
  * Contains code to make it easier to have exportable objects.
  *
- * Documentation for exportable objects is contained in help/export.html
+ * Documentation for exportable objects is contained in help/export.html.
  */
 
 /**
@@ -126,6 +126,7 @@ function ctools_export_crud_load_multiple($table, array $names) {
  *   If TRUE, the static cache of all objects will be flushed prior to
  *   loading all. This can be important on listing pages where items
  *   might have changed on the page load.
+ *
  * @return
  *   An array of all loaded objects, keyed by the unique IDs of the export key.
  */
@@ -328,7 +329,6 @@ function ctools_export_crud_set_status($table, $object, $status) {
 
 }
 
-
 /**
  * Enable a certain object.
  *
@@ -426,7 +426,7 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
     }
   }
 
-  // Build the query
+  // Build the query.
   $query = db_select($table, 't__0')->fields('t__0');
   $alias_count = 1;
   if (!empty($schema['join'])) {
@@ -451,7 +451,7 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
   if ($type == 'names') {
     $query->condition($export['key'], $args, 'IN');
   }
-  else if ($type == 'conditions') {
+  elseif ($type == 'conditions') {
     foreach ($args as $key => $value) {
       if (isset($schema['fields'][$key])) {
         $query->condition($key, $value);
@@ -499,7 +499,7 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
   if ($defaults) {
     foreach ($defaults as $object) {
       if ($type == 'conditions') {
-        // if this does not match all of our conditions, skip it.
+        // If this does not match all of our conditions, skip it.
         foreach ($args as $key => $value) {
           if (!isset($object->$key)) {
             continue 2;
@@ -509,12 +509,12 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
               continue 2;
             }
           }
-          else if ($object->$key != $value) {
+          elseif ($object->$key != $value) {
             continue 2;
           }
         }
       }
-      else if ($type == 'names') {
+      elseif ($type == 'names') {
         if (!in_array($object->{$export['key']}, $args)) {
           continue;
         }
@@ -561,7 +561,6 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
     }
   }
 
-  // For conditions,
   return $return;
 }
 
@@ -638,11 +637,19 @@ function ctools_get_default_object($table, $name) {
 }
 
 /**
+ * Get export object defaults.
+ *
  * Call the hook to get all default objects of the given type from the
  * export. If configured properly, this could include loading up an API
  * to get default objects.
+ *
+ * @param string $table
+ *   The name of the table to be loaded. Data is expected to be in the
+ *   schema to make all this work.
+ * @param array $export
+ *   The export definition from the table's hook_schema() definition.
  */
-function _ctools_export_get_defaults($table, $export) {
+function _ctools_export_get_defaults($table, array $export) {
   $cache = &drupal_static(__FUNCTION__, array());
 
   // If defaults may be cached, first see if we can load from cache.
@@ -685,7 +692,8 @@ function _ctools_export_get_defaults($table, $export) {
               $cache[$table][$name] = $object;
             }
             else {
-              // If version checking is enabled, ensure that the object can be used.
+              // If version checking is enabled, ensure that the object can be
+              // used.
               if (isset($object->api_version) &&
                 version_compare($object->api_version, $export['api']['minimum_version']) >= 0 &&
                 version_compare($object->api_version, $export['api']['current_version']) <= 0) {
@@ -807,10 +815,10 @@ function _ctools_export_get_some_defaults($table, $export, $names) {
 function _ctools_export_unpack_object($schema, $data, $object = 'stdClass') {
   if (is_string($object)) {
     if (class_exists($object)) {
-      $object = new $object;
+      $object = new $object();
     }
     else {
-      $object = new stdClass;
+      $object = new stdClass();
     }
   }
 
@@ -867,20 +875,21 @@ function ctools_var_export($var, $prefix = '') {
     }
     else {
       $output = "array(\n";
+      ksort($var);
       foreach ($var as $key => $value) {
         $output .= $prefix . "  " . ctools_var_export($key) . " => " . ctools_var_export($value, $prefix . '  ') . ",\n";
       }
       $output .= $prefix . ')';
     }
   }
-  else if (is_object($var) && get_class($var) === 'stdClass') {
+  elseif (is_object($var) && get_class($var) === 'stdClass') {
     // var_export() will export stdClass objects using an undefined
     // magic method __set_state() leaving the export broken. This
     // workaround avoids this by casting the object as an array for
     // export and casting it back to an object when evaluated.
     $output = '(object) ' . ctools_var_export((array) $var, $prefix);
   }
-  else if (is_bool($var)) {
+  elseif (is_bool($var)) {
     $output = $var ? 'TRUE' : 'FALSE';
   }
   else {
@@ -902,7 +911,8 @@ function ctools_export_object($table, $object, $indent = '', $identifier = NULL,
   $output = $indent . '$' . $identifier . ' = new ' . get_class($object) . "();\n";
 
   if ($schema['export']['can disable']) {
-    $output .= $indent . '$' . $identifier . '->disabled = FALSE; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
+    $disabled = !isset($object->disabled) || $object->disabled != TRUE ? 'FALSE' : 'TRUE';
+    $output .= $indent . '$' . $identifier . '->disabled = ' . $disabled . '; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
   }
   if (!empty($schema['export']['api']['current_version'])) {
     $output .= $indent . '$' . $identifier . '->api_version = ' . $schema['export']['api']['current_version'] . ";\n";
@@ -958,7 +968,7 @@ function ctools_export_object($table, $object, $indent = '', $identifier = NULL,
     }
   }
 
-  // And bottom additions here
+  // And bottom additions here.
   foreach ($additions2 as $field => $value) {
     $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
   }
@@ -986,7 +996,7 @@ function ctools_export_get_schema($table) {
     // simply hasn't been cached. If we've been asked, let's force the
     // issue.
     if (!$schema || empty($schema['export'])) {
-      // force a schema reset:
+      // Force a schema reset:
       $schema = drupal_get_schema($table, TRUE);
     }
 
@@ -998,7 +1008,7 @@ function ctools_export_get_schema($table) {
       return array();
     }
 
-    // Add some defaults
+    // Add some defaults.
     $schema['export'] += array(
       'key' => 'name',
       'key name' => 'Name',
@@ -1106,7 +1116,7 @@ function ctools_export_set_object_status($object, $new_status = TRUE) {
   $export = $schema['export'];
   $status = variable_get($export['status'], array());
 
-  // Compare
+  // Compare.
   if (!$new_status && $object->export_type & EXPORT_IN_DATABASE) {
     unset($status[$object->{$export['key']}]);
   }
@@ -1149,12 +1159,12 @@ function ctools_export_new_object($table, $set_defaults = TRUE) {
   $schema = ctools_export_get_schema($table);
   $export = $schema['export'];
 
-  $object = new $export['object'];
+  $object = new $export['object']();
   foreach ($schema['fields'] as $field => $info) {
     if (isset($info['object default'])) {
       $object->$field = $info['object default'];
     }
-    else if (isset($info['default'])) {
+    elseif (isset($info['default'])) {
       $object->$field = $info['default'];
     }
     else {
@@ -1179,11 +1189,11 @@ function ctools_export_new_object($table, $set_defaults = TRUE) {
 function ctools_export_to_hook_code(&$code, $table, $names = array(), $name = 'foo') {
   $schema = ctools_export_get_schema($table);
   $export = $schema['export'];
-  // Use the schema-specified function for generating hook code, if one exists
+  // Use the schema-specified function for generating hook code, if one exists.
   if (function_exists($export['to hook code callback'])) {
     $output = $export['to hook code callback']($names, $name);
   }
-  // Otherwise, the following code generates basic hook code
+  // Otherwise, the following code generates basic hook code.
   else {
     $output = ctools_export_default_to_hook_code($schema, $table, $names, $name);
   }
@@ -1227,7 +1237,7 @@ function ctools_export_default_to_hook_code($schema, $table, $names, $name) {
     $output .= "  \${$export['identifier']}s = array();\n\n";
     foreach ($objects as $object) {
       $output .= ctools_export_crud_export($table, $object, '  ');
-      $output .= "  \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n";
+      $output .= "  \${$export['identifier']}s['" . check_plain($object->{$export['key']}) . "'] = \${$export['identifier']};\n\n";
     }
     $output .= "  return \${$export['identifier']}s;\n";
     $output .= "}\n";
@@ -1235,6 +1245,7 @@ function ctools_export_default_to_hook_code($schema, $table, $names, $name) {
 
   return $output;
 }
+
 /**
  * Default function for listing bulk exportable objects.
  */
diff --git a/includes/fields.inc b/includes/fields.inc
index 162262c7817c1700b0dd8c6da5d7b7336e3b56d5..aa10ad917637069b062f2441bae268305c6de3bf 100644
--- a/includes/fields.inc
+++ b/includes/fields.inc
@@ -5,7 +5,6 @@
  * Extend core fields with some helper functions to reduce code complexity within views and ctools plugins.
  */
 
-
 /**
  * Fake an instance of a field.
  *
@@ -19,7 +18,8 @@
  *   An array of key value pairs.  These will be used as #default_value for the form elements generated by a call to hook_field_formatter_settings_form() for this field type.
  *   Typically we'll pass an empty array to begin with and then pass this information back to ourselves on form submit so that we can set the values for later edit sessions.
  */
-function ctools_fields_fake_field_instance($field_name, $view_mode = 'ctools', $formatter, $formatter_settings) {
+function ctools_fields_fake_field_instance($field_name, $view_mode, $formatter, $formatter_settings) {
+  $view_mode = isset($view_mode) ? $view_mode : 'ctools';
   $field = field_read_field($field_name);
 
   $field_type = field_info_field_types($field['type']);
@@ -75,15 +75,31 @@ function ctools_fields_get_field_formatter_settings_form($field, $formatter_type
     $conf['formatter_settings'] += $formatter['settings'];
   }
   $function = $formatter['module'] . '_field_formatter_settings_form';
+
+  $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
   if (function_exists($function)) {
-    $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
     $settings_form = $function($field, $instance, $view_mode, $form, $form_state);
-    if ($settings_form) {
-      $form['ctools_field_list']['#value'][] = $field;
-      $form += $settings_form;
-    }
+  }
+  if (empty($settings_form)) {
+    $settings_form = array();
   }
 
+  // Allow other modules to alter the formatter settings form.
+  $context = array(
+    'module' => $formatter['module'],
+    'formatter' => $formatter,
+    'field' => $field,
+    'instance' => $instance,
+    'view_mode' => $view_mode,
+    'form' => $form,
+    'form_state' => $form_state,
+  );
+  drupal_alter('field_formatter_settings_form', $settings_form, $context);
+
+  $settings_form['#tree'] = TRUE;
+  $form['ctools_field_list']['#value'][] = $field;
+  $form += $settings_form;
+
   if (isset($field['cardinality']) && $field['cardinality'] != 1) {
     list($prefix, $suffix) = explode('@count', t('Skip the first @count item(s)'));
     $form['delta_offset'] = array(
@@ -124,7 +140,7 @@ function ctools_fields_get_field_formatter_settings_form($field, $formatter_type
  */
 function ctools_fields_get_field_formatter_info($fields) {
   $info = array();
-  $field_info = module_invoke_all('field_formatter_info');
+  $field_info = field_info_formatter_types();
   foreach ($fields as $field) {
     foreach ($field_info as $format_name => $formatter_info) {
       if (in_array($field['type'], $formatter_info['field types'])) {
@@ -132,7 +148,6 @@ function ctools_fields_get_field_formatter_info($fields) {
       }
     }
   }
-  drupal_alter('field_formatter_info', $info);
   return $info;
 }
 
@@ -196,15 +211,15 @@ function ctools_field_label($field_name) {
  *   - Otherwise NULL.
  * @param $options
  *   An associative array of additional options, with the following keys:
- *  - 'field_name': The name of the field whose operation should be
+ *   - 'field_name': The name of the field whose operation should be
  *    invoked. By default, the operation is invoked on all the fields
  *    in the entity's bundle. NOTE: This option is not compatible with
  *    the 'deleted' option; the 'field_id' option should be used
  *    instead.
- *  - 'field_id': The id of the field whose operation should be
+ *   - 'field_id': The id of the field whose operation should be
  *    invoked. By default, the operation is invoked on all the fields
  *    in the entity's' bundles.
- *  - 'default': A boolean value, specifying which implementation of
+ *   - 'default': A boolean value, specifying which implementation of
  *    the operation should be invoked.
  *    - if FALSE (default), the field types implementation of the operation
  *      will be invoked (hook_field_[op])
@@ -212,10 +227,10 @@ function ctools_field_label($field_name) {
  *      will be invoked (field_default_[op])
  *    Internal use only. Do not explicitely set to TRUE, but use
  *    _field_invoke_default() instead.
- *  - 'deleted': If TRUE, the function will operate on deleted fields
+ *   - 'deleted': If TRUE, the function will operate on deleted fields
  *    as well as non-deleted fields. If unset or FALSE, only
  *    non-deleted fields are operated on.
- *  - 'language': A language code or an array of language codes keyed by field
+ *   - 'language': A language code or an array of language codes keyed by field
  *    name. It will be used to narrow down to a single value the available
  *    languages to act on.
  *
@@ -224,8 +239,6 @@ function ctools_field_label($field_name) {
 function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
   if (is_array($field_name)) {
     $instance = $field_name;
-    $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field'];
-    $field_name = $instance['field_name'];
   }
   else {
     list(, , $bundle) = entity_extract_ids($entity_type, $entity);
@@ -236,6 +249,11 @@ function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a
     return;
   }
 
+  // Keep the variables consistent regardless if we retrieve the field instance
+  // ourself, or if one is provided to us via the $field_name variable.
+  $field = field_info_field($instance['field_name']);
+  $field_name = $instance['field_name'];
+
   // Merge default options.
   $default_options = array(
     'default' => FALSE,
@@ -328,7 +346,7 @@ function ctools_field_foreign_keys($field_name) {
       $foreign_keys[$field_name] = $field['foreign keys'];
     }
     else {
-      // try to fetch foreign keys from schema, as not everything
+      // Try to fetch foreign keys from schema, as not everything
       // stores foreign keys properly in the field info.
       $module = $field['module'];
 
diff --git a/includes/jump-menu.inc b/includes/jump-menu.inc
index a5f99aa38187b983861c6839d88a482218bf1acc..e2ae1cfcdb18d7efa3bbd5ede7cebbb1d6d16ef5 100644
--- a/includes/jump-menu.inc
+++ b/includes/jump-menu.inc
@@ -8,7 +8,6 @@
  * if javascript is in use. Each item is keyed to the href that the button
  * should go to. With javascript, the page is immediately redirected. Without
  * javascript, the form is submitted and a drupal_goto() is given.
- *
  */
 
 /**
@@ -51,7 +50,7 @@ function ctools_jump_menu($form, &$form_state, $select, $options = array()) {
     'hide' => TRUE,
   );
 
-  ctools_add_js('jump-menu');
+  $form['#attached']['js'][] = ctools_attach_js('jump-menu');
 
   if (!empty($options['choose'])) {
     $select = array('' => $options['choose']) + $select;
@@ -127,7 +126,7 @@ function ctools_jump_menu_submit($form, &$form_state) {
   // This allows duplicate paths to be used in jump menus for multiple options.
   $redirect_array = explode("::", $form_state['values']['jump']);
 
-  if(isset($redirect_array[1]) && !empty($redirect_array[1])){
+  if (isset($redirect_array[1]) && !empty($redirect_array[1])) {
     $redirect = $redirect_array[1];
   }
   else {
diff --git a/includes/language.inc b/includes/language.inc
index 9a7850b779871440125b739e2c27d153e73d9f72..a850670ec5a1ee41b3e4aba8c40df53fc871c587 100644
--- a/includes/language.inc
+++ b/includes/language.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Returns array of language names.
  *
@@ -32,7 +36,6 @@ function ctools_language_list($field = 'name', $all = FALSE) {
  * Returns an array of language names similar to ctools_language_list() except
  * that additional choices have been added for ease of use.
  */
-
 function ctools_language_list_all() {
   $languages = array(
     '***CURRENT_LANGUAGE***' => t("Current user's language"),
@@ -41,4 +44,4 @@ function ctools_language_list_all() {
   );
   $languages = array_merge($languages, ctools_language_list());
   return $languages;
-}
\ No newline at end of file
+}
diff --git a/includes/math-expr.inc b/includes/math-expr.inc
index beffb93c27735652e8b70dc9961cd080c1a766bd..44ba015f90228f7d7e9ea4182be31432bc075fc9 100644
--- a/includes/math-expr.inc
+++ b/includes/math-expr.inc
@@ -1,388 +1,933 @@
 <?php
 
-/*
-================================================================================
-
-ctools_math_expr - PHP Class to safely evaluate math expressions
-Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
-
-================================================================================
-
-NAME
-    ctools_math_expr - safely evaluate math expressions
-
-SYNOPSIS
-      include('ctools_math_expr.class.php');
-      $m = new ctools_math_expr;
-      // basic evaluation:
-      $result = $m->evaluate('2+2');
-      // supports: order of operation; parentheses; negation; built-in functions
-      $result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');
-      // create your own variables
-      $m->evaluate('a = e^(ln(pi))');
-      // or functions
-      $m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
-      // and then use them
-      $result = $m->evaluate('3*f(42,a)');
-
-DESCRIPTION
-    Use the ctools_math_expr class when you want to evaluate mathematical expressions
-    from untrusted sources.  You can define your own variables and functions,
-    which are stored in the object.  Try it, it's fun!
-
-METHODS
-    $m->evalute($expr)
-        Evaluates the expression and returns the result.  If an error occurs,
-        prints a warning and returns false.  If $expr is a function assignment,
-        returns true on success.
-
-    $m->e($expr)
-        A synonym for $m->evaluate().
-
-    $m->vars()
-        Returns an associative array of all user-defined variables and values.
-
-    $m->funcs()
-        Returns an array of all user-defined functions.
-
-PARAMETERS
-    $m->suppress_errors
-        Set to true to turn off warnings when evaluating expressions
-
-    $m->last_error
-        If the last evaluation failed, contains a string describing the error.
-        (Useful when suppress_errors is on).
-
-AUTHOR INFORMATION
-    Copyright 2005, Miles Kaufmann.
-
-LICENSE
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions are
-    met:
-
-    1   Redistributions of source code must retain the above copyright
-        notice, this list of conditions and the following disclaimer.
-    2.  Redistributions in binary form must reproduce the above copyright
-        notice, this list of conditions and the following disclaimer in the
-        documentation and/or other materials provided with the distribution.
-    3.  The name of the author may not be used to endorse or promote
-        products derived from this software without specific prior written
-        permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
-    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-    POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
+/**
+ * @file
+ * =============================================================================.
+ *
+ * ctools_math_expr - PHP Class to safely evaluate math expressions
+ * Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
+ *
+ * =============================================================================
+ *
+ * NAME
+ *     ctools_math_expr - safely evaluate math expressions
+ *
+ * SYNOPSIS
+ *     $m = new ctools_math_expr();
+ *     // basic evaluation:
+ *     $result = $m->evaluate('2+2');
+ *     // supports: order of operation; parentheses; negation; built-in
+ *     // functions.
+ *     $result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');
+ *     // create your own variables
+ *     $m->evaluate('a = e^(ln(pi))');
+ *     // or functions
+ *     $m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
+ *     // and then use them
+ *     $result = $m->evaluate('3*f(42,a)');
+ *
+ * DESCRIPTION
+ *     Use the ctools_math_expr class when you want to evaluate mathematical
+ *     expressions from untrusted sources.  You can define your own variables
+ *     and functions, which are stored in the object.  Try it, it's fun!
+ *
+ * AUTHOR INFORMATION
+ *     Copyright 2005, Miles Kaufmann.
+ *     Enhancements, 2005 onwards, Drupal Community.
+ *
+ * LICENSE
+ *     Redistribution and use in source and binary forms, with or without
+ *     modification, are permitted provided that the following conditions are
+ *     met:
+ *
+ *     1   Redistributions of source code must retain the above copyright
+ *         notice, this list of conditions and the following disclaimer.
+ *     2.  Redistributions in binary form must reproduce the above copyright
+ *         notice, this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *     3.  The name of the author may not be used to endorse or promote
+ *         products derived from this software without specific prior written
+ *         permission.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ *     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ *     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *     POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * ctools_math_expr Class.
+ */
 class ctools_math_expr {
-    var $suppress_errors = false;
-    var $last_error = null;
-
-    var $v = array('e'=>2.71,'pi'=>3.14); // variables (and constants)
-    var $f = array(); // user-defined functions
-    var $vb = array('e', 'pi'); // constants
-    var $fb = array(  // built-in functions
-        'sin','sinh','arcsin','asin','arcsinh','asinh',
-        'cos','cosh','arccos','acos','arccosh','acosh',
-        'tan','tanh','arctan','atan','arctanh','atanh',
-        'pow', 'exp',
-        'sqrt','abs','ln','log',
-        'time', 'ceil', 'floor', 'min', 'max', 'round');
-
-    function ctools_math_expr() {
-        // make the variables a little more accurate
-        $this->v['pi'] = pi();
-        $this->v['e'] = exp(1);
-        drupal_alter('ctools_math_expression_functions', $this->fb);
+
+  /**
+   * If TRUE do not call trigger_error on error other wise do.
+   *
+   * @var bool
+   */
+  public $suppress_errors = FALSE;
+
+  /**
+   * The last error message reported.
+   *
+   * @var string
+   */
+  public $last_error = NULL;
+
+  /**
+   * List of all errors reported.
+   *
+   * @var array
+   */
+  public $errors = array();
+
+  /**
+   * Variable and constant values.
+   *
+   * @var array
+   */
+  protected $vars;
+
+  /**
+   * User defined functions.
+   *
+   * @var array
+   */
+  protected $userfuncs;
+
+  /**
+   * The names of constants, used to make constants read-only.
+   *
+   * @var array
+   */
+  protected $constvars;
+
+  /**
+   * Built in simple (one arg) functions.
+   * Merged into $this->funcs in constructor.
+   *
+   * @var array
+   */
+  protected $simplefuncs;
+
+  /**
+   * Definitions of all built-in functions.
+   *
+   * @var array
+   */
+  protected $funcs;
+
+  /**
+   * Operators and their precedence.
+   *
+   * @var array
+   */
+  protected $ops;
+
+  /**
+   * The set of operators using two arguments.
+   *
+   * @var array
+   */
+  protected $binaryops;
+
+  /**
+   * Public constructor.
+   */
+  public function __construct() {
+    $this->userfuncs = array();
+    $this->simplefuncs = array(
+      'sin',
+      'sinh',
+      'asin',
+      'asinh',
+      'cos',
+      'cosh',
+      'acos',
+      'acosh',
+      'tan',
+      'tanh',
+      'atan',
+      'atanh',
+      'exp',
+      'sqrt',
+      'abs',
+      'log',
+      'ceil',
+      'floor',
+      'round',
+    );
+
+    $this->ops = array(
+      '+' => array('precedence' => 0),
+      '-' => array('precedence' => 0),
+      '*' => array('precedence' => 1),
+      '/' => array('precedence' => 1),
+      '^' => array('precedence' => 2, 'right' => TRUE),
+      '_' => array('precedence' => 1),
+      '==' => array('precedence' => -1),
+      '!=' => array('precedence' => -1),
+      '>=' => array('precedence' => -1),
+      '<=' => array('precedence' => -1),
+      '>' => array('precedence' => -1),
+      '<' => array('precedence' => -1),
+    );
+
+    $this->binaryops = array(
+      '+', '-', '*', '/', '^', '==', '!=', '<', '<=', '>=', '>',
+    );
+
+    $this->funcs = array(
+      'ln' => array(
+        'function' => 'log',
+        'arguments' => 1,
+      ),
+      'arcsin' => array(
+        'function' => 'asin',
+        'arguments' => 1,
+      ),
+      'arcsinh' => array(
+        'function' => 'asinh',
+        'arguments' => 1,
+      ),
+      'arccos' => array(
+        'function' => 'acos',
+        'arguments' => 1,
+      ),
+      'arccosh' => array(
+        'function' => 'acosh',
+        'arguments' => 1,
+      ),
+      'arctan' => array(
+        'function' => 'atan',
+        'arguments' => 1,
+      ),
+      'arctanh' => array(
+        'function' => 'atanh',
+        'arguments' => 1,
+      ),
+      'min' => array(
+        'function' => 'min',
+        'arguments' => 2,
+        'max arguments' => 99,
+      ),
+      'max' => array(
+        'function' => 'max',
+        'arguments' => 2,
+        'max arguments' => 99,
+      ),
+      'pow' => array(
+        'function' => 'pow',
+        'arguments' => 2,
+      ),
+      'if' => array(
+        'function' => 'ctools_math_expr_if',
+        'arguments' => 2,
+        'max arguments' => 3,
+      ),
+      'number' => array(
+        'function' => 'ctools_math_expr_number',
+        'arguments' => 1,
+      ),
+      'time' => array(
+        'function' => 'time',
+        'arguments' => 0,
+      ),
+    );
+
+    // Allow modules to add custom functions.
+    $context = array('final' => &$this->funcs);
+    drupal_alter('ctools_math_expression_functions', $this->simplefuncs, $context);
+
+    // Set up the initial constants and mark them read-only.
+    $this->vars = array('e' => exp(1), 'pi' => pi());
+    drupal_alter('ctools_math_expression_constants', $this->vars);
+    $this->constvars = array_keys($this->vars);
+
+    // Translate the older, simpler style into the newer, richer style.
+    foreach ($this->simplefuncs as $function) {
+      $this->funcs[$function] = array(
+        'function' => $function,
+        'arguments' => 1,
+      );
     }
+  }
+
+  /**
+   * Change the suppress errors flag.
+   *
+   * When errors are not suppressed, trigger_error is used to cause a PHP error
+   * when an evaluation error occurs, as a result of calling trigger(). With
+   * errors suppressed this doesn't happen.
+   *
+   * @param bool $enable
+   *   If FALSE, enable triggering of php errors when expression errors occurs.
+   *   otherwise, suppress triggering the errors.
+   *
+   * @return bool
+   *   The new (current) state of the flag.
+   *
+   * @see ctools_math_expr::trigger()
+   */
+  public function set_suppress_errors($enable) {
+    return $this->suppress_errors = (bool) $enable;
+  }
+
+  /**
+   * Backwards compatible wrapper for evaluate().
+   *
+   * @see ctools_math_expr::evaluate()
+   */
+  public function e($expr) {
+    return $this->evaluate($expr);
+  }
+
+  /**
+   * Evaluate the expression.
+   *
+   * @param string $expr
+   *   The expression to evaluate.
+   *
+   * @return string|bool
+   *   The result of the expression, or FALSE if an error occurred, or TRUE if
+   *   an user-defined function was created.
+   */
+  public function evaluate($expr) {
+    $this->last_error = NULL;
+    $expr = trim($expr);
+
+    // Strip possible semicolons at the end.
+    if (substr($expr, -1, 1) == ';') {
+      $expr = (string) substr($expr, 0, -1);
+    }
+
+    // Is it a variable assignment?
+    if (preg_match('/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
+
+      // Make sure we're not assigning to a constant.
+      if (in_array($matches[1], $this->constvars)) {
+        return $this->trigger("cannot assign to constant '$matches[1]'");
+      }
+
+      // Get the result and make sure it's good:
+      if (($tmp = $this->pfx($this->nfx($matches[2]))) === FALSE) {
+        return FALSE;
+      }
+      // If so, stick it in the variable array...
+      $this->vars[$matches[1]] = $tmp;
+      // ...and return the resulting value:
+      return $this->vars[$matches[1]];
 
-    function e($expr) {
-        return $this->evaluate($expr);
     }
+    // Is it a function assignment?
+    elseif (preg_match('/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
+      // Get the function name.
+      $fnn = $matches[1];
+      // Make sure it isn't built in:
+      if (isset($this->funcs[$matches[1]])) {
+        return $this->trigger("cannot redefine built-in function '$matches[1]()'");
+      }
+
+      // Get the arguments.
+      $args = explode(",", preg_replace("/\s+/", "", $matches[2]));
+      // See if it can be converted to postfix.
+      $stack = $this->nfx($matches[3]);
+      if ($stack === FALSE) {
+        return FALSE;
+      }
+
+      // Freeze the state of the non-argument variables.
+      for ($i = 0; $i < count($stack); $i++) {
+        $token = (string) $stack[$i];
+        if (preg_match('/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
+          if (array_key_exists($token, $this->vars)) {
+            $stack[$i] = $this->vars[$token];
+          }
+          else {
+            return $this->trigger("undefined variable '$token' in function definition");
+          }
+        }
+      }
+      $this->userfuncs[$fnn] = array('args' => $args, 'func' => $stack);
+
+      return TRUE;
+    }
+    else {
+      // Straight up evaluation.
+      return trim($this->pfx($this->nfx($expr)), '"');
+    }
+  }
+
+  /**
+   * Fetch an array of variables used in the expression.
+   *
+   * @return array
+   *   Array of name : value pairs, one for each variable defined.
+   */
+  public function vars() {
+    $output = $this->vars;
+
+    // @todo: Is this supposed to remove all constants? we should remove all
+    // those in $this->constvars!
+    unset($output['pi']);
+    unset($output['e']);
+
+    return $output;
+  }
+
+  /**
+   * Fetch all user defined functions in the expression.
+   *
+   * @return array
+   *   Array of name : string pairs, one for each function defined. The string
+   *   will be of the form fname(arg1,arg2). The function body is not returned.
+   */
+  public function funcs() {
+    $output = array();
+    foreach ($this->userfuncs as $fnn => $dat) {
+      $output[] = $fnn . '(' . implode(',', $dat['args']) . ')';
+    }
+
+    return $output;
+  }
+
+  /**
+   * Convert infix to postfix notation.
+   *
+   * @param string $expr
+   *   The expression to convert.
+   *
+   * @return array|bool
+   *   The expression as an ordered list of postfix action tokens.
+   */
+  private function nfx($expr) {
+
+    $index = 0;
+    $stack = new ctools_math_expr_stack();
+    // Postfix form of expression, to be passed to pfx().
+    $output = array();
+
+    // @todo: Because the expr can contain string operands, using strtolower here is a bug.
+    $expr = trim(strtolower($expr));
+
+    // We use this in syntax-checking the expression and determining when
+    // '-' is a negation.
+    $expecting_op = FALSE;
+
+    while (TRUE) {
+      $op = substr($expr, $index, 1);
+      // Get the first character at the current index, and if the second
+      // character is an =, add it to our op as well (accounts for <=).
+      if (substr($expr, $index + 1, 1) === '=') {
+        $op = substr($expr, $index, 2);
+        $index++;
+      }
+
+      // Find out if we're currently at the beginning of a number/variable/
+      // function/parenthesis/operand.
+      $ex = preg_match('/^([a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', (string) substr($expr, $index), $match);
+
+      // Is it a negation instead of a minus?
+      if ($op === '-' and !$expecting_op) {
+        // Put a negation on the stack.
+        $stack->push('_');
+        $index++;
+      }
+      // We have to explicitly deny this, because it's legal on the stack but
+      // not in the input expression.
+      elseif ($op == '_') {
+        return $this->trigger("illegal character '_'");
+
+      }
+      // Are we putting an operator on the stack?
+      elseif ((isset($this->ops[$op]) || $ex) && $expecting_op) {
+        // Are we expecting an operator but have a num, var, func, or
+        // open-paren?
+        if ($ex) {
+          $op = '*';
+          // It's an implicit multiplication.
+          $index--;
+        }
+        // Heart of the algorithm:
+        while ($stack->count() > 0 &&
+          ($o2 = $stack->last()) &&
+          isset($this->ops[$o2]) &&
+          (!empty($this->ops[$op]['right']) ?
+            $this->ops[$op]['precedence'] < $this->ops[$o2]['precedence'] :
+            $this->ops[$op]['precedence'] <= $this->ops[$o2]['precedence'])) {
+
+          // Pop stuff off the stack into the output.
+          $output[] = $stack->pop();
+        }
+        // Many thanks: http://en.wikipedia.org/wiki/Reverse_Polish_notation#The_algorithm_in_detail
+        // finally put OUR operator onto the stack.
+        $stack->push($op);
+        $index++;
+        $expecting_op = FALSE;
+
+      }
+      // Ready to close a parenthesis?
+      elseif ($op === ')') {
+
+        // Pop off the stack back to the last '('.
+        while (($o2 = $stack->pop()) !== '(') {
+          if (is_null($o2)) {
+            return $this->trigger("unexpected ')'");
+          }
+          else {
+            $output[] = $o2;
+          }
+        }
 
-    function evaluate($expr) {
-        $this->last_error = null;
-        $expr = trim($expr);
-        if (substr($expr, -1, 1) == ';') $expr = substr($expr, 0, strlen($expr)-1); // strip semicolons at the end
-        //===============
-        // is it a variable assignment?
-        if (preg_match('/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
-            if (in_array($matches[1], $this->vb)) { // make sure we're not assigning to a constant
-                return $this->trigger("cannot assign to constant '$matches[1]'");
+        // Did we just close a function?
+        if (preg_match("/^([a-z]\w*)\($/", (string) $stack->last(2), $matches)) {
+
+          // Get the function name.
+          $fnn = $matches[1];
+          // See how many arguments there were (cleverly stored on the stack,
+          // thank you).
+          $arg_count = $stack->pop();
+          // Pop the function and push onto the output.
+          $output[] = $stack->pop();
+
+          // Check the argument count:
+          if (isset($this->funcs[$fnn])) {
+            $fdef = $this->funcs[$fnn];
+            $max_arguments = isset($fdef['max arguments']) ? $fdef['max arguments'] : $fdef['arguments'];
+            if ($arg_count > $max_arguments) {
+              return $this->trigger("too many arguments ($arg_count given, $max_arguments expected)");
             }
-            if (($tmp = $this->pfx($this->nfx($matches[2]))) === false) return false; // get the result and make sure it's good
-            $this->v[$matches[1]] = $tmp; // if so, stick it in the variable array
-            return $this->v[$matches[1]]; // and return the resulting value
-        //===============
-        // is it a function assignment?
-        } elseif (preg_match('/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
-            $fnn = $matches[1]; // get the function name
-            if (in_array($matches[1], $this->fb)) { // make sure it isn't built in
-                return $this->trigger("cannot redefine built-in function '$matches[1]()'");
+          }
+          elseif (array_key_exists($fnn, $this->userfuncs)) {
+            $fdef = $this->userfuncs[$fnn];
+            if ($arg_count !== count($fdef['args'])) {
+              return $this->trigger("wrong number of arguments ($arg_count given, " . count($fdef['args']) . ' expected)');
+            }
+          }
+          else {
+            // Did we somehow push a non-function on the stack? this should
+            // never happen.
+            return $this->trigger('internal error');
+          }
+        }
+        $index++;
+
+      }
+      // Did we just finish a function argument?
+      elseif ($op === ',' && $expecting_op) {
+        $index++;
+        $expecting_op = FALSE;
+      }
+      elseif ($op === '(' && !$expecting_op) {
+        $stack->push('(');
+        $index++;
+
+      }
+      elseif ($ex && !$expecting_op) {
+        // Make sure there was a function.
+        if (preg_match("/^([a-z]\w*)\($/", (string) $stack->last(3), $matches)) {
+          // Pop the argument expression stuff and push onto the output:
+          while (($o2 = $stack->pop()) !== '(') {
+            // Oops, never had a '('.
+            if (is_null($o2)) {
+              return $this->trigger("unexpected argument in $expr $o2");
             }
-            $args = explode(",", preg_replace("/\s+/", "", $matches[2])); // get the arguments
-            if (($stack = $this->nfx($matches[3])) === false) return false; // see if it can be converted to postfix
-            for ($i = 0; $i<count($stack); $i++) { // freeze the state of the non-argument variables
-                $token = $stack[$i];
-                if (preg_match('/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
-                    if (array_key_exists($token, $this->v)) {
-                        $stack[$i] = $this->v[$token];
-                    } else {
-                        return $this->trigger("undefined variable '$token' in function definition");
-                    }
-                }
+            else {
+              $output[] = $o2;
             }
-            $this->f[$fnn] = array('args'=>$args, 'func'=>$stack);
-            return true;
-        //===============
-        } else {
-            return $this->pfx($this->nfx($expr)); // straight up evaluation, woo
+          }
+
+          // Increment the argument count.
+          $stack->push($stack->pop() + 1);
+          // Put the ( back on, we'll need to pop back to it again.
+          $stack->push('(');
+        }
+
+        // Do we now have a function/variable/number?
+        $expecting_op = TRUE;
+        $val = (string) $match[1];
+        if (preg_match("/^([a-z]\w*)\($/", $val, $matches)) {
+          // May be func, or variable w/ implicit multiplication against
+          // parentheses...
+          if (isset($this->funcs[$matches[1]]) or array_key_exists($matches[1], $this->userfuncs)) {
+            $stack->push($val);
+            $stack->push(0);
+            $stack->push('(');
+            $expecting_op = FALSE;
+          }
+          // it's a var w/ implicit multiplication.
+          else {
+            $val = $matches[1];
+            $output[] = $val;
+          }
         }
+        // it's a plain old var or num.
+        else {
+          $output[] = $val;
+        }
+        $index += strlen($val);
+
+      }
+      elseif ($op === ')') {
+        // Miscellaneous error checking.
+        return $this->trigger("unexpected ')'");
+      }
+      elseif (isset($this->ops[$op]) and !$expecting_op) {
+        return $this->trigger("unexpected operator '$op'");
+      }
+      elseif ($op === '"') {
+        // Fetch a quoted string.
+        $string = (string) substr($expr, $index);
+        if (preg_match('/"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"/s', $string, $matches)) {
+          $string = $matches[0];
+          // Trim the quotes off:
+          $output[] = $string;
+          $index += strlen($string);
+          $expecting_op = TRUE;
+        }
+        else {
+          return $this->trigger('open quote without close quote.');
+        }
+      }
+      else {
+        // I don't even want to know what you did to get here.
+        return $this->trigger("an unexpected error occurred at $op");
+      }
+      if ($index === strlen($expr)) {
+        if (isset($this->ops[$op])) {
+          // Did we end with an operator? bad.
+          return $this->trigger("operator '$op' lacks operand");
+        }
+        else {
+          break;
+        }
+      }
+
+      // Step the index past whitespace (pretty much turns whitespace into
+      // implicit multiplication if no operator is there).
+      while (substr($expr, $index, 1) === ' ') {
+        $index++;
+      }
     }
 
-    function vars() {
-        $output = $this->v;
-        unset($output['pi']);
-        unset($output['e']);
-        return $output;
+    // Pop everything off the stack and push onto output:
+    while (!is_null($op = $stack->pop())) {
+
+      // If there are (s on the stack, ()s were unbalanced.
+      if ($op === '(') {
+        return $this->trigger("expecting ')'");
+      }
+      $output[] = $op;
     }
 
-    function funcs() {
-        $output = array();
-        foreach ($this->f as $fnn=>$dat)
-            $output[] = $fnn . '(' . implode(',', $dat['args']) . ')';
-        return $output;
+    return $output;
+  }
+
+  /**
+   * Evaluate a prefix-operator stack expression.
+   *
+   * @param array $tokens
+   *   The array of token values to evaluate. A token is a string value
+   *   representing either an operation to perform, a variable, or a value.
+   *   Literal values are checked using is_numeric(), or a value that starts
+   *   with a double-quote; functions and variables by existence in the
+   *   appropriate tables.
+   *   If FALSE is passed in the function terminates immediately, returning
+   *   FALSE.
+   * @param array $vars
+   *   Additional variable values to use when evaluating the expression. These
+   *   variables do not override internal variables with the same name.
+   *
+   * @return bool|mixed
+   *   The expression's value, otherwise FALSE is returned if there is an error
+   *   detected unless php error handling intervenes: see suppress_error.
+   */
+  public function pfx(array $tokens, array $vars = array()) {
+
+    if ($tokens == FALSE) {
+      return FALSE;
     }
 
-    //===================== HERE BE INTERNAL METHODS ====================\\
+    $stack = new ctools_math_expr_stack();
 
-    // Convert infix to postfix notation
-    function nfx($expr) {
+    foreach ($tokens as $token) {
+      // If the token is a binary operator, pop two values off the stack, do
+      // the operation, and push the result back on again.
+      if (in_array($token, $this->binaryops)) {
+        if (is_null($op2 = $stack->pop())) {
+          return $this->trigger('internal error');
+        }
+        if (is_null($op1 = $stack->pop())) {
+          return $this->trigger('internal error');
+        }
+        switch ($token) {
+          case '+':
+            $stack->push($op1 + $op2);
+            break;
+
+          case '-':
+            $stack->push($op1 - $op2);
+            break;
+
+          case '*':
+            $stack->push($op1 * $op2);
+            break;
+
+          case '/':
+            if ($op2 == 0) {
+              return $this->trigger('division by zero');
+            }
+            $stack->push($op1 / $op2);
+            break;
 
-        $index = 0;
-        $stack = new ctools_math_expr_stack;
-        $output = array(); // postfix form of expression, to be passed to pfx()
-        $expr = trim(strtolower($expr));
+          case '^':
+            $stack->push(pow($op1, $op2));
+            break;
 
-        $ops   = array('+', '-', '*', '/', '^', '_');
-        $ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>1); // right-associative operator?
-        $ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2); // operator precedence
+          case '==':
+            $stack->push((int) ($op1 == $op2));
+            break;
 
-        $expecting_op = false; // we use this in syntax-checking the expression
-                               // and determining when a - is a negation
+          case '!=':
+            $stack->push((int) ($op1 != $op2));
+            break;
 
-        if (preg_match("/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { // make sure the characters are all good
-            return $this->trigger("illegal character '{$matches[0]}'");
-        }
+          case '<=':
+            $stack->push((int) ($op1 <= $op2));
+            break;
 
-        while(1) { // 1 Infinite Loop ;)
-            $op = substr($expr, $index, 1); // get the first character at the current index
-            // find out if we're currently at the beginning of a number/variable/function/parenthesis/operand
-            $ex = preg_match('/^([a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
-            //===============
-            if ($op == '-' and !$expecting_op) { // is it a negation instead of a minus?
-                $stack->push('_'); // put a negation on the stack
-                $index++;
-            } elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
-                return $this->trigger("illegal character '_'"); // but not in the input expression
-            //===============
-            } elseif ((in_array($op, $ops) or $ex) and $expecting_op) { // are we putting an operator on the stack?
-                if ($ex) { // are we expecting an operator but have a number/variable/function/opening parethesis?
-                    $op = '*'; $index--; // it's an implicit multiplication
-                }
-                // heart of the algorithm:
-                while($stack->count > 0 and ($o2 = $stack->last()) and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] : $ops_p[$op] <= $ops_p[$o2])) {
-                    $output[] = $stack->pop(); // pop stuff off the stack into the output
-                }
-                // many thanks: http://en.wikipedia.org/wiki/Reverse_Polish_notation#The_algorithm_in_detail
-                $stack->push($op); // finally put OUR operator onto the stack
-                $index++;
-                $expecting_op = false;
-            //===============
-            } elseif ($op == ')' and $expecting_op) { // ready to close a parenthesis?
-                while (($o2 = $stack->pop()) != '(') { // pop off the stack back to the last (
-                    if (is_null($o2)) return $this->trigger("unexpected ')'");
-                    else $output[] = $o2;
-                }
-                if (preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches)) { // did we just close a function?
-                    $fnn = $matches[1]; // get the function name
-                    $arg_count = $stack->pop(); // see how many arguments there were (cleverly stored on the stack, thank you)
-                    $output[] = $stack->pop(); // pop the function and push onto the output
-                    if (in_array($fnn, $this->fb)) { // check the argument count
-                        if($arg_count > 1)
-                            return $this->trigger("too many arguments ($arg_count given, 1 expected)");
-                    } elseif (array_key_exists($fnn, $this->f)) {
-                        if ($arg_count != count($this->f[$fnn]['args']))
-                            return $this->trigger("wrong number of arguments ($arg_count given, " . count($this->f[$fnn]['args']) . " expected)");
-                    } else { // did we somehow push a non-function on the stack? this should never happen
-                        return $this->trigger("internal error");
-                    }
-                }
-                $index++;
-            //===============
-            } elseif ($op == ',' and $expecting_op) { // did we just finish a function argument?
-                while (($o2 = $stack->pop()) != '(') {
-                    if (is_null($o2)) return $this->trigger("unexpected ','"); // oops, never had a (
-                    else $output[] = $o2; // pop the argument expression stuff and push onto the output
-                }
-                // make sure there was a function
-                if (!preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches))
-                    return $this->trigger("unexpected ','");
-                $stack->push($stack->pop()+1); // increment the argument count
-                $stack->push('('); // put the ( back on, we'll need to pop back to it again
-                $index++;
-                $expecting_op = false;
-            //===============
-            } elseif ($op == '(' and !$expecting_op) {
-                $stack->push('('); // that was easy
-                $index++;
-                $allow_neg = true;
-            //===============
-            } elseif ($ex and !$expecting_op) { // do we now have a function/variable/number?
-                $expecting_op = true;
-                $val = $match[1];
-                if (preg_match("/^([a-z]\w*)\($/", $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
-                    if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) { // it's a func
-                        $stack->push($val);
-                        $stack->push(1);
-                        $stack->push('(');
-                        $expecting_op = false;
-                    } else { // it's a var w/ implicit multiplication
-                        $val = $matches[1];
-                        $output[] = $val;
-                    }
-                } else { // it's a plain old var or num
-                    $output[] = $val;
-                }
-                $index += strlen($val);
-            //===============
-            } elseif ($op == ')') { // miscellaneous error checking
-                return $this->trigger("unexpected ')'");
-            } elseif (in_array($op, $ops) and !$expecting_op) {
-                return $this->trigger("unexpected operator '$op'");
-            } else { // I don't even want to know what you did to get here
-                return $this->trigger("an unexpected error occured");
-            }
-            if ($index == strlen($expr)) {
-                if (in_array($op, $ops)) { // did we end with an operator? bad.
-                    return $this->trigger("operator '$op' lacks operand");
-                } else {
-                    break;
-                }
-            }
-            while (substr($expr, $index, 1) == ' ') { // step the index past whitespace (pretty much turns whitespace
-                $index++;                             // into implicit multiplication if no operator is there)
-            }
+          case '<':
+            $stack->push((int) ($op1 < $op2));
+            break;
+
+          case '>=':
+            $stack->push((int) ($op1 >= $op2));
+            break;
 
+          case '>':
+            $stack->push((int) ($op1 > $op2));
+            break;
         }
-        while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
-            if ($op == '(') return $this->trigger("expecting ')'"); // if there are (s on the stack, ()s were unbalanced
-            $output[] = $op;
+      }
+      // If the token is a unary operator, pop one value off the stack, do the
+      // operation, and push it back on again.
+      elseif ($token === "_") {
+        $stack->push(-1 * $stack->pop());
+      }
+      // If the token is a function, pop arguments off the stack, hand them to
+      // the function, and push the result back on again.
+      elseif (preg_match("/^([a-z]\w*)\($/", (string) $token, $matches)) {
+        $fnn = $matches[1];
+
+        // Check for a built-in function.
+        if (isset($this->funcs[$fnn])) {
+          $args = array();
+          // Collect all required args from the stack.
+          for ($i = 0; $i < $this->funcs[$fnn]['arguments']; $i++) {
+            if (is_null($op1 = $stack->pop())) {
+              return $this->trigger("function $fnn missing argument $i");
+            }
+            $args[] = $op1;
+          }
+          // If func allows additional args, collect them too, stopping on a
+          // NULL arg.
+          if (!empty($this->funcs[$fnn]['max arguments'])) {
+            for (; $i < $this->funcs[$fnn]['max arguments']; $i++) {
+              $arg = $stack->pop();
+              if (!isset($arg)) {
+                break;
+              }
+              $args[] = $arg;
+            }
+          }
+          $stack->push(
+            call_user_func_array($this->funcs[$fnn]['function'], array_reverse($args))
+          );
         }
-        return $output;
-    }
 
-    // evaluate postfix notation
-    function pfx($tokens, $vars = array()) {
-
-        if ($tokens == false) return false;
-
-        $stack = new ctools_math_expr_stack;
-
-        foreach ($tokens as $token) { // nice and easy
-            // if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
-            if (in_array($token, array('+', '-', '*', '/', '^'))) {
-                if (is_null($op2 = $stack->pop())) return $this->trigger("internal error");
-                if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
-                switch ($token) {
-                    case '+':
-                        $stack->push($op1+$op2); break;
-                    case '-':
-                        $stack->push($op1-$op2); break;
-                    case '*':
-                        $stack->push($op1*$op2); break;
-                    case '/':
-                        if ($op2 == 0) return $this->trigger("division by zero");
-                        $stack->push($op1/$op2); break;
-                    case '^':
-                        $stack->push(pow($op1, $op2)); break;
-                }
-            // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
-            } elseif ($token == "_") {
-                $stack->push(-1*$stack->pop());
-            // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
-            } elseif (preg_match("/^([a-z]\w*)\($/", $token, $matches)) { // it's a function!
-                $fnn = $matches[1];
-                if (in_array($fnn, $this->fb)) { // built-in function:
-                    if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
-                    $fnn = preg_replace("/^arc/", "a", $fnn); // for the 'arc' trig synonyms
-                    if ($fnn == 'ln') $fnn = 'log';
-                    eval('$stack->push(' . $fnn . '($op1));'); // perfectly safe eval()
-                } elseif (array_key_exists($fnn, $this->f)) { // user function
-                    // get args
-                    $args = array();
-                    for ($i = count($this->f[$fnn]['args'])-1; $i >= 0; $i--) {
-                        if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) return $this->trigger("internal error");
-                    }
-                    $stack->push($this->pfx($this->f[$fnn]['func'], $args)); // yay... recursion!!!!
-                }
-            // if the token is a number or variable, push it on the stack
-            } else {
-                if (is_numeric($token)) {
-                    $stack->push($token);
-                } elseif (array_key_exists($token, $this->v)) {
-                    $stack->push($this->v[$token]);
-                } elseif (array_key_exists($token, $vars)) {
-                    $stack->push($vars[$token]);
-                } else {
-                    return $this->trigger("undefined variable '$token'");
-                }
+        // Check for a user function.
+        elseif (isset($fnn, $this->userfuncs)) {
+          $args = array();
+          for ($i = count($this->userfuncs[$fnn]['args']) - 1; $i >= 0; $i--) {
+            $value = $stack->pop();
+            $args[$this->userfuncs[$fnn]['args'][$i]] = $value;
+            if (is_null($value)) {
+              return $this->trigger('internal error');
             }
+          }
+          // yay... recursion!!!!
+          $stack->push($this->pfx($this->userfuncs[$fnn]['func'], $args));
+        }
+      }
+      // If the token is a number or variable, push it on the stack.
+      else {
+        if (is_numeric($token) || $token[0] == '"') {
+          $stack->push($token);
         }
-        // when we're out of tokens, the stack should have a single element, the final result
-        if ($stack->count != 1) return $this->trigger("internal error");
-        return $stack->pop();
+        elseif (array_key_exists($token, $this->vars)) {
+          $stack->push($this->vars[$token]);
+        }
+        elseif (array_key_exists($token, $vars)) {
+          $stack->push($vars[$token]);
+        }
+        else {
+          return $this->trigger("undefined variable '$token'");
+        }
+      }
+    }
+    // When we're out of tokens, the stack should have a single element, the
+    // final result:
+    if ($stack->count() !== 1) {
+      return $this->trigger('internal error');
     }
 
-    // trigger an error, but nicely, if need be
-    function trigger($msg) {
-        $this->last_error = $msg;
-        if (!$this->suppress_errors) trigger_error($msg, E_USER_WARNING);
-        return false;
+    return $stack->pop();
+  }
+
+  /**
+   * Trigger an error, but nicely, if need be.
+   *
+   * @param string $msg
+   *   Message to add to trigger error.
+   *
+   * @return bool
+   *   Can trigger error, then returns FALSE.
+   */
+  protected function trigger($msg) {
+    $this->errors[] = $msg;
+    $this->last_error = $msg;
+    if (!$this->suppress_errors) {
+      trigger_error($msg, E_USER_WARNING);
     }
+
+    return FALSE;
+  }
+
 }
 
-// for internal use
+/**
+ * Class implementing a simple stack structure, used by ctools_math_expr.
+ */
 class ctools_math_expr_stack {
 
-    var $stack = array();
-    var $count = 0;
-
-    function push($val) {
-        $this->stack[$this->count] = $val;
-        $this->count++;
+  /**
+   * The stack.
+   *
+   * @var array
+   */
+  private $stack;
+  /**
+   * The stack pointer, points at the first empty space.
+   *
+   * @var int
+   */
+  private $count;
+
+  /**
+   * Ctools_math_expr_stack constructor.
+   */
+  public function __construct() {
+    $this->stack = array();
+    $this->count = 0;
+  }
+
+  /**
+   * Push the value onto the stack.
+   *
+   * @param mixed $val
+   */
+  public function push($val) {
+    $this->stack[$this->count] = $val;
+    $this->count++;
+  }
+
+  /**
+   * Remove the most recently pushed value and return it.
+   *
+   * @return mixed|null
+   *   The most recently pushed value, or NULL if the stack was empty.
+   */
+  public function pop() {
+    if ($this->count > 0) {
+      $this->count--;
+
+      return $this->stack[$this->count];
     }
+    return NULL;
+  }
+
+  /**
+   * "Peek" the stack, or Return a value from the stack without removing it.
+   *
+   * @param int $n
+   *   Integer indicating which value to return. 1 is the topmost (i.e. the
+   *   value that pop() would return), 2 indicates the next, 3 the third, etc.
+   *
+   * @return mixed|null
+   *   A value pushed onto the stack at the nth position, or NULL if the stack
+   *   was empty.
+   */
+  public function last($n = 1) {
+    return !empty($this->stack[$this->count - $n]) ? $this->stack[$this->count - $n] : NULL;
+  }
+
+  /**
+   * Return the number of items on the stack.
+   *
+   * @return int
+   *   The number of items.
+   */
+  public function count() {
+    return $this->count;
+  }
 
-    function pop() {
-        if ($this->count > 0) {
-            $this->count--;
-            return $this->stack[$this->count];
-        }
-        return null;
-    }
+}
 
-    function last($n=1) {
-        return !empty($this->stack[$this->count-$n]) ? $this->stack[$this->count-$n] : NULL;
-    }
+/**
+ * Helper function for evaluating 'if' condition.
+ *
+ * @param int $expr
+ *   The expression to test: if <> 0 then the $if expression is returned.
+ * @param mixed $if
+ *   The expression returned if the condition is true.
+ * @param mixed $else
+ *   Optional. The expression returned if the expression is false.
+ *
+ * @return mixed|null
+ *   The result. NULL is returned when an If condition is False and no Else
+ *   expression is provided.
+ */
+function ctools_math_expr_if($expr, $if, $else = NULL) {
+  return $expr ? $if : $else;
 }
 
+/**
+ * Remove any non-digits so that numbers like $4,511.23 still work.
+ *
+ * It might be good for those using the 12,345.67 format, but is awful for
+ * those using other conventions.
+ * Use of the php 'intl' module might work here, if the correct locale can be
+ * derived, but that seems unlikely to be true in all cases.
+ *
+ * @todo: locale could break this since in some locales that's $4.512,33 so
+ * there needs to be a way to detect that and make it work properly.
+ *
+ * @param mixed $arg
+ *   A number string with possible leading chars.
+ *
+ * @return mixed
+ *   Returns a number string.
+ */
+function ctools_math_expr_number($arg) {
+  // @todo: A really bad idea: It might be good for those using the 12,345.67
+  // format, but is awful for those using other conventions.
+  // $arg = preg_replace("/[^0-9\.]/", '', $arg);.
+  return $arg;
+}
diff --git a/includes/modal.inc b/includes/modal.inc
index 4f994b67bceffe2ce098a8da62f9a28d865c7c3b..30eadbf40b77593e700d61b1c2f2e8a9805d136e 100644
--- a/includes/modal.inc
+++ b/includes/modal.inc
@@ -55,9 +55,9 @@ function ctools_modal_add_js() {
         'alt' => t('Close window'),
       )),
       'throbber' => theme('image', array(
-          'path' => ctools_image_path('throbber.gif'),
-          'title' => t('Loading...'),
-          'alt' => t('Loading'),
+        'path' => ctools_image_path('throbber.gif'),
+        'title' => t('Loading...'),
+        'alt' => t('Loading'),
       )),
     ),
   );
@@ -66,6 +66,7 @@ function ctools_modal_add_js() {
   drupal_add_library('system', 'jquery.form');
   drupal_add_library('system', 'drupal.progress');
   drupal_add_library('system', 'drupal.ajax');
+  drupal_add_library('system', 'ui');
   ctools_add_js('modal');
 
   ctools_add_css('modal');
@@ -73,7 +74,7 @@ function ctools_modal_add_js() {
 }
 
 /**
- * @todo this is deprecated
+ * @todo Deprecated this.
  */
 function ctools_modal_add_plugin_js($plugins) {
   $css = array();
@@ -84,7 +85,7 @@ function ctools_modal_add_plugin_js($plugins) {
         if (file_exists($file)) {
           $js[$file] = TRUE;
         }
-        else if (file(exists($subtype['path'] . '/' . $file))) {
+        elseif (file_exists($subtype['path'] . '/' . $file)) {
           $js[$subtype['path'] . '/' . $file] = TRUE;
         }
       }
@@ -94,7 +95,7 @@ function ctools_modal_add_plugin_js($plugins) {
         if (file_exists($file)) {
           $css[$file] = TRUE;
         }
-        else if (file(exists($subtype['path'] . '/' . $file))) {
+        elseif (file_exists($subtype['path'] . '/' . $file)) {
           $css[$subtype['path'] . '/' . $file] = TRUE;
         }
       }
@@ -139,7 +140,7 @@ function ctools_modal_command_dismiss() {
 }
 
 /**
- * Display loading screen in the modal
+ * Display loading screen in the modal.
  */
 function ctools_modal_command_loading() {
   return array(
@@ -187,8 +188,8 @@ function ctools_modal_text_button($text, $dest, $alt, $class = '') {
 /**
  * Wrap a form so that we can use it properly with AJAX. Essentially if the
  * form wishes to render, it automatically does that, otherwise it returns
- * so we can see submission results.
-
+ * the render array so we can see submission results.
+ *
  * @param array $form
  *   An associative array containing the structure of the form.
  * @param array $form_state
@@ -201,9 +202,9 @@ function ctools_modal_text_button($text, $dest, $alt, $class = '') {
  *   is set, this will use ctools_modal_form_render so it will be
  *   a $command object suitable for ajax_render already.
  *
- *   The return will be NULL if the form was successfully submitted unless
- *   you specifically set re_render = TRUE. If ajax is set the
- *   form will never be redirected.
+ *   If the form was not rendered, the raw render array will be returned.
+ *
+ *   If ajax is set the form will never be redirected.
  */
 function ctools_modal_form_wrapper($form_id, &$form_state) {
   // Since this will run again on form rebuild while still in the modal, prevent
@@ -220,8 +221,8 @@ function ctools_modal_form_wrapper($form_id, &$form_state) {
   );
 
   $output = drupal_build_form($form_id, $form_state);
- if (!empty($form_state['ajax']) && (!$form_state['executed'] || $form_state['rebuild'])) {
-     return ctools_modal_form_render($form_state, $output);
+  if (!empty($form_state['ajax']) && (!$form_state['executed'] || $form_state['rebuild'])) {
+    return ctools_modal_form_render($form_state, $output);
   }
 
   return $output;
diff --git a/includes/object-cache.inc b/includes/object-cache.inc
index 29225b05bdda8ef6102c5509790b43679e918a61..34c26623a0b6dd6612241e02182bc608f881ffdc 100644
--- a/includes/object-cache.inc
+++ b/includes/object-cache.inc
@@ -21,12 +21,12 @@
  * @param $name
  *   The name of the object being stored.
  * @param $skip_cache
+ *   Deprecated in favor of drupal_static*
  *   Skip the memory cache, meaning this must be read from the db again.
  * @param $sid
  *   The session id, allowing someone to use Session API or their own solution;
  *   defaults to session_id().
  *
- * @deprecated $skip_cache is deprecated in favor of drupal_static*
  * @return
  *   The data that was cached.
  */
@@ -42,8 +42,11 @@ function ctools_object_cache_get($obj, $name, $skip_cache = FALSE, $sid = NULL)
   }
 
   if (!array_key_exists($key, $cache)) {
-    $data = db_query('SELECT * FROM {ctools_object_cache} WHERE sid = :session_id AND obj = :object AND name = :name', array(':session_id' => $sid, ':object' => $obj, ':name' => $name))
-      ->fetchObject();
+    $data = db_query('SELECT * FROM {ctools_object_cache} WHERE sid = :session_id AND obj = :object AND name = :name', array(
+      ':session_id' => $sid,
+      ':object' => $obj,
+      ':name' => md5($name),
+    ))->fetchObject();
     if ($data) {
       $cache[$key] = unserialize($data->data);
     }
@@ -83,7 +86,7 @@ function ctools_object_cache_set($obj, $name, $cache, $sid = NULL) {
     ->fields(array(
       'sid' => $sid,
       'obj' => $obj,
-      'name' => $name,
+      'name' => md5($name),
       'data' => serialize($cache),
       'updated' => REQUEST_TIME,
     ))
@@ -91,7 +94,7 @@ function ctools_object_cache_set($obj, $name, $cache, $sid = NULL) {
 }
 
 /**
- * Remove an object from the non-volatile ctools cache
+ * Remove an object from the non-volatile ctools cache.
  *
  * @param $obj
  *   A 128 character or less string to define what kind of object is being
@@ -103,7 +106,6 @@ function ctools_object_cache_set($obj, $name, $cache, $sid = NULL) {
  *   defaults to session_id().
  */
 function ctools_object_cache_clear($obj, $name, $sid = NULL) {
-
   if (!$sid) {
     $sid = session_id();
   }
@@ -111,13 +113,12 @@ function ctools_object_cache_clear($obj, $name, $sid = NULL) {
   db_delete('ctools_object_cache')
     ->condition('sid', $sid)
     ->condition('obj', $obj)
-    ->condition('name', $name)
+    ->condition('name', md5($name))
     ->execute();
   // Ensure the static cache is emptied of this obj:name set.
   drupal_static_reset('ctools_object_cache_get');
 }
 
-
 /**
  * Determine if another user has a given object cached.
  *
@@ -142,8 +143,11 @@ function ctools_object_cache_test($obj, $name, $sid = NULL) {
     $sid = session_id();
   }
 
-  return db_query('SELECT s.uid, c.updated FROM {ctools_object_cache} c INNER JOIN {sessions} s ON c.sid = s.sid WHERE s.sid <> :session_id AND c.obj = :obj AND c.name = :name ORDER BY c.updated ASC', array(':session_id' => $sid, ':obj' => $obj, ':name' => $name))
-    ->fetchObject();
+  return db_query('SELECT s.uid, c.updated FROM {ctools_object_cache} c INNER JOIN {sessions} s ON c.sid = s.sid WHERE s.sid <> :session_id AND c.obj = :obj AND c.name = :name ORDER BY c.updated ASC', array(
+    ':session_id' => $sid,
+    ':obj' => $obj,
+    ':name' => md5($name),
+  ))->fetchObject();
 }
 
 /**
@@ -162,6 +166,7 @@ function ctools_object_cache_test($obj, $name, $sid = NULL) {
  *   An array of objects containing the UID and updated date for each name found.
  */
 function ctools_object_cache_test_objects($obj, $names) {
+  array_walk($names, 'md5');
   return db_query("SELECT c.name, s.uid, c.updated FROM {ctools_object_cache} c INNER JOIN {sessions} s ON c.sid = s.sid WHERE c.obj = :obj AND c.name IN (:names) ORDER BY c.updated ASC", array(':obj' => $obj, ':names' => $names))
     ->fetchAllAssoc('name');
 }
@@ -180,7 +185,7 @@ function ctools_object_cache_test_objects($obj, $names) {
 function ctools_object_cache_clear_all($obj, $name) {
   db_delete('ctools_object_cache')
     ->condition('obj', $obj)
-    ->condition('name', $name)
+    ->condition('name', md5($name))
     ->execute();
   // Ensure the static cache is emptied of this obj:name set.
   $cache = &drupal_static('ctools_object_cache_get', array());
@@ -197,7 +202,8 @@ function ctools_object_cache_clear_all($obj, $name) {
  */
 function ctools_object_cache_clean($age = NULL) {
   if (empty($age)) {
-    $age = 86400 * 7; // 7 days
+    // 7 days.
+    $age = 86400 * 7;
   }
   db_delete('ctools_object_cache')
     ->condition('updated', REQUEST_TIME - $age, '<')
diff --git a/includes/page-wizard.inc b/includes/page-wizard.inc
index a211361b214938c3e2d84e3b5f72f05f1242fe59..d45d80421e1e1e77d7d31c1fa9252515cc8434e0 100644
--- a/includes/page-wizard.inc
+++ b/includes/page-wizard.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Fetch metadata on a specific page_wizard plugin.
  *
@@ -53,7 +57,7 @@ function page_manager_get_wizard_cache($plugin) {
 }
 
 function page_manager_make_wizard_cache($plugin) {
-  $cache = new stdClass;
+  $cache = new stdClass();
   $cache->plugin = $plugin;
   if ($function = ctools_plugin_get_function($plugin, 'default cache')) {
     $function($cache);
@@ -93,7 +97,7 @@ function page_manager_page_wizard($name, $step = NULL) {
   }
 
   // Check for possibly more complex access callback on plugin.
-  if ($function = ctools_plugin_get_function($plugin, 'access callback') && !$function($plugin)) {
+  if (($function = ctools_plugin_get_function($plugin, 'access callback')) && !$function($plugin)) {
     return MENU_ACCESS_DENIED;
   }
 
diff --git a/includes/plugins-admin.inc b/includes/plugins-admin.inc
index d4ead0a4801e82efefd0388441bd1971ee7d9c20..c11fcfd6800d4d8852c25de72e7fab22a5b51233 100644
--- a/includes/plugins-admin.inc
+++ b/includes/plugins-admin.inc
@@ -10,6 +10,7 @@
  *
  * Implementing this
  */
+
 /**
  * Get a plugin configuration form.
  *
@@ -100,7 +101,7 @@ function _ctools_plugin_configure_create_form_info(&$form_info, $plugin_definiti
     if (empty($plugin_definition['title'])) {
       $title = t('Configure');
     }
-    else if ($op == 'add') {
+    elseif ($op == 'add') {
       $title = t('Configure new !plugin_title', array('!plugin_title' => $plugin_definition['title']));
     }
     else {
@@ -134,10 +135,10 @@ function _ctools_plugin_configure_create_form_info(&$form_info, $plugin_definiti
       $form_info['forms']['form']['wrapper'] = 'ctools_plugins_default_form_wrapper';
     }
   }
-  else if (is_array($info)) {
-      if (empty($form_info['order'])) {
-        $form_info['order'] = array();
-      }
+  elseif (is_array($info)) {
+    if (empty($form_info['order'])) {
+      $form_info['order'] = array();
+    }
     if (empty($form_info['forms'])) {
       $form_info['forms'] = array();
     }
diff --git a/includes/plugins.inc b/includes/plugins.inc
index cf3ac05c09a5508c33d6aa8459bb453f5bc3d211..7b53ae19cd611d0f7069d4dd8282c373d0cada9a 100644
--- a/includes/plugins.inc
+++ b/includes/plugins.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Contains routines to organize and load plugins. It allows a special
  * variation of the hook system so that plugins can be kept in separate
  * .inc files, and can be either loaded all at once or loaded only when
@@ -70,7 +69,7 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
       if (isset($info['version'])) {
         $version = $info['version'];
       }
-      else if (isset($info['api'])) {
+      elseif (isset($info['api'])) {
         $version = $info['api'];
       }
 
@@ -79,7 +78,9 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
       }
 
       // Only process if version is between minimum and current, inclusive.
-      if (version_compare($version, $minimum_version, '>=') && version_compare($version, $current_version, '<=')) {
+      if (($version == $minimum_version) || ($version == $current_version)
+        || (version_compare($version, $minimum_version, '>=')
+        && version_compare($version, $current_version, '<='))) {
         if (!isset($info['path'])) {
           $info['path'] = drupal_get_path('module', $module);
         }
@@ -97,7 +98,7 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
         }
 
         // Only process if version is between minimum and current, inclusive.
-      if (version_compare($info['version'], $minimum_version, '>=') && version_compare($info['version'], $current_version, '<=')) {
+        if (version_compare($info['version'], $minimum_version, '>=') && version_compare($info['version'], $current_version, '<=')) {
           if (!isset($info['path'])) {
             $info['path'] = '';
           }
@@ -110,7 +111,7 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
     }
 
     // Allow other modules to hook in.
-    drupal_alter($hook, $cache[$owner][$api]);
+    drupal_alter($hook, $cache[$owner][$api], $owner, $api);
   }
 
   return $cache[$owner][$api];
@@ -149,7 +150,7 @@ function ctools_plugin_api_include($owner, $api, $minimum_version, $current_vers
       if (isset($plugin_info["$api file"])) {
         $file = $plugin_info["$api file"];
       }
-      else if (isset($plugin_info['file'])) {
+      elseif (isset($plugin_info['file'])) {
         $file = $plugin_info['file'];
       }
       else {
@@ -159,7 +160,7 @@ function ctools_plugin_api_include($owner, $api, $minimum_version, $current_vers
       if (file_exists(DRUPAL_ROOT . "/$plugin_info[path]/$file")) {
         require_once DRUPAL_ROOT . "/$plugin_info[path]/$file";
       }
-      else if (file_exists(DRUPAL_ROOT . "/$file")) {
+      elseif (file_exists(DRUPAL_ROOT . "/$file")) {
         require_once DRUPAL_ROOT . "/$file";
       }
       $already_done[$owner][$api][$module] = TRUE;
@@ -182,7 +183,7 @@ function ctools_plugin_api_get_hook($owner, $api) {
   if (function_exists($function = $owner . '_' . $api . '_hook_name')) {
     $hook = $function();
   }
-  else if (function_exists($function = $owner . '_ctools_plugin_api_hook_name')) {
+  elseif (function_exists($function = $owner . '_ctools_plugin_api_hook_name')) {
     $hook = $function();
   }
 
@@ -198,29 +199,38 @@ function ctools_plugin_api_get_hook($owner, $api) {
 /**
  * Fetch a group of plugins by name.
  *
- * @param $module
- *   The name of the module that utilizes this plugin system. It will be
- *   used to call hook_ctools_plugin_$plugin() to get more data about the plugin.
- * @param $type
+ * @param string $module
+ *   The name of the module that utilizes this plugin system. It will be used to
+ *   get more data about the plugin as defined on hook_ctools_plugin_type().
+ * @param string $type
  *   The type identifier of the plugin.
- * @param $id
+ * @param string $id
  *   If specified, return only information about plugin with this identifier.
  *   The system will do its utmost to load only plugins with this id.
  *
- * @return
- *   An array of information arrays about the plugins received. The contents
- *   of the array are specific to the plugin.
+ * @return array
+ *   An array of information arrays about the plugins received. The contents of
+ *   the array are specific to the plugin.
  */
 function ctools_get_plugins($module, $type, $id = NULL) {
   // Store local caches of plugins and plugin info so we don't have to do full
-  // lookups everytime.
-  $plugins = &drupal_static('ctools_plugins', array());
+  // lookups every time.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['plugins'] = &drupal_static('ctools_plugins', array());
+  }
+  $plugins = &$drupal_static_fast['plugins'];
+
   $info = ctools_plugin_get_plugin_type_info();
 
-  // Bail out noisily if an invalid module/type combination is requested.
   if (!isset($info[$module][$type])) {
-    watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
-    return array();
+    // If we don't find the plugin we attempt a cache rebuild before bailing out.
+    $info = ctools_plugin_get_plugin_type_info(TRUE);
+    // Bail out noisily if an invalid module/type combination is requested.
+    if (!isset($info[$module][$type])) {
+      watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
+      return array();
+    }
   }
 
   // Make sure our plugins array is populated.
@@ -228,8 +238,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
     $plugins[$module][$type] = array();
   }
 
-  // Attempt to shortcut this whole piece of code if we already have
-  // the requested plugin:
+  // Attempt to shortcut this whole piece of code if we already have the
+  // requested plugin:
   if ($id && array_key_exists($id, $plugins[$module][$type])) {
     return $plugins[$module][$type][$id];
   }
@@ -247,9 +257,9 @@ function ctools_get_plugins($module, $type, $id = NULL) {
 
     if (!empty($cache->data)) {
       // Cache load succeeded so use the cached plugin list.
-      $plugins[$module][$type]   = $cache->data;
+      $plugins[$module][$type] = $cache->data;
       // Set $setup to true so we know things where loaded.
-      $setup[$module][$type]     = TRUE;
+      $setup[$module][$type] = TRUE;
     }
     else {
       // Cache load failed so store that we need to build and write the cache.
@@ -264,8 +274,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
     $plugins[$module][$type] = ctools_plugin_load_hooks($info[$module][$type]);
   }
 
-  // Then see if we should load all files. We only do this if we
-  // want a list of all plugins or there was a cache miss.
+  // Then see if we should load all files. We only do this if we want a list of
+  // all plugins or there was a cache miss.
   if (empty($setup[$module][$type]) && ($build_cache || !$id)) {
     $setup[$module][$type] = TRUE;
     $plugins[$module][$type] = array_merge($plugins[$module][$type], ctools_plugin_load_includes($info[$module][$type]));
@@ -288,9 +298,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
     }
   }
 
-
-  // If we were told earlier that this is cacheable and the cache was
-  // empty, give something back.
+  // If we were told earlier that this is cacheable and the cache was empty,
+  // give something back.
   if ($build_cache) {
     cache_set("plugins:$module:$type", $plugins[$module][$type], $info[$module][$type]['cache table']);
   }
@@ -302,7 +311,7 @@ function ctools_get_plugins($module, $type, $id = NULL) {
     return array_filter($plugins[$module][$type]);
   }
 
-  // Check to see if we need to look for the file
+  // Check to see if we need to look for the file.
   if (!array_key_exists($id, $plugins[$module][$type])) {
     // If we can have child plugins, check to see if the plugin name is in the
     // format of parent:child and break it up if it is.
@@ -408,40 +417,31 @@ function ctools_get_plugins_reset() {
 /**
  * Load plugins from a directory.
  *
- * @param $info
+ * @param array $info
  *   The plugin info as returned by ctools_plugin_get_info()
- * @param $file
+ * @param string $filename
  *   The file to load if we're looking for just one particular plugin.
  *
- * @return
- *   An array of information created for this plugin.
+ * @return array
+ *   A (possibly empty) array of information created for this plugin.
  */
 function ctools_plugin_load_includes($info, $filename = NULL) {
   // Keep a static array so we don't hit file_scan_directory more than necessary.
   $all_files = &drupal_static(__FUNCTION__, array());
 
-  // store static of plugin arrays for reference because they can't be reincluded.
+  // Store static of plugin arrays for reference because they can't be
+  // reincluded, so there is no point in using drupal_static().
   static $plugin_arrays = array();
 
-  // If we're being asked for all plugins of a type, skip any caching
-  // we may have done because this is an admin task and it's ok to
-  // spend the extra time.
-  if (!isset($filename)) {
-    $all_files[$info['module']][$info['type']] = NULL;
-  }
-
   if (!isset($all_files[$info['module']][$info['type']])) {
-    // If a filename was set, we will try to load our list of files from
-    // cache. This is considered normal operation and we try to reduce
-    // the time spent finding files.
-    if (isset($filename)) {
-      $cache = cache_get("ctools_plugin_files:$info[module]:$info[type]");
-      if ($cache) {
-        $all_files[$info['module']][$info['type']] = $cache->data;
-      }
-    }
-
-    if (!isset($all_files[$info['module']][$info['type']])) {
+    $cache = cache_get("ctools_plugin_files:$info[module]:$info[type]");
+    if ($cache) {
+      $all_files[$info['module']][$info['type']] = $cache->data;
+    }
+    // Do not attempt any file scan even if the cached entry was empty.
+    // A NULL entry here would mean the plugin just does not exists, and we
+    // cannot afford to run file scan on production sites normal run.
+    elseif (!isset($all_files[$info['module']][$info['type']])) {
       $all_files[$info['module']][$info['type']] = array();
       // Load all our plugins.
       $directories = ctools_plugin_get_directories($info);
@@ -465,24 +465,23 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
     }
     foreach ($files as $file) {
       if (!empty($info['info file'])) {
-        // Parse a .info file
+        // Parse a .info file.
         $result = ctools_plugin_process_info($info, $module, $file);
       }
       else {
         // Parse a hook.
-        $plugin = NULL; // ensure that we don't have something leftover from earlier.
+        // Ensure that we don't have something leftover from earlier.
+        $plugin = NULL;
 
         if (isset($plugin_arrays[$file->uri])) {
           $identifier = $plugin_arrays[$file->uri];
         }
         else {
-
-          require_once DRUPAL_ROOT . '/' . $file->uri;
+          include_once DRUPAL_ROOT . '/' . $file->uri;
           // .inc files have a special format for the hook identifier.
           // For example, 'foo.inc' in the module 'mogul' using the plugin
-          // whose hook is named 'borg_type' should have a function named (deep breath)
-          // mogul_foo_borg_type()
-
+          // whose hook is named 'borg_type' should have a function named
+          // (deep breath) mogul_foo_borg_type().
           // If, however, the .inc file set the quasi-global $plugin array, we
           // can use that and not even call a function. Set the $identifier
           // appropriately and ctools_plugin_process() will handle it.
@@ -495,7 +494,8 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
           }
         }
 
-        $result = ctools_plugin_process($info, $module, $identifier, dirname($file->uri), basename($file->uri), $file->name);
+        $result = ctools_plugin_process($info, $module, $identifier,
+          dirname($file->uri), basename($file->uri), $file->name);
       }
       if (is_array($result)) {
         $plugins = array_merge($plugins, $result);
@@ -515,7 +515,7 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
  * @param $info
  *   The $info array for the plugin as returned by ctools_plugin_get_info().
  *
- * @return array $directories
+ * @return array
  *   An array of directories to search.
  */
 function ctools_plugin_get_directories($info) {
@@ -541,10 +541,9 @@ function ctools_plugin_get_directories($info) {
 }
 
 /**
- * Helper function to build a ctools-friendly list of themes capable of
- * providing plugins.
+ * Helper to build a ctools-friendly list of themes capable of providing plugins.
  *
- * @return array $themes
+ * @return array
  *   A list of themes that can act as plugin providers, sorted parent-first with
  *   the active theme placed last.
  */
@@ -555,7 +554,7 @@ function _ctools_list_themes() {
     $themes = $active = array();
     $all_themes = list_themes();
     foreach ($all_themes as $name => $theme) {
-      // Only search from active themes
+      // Only search from active themes.
       if (empty($theme->status) && $theme->name != $current) {
         continue;
       }
@@ -566,19 +565,19 @@ function _ctools_list_themes() {
       }
     }
 
-    // Construct a parent-first list of all themes
+    // Construct a parent-first list of all themes.
     foreach ($active as $name => $theme) {
       $base_themes = isset($theme->base_themes) ? $theme->base_themes : array();
       $themes = array_merge($themes, $base_themes, array($name => $theme->info['name']));
     }
-    // Put the actual theme info objects into the array
+    // Put the actual theme info objects into the array.
     foreach (array_keys($themes) as $name) {
       if (isset($all_themes[$name])) {
         $themes[$name] = $all_themes[$name];
       }
     }
 
-    // Make sure the current default theme always gets the last word
+    // Make sure the current default theme always gets the last word.
     if ($current_key = array_search($current, array_keys($themes))) {
       $themes += array_splice($themes, $current_key, 1);
     }
@@ -586,7 +585,6 @@ function _ctools_list_themes() {
   return $themes;
 }
 
-
 /**
  * Find all the base themes for the specified theme.
  *
@@ -602,9 +600,10 @@ function _ctools_list_themes() {
  *   The name of the theme whose base we are looking for.
  * @param $used_keys
  *   A recursion parameter preventing endless loops.
- * @return
+ *
+ * @return array
  *   Returns an array of all of the theme's ancestors; the first element's value
- *   will be NULL if an error occurred.
+ *   will be NULL if an error occurred. (Note: this is NOT $arr[0]).
  */
 function ctools_find_base_themes($themes, $key, $used_keys = array()) {
   $base_key = $themes[$key]->info['base theme'];
@@ -632,7 +631,6 @@ function ctools_find_base_themes($themes, $key, $used_keys = array()) {
   return $current_base_theme;
 }
 
-
 /**
  * Load plugin info for the provided hook; this is handled separately from
  * plugins from files.
@@ -657,22 +655,28 @@ function ctools_plugin_load_hooks($info) {
 /**
  * Process a single hook implementation of a ctools plugin.
  *
- * @param $info
+ * @param array $info
  *   The $info array about the plugin as returned by ctools_plugin_get_info()
- * @param $module
+ * @param string $module
  *   The module that implements the plugin being processed.
- * @param $identifier
- *   The plugin identifier, which is used to create the name of the hook
- *   function being called.
- * @param $path
+ * @param string|array $identifier
+ *   Used to create the base setting of return value. If:
+ *    - $identifier is a string, a hook name is created from this and the 'hook'
+ *      key of the $info array, and the return value of that hook function is
+ *      used. The hook is called like this: $identifier_$hook($info);
+ *    - $identifier is an array, this array is used directly.
+ * @param string $path
  *   The path where files utilized by this plugin will be found.
- * @param $file
+ * @param string $file
  *   The file that was loaded for this plugin, if it exists.
- * @param $base
+ * @param string $base
  *   The base plugin name to use. If a file was loaded for the plugin, this
  *   is the plugin to assume must be present. This is used to automatically
  *   translate the array to make the syntax more friendly to plugin
  *   implementors.
+ *
+ * @return null|array
+ *   NULL on failure, otherwise an array containing the results keyed by name.
  */
 function ctools_plugin_process($info, $module, $identifier, $path, $file = NULL, $base = NULL) {
   if (is_array($identifier)) {
@@ -683,7 +687,7 @@ function ctools_plugin_process($info, $module, $identifier, $path, $file = NULL,
     if (!function_exists($function)) {
       return NULL;
     }
-    $result = $function();
+    $result = $function($info);
     if (!isset($result) || !is_array($result)) {
       return NULL;
     }
@@ -740,9 +744,19 @@ function _ctools_process_data($result, $plugin_type_info, $module, $path, $file)
   return $result;
 }
 
-
 /**
  * Process an info file for plugin information, rather than a hook.
+ *
+ * @param array $info
+ *   The $info array about the plugin as returned by ctools_plugin_get_info()
+ * @param string $module
+ *   The module that implements the plugin being processed.
+ * @param object $file
+ *   An object containing 'uri' and 'name' properties. 'uri' is the name of the
+ *   'info' file to process. 'name' is the plugin key-name.
+ *
+ * @return null|array
+ *   NULL on failure, otherwise an array containing the results keyed by name.
  */
 function ctools_plugin_process_info($info, $module, $file) {
   $result = drupal_parse_info_file($file->uri);
@@ -769,7 +783,7 @@ function ctools_plugin_get_info($module, $type) {
  * @param $function_name
  *   The identifier of the function. For example, 'settings form'.
  *
- * @return
+ * @return string
  *   The actual name of the function to call, or NULL if the function
  *   does not exist.
  */
@@ -786,7 +800,7 @@ function ctools_plugin_get_function($plugin_definition, $function_name) {
   }
 
   if (!isset($plugin_definition[$function_name])) {
-    return;
+    return NULL;
   }
 
   if (is_array($plugin_definition[$function_name]) && isset($plugin_definition[$function_name]['function'])) {
@@ -821,7 +835,7 @@ function ctools_plugin_get_function($plugin_definition, $function_name) {
  * @param $function_name
  *   The identifier of the function. For example, 'settings form'.
  *
- * @return
+ * @return string
  *   The actual name of the function to call, or NULL if the function
  *   does not exist.
  */
@@ -839,7 +853,7 @@ function ctools_plugin_load_function($module, $type, $id, $function_name) {
  * @param $class_name
  *   The identifier of the class. For example, 'handler'.
  *
- * @return
+ * @return string
  *   The actual name of the class to call, or NULL if the class does not exist.
  */
 function ctools_plugin_get_class($plugin_definition, $class_name) {
@@ -858,11 +872,11 @@ function ctools_plugin_get_class($plugin_definition, $class_name) {
   if (!isset($plugin_definition[$class_name])) {
     return;
   }
-  else if (is_string($plugin_definition[$class_name])) {
+  elseif (is_string($plugin_definition[$class_name])) {
     // Plugin uses the string form shorthand.
     $return = $plugin_definition[$class_name];
   }
-  else if (isset($plugin_definition[$class_name]['class'])) {
+  elseif (isset($plugin_definition[$class_name]['class'])) {
     // Plugin uses the verbose array form.
     $return = $plugin_definition[$class_name]['class'];
   }
@@ -884,7 +898,7 @@ function ctools_plugin_get_class($plugin_definition, $class_name) {
  * @param $class_name
  *   The identifier of the class. For example, 'handler'.
  *
- * @return
+ * @return string
  *   The actual name of the class to call, or NULL if the class does not exist.
  */
 function ctools_plugin_load_class($module, $type, $id, $class_name) {
diff --git a/includes/registry.inc b/includes/registry.inc
index 9d4328e693befc29c6d176de4bb940cec4203b95..7e517bb980071ee69f2e6ebdc6e97967100b93e9 100644
--- a/includes/registry.inc
+++ b/includes/registry.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Registry magic. In a separate file to minimize unnecessary code loading.
  */
 
diff --git a/includes/stylizer.inc b/includes/stylizer.inc
index 9fdc81d771481aedf81d220f99762515dffbf75d..488a7f3ef775f4f137232d9e9cfa325b03dbff9a 100644
--- a/includes/stylizer.inc
+++ b/includes/stylizer.inc
@@ -202,7 +202,7 @@ function ctools_stylizer_get_settings_name($settings) {
 }
 
 /**
- * Get the path where images will be stored for a given style plugin and settings.
+ * Get the path where images will be stored for a style plugin and settings.
  *
  * This function will make sure the path exists.
  */
@@ -249,7 +249,7 @@ class ctools_stylizer_image_processor {
     if (is_string($plugin['actions']) && function_exists($plugin['actions'])) {
       $actions = $plugin['actions']($plugin, $settings);
     }
-    else if (is_array($plugin['actions'])) {
+    elseif (is_array($plugin['actions'])) {
       $actions = $plugin['actions'];
     }
 
@@ -318,7 +318,7 @@ class ctools_stylizer_image_processor {
   function command_load($name, $file) {
     $this->log("New workspace: $name (from $file)");
     if (!file_exists($file)) {
-      // Try it relative to the plugin
+      // Try it relative to the plugin.
       $file = $this->plugin['path'] . '/' . $file;
       if (!file_exists($file)) {
         $this->log("Unable to open $file");
@@ -336,7 +336,7 @@ class ctools_stylizer_image_processor {
   }
 
   /**
-   * Create a new workspace using the properties of an existing workspace
+   * Create a new workspace using the properties of an existing workspace.
    */
   function command_new_from($name, $workspace) {
     $this->log("New workspace: $name from existing $workspace");
@@ -372,7 +372,7 @@ class ctools_stylizer_image_processor {
   function command_merge_from($workspace, $x = 0, $y = 0) {
     $this->log("Merge from: $workspace ($x, $y)");
     if (empty($this->workspaces[$workspace])) {
-      $this->log("Workspace $name does not exist.", 'error');
+      $this->log("Workspace $workspace does not exist.", 'error');
       return;
     }
 
@@ -382,7 +382,7 @@ class ctools_stylizer_image_processor {
   function command_merge_to($workspace, $x = 0, $y = 0) {
     $this->log("Merge to: $workspace ($x, $y)");
     if (empty($this->workspaces[$workspace])) {
-      $this->log("Workspace $name does not exist.", 'error');
+      $this->log("Workspace $workspace does not exist.", 'error');
       return;
     }
 
@@ -500,7 +500,7 @@ class ctools_stylizer_image_processor {
     $palette[$luminosity_input]['green'] = $green;
     $palette[$luminosity_input]['blue'] = $blue;
 
-    // Now we complete the palette, first we'll do it tothe black, and then to
+    // Now we complete the palette, first we'll do it to the black, and then to
     // the white.
 
     // From input to black
@@ -822,7 +822,7 @@ function ctools_stylizer_add_plugin_forms(&$form_info, $plugin, $op) {
     if ($op == 'add' && isset($plugin['add form'])) {
       $id = $plugin['add form'];
     }
-    else if (isset($plugin['edit form'])) {
+    elseif (isset($plugin['edit form'])) {
       $id = $plugin['edit form'];
     }
     else {
diff --git a/includes/stylizer.theme.inc b/includes/stylizer.theme.inc
index 85346c155c62e5ac9a5f911dff182f833c953d0a..0ceedffc7c5ca6a80a164c2719690a9eceb37172 100644
--- a/includes/stylizer.theme.inc
+++ b/includes/stylizer.theme.inc
@@ -25,4 +25,3 @@ function ctools_stylizer_theme(&$theme) {
     'file' => 'includes/stylizer.inc',
   );
 }
-
diff --git a/includes/utility.inc b/includes/utility.inc
index 82fc1471a21b8a6af9f711030f02ecb958b9a02f..3c939a441d93f6f84ecb9a7b99d1e9dbe2c22a30 100644
--- a/includes/utility.inc
+++ b/includes/utility.inc
@@ -23,7 +23,7 @@ function ctools_passthrough($module, $type, &$items) {
     require_once DRUPAL_ROOT . '/' . $file->uri;
     list($tool) = explode('.', $file->name, 2);
 
-    $function = $module . '_' . str_replace ('-', '_', $tool) . '_' . str_replace('-', '_', $type);
+    $function = $module . '_' . str_replace('-', '_', $tool) . '_' . str_replace('-', '_', $type);
     if (function_exists($function)) {
       $function($items);
     }
diff --git a/includes/uuid.inc b/includes/uuid.inc
index b0567d34207331d951b941df029578d7b215a561..f51838be0eefab06ae5840237f760d3f6d241d19 100644
--- a/includes/uuid.inc
+++ b/includes/uuid.inc
@@ -9,7 +9,9 @@
 /**
  * Pattern for detecting a valid UUID.
  */
-define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+if (!defined('UUID_PATTERN')) {
+  define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+}
 
 /**
  * Generates a UUID using the Windows internal GUID generator.
@@ -25,7 +27,8 @@ function _ctools_uuid_generate_com() {
  * Generates an universally unique identifier using the PECL extension.
  */
 function _ctools_uuid_generate_pecl() {
-  return uuid_create(UUID_TYPE_DEFAULT);
+  $uuid_type = UUID_TYPE_DEFAULT;
+  return uuid_create($uuid_type);
 }
 
 /**
@@ -64,4 +67,5 @@ if (!function_exists('uuid_is_valid')) {
   function uuid_is_valid($uuid) {
     return preg_match('/^' . UUID_PATTERN . '$/', $uuid);
   }
+
 }
diff --git a/includes/views.inc b/includes/views.inc
index 4ef6439e727444369645dcd3c2042ab238ea15e3..9c1ee6c3df6101c552d06e0632b77b2709da3ffc 100644
--- a/includes/views.inc
+++ b/includes/views.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Generate new context classes by argument settings on the view.
  */
diff --git a/includes/wizard.inc b/includes/wizard.inc
index 6f5d7944b863ec48f4934a24dfb7fd749399f1fb..e0b8fbd14e8f178226ac87846f68e5b85d111c43 100644
--- a/includes/wizard.inc
+++ b/includes/wizard.inc
@@ -47,7 +47,7 @@ function ctools_wizard_multistep_form($form_info, $step, &$form_state) {
   // with form caching.
   ctools_form_include($form_state, 'wizard');
 
-  // allow order array to be optional
+  // Allow order array to be optional.
   if (empty($form_info['order'])) {
     foreach ($form_info['forms'] as $step_id => $params) {
       $form_info['order'][$step_id] = $params['title'];
@@ -83,7 +83,7 @@ function ctools_wizard_multistep_form($form_info, $step, &$form_state) {
       $form_info['cache location'] = 'storage';
     }
 
-    // If absolutely nothing was set for the cache area to work on
+    // If absolutely nothing was set for the cache area to work on.
     if (!isset($form_state[$form_info['cache location']])) {
       ctools_include('cache');
       $form_state[$form_info['cache location']] = ctools_cache_get($form_info['cache mechanism'], $form_info['cache key']);
@@ -199,7 +199,7 @@ function ctools_wizard_multistep_form($form_info, $step, &$form_state) {
         }
       }
     }
-    else if (isset($form_state['ajax next'])) {
+    elseif (isset($form_state['ajax next'])) {
       // Clear a few items off the form state so we don't double post:
       $next = $form_state['ajax next'];
       unset($form_state['ajax next']);
@@ -274,7 +274,7 @@ function ctools_wizard_wrapper($form, &$form_state) {
   if (!empty($form_info['show trail'])) {
     ctools_add_css('wizard');
     $form['ctools_trail'] = array(
-      '#markup' => theme(array('ctools_wizard_trail__' . $form_info['id'], 'ctools_wizard_trail'), array('trail' => $trail)),
+      '#markup' => theme(array('ctools_wizard_trail__' . $form_info['id'], 'ctools_wizard_trail'), array('trail' => $trail, 'form_info' => $form_info)),
       '#weight' => -1000,
     );
   }
@@ -299,7 +299,7 @@ function ctools_wizard_wrapper($form, &$form_state) {
         '#wizard type' => 'next',
         '#weight' => -2000,
         '#limit_validation_errors' => array(),
-        // hardcode the submit so that it doesn't try to save data.
+        // Hardcode the submit so that it doesn't try to save data.
         '#submit' => array('ctools_wizard_submit'),
         '#attributes' => $button_attributes,
       );
@@ -325,19 +325,18 @@ function ctools_wizard_wrapper($form, &$form_state) {
     // end of the form list (i.e, there is a next) then it's "update and return"
     // to be clear. If this is the end of the path and there is no next, we
     // call it 'Finish'.
-
     // Even if there is no direct return path (some forms may not want you
     // leaving in the middle) the final button is always a Finish and it does
     // whatever the return action is.
     if (!empty($form_info['show return']) && !empty($form_state['next'])) {
       $form['buttons']['return'] = array(
         '#type' => 'submit',
-        '#value' =>  $form_info['return text'],
+        '#value' => $form_info['return text'],
         '#wizard type' => 'return',
         '#attributes' => $button_attributes,
       );
     }
-    else if (empty($form_state['next']) || !empty($form_info['free trail'])) {
+    elseif (empty($form_state['next']) || !empty($form_info['free trail'])) {
       $form['buttons']['return'] = array(
         '#type' => 'submit',
         '#value' => $form_info['finish text'],
@@ -352,7 +351,7 @@ function ctools_wizard_wrapper($form, &$form_state) {
         '#type' => 'submit',
         '#value' => $form_info['cancel text'],
         '#wizard type' => 'cancel',
-        // hardcode the submit so that it doesn't try to save data.
+        // Hardcode the submit so that it doesn't try to save data.
         '#limit_validation_errors' => array(),
         '#submit' => array('ctools_wizard_submit'),
         '#attributes' => $button_attributes,
@@ -370,7 +369,6 @@ function ctools_wizard_wrapper($form, &$form_state) {
 
     // Set up our submit handler after theirs. Since putting something here will
     // skip Drupal's autodetect, we autodetect for it.
-
     // We make sure ours is after theirs so that they get to change #next if
     // the want to.
     $form['#submit'] = array();
@@ -398,7 +396,7 @@ function ctools_wizard_wrapper($form, &$form_state) {
 
       $params = array($url, $options);
     }
-    $form['#action'] =  call_user_func_array('url', $params);
+    $form['#action'] = call_user_func_array('url', $params);
   }
 
   if (isset($info['wrapper']) && function_exists($info['wrapper'])) {
@@ -418,7 +416,7 @@ function ctools_wizard_submit(&$form, &$form_state) {
   if (isset($form_state['clicked_button']['#wizard type'])) {
     $type = $form_state['clicked_button']['#wizard type'];
 
-    // if AJAX enabled, we proceed slightly differently here.
+    // If AJAX enabled, we proceed slightly differently here.
     if (!empty($form_state['ajax'])) {
       if ($type == 'next') {
         $form_state['ajax next'] = $form_state['clicked_button']['#next'];
@@ -428,7 +426,7 @@ function ctools_wizard_submit(&$form, &$form_state) {
       if ($type == 'cancel' && isset($form_state['form_info']['cancel path'])) {
         $form_state['redirect'] = $form_state['form_info']['cancel path'];
       }
-      else if ($type == 'next') {
+      elseif ($type == 'next') {
         $form_state['redirect'] = ctools_wizard_get_path($form_state['form_info'], $form_state['clicked_button']['#next']);
         if (!empty($_GET['destination'])) {
           // We don't want drupal_goto redirect this request
@@ -437,10 +435,10 @@ function ctools_wizard_submit(&$form, &$form_state) {
           unset($_GET['destination']);
         }
       }
-      else if (isset($form_state['form_info']['return path'])) {
+      elseif (isset($form_state['form_info']['return path'])) {
         $form_state['redirect'] = $form_state['form_info']['return path'];
       }
-      else if ($type == 'finish' && isset($form_state['form_info']['cancel path'])) {
+      elseif ($type == 'finish' && isset($form_state['form_info']['cancel path'])) {
         $form_state['redirect'] = $form_state['form_info']['cancel path'];
       }
     }
@@ -469,10 +467,8 @@ function ctools_wizard_get_path($form_info, $step) {
     if (!isset($path[1]) || !is_array($path[1])) {
       $path[1] = array();
     }
-    // Ensure that the query part of options is an array.
-    $path[1] += array('query' => array());
     // Add the destination parameter, if not set already.
-    $path[1]['query'] += drupal_get_destination();
+    $path[1] += drupal_get_destination();
   }
 
   return $path;
@@ -505,15 +501,15 @@ function ctools_wizard_defaults(&$form_info) {
   }
 
   $form_info = $form_info + $defaults;
-  // set form callbacks if they aren't defined
+  // Set form callbacks if they aren't defined.
   foreach ($form_info['forms'] as $step => $params) {
-    if (!$params['form id']) {
-       $form_callback = $hook . '_' . $step . '_form';
-       $form_info['forms'][$step]['form id'] = $form_callback;
+    if (empty($params['form id'])) {
+      $form_callback = $hook . '_' . $step . '_form';
+      $form_info['forms'][$step]['form id'] = $form_callback;
     }
   }
 
-  // set button callbacks
+  // Set button callbacks.
   $callbacks = array(
     'back callback' => '_back',
     'next callback' => '_next',
@@ -523,10 +519,10 @@ function ctools_wizard_defaults(&$form_info) {
   );
 
   foreach ($callbacks as $key => $callback) {
-    // never overwrite if explicity defined
+    // Never overwrite if explicity defined.
     if (empty($form_info[$key])) {
       $wizard_callback = $hook . $callback;
-      if (function_exists($wizard_callback))  {
+      if (function_exists($wizard_callback)) {
         $form_info[$key] = $wizard_callback;
       }
     }
diff --git a/includes/wizard.theme.inc b/includes/wizard.theme.inc
index 304906c02ee7a8feff46d47e998f9e3247aa94f3..c1a26468d7234f7aaaa4f08b333746d556e3a38d 100644
--- a/includes/wizard.theme.inc
+++ b/includes/wizard.theme.inc
@@ -7,19 +7,16 @@
 
 function ctools_wizard_theme(&$theme) {
   $theme['ctools_wizard_trail'] = array(
-    'variables' => array('trail' => NULL),
+    'variables' => array('trail' => NULL, 'form_info' => NULL, 'divider' => ' » '),
     'file' => 'includes/wizard.theme.inc',
   );
 }
 
 /**
- * Themable display of the 'breadcrumb' trail to show the order of the
- * forms.
+ * Themable display of the 'breadcrumb' trail to show the order of the forms.
  */
 function theme_ctools_wizard_trail($vars) {
-  $trail = $vars['trail'];
-  if (!empty($trail)) {
-    return '<div class="wizard-trail">' . implode(' » ', $trail) . '</div>';
+  if (!empty($vars['trail'])) {
+    return '<div class="wizard-trail">' . implode($vars['divider'], $vars['trail']) . '</div>';
   }
 }
-
diff --git a/js/ajax-responder.js b/js/ajax-responder.js
index 1cad618efbdbc0e82fcb4128efd08e2c49014f14..116d4744f56d7bd4d73dddb3ae9def7ff3b9f302 100644
--- a/js/ajax-responder.js
+++ b/js/ajax-responder.js
@@ -26,7 +26,7 @@
     // Grab all the links that match this url and add the fetching class.
     // This allows the caching system to grab each url once and only once
     // instead of grabbing the url once per <a>.
-    var $objects = $('a[href="' + old_url + '"]')
+    var $objects = $('a[href="' + old_url + '"]');
     $objects.addClass('ctools-fetching');
     try {
       url = old_url.replace(/\/nojs(\/|$)/g, '/ajax$1');
@@ -98,29 +98,30 @@
   };
 
   // Hide these in a ready to ensure that Drupal.ajax is set up first.
-  $(function() {
-    Drupal.ajax.prototype.commands.attr = function(ajax, data, status) {
-      $(data.selector).attr(data.name, data.value);
-    };
+  Drupal.behaviors.ctools_add_ajax_responder_commands = {
+    attach: function () {
+      Drupal.ajax.prototype.commands.attr = function (ajax, data, status) {
+        $(data.selector).attr(data.name, data.value);
+      };
 
-
-    Drupal.ajax.prototype.commands.redirect = function(ajax, data, status) {
-      if (data.delay > 0) {
-        setTimeout(function () {
+      Drupal.ajax.prototype.commands.redirect = function (ajax, data, status) {
+        if (data.delay > 0) {
+          setTimeout(function () {
+            location.href = data.url;
+          }, data.delay);
+        }
+        else {
           location.href = data.url;
-        }, data.delay);
-      }
-      else {
-        location.href = data.url;
-      }
-    };
+        }
+      };
 
-    Drupal.ajax.prototype.commands.reload = function(ajax, data, status) {
-      location.reload();
-    };
+      Drupal.ajax.prototype.commands.reload = function (ajax, data, status) {
+        location.reload();
+      };
 
-    Drupal.ajax.prototype.commands.submit = function(ajax, data, status) {
-      $(data.selector).submit();
+      Drupal.ajax.prototype.commands.submit = function (ajax, data, status) {
+        $(data.selector).submit();
+      }
     }
-  });
+  };
 })(jQuery);
diff --git a/js/auto-submit.js b/js/auto-submit.js
index a3e9aa42a07970d10998693e51f25cd1606ddd4a..0e97e2eb5a866e3d281b11b23c8750a3fe790485 100644
--- a/js/auto-submit.js
+++ b/js/auto-submit.js
@@ -36,9 +36,11 @@ Drupal.behaviors.CToolsAutoSubmit = {
   attach: function(context) {
     // 'this' references the form element
     function triggerSubmit (e) {
-      var $this = $(this);
-      if (!$this.hasClass('ctools-ajaxing')) {
-        $this.find('.ctools-auto-submit-click').click();
+      if ($.contains(document.body, this)) {
+        var $this = $(this);
+        if (!$this.hasClass('ctools-ajaxing')) {
+          $this.find('.ctools-auto-submit-click').click();
+        }
       }
     }
 
@@ -96,5 +98,5 @@ Drupal.behaviors.CToolsAutoSubmit = {
           });
       });
   }
-}
+};
 })(jQuery);
diff --git a/js/collapsible-div.js b/js/collapsible-div.js
index 134151c3d09c71bfdcada5db1f16d80095d2f780..4719d7cc4f4f389c0e9033b783b9dc5b566c843f 100644
--- a/js/collapsible-div.js
+++ b/js/collapsible-div.js
@@ -123,7 +123,7 @@
       var cookie = '';
 
       // Get a list of IDs, saparated by comma
-      for (i in this.state) {
+      for (var i in this.state) {
         if (cookie != '') {
           cookie += ',';
         }
@@ -190,15 +190,15 @@
 
       var afterToggle = function () {
         if (Drupal.CTools.CollapsibleCallbacksAfterToggle) {
-          for (i in Drupal.CTools.CollapsibleCallbacksAfterToggle) {
+          for (var i in Drupal.CTools.CollapsibleCallbacksAfterToggle) {
             Drupal.CTools.CollapsibleCallbacksAfterToggle[i]($container, handle, content, toggle);
           }
         }
-      }
+      };
 
       var clickMe = function () {
         if (Drupal.CTools.CollapsibleCallbacks) {
-          for (i in Drupal.CTools.CollapsibleCallbacks) {
+          for (var i in Drupal.CTools.CollapsibleCallbacks) {
             Drupal.CTools.CollapsibleCallbacks[i]($container, handle, content, toggle);
           }
         }
@@ -222,7 +222,7 @@
         }
 
         return false;
-      }
+      };
 
       // Let both the toggle and the handle be clickable.
       toggle.click(clickMe);
@@ -237,5 +237,5 @@
     attach: function(context) {
       $('.ctools-collapsible-container', context).once('ctools-collapsible', Drupal.CTools.bindCollapsible);
     }
-  }
+  };
 })(jQuery);
diff --git a/js/dependent.js b/js/dependent.js
index e9e2447c4cd367484fd9ae3aba381e73bbf82917..6e4b796706f90fb9ed4bd8aec970f2ac88cef944 100644
--- a/js/dependent.js
+++ b/js/dependent.js
@@ -14,7 +14,7 @@
  * - Checkboxes don't have their own id, so you need to add one in a div
  *   around the checkboxes via #prefix and #suffix. You actually need to add TWO
  *   divs because it's the parent that gets hidden. Also be sure to retain the
- *   'expand_checkboxes' in the #process array, because the CTools process will
+ *   'form_process_checkboxes' in the #process array, because the CTools process will
  *   override it.
  */
 
@@ -34,13 +34,13 @@
       }
     }
     return false;
-  }
+  };
 
 
   Drupal.CTools.dependent.autoAttach = function() {
     // Clear active bindings and triggers.
-    for (i in Drupal.CTools.dependent.activeTriggers) {
-      $(Drupal.CTools.dependent.activeTriggers[i]).unbind('change');
+    for (var i in Drupal.CTools.dependent.activeTriggers) {
+      $(Drupal.CTools.dependent.activeTriggers[i]).unbind('change.ctools-dependent');
     }
     Drupal.CTools.dependent.activeTriggers = [];
     Drupal.CTools.dependent.activeBindings = {};
@@ -51,7 +51,7 @@
     }
 
     // Iterate through all relationships
-    for (id in Drupal.settings.CTools.dependent) {
+    for (var id in Drupal.settings.CTools.dependent) {
       // Test to make sure the id even exists; this helps clean up multiple
       // AJAX calls with multiple forms.
 
@@ -59,7 +59,7 @@
       // whether the binding is active or not.  Defaults to no.
       Drupal.CTools.dependent.activeBindings[id] = 0;
       // Iterate through all possible values
-      for(bind_id in Drupal.settings.CTools.dependent[id].values) {
+      for (var bind_id in Drupal.settings.CTools.dependent[id].values) {
         // This creates a backward relationship.  The bind_id is the ID
         // of the element which needs to change in order for the id to hide or become shown.
         // The id is the ID of the item which will be conditionally hidden or shown.
@@ -87,7 +87,7 @@
         }
 
         var getValue = function(item, trigger) {
-          if ($(trigger).size() == 0) {
+          if ($(trigger).length == 0) {
             return null;
           }
 
@@ -97,7 +97,13 @@
           else {
             switch ($(trigger).attr('type')) {
               case 'checkbox':
-                var val = $(trigger).attr('checked') ? true : false;
+                // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+                if ($().prop) {
+                  var val = $(trigger).prop('checked') ? true : false;
+                }
+                else {
+                  var val = $(trigger).attr('checked') ? true : false;
+                }
 
                 if (val) {
                   $(trigger).siblings('label').removeClass('hidden-options').addClass('expanded-options');
@@ -112,7 +118,7 @@
             }
           }
           return val;
-        }
+        };
 
         var setChangeTrigger = function(trigger_id, bind_id) {
           // Triggered when change() is clicked.
@@ -123,7 +129,7 @@
               return;
             }
 
-            for (i in Drupal.CTools.dependent.bindings[bind_id]) {
+            for (var i in Drupal.CTools.dependent.bindings[bind_id]) {
               var id = Drupal.CTools.dependent.bindings[bind_id][i];
               // Fix numerous errors
               if (typeof id != 'string') {
@@ -144,38 +150,45 @@
               }
 
               var len = 0;
-              for (i in Drupal.CTools.dependent.activeBindings[id]) {
+              for (var i in Drupal.CTools.dependent.activeBindings[id]) {
                 len++;
               }
 
-              var object = $('#' + id + '-wrapper');
-              if (!object.size()) {
-                // Some elements can't use the parent() method or they can
-                // damage things. They are guaranteed to have wrappers but
-                // only if dependent.inc provided them. This check prevents
-                // problems when multiple AJAX calls cause settings to build
-                // up.
-                var $original = $('#' + id);
-                if ($original.is('fieldset') || $original.is('textarea')) {
-                  continue;
-                }
-
-                object = $('#' + id).parent();
+              var $original = $('#' + id);
+              if ($original.is('fieldset') || $original.is('textarea')) {
+                continue;
               }
 
+              var object = $original.parent();
+
               if (Drupal.settings.CTools.dependent[id].type == 'disable') {
                 if (Drupal.settings.CTools.dependent[id].num <= len) {
                   // Show if the element if criteria is matched
-                  object.attr('disabled', false);
-                  object.addClass('dependent-options');
-                  object.children().attr('disabled', false);
+                  // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+                  if (typeof $().prop == 'function') {
+                    object.prop('disabled', false);
+                    object.addClass('dependent-options');
+                    object.children().prop('disabled', false);
+                  }
+                  else {
+                    object.attr('disabled', false);
+                    object.addClass('dependent-options');
+                    object.children().attr('disabled', false);
+                  }
                 }
                 else {
                   // Otherwise hide. Use css rather than hide() because hide()
                   // does not work if the item is already hidden, for example,
                   // in a collapsed fieldset.
-                  object.attr('disabled', true);
-                  object.children().attr('disabled', true);
+                  // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+                  if (typeof $().prop == 'function') {
+                    object.prop('disabled', true);
+                    object.children().prop('disabled', true);
+                  }
+                  else {
+                    object.attr('disabled', true);
+                    object.children().attr('disabled', true);
+                  }
                 }
               }
               else {
@@ -192,20 +205,20 @@
                 }
               }
             }
-          }
+          };
 
-          $(trigger_id).change(function() {
+          $(trigger_id).bind('change.ctools-dependent', function() {
             // Trigger the internal change function
             // the attr('id') is used because closures are more confusing
             changeTrigger(trigger_id, bind_id);
           });
           // Trigger initial reaction
           changeTrigger(trigger_id, bind_id);
-        }
+        };
         setChangeTrigger(trigger_id, bind_id);
       }
     }
-  }
+  };
 
   Drupal.behaviors.CToolsDependent = {
     attach: function (context) {
@@ -215,7 +228,7 @@
       // is a sort of hacked one that's faster but much less flexible.
       $("select.ctools-master-dependent")
         .once('ctools-dependent')
-        .change(function() {
+        .bind('change.ctools-dependent', function() {
           var val = $(this).val();
           if (val == 'all') {
             $('.ctools-dependent-all').show(0);
@@ -225,7 +238,7 @@
             $('.ctools-dependent-' + val).show(0);
           }
         })
-        .trigger('change');
+        .trigger('change.ctools-dependent');
     }
-  }
+  };
 })(jQuery);
diff --git a/js/dropbutton.js b/js/dropbutton.js
index f505550b6cc4ac799d9f2415d4742caaa145a890..6d08d05a59e38fc70e3e9e1a07925fbc7f3bbff0 100644
--- a/js/dropbutton.js
+++ b/js/dropbutton.js
@@ -69,7 +69,7 @@
             $secondaryActions.animate({height: "show", opacity: "show"}, 100);
             $dropbutton.addClass('open');
           }
-        }
+        };
         // Hide the secondary actions initially.
         $secondaryActions.hide();
 
@@ -90,5 +90,5 @@
         );
       });
     }
-  }
+  };
 })(jQuery);
diff --git a/js/dropdown.js b/js/dropdown.js
index c829ae2fe134cbf97064fcf44fe8b9425636009a..e2488b1ea4619ab99a80fcc878fa0b0ac638346f 100644
--- a/js/dropdown.js
+++ b/js/dropdown.js
@@ -61,7 +61,7 @@
             $("div.ctools-dropdown-container", $dropdown)
               .animate({height: "show", opacity: "show"}, 100);
           }
-        }
+        };
         $("a.ctools-dropdown-link", $dropdown).click(function() {
           toggle();
           return false;
@@ -83,5 +83,5 @@
         );
       });
     }
-  }
+  };
 })(jQuery);
diff --git a/js/jump-menu.js b/js/jump-menu.js
index 7b0928a68e79fdbb2d3490094b59b56ac6477a7a..14852d5adf864e345c1e2edb6427f8ece8d08346 100644
--- a/js/jump-menu.js
+++ b/js/jump-menu.js
@@ -38,5 +38,5 @@
           return false;
         });
     }
-  }
+  };
 })(jQuery);
diff --git a/js/modal.js b/js/modal.js
index 98f360974e33f92de5a67ab524088042afa5cfba..92f8d78608b122eb9f1dc8352a1c3bd8b2c953c6 100644
--- a/js/modal.js
+++ b/js/modal.js
@@ -48,7 +48,8 @@
       modalOptions: {
         opacity: .55,
         background: '#fff'
-      }
+      },
+      modalClass: 'default'
     };
 
     var settings = {};
@@ -85,7 +86,7 @@
         'width': (width - Drupal.CTools.Modal.currentSettings.modalSize.contentRight) + 'px',
         'height': (height - Drupal.CTools.Modal.currentSettings.modalSize.contentBottom) + 'px'
       });
-    }
+    };
 
     if (!Drupal.CTools.Modal.modal) {
       Drupal.CTools.Modal.modal = $(Drupal.theme(settings.modalTheme));
@@ -97,8 +98,8 @@
     resize();
 
     $('span.modal-title', Drupal.CTools.Modal.modal).html(Drupal.CTools.Modal.currentSettings.loadingText);
-    Drupal.CTools.Modal.modalContent(Drupal.CTools.Modal.modal, settings.modalOptions, settings.animation, settings.animationSpeed);
-    $('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme));
+    Drupal.CTools.Modal.modalContent(Drupal.CTools.Modal.modal, settings.modalOptions, settings.animation, settings.animationSpeed, settings.modalClass);
+    $('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme)).addClass('ctools-modal-loading');
 
     // Position autocomplete results based on the scroll position of the modal.
     $('#modalContent .modal-content').delegate('input.form-autocomplete', 'keyup', function() {
@@ -119,33 +120,33 @@
    * Provide the HTML to create the modal dialog.
    */
   Drupal.theme.prototype.CToolsModalDialog = function () {
-    var html = ''
-    html += '  <div id="ctools-modal">'
-    html += '    <div class="ctools-modal-content">' // panels-modal-content
-    html += '      <div class="modal-header">';
-    html += '        <a class="close" href="#">';
-    html +=            Drupal.CTools.Modal.currentSettings.closeText + Drupal.CTools.Modal.currentSettings.closeImage;
-    html += '        </a>';
-    html += '        <span id="modal-title" class="modal-title">&nbsp;</span>';
-    html += '      </div>';
-    html += '      <div id="modal-content" class="modal-content">';
-    html += '      </div>';
+    var html = '';
+    html += '<div id="ctools-modal">';
+    html += '  <div class="ctools-modal-content">'; // panels-modal-content
+    html += '    <div class="modal-header">';
+    html += '      <a class="close" href="#">';
+    html +=          Drupal.CTools.Modal.currentSettings.closeText + Drupal.CTools.Modal.currentSettings.closeImage;
+    html += '      </a>';
+    html += '      <span id="modal-title" class="modal-title">&nbsp;</span>';
+    html += '    </div>';
+    html += '    <div id="modal-content" class="modal-content">';
     html += '    </div>';
     html += '  </div>';
+    html += '</div>';
 
     return html;
-  }
+  };
 
   /**
    * Provide the HTML to create the throbber.
    */
   Drupal.theme.prototype.CToolsModalThrobber = function () {
     var html = '';
-    html += '  <div id="modal-throbber">';
-    html += '    <div class="modal-throbber-wrapper">';
-    html +=        Drupal.CTools.Modal.currentSettings.throbber;
-    html += '    </div>';
+    html += '<div id="modal-throbber">';
+    html += '  <div class="modal-throbber-wrapper">';
+    html +=      Drupal.CTools.Modal.currentSettings.throbber;
     html += '  </div>';
+    html += '</div>';
 
     return html;
   };
@@ -158,7 +159,7 @@
     if (match) {
       return match[1];
     }
-  }
+  };
 
   /**
    * Click function for modals that can be cached.
@@ -185,7 +186,7 @@
 
     setTimeout(function() { Drupal.CTools.AJAX.ajaxSubmit($form, url); }, 1);
     return false;
-  }
+  };
 
   /**
    * Bind links that will open modals to the appropriate function.
@@ -249,7 +250,7 @@
 
         element_settings.url = $this.attr('action');
         element_settings.event = 'submit';
-        element_settings.progress = { 'type': 'throbber' }
+        element_settings.progress = { 'type': 'throbber' };
         var base = $this.attr('id');
 
         Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
@@ -264,7 +265,10 @@
           }
           // An empty event means we were triggered via .click() and
           // in jquery 1.4 this won't trigger a submit.
-          if (event.bubbles == undefined) {
+          // We also have to check jQuery version to prevent
+          // IE8 + jQuery 1.4.4 to break on other events
+          // bound to the submit button.
+          if (jQuery.fn.jquery.substr(0, 3) === '1.4' && typeof event.bubbles === "undefined") {
             $(this.form).trigger('submit');
             return false;
           }
@@ -287,19 +291,36 @@
    * AJAX responder command to place HTML within the modal.
    */
   Drupal.CTools.Modal.modal_display = function(ajax, response, status) {
+    var settings = response.settings || ajax.settings || Drupal.settings;
+    // If the modal does not exist yet, create it.
     if ($('#modalContent').length == 0) {
       Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(ajax.element));
     }
+    // If the modal exists run detachBehaviors before removing existing content.
+    else {
+      Drupal.detachBehaviors($('#modalContent'), settings, 'unload');
+    }
     $('#modal-title').html(response.title);
     // Simulate an actual page load by scrolling to the top after adding the
     // content. This is helpful for allowing users to see error messages at the
     // top of a form, etc.
     $('#modal-content').html(response.output).scrollTop(0);
+    $(document).trigger('CToolsAttachBehaviors', $('#modalContent'));
 
     // Attach behaviors within a modal dialog.
-    var settings = response.settings || ajax.settings || Drupal.settings;
-    Drupal.attachBehaviors('#modalContent', settings);
-  }
+    Drupal.attachBehaviors($('#modalContent'), settings);
+
+    if ($('#modal-content').hasClass('ctools-modal-loading')) {
+      $('#modal-content').removeClass('ctools-modal-loading');
+    }
+    else {
+      // If the modal was already shown, and we are simply replacing its
+      // content, then focus on the first focusable element in the modal.
+      // (When first showing the modal, focus will be placed on the close
+      // button by the show() function called above.)
+      $('#modal-content :focusable:first').focus();
+    }
+  };
 
   /**
    * AJAX responder command to dismiss the modal.
@@ -307,7 +328,7 @@
   Drupal.CTools.Modal.modal_dismiss = function(command) {
     Drupal.CTools.Modal.dismiss();
     $('link.ctools-temporary-css').remove();
-  }
+  };
 
   /**
    * Display loading
@@ -318,7 +339,7 @@
       output: Drupal.theme(Drupal.CTools.Modal.currentSettings.throbberTheme),
       title: Drupal.CTools.Modal.currentSettings.loadingText
     });
-  }
+  };
 
   /**
    * Find a URL for an AJAX button.
@@ -349,8 +370,9 @@
    * @param css obj of css attributes
    * @param animation (fadeIn, slideDown, show)
    * @param speed (valid animation speeds slow, medium, fast or # in ms)
+   * @param modalClass class added to div#modalContent
    */
-  Drupal.CTools.Modal.modalContent = function(content, css, animation, speed) {
+  Drupal.CTools.Modal.modalContent = function(content, css, animation, speed, modalClass) {
     // If our animation isn't set, make it just show/pop
     if (!animation) {
       animation = 'show';
@@ -362,7 +384,7 @@
       }
     }
 
-    if (!speed) {
+    if (!speed && 0 !== speed) {
       speed = 'fast';
     }
 
@@ -379,9 +401,9 @@
     css.filter = 'alpha(opacity=' + (100 * css.opacity) + ')';
     content.hide();
 
-    // if we already ahve a modalContent, remove it
-    if ( $('#modalBackdrop')) $('#modalBackdrop').remove();
-    if ( $('#modalContent')) $('#modalContent').remove();
+    // If we already have modalContent, remove it.
+    if ($('#modalBackdrop').length) $('#modalBackdrop').remove();
+    if ($('#modalContent').length) $('#modalContent').remove();
 
     // position code lifted from http://www.quirksmode.org/viewport/compatibility.html
     if (self.pageYOffset) { // all except Explorer
@@ -402,9 +424,56 @@
     if( docHeight < winHeight ) docHeight = winHeight;
 
     // Create our divs
-    $('body').append('<div id="modalBackdrop" style="z-index: 1000; display: none;"></div><div id="modalContent" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>');
+    $('body').append('<div id="modalBackdrop" class="backdrop-' + modalClass + '" style="z-index: 1000; display: none;"></div><div id="modalContent" class="modal-' + modalClass + '" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>');
+
+    // Get a list of the tabbable elements in the modal content.
+    var getTabbableElements = function () {
+      var tabbableElements = $('#modalContent :tabbable'),
+          radioButtons = tabbableElements.filter('input[type="radio"]');
+
+      // The list of tabbable elements from jQuery is *almost* right. The
+      // exception is with groups of radio buttons. The list from jQuery will
+      // include all radio buttons, when in fact, only the selected radio button
+      // is tabbable, and if no radio buttons in a group are selected, then only
+      // the first is tabbable.
+      if (radioButtons.length > 0) {
+        // First, build up an index of which groups have an item selected or not.
+        var anySelected = {};
+        radioButtons.each(function () {
+          var name = this.name;
+
+          if (typeof anySelected[name] === 'undefined') {
+            anySelected[name] = radioButtons.filter('input[name="' + name + '"]:checked').length !== 0;
+          }
+        });
+
+        // Next filter out the radio buttons that aren't really tabbable.
+        var found = {};
+        tabbableElements = tabbableElements.filter(function () {
+          var keep = true;
+
+          if (this.type == 'radio') {
+            if (anySelected[this.name]) {
+              // Only keep the selected one.
+              keep = this.checked;
+            }
+            else {
+              // Only keep the first one.
+              if (found[this.name]) {
+                keep = false;
+              }
+              found[this.name] = true;
+            }
+          }
+
+          return keep;
+        });
+      }
+
+      return tabbableElements.get();
+    };
 
-    // Keyboard and focus event handler ensures focus stays on modal elements only
+    // Keyboard and focus event handler ensures only modal elements gain focus.
     modalEventHandler = function( event ) {
       target = null;
       if ( event ) { //Mozilla
@@ -421,26 +490,85 @@
           return true;
         }
       }
-      if( $(target).filter('*:visible').parents('#modalContent').size()) {
-        // allow the event only if target is a visible child node of #modalContent
+
+      if ($(target).is('#modalContent, body') || $(target).filter('*:visible').parents('#modalContent').length) {
+        // Allow the event only if target is a visible child node
+        // of #modalContent.
         return true;
       }
-      if ( $('#modalContent')) $('#modalContent').get(0).focus();
-      return false;
+      else {
+        getTabbableElements()[0].focus();
+      }
+
+      event.preventDefault();
     };
     $('body').bind( 'focus', modalEventHandler );
     $('body').bind( 'keypress', modalEventHandler );
 
+    // Keypress handler Ensures you can only TAB to elements within the modal.
+    // Based on the psuedo-code from WAI-ARIA 1.0 Authoring Practices section
+    // 3.3.1 "Trapping Focus".
+    modalTabTrapHandler = function (evt) {
+      // We only care about the TAB key.
+      if (evt.which != 9) {
+        return true;
+      }
+
+      var tabbableElements = getTabbableElements(),
+          firstTabbableElement = tabbableElements[0],
+          lastTabbableElement = tabbableElements[tabbableElements.length - 1],
+          singleTabbableElement = firstTabbableElement == lastTabbableElement,
+          node = evt.target;
+
+      // If this is the first element and the user wants to go backwards, then
+      // jump to the last element.
+      if (node == firstTabbableElement && evt.shiftKey) {
+        if (!singleTabbableElement) {
+          lastTabbableElement.focus();
+        }
+        return false;
+      }
+      // If this is the last element and the user wants to go forwards, then
+      // jump to the first element.
+      else if (node == lastTabbableElement && !evt.shiftKey) {
+        if (!singleTabbableElement) {
+          firstTabbableElement.focus();
+        }
+        return false;
+      }
+      // If this element isn't in the dialog at all, then jump to the first
+      // or last element to get the user into the game.
+      else if ($.inArray(node, tabbableElements) == -1) {
+        // Make sure the node isn't in another modal (ie. WYSIWYG modal).
+        var parents = $(node).parents().get();
+        for (var i = 0; i < parents.length; ++i) {
+          var position = $(parents[i]).css('position');
+          if (position == 'absolute' || position == 'fixed') {
+            return true;
+          }
+        }
+
+        if (evt.shiftKey) {
+          lastTabbableElement.focus();
+        }
+        else {
+          firstTabbableElement.focus();
+        }
+      }
+    };
+    $('body').bind('keydown', modalTabTrapHandler);
+
     // Create our content div, get the dimensions, and hide it
     var modalContent = $('#modalContent').css('top','-1000px');
-    var mdcTop = wt + ( winHeight / 2 ) - (  modalContent.outerHeight() / 2);
+    var $modalHeader = modalContent.find('.modal-header');
+    var mdcTop = wt + Math.max((winHeight / 2) - (modalContent.outerHeight() / 2), 0);
     var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
     $('#modalBackdrop').css(css).css('top', 0).css('height', docHeight + 'px').css('width', docWidth + 'px').show();
     modalContent.css({top: mdcTop + 'px', left: mdcLeft + 'px'}).hide()[animation](speed);
 
     // Bind a click for closing the modalContent
     modalContentClose = function(){close(); return false;};
-    $('.close').bind('click', modalContentClose);
+    $('.close', $modalHeader).bind('click', modalContentClose);
 
     // Bind a keypress on escape for closing the modalContent
     modalEventEscapeCloseHandler = function(event) {
@@ -452,31 +580,64 @@
 
     $(document).bind('keydown', modalEventEscapeCloseHandler);
 
+    // Per WAI-ARIA 1.0 Authoring Practices, initial focus should be on the
+    // close button, but we should save the original focus to restore it after
+    // the dialog is closed.
+    var oldFocus = document.activeElement;
+    $('.close', $modalHeader).focus();
+
     // Close the open modal content and backdrop
     function close() {
       // Unbind the events
       $(window).unbind('resize',  modalContentResize);
       $('body').unbind( 'focus', modalEventHandler);
       $('body').unbind( 'keypress', modalEventHandler );
-      $('.close').unbind('click', modalContentClose);
-      $('body').unbind('keypress', modalEventEscapeCloseHandler);
+      $('body').unbind( 'keydown', modalTabTrapHandler );
+      $('.close', $modalHeader).unbind('click', modalContentClose);
+      $(document).unbind('keydown', modalEventEscapeCloseHandler);
+      $(document).trigger('CToolsCloseModalBehaviors', $('#modalContent'));
       $(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
 
-      // Set our animation parameters and use them
-      if ( animation == 'fadeIn' ) animation = 'fadeOut';
-      if ( animation == 'slideDown' ) animation = 'slideUp';
-      if ( animation == 'show' ) animation = 'hide';
+      // Closing animation.
+      switch (animation) {
+        case 'fadeIn':
+          modalContent.fadeOut(speed, modalContentRemove);
+          break;
 
-      // Close the content
-      modalContent.hide()[animation](speed);
+        case 'slideDown':
+          modalContent.slideUp(speed, modalContentRemove);
+          break;
 
-      // Remove the content
+        case 'show':
+          modalContent.hide(speed, modalContentRemove);
+          break;
+      }
+    }
+
+    // Remove the content.
+    modalContentRemove = function () {
       $('#modalContent').remove();
       $('#modalBackdrop').remove();
+
+      // Restore focus to where it was before opening the dialog.
+      $(oldFocus).focus();
     };
 
-    // Move and resize the modalBackdrop and modalContent on resize of the window
-     modalContentResize = function(){
+    // Move and resize the modalBackdrop and modalContent on window resize.
+    modalContentResize = function () {
+      // Reset the backdrop height/width to get accurate document size.
+      $('#modalBackdrop').css('height', '').css('width', '');
+
+      // Position code lifted from:
+      // http://www.quirksmode.org/viewport/compatibility.html
+      if (self.pageYOffset) { // all except Explorer
+        var wt = self.pageYOffset;
+      } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
+        var wt = document.documentElement.scrollTop;
+      } else if (document.body) { // all other Explorers
+        var wt = document.body.scrollTop;
+      }
+
       // Get our heights
       var docHeight = $(document).height();
       var docWidth = $(document).width();
@@ -486,7 +647,7 @@
 
       // Get where we should move content to
       var modalContent = $('#modalContent');
-      var mdcTop = ( winHeight / 2 ) - (  modalContent.outerHeight() / 2);
+      var mdcTop = wt + Math.max((winHeight / 2) - (modalContent.outerHeight() / 2), 0);
       var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
 
       // Apply the changes
@@ -494,8 +655,6 @@
       modalContent.css('top', mdcTop + 'px').css('left', mdcLeft + 'px').show();
     };
     $(window).bind('resize', modalContentResize);
-
-    $('#modalContent').focus();
   };
 
   /**
@@ -518,8 +677,12 @@
     $(window).unbind('resize', modalContentResize);
     $('body').unbind('focus', modalEventHandler);
     $('body').unbind('keypress', modalEventHandler);
-    $('.close').unbind('click', modalContentClose);
-    $(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
+    $('body').unbind( 'keydown', modalTabTrapHandler );
+    var $modalContent = $('#modalContent');
+    var $modalHeader = $modalContent.find('.modal-header');
+    $('.close', $modalHeader).unbind('click', modalContentClose);
+    $(document).unbind('keydown', modalEventEscapeCloseHandler);
+    $(document).trigger('CToolsDetachBehaviors', $modalContent);
 
     // jQuery magic loop through the instances and run the animations or removal.
     content.each(function(){
diff --git a/js/states-show.js b/js/states-show.js
new file mode 100644
index 0000000000000000000000000000000000000000..88df58419ceda9e70e2dc0e04a016c23ed68420f
--- /dev/null
+++ b/js/states-show.js
@@ -0,0 +1,43 @@
+/**
+ * @file
+ * Custom state for handling visibility
+ */
+
+/**
+ * Add a new state to Drupal #states. We use this to toggle element-invisible
+ * to show/hidden #states elements. This allows elements to be visible to
+ * screen readers.
+ *
+ * To use:
+ * $form['my_form_field'] = array(
+ *   ..
+ *   // Only show this field if 'some_other_field' is checked.
+ *   '#states => array(
+ *     'show' => array(
+ *       'some-other-field' => array('checked' => TRUE),
+ *     ),
+ *   ),
+ *   ..
+ *   // Required to load the 'show' state handler.
+ *   '#attached' => array(
+ *     'js' => array(ctools_attach_js('states-show')),
+ *   ),
+ * );
+ */
+
+(function ($) {
+  'use strict';
+
+  Drupal.states.State.aliases.hidden = '!show';
+
+  // Show/hide form items by toggling the 'element-invisible' class. This is a
+  // more accessible option than the core 'visible' state.
+  $(document).bind('state:show', function(e) {
+    if (e.trigger) {
+      var element = $(e.target).closest('.form-item, .form-submit, .form-wrapper');
+      element.toggle(e.value);
+      e.value === true ? element.removeClass('element-invisible') : element.addClass('element-invisible');
+    }
+  });
+
+})(jQuery);
diff --git a/js/stylizer.js b/js/stylizer.js
index 16d6c49d5ea9650cd2146adc5cc42efd59712a28..227d4f4be8074c48dadef6cc47517afcb2cfcaab 100644
--- a/js/stylizer.js
+++ b/js/stylizer.js
@@ -5,7 +5,7 @@
 
   Drupal.CTools.Stylizer.addFarbtastic = function(context) {
     // This behavior attaches by ID, so is only valid once on a page.
-    if ($('ctools_stylizer_color_scheme_form .color-form.Stylizer-processed').size()) {
+    if ($('#ctools_stylizer_color_scheme_form .color-form.Stylizer-processed').length) {
       return;
     }
 
@@ -21,7 +21,7 @@
 
     // Decode reference colors to HSL
   /*var reference = Drupal.settings.Stylizer.reference.clone();
-    for (i in reference) {
+    for (var i in reference) {
       reference[i] = farb.RGBToHSL(farb.unpack(reference[i]));
     } */
 
@@ -30,7 +30,7 @@
       var colors = this.options[this.selectedIndex].value;
       if (colors != '') {
         colors = colors.split(',');
-        for (i in colors) {
+        for (var i in colors) {
           callback(inputs[i], colors[i], false, true);
         }
       }
@@ -180,7 +180,7 @@
         );
         $(this).after(lock);
         locks.push(lock);
-      };
+      }
 
       // Add hook
       var $this = $(this);
@@ -216,5 +216,5 @@
           $widget.attr('checked', !$widget.attr('checked') || $widget.is('input[type=radio]'));
         });
     }
-  }
+  };
 })(jQuery);
diff --git a/page_manager/css/page-manager.css b/page_manager/css/page-manager.css
index 1a7dd5e4bcd3287bb45df6c48d6435e74758cd9f..5abe39e24749852d918998d6a4ce85354cc6b299 100644
--- a/page_manager/css/page-manager.css
+++ b/page_manager/css/page-manager.css
@@ -100,7 +100,7 @@ body form#page-manager-list-pages-form {
 
 #page-manager-edit .page-manager-edit-operations li {
   list-style: none;
-  background: #F6F6F6;
+  background: #f6f6f6;
   border-top: 1px solid #aaa;
   border-left: 1px solid #aaa;
   border-right: 1px solid #aaa;
@@ -111,7 +111,7 @@ body form#page-manager-list-pages-form {
 
 #page-manager-edit .page-manager-edit-operations li.active,
 #page-manager-edit .page-manager-edit-operations li.active-group .page-manager-group-title {
-  background: #FFFFFF url(../images/arrow-active.png) no-repeat scroll right center;
+  background: #ffffff url(../images/arrow-active.png) no-repeat scroll right center;
 }
 
 #page-manager-edit .page-manager-edit-operations li.changed,
@@ -123,7 +123,7 @@ body form#page-manager-list-pages-form {
 /** provide a reset for non active stray paths */
 #page-manager-edit .page-manager-edit-operations li.active-group li.not-active .page-manager-group-title,
 #page-manager-edit .page-manager-edit-operations li.changed-group li.not-changed .page-manager-group-title {
-  background: #F6F6F6;
+  background: #f6f6f6;
 }
 
 #page-manager-edit .page-manager-edit-operations li.active {
@@ -132,7 +132,7 @@ body form#page-manager-list-pages-form {
 
 #page-manager-edit .page-manager-edit-operations li.active a,
 #page-manager-edit .page-manager-edit-operations li.active a:hover {
-  background: #FFFFFF url(../images/arrow-active.png) no-repeat scroll right center;
+  background: #ffffff url(../images/arrow-active.png) no-repeat scroll right center;
   color: #000000;
   font-weight: bold;
 }
@@ -271,8 +271,8 @@ body form#page-manager-list-pages-form {
 #page-manager-edit .actions li a {
   display: block;
   padding: 0.2em 0.5em;
-  color:#0062A0;
-  background-color: #F6F6F6;
+  color: #0062a0;
+  background-color: #f6f6f6;
 }
 
 #page-manager-edit .page-manager-changed {
diff --git a/page_manager/help/getting-started.html b/page_manager/help/getting-started.html
index 4e4f24ae8f3ec30c0ed038f1f3419b36b0371f8d..6a75a3706b0ccb0ea2bc7998fca7b43cf3b8cdb7 100644
--- a/page_manager/help/getting-started.html
+++ b/page_manager/help/getting-started.html
@@ -4,7 +4,7 @@ Note: this page is currently very preliminary. Please visit <a href="http://drup
 This is a quick summary:
 
 <ul>
-<li>Visit administer >> site building >> pages to get to the primary page manager interface.</li>
+<li>Visit administer >> structure >> pages to get to the primary page manager interface.</li>
 <li>You can add custom pages for your basic landing pages, front pages, whatever you like for normal content display.</li>
 <li>You can use the system pages to create finer control of how taxonomy vocabularies, nodes and user profiles are displayed.</li>
 <li>When you add your first custom page, do not bother with the optional features. You will not need these until you get to more advanced tasks.</li>
diff --git a/page_manager/page_manager.admin.inc b/page_manager/page_manager.admin.inc
index 6ef02687973c9eb25bed364d4f31f4cd30f925e1..f4acb78a146bb51b07eb5aa49621da7956629e11 100644
--- a/page_manager/page_manager.admin.inc
+++ b/page_manager/page_manager.admin.inc
@@ -95,6 +95,7 @@ function page_manager_list_page($js = NULL) {
 
   $header = array(
     array('data' => t('Type'), 'class' => array('page-manager-page-type')),
+    array('data' => t('Module'), 'class' => array('page-manager-page-module')),
     array('data' => t('Name'), 'class' => array('page-manager-page-name')),
     array('data' => t('Title'), 'class' => array('page-manager-page-title')),
     array('data' => t('Path'), 'class' => array('page-manager-page-path')),
@@ -175,9 +176,18 @@ function page_manager_get_pages($tasks, &$pages, $task_id = NULL) {
     $row = array('data' => array(), 'class' => $class, 'title' => strip_tags($task['admin description']));
 
     $type = isset($task['admin type']) ? $task['admin type'] : t('System');
+    if (isset($task['module'])) {
+      $module = $task['module'];
+    }
+    elseif (isset($task['subtask']->export_module)) {
+      $module = $task['subtask']->export_module;
+    }
+    else {
+      $module = '';
+    }
     $pages['types'][$type] = $type;
     $row['data']['type'] = array('data' => $type, 'class' => array('page-manager-page-type'));
-
+    $row['data']['module'] = array('data' => $module, 'class' => array('page-manager-page-module'));
     $row['data']['name'] = array('data' => $task_name, 'class' => array('page-manager-page-name'));
     $row['data']['title'] = array('data' => $task['admin title'], 'class' => array('page-manager-page-title'));
     $row['data']['path'] = array('data' => $visible_path, 'class' => array('page-manager-page-path'));
@@ -401,7 +411,7 @@ function page_manager_list_pages_form_submit(&$form, &$form_state) {
  * Render the edit page for a a page, custom or system.
  */
 function page_manager_edit_page($page) {
-  drupal_set_title($page->subtask['admin title']);
+  drupal_set_title($page->subtask['admin title'], PASS_THROUGH);
   // Provide and process the save page form before anything else.
   $form_state = array('page' => &$page);
   $built_form = drupal_build_form('page_manager_save_page_form', $form_state);
@@ -464,7 +474,7 @@ function page_manager_edit_page_operation() {
     return;
   }
 
-  drupal_set_title($page->subtask['admin title']);
+  drupal_set_title($page->subtask['admin title'], PASS_THROUGH);
   return $output;
 }
 
@@ -577,8 +587,8 @@ function page_manager_get_operations($page, $operations = NULL) {
     ),
   );
 
-  // Restrict variant import to users who can already execute arbitrary PHP
-  if (user_access('use PHP for settings')) {
+  // Restrict variant import due to security implications.
+  if (user_access('use ctools import')) {
     $result['actions']['children']['import'] = array(
       'title' => t('Import variant'),
       'description' => t('Add a new variant to this page from code exported from another page.'),
@@ -621,7 +631,7 @@ function page_manager_get_operations($page, $operations = NULL) {
       if (isset($plugin['add features'][$id])) {
         $result['actions']['children']['configure']['form']['order'][$id] = $plugin['add features'][$id];
       }
-      else if (isset($plugin['required forms'][$id])) {
+      elseif (isset($plugin['required forms'][$id])) {
         $result['actions']['children']['configure']['form']['order'][$id] = $plugin['required forms'][$id];
       }
     }
@@ -722,7 +732,7 @@ function page_manager_get_handler_operations(&$page) {
         ),
       );
     }
-    else if ($handler->export_type != EXPORT_IN_CODE) {
+    elseif ($handler->export_type != EXPORT_IN_CODE) {
       $actions['delete'] = array(
         'title' => t('Delete'),
         'description' => t('Remove this variant from the page completely.'),
@@ -1134,7 +1144,7 @@ function page_manager_render_operations(&$page, $operations, $active_trail, $att
       if ($id == $first) {
         $class[] = 'operation-first';
       }
-      else if ($id == $last) {
+      elseif ($id == $last) {
         $class[] = 'operation-last';
       }
 
@@ -1308,6 +1318,7 @@ function page_manager_handler_add_submit(&$form, &$form_state) {
   else {
     $handler->conf['title'] = $plugin['title'];
   }
+  $handler->conf['name'] = $form_state['values']['name'];
   $cache->new_handler = $handler;
 
   // Figure out which forms to present them with
@@ -1398,6 +1409,21 @@ function page_manager_handler_add_form($form, $form_state, $features = array())
       '#title' => t('Title'),
       '#description' => t('Administrative title of this variant. If you leave blank it will be automatically assigned.'),
     );
+
+    $form['name'] = array(
+      '#type' => 'machine_name',
+      '#title' => t('Machine name'),
+      '#required' => FALSE,
+      '#description' => t("A unique machine-readable name for this variant. It must only contain lowercase letters, numbers, and underscores. This name will be used when exporting the variant. If left empty the variant's name will be used instead."),
+      '#size' => 32,
+      '#maxlength' => 32,
+      '#machine_name' => array(
+        'exists' => 'page_manager_handler_check_machine_name',
+        'source' => array('title'),
+      ),
+      '#field_prefix' => '<span dir="ltr">' . $form_state['task_name'] . '__',
+      '#field_suffix' => '</span>&lrm;',
+    );
   }
 
   $form['handler'] = array(
@@ -1436,6 +1462,15 @@ function page_manager_handler_add_form($form, $form_state, $features = array())
   return $form;
 }
 
+/*
+ * Check if handler's machine-name is unique
+ */
+function page_manager_handler_check_machine_name($name, $element, $form_state) {
+  $name = $form_state['task_name'] . '__' . $name;
+
+  return count(ctools_export_load_object('page_manager_handlers', 'names', array($name)));
+}
+
 /**
  * Rearrange the order of variants.
  */
@@ -1446,15 +1481,16 @@ function page_manager_handler_import($form, &$form_state) {
     '#description' => t('Enter the name of the new variant.'),
   );
 
-  if (user_access('use PHP for settings')) {
+  if (user_access('use ctools import')) {
     $form['object'] = array(
       '#type' => 'textarea',
       '#title' => t('Paste variant code here'),
       '#rows' => 15,
     );
   }
-  // Users ordinarily can't get here without the PHP block visibility perm.
-  // In case they somehow do, though, disable the form widget for extra safety.
+  // Users ordinarily can't get here without the 'import' permission, due to
+  // security implications. In case they somehow do, though, disable the form
+  // widget for extra safety.
   else {
     $form['shoveoff'] = array(
       '#markup' => '<div>' . t('You do not have sufficient permissions to perform this action.') . '</div>',
@@ -1468,7 +1504,7 @@ function page_manager_handler_import($form, &$form_state) {
  * Make sure that an import actually provides a handler.
  */
 function page_manager_handler_import_validate($form, &$form_state) {
-  if (!user_access('use PHP for settings')) {
+  if (!user_access('use ctools import')) {
     form_error($form['shoveoff'], t('You account permissions do not permit you to import.'));
     return;
   }
@@ -1506,25 +1542,42 @@ function page_manager_handler_import_submit(&$form, &$form_state) {
  * Rearrange the order of variants.
  */
 function page_manager_handler_rearrange($form, &$form_state) {
+  ctools_include('context-task-handler');
   $page = $form_state['page'];
 
   $form['handlers'] = array('#tree' => TRUE);
 
+  // Get the number of variants to be displayed in order to set the delta
+  // to the proper value.  This fixes problems in previous versions with sorting
+  // large numbers of variants.
+  $delta = count($page->handler_info)/2 + 1;
+
   foreach ($page->handler_info as $id => $info) {
     if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) {
       continue;
     }
     $handler = $page->handlers[$id];
     $plugin = page_manager_get_task_handler($handler->handler);
-
+    $object = ctools_context_handler_get_task_object($page->task, $page->subtask, $handler);
+    $display = new stdClass();
+    $display->context = ctools_context_load_contexts($object, TRUE);
+    $content = page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id);
+    $access = ctools_access_group_summary(!empty($handler->conf['access']) ? $handler->conf['access'] : array(), $display->context);
+    if ($access) {
+      $access = t('This panel will be selected if @conditions.', array('@conditions' => $access));
+    }
+    else {
+      $access = t('This panel will always be selected.');
+    }
+    $content .= '<div>' . $access . '</div>';
     $form['handlers'][$id]['title'] = array(
-      '#markup' => page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id),
+      '#markup' => $content,
     );
 
     $form['handlers'][$id]['weight'] = array(
       '#type' => 'weight',
       '#default_value' => $info['weight'],
-      '#delta' => 30,
+      '#delta' => $delta,
     );
   }
 
@@ -1635,6 +1688,12 @@ function page_manager_handler_clone_submit(&$form, &$form_state) {
 
   page_manager_handler_add_to_page($form_state['page'], $handler, $form_state['values']['title']);
 
+  // Variant is cloned and added to the Page. Ensure the uuids are re-generated.
+  panels_panel_context_get_display($handler);
+  if (isset($handler->conf['display']) && method_exists($handler->conf['display'], 'clone_display')) {
+    $handler->conf['display'] = $handler->conf['display']->clone_display();
+  }
+
   $plugin = page_manager_get_task_handler($handler->handler);
   // It has no forms at all. Add the variant and go to its first operation.
   $keys = array_keys($plugin['operations']);
diff --git a/page_manager/page_manager.info b/page_manager/page_manager.info
index 4398f5c72e22b29c6b6c3806cbd8d700eff98e44..bb0dc0e0e6f86147ee1c691380c2c623ab7b80cb 100644
--- a/page_manager/page_manager.info
+++ b/page_manager/page_manager.info
@@ -3,3 +3,5 @@ description = Provides a UI and API to manage pages within the site.
 core = 7.x
 dependencies[] = ctools
 package = Chaos tool suite
+
+files[] = tests/head_links.test
diff --git a/page_manager/page_manager.module b/page_manager/page_manager.module
index da99a578fc9e9e9e660fcc6a8f8c1b4ecb2b66b2..ed2066b46fceb5dfc132e271486d6f201fed5a71 100644
--- a/page_manager/page_manager.module
+++ b/page_manager/page_manager.module
@@ -205,7 +205,7 @@ function page_manager_menu_alter(&$items) {
     if ($function = ctools_plugin_get_function($task, 'hook menu alter')) {
       $function($items, $task);
     }
-    // let the subtasks alter the menu items too.
+    // Let the subtasks alter the menu items too.
     foreach (page_manager_get_task_subtasks($task) as $subtask_id => $subtask) {
       if ($function = ctools_plugin_get_function($subtask, 'hook menu alter')) {
         $function($items, $subtask);
@@ -213,10 +213,34 @@ function page_manager_menu_alter(&$items) {
     }
   }
 
+  // Override the core node revisions display to use the configured Page
+  // display handler.
+  if (!variable_get('page_manager_node_view_disabled', TRUE) && isset($items['node/%node/revisions/%/view'])) {
+    // Abstract the basic settings.
+    $item = array(
+      // Handle the page arguments.
+      'load arguments' => array(3),
+      'page arguments' => array(1, TRUE),
+
+      // Replace the normal node_show call with Page Manager's node view.
+      'page callback' => 'page_manager_node_view_page',
+
+      // Provide the correct path to the Page Manager file.
+      'file' => 'node_view.inc',
+      'file path' => drupal_get_path('module', 'page_manager') . '/plugins/tasks',
+    );
+    // Re-build the menu item using the normal values from node.module.
+    $items['node/%node/revisions/%/view'] = array(
+      'title' => 'Revisions',
+      'access callback' => '_node_revision_access',
+      'access arguments' => array(1),
+    ) + $item;
+  }
+
   return $items;
 }
 
-/*
+/**
  * Implements hook_theme()
  */
 function page_manager_theme() {
@@ -273,7 +297,7 @@ function page_manager_theme() {
  * Get the cached changes to a given task handler.
  */
 function page_manager_get_page_cache($task_name) {
-  $caches = drupal_static(__FUNCTION__, array());
+  $caches = &drupal_static(__FUNCTION__, array());
   if (!isset($caches[$task_name])) {
     ctools_include('object-cache');
     $cache = ctools_object_cache_get('page_manager_page', $task_name);
@@ -309,7 +333,7 @@ function page_manager_get_page_cache($task_name) {
       }
     }
     else {
-      // ensure the task is loaded.
+      // Ensure the task is loaded.
       page_manager_get_task($cache->task_id);
     }
 
@@ -366,11 +390,10 @@ function page_manager_save_page_cache($cache) {
   foreach ($cache->handler_info as $id => $info) {
     $handler = &$cache->handlers[$id];
     // If it has been marked for deletion, delete it.
-
     if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) {
       page_manager_delete_task_handler($handler);
     }
-    // If it has been somehow edited (or added), write the cached version
+    // If it has been somehow edited (or added), write the cached version.
     elseif ($info['changed'] & PAGE_MANAGER_CHANGED_CACHED) {
       // Make sure we get updated weight from the form for this.
       $handler->weight = $info['weight'];
@@ -403,7 +426,7 @@ function page_manager_save_page_cache($cache) {
  * Menu callback to load a page manager cache object for menu callbacks.
  */
 function page_manager_cache_load($task_name) {
-  // load context plugin as there may be contexts cached here.
+  // Load context plugin as there may be contexts cached here.
   ctools_include('context');
   return page_manager_get_page_cache($task_name);
 }
@@ -416,16 +439,22 @@ function page_manager_cache_load($task_name) {
  */
 function page_manager_handler_get_name($task_name, $handlers, $handler) {
   $base = str_replace('-', '_', $task_name);
-  // Generate a unique name. Unlike most named objects, we don't let people choose
-  // names for task handlers because they mostly don't make sense.
-  $base .= '_' . $handler->handler;
+  $name = '';
+
+  // Optional machine name.
+  if (!empty($handler->conf['name'])) {
+    $name = $base . '__' . $handler->conf['name'];
+    if (count(ctools_export_load_object('page_manager_handlers', 'names', array($name)))) {
+      $name = '';
+    }
+  }
 
-  // Once we have a base, check to see if it is used. If it is, start counting up.
-  $name = $base;
-  $count = 1;
-  // If taken
-  while (isset($handlers[$name])) {
-    $name = $base . '_' . ++$count;
+  // If no machine name was provided or the name is in use, generate a unique name.
+  if (empty($name)) {
+    $base .= '__' . $handler->handler;
+
+    // Use the ctools uuid generator to generate a unique id.
+    $name = $base . '_' . ctools_uuid_generate();
   }
 
   return $name;
@@ -447,6 +476,10 @@ function page_manager_handler_add_to_page(&$page, &$handler, $title = NULL) {
 
   if ($title) {
     $handler->conf['title'] = $title;
+    $handler->conf['name'] = trim(preg_replace('/[^a-z0-9_]+/', '-', strtolower($title)), '-');
+  }
+  else {
+    $handler->conf['name'] = '';
   }
 
   $name = page_manager_handler_get_name($page->task_name, $page->handlers, $handler);
@@ -466,7 +499,6 @@ function page_manager_handler_add_to_page(&$page, &$handler, $title = NULL) {
 //
 // This includes fetching plugins and plugin info as well as specialized
 // fetch methods to get groups of task handlers per task.
-
 /**
  * Load a single task handler by name.
  *
@@ -548,7 +580,7 @@ function page_manager_get_default_task_handlers($task, $subtask_id) {
       $handlers = $subtask['default handlers'];
     }
   }
-  else if (isset($task['default handlers'])) {
+  elseif (isset($task['default handlers'])) {
     $handlers = $task['default handlers'];
   }
 
@@ -570,6 +602,7 @@ function page_manager_get_default_task_handlers($task, $subtask_id) {
  *   A list of handlers provided by the default task.
  * @param $name
  *   Which handler to compare.
+ *
  * @return
  *   Which handler to use, if any. May be NULL.
  */
@@ -581,10 +614,10 @@ function page_manager_compare_task_handlers($result, $handlers, $name) {
     $handlers[$name]->export_type = EXPORT_IN_CODE;
     return $handlers[$name];
   }
-  else if (isset($result[$name]) && !isset($handlers[$name])) {
+  elseif (isset($result[$name]) && !isset($handlers[$name])) {
     return $result[$name];
   }
-  else if (isset($result[$name]) && isset($handlers[$name])) {
+  elseif (isset($result[$name]) && isset($handlers[$name])) {
     if ($result[$name]->export_type & EXPORT_IN_DATABASE) {
       $result[$name]->type = t('Overridden');
       $result[$name]->export_type = $result[$name]->export_type | EXPORT_IN_CODE;
@@ -742,9 +775,8 @@ function page_manager_export_task_handler_load($name) {
 function page_manager_new_task_handler($plugin) {
   // Generate a unique name. Unlike most named objects, we don't let people choose
   // names for task handlers because they mostly don't make sense.
-
   // Create a new, empty handler object.
-  $handler          = new stdClass;
+  $handler          = new stdClass();
   $handler->title   = $plugin['title'];
   $handler->task    = NULL;
   $handler->subtask = NULL;
@@ -763,7 +795,7 @@ function page_manager_new_task_handler($plugin) {
     if (is_array($plugin['default conf'])) {
       $handler->conf = $plugin['default conf'];
     }
-    else if (function_exists($plugin['default conf'])) {
+    elseif (function_exists($plugin['default conf'])) {
       $handler->conf = $plugin['default conf']($handler);
     }
   }
@@ -789,7 +821,6 @@ function page_manager_update_task_handler_weight($handler, $weight) {
     ->execute();
 }
 
-
 /**
  * Shortcut function to get task plugins.
  */
@@ -1166,9 +1197,9 @@ function page_manager_page_manager_pages_to_hook_code($names = array(), $name =
     $code .= " */\n";
     $code .= "function " . $name . "_{$export['default hook']}() {\n";
     foreach ($objects as $object) {
-      // Have to implement our own because this export func sig requires it
+      // Have to implement our own because this export func sig requires it.
       $code .= $export['export callback']($object, TRUE, '  ');
-      $code .= "  \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n";
+      $code .= "  \${$export['identifier']}s['" . check_plain($object->{$export['key']}) . "'] = \${$export['identifier']};\n\n";
     }
     $code .= "  return \${$export['identifier']}s;\n";
     $code .= "}\n";
@@ -1276,7 +1307,7 @@ function page_manager_addressable_content($address, $type) {
     $arguments = explode('..', $arguments);
   }
   else {
-    // implode does not return an empty array on an empty
+    // Implode does not return an empty array on an empty
     // string so do it specifically.
     $arguments = array();
   }
diff --git a/page_manager/plugins/cache/page_manager_context.inc b/page_manager/plugins/cache/page_manager_context.inc
index 2f01b56033c12e257f0571a8dc3b4a7c7230631d..a60b9e6bd9970ad0e036e12d1efaa9fac02c24a4 100644
--- a/page_manager/plugins/cache/page_manager_context.inc
+++ b/page_manager/plugins/cache/page_manager_context.inc
@@ -7,7 +7,7 @@
  */
 
 $plugin = array(
-  // cache plugins are the rare plugin types that have no real UI but
+  // Cache plugins are the rare plugin types that have no real UI but
   // we're providing a title just in case.
   'title' => t('Page manager context'),
   'cache get' => 'page_manager_cache_page_manager_context_cache_get',
@@ -46,7 +46,7 @@ function page_manager_cache_page_manager_context_cache_set($data, $key, $object)
 }
 
 /**
- * Copy temporary data from the page manager cache
+ * Copy temporary data from the page manager cache.
  */
 function page_manager_cache_page_manager_context_cache_finalize($data, $key, $object) {
   // Statically cached so there shouldn't be any worries. It's an object so
diff --git a/page_manager/plugins/task_handlers/http_response.inc b/page_manager/plugins/task_handlers/http_response.inc
index e5c01414da878c4312d88e7a29e4d5939fa0c0c6..9c53f3467a5ebb3f264a5e5fa4c37930c825635e 100644
--- a/page_manager/plugins/task_handlers/http_response.inc
+++ b/page_manager/plugins/task_handlers/http_response.inc
@@ -2,13 +2,13 @@
 
 /**
  * @file
- *
- * This is the task handler plugin to handle generating 403, 404 and 301 response codes.
+ * This is the task handler plugin to handle generating 403, 404, 301 and 302
+ * response codes.
  */
 
-// Plugin definition
+// Plugin definition.
 $plugin = array(
-  // is a 'context' handler type, meaning it supports the API of the
+  // Is a 'context' handler type, meaning it supports the API of the
   // context handlers provided by ctools context plugins.
   'handler type' => 'context',
   'visible' => TRUE, // may be added up front.
@@ -108,7 +108,8 @@ function page_manager_http_response_codes() {
     403 => t('403 Access denied'),
     404 => t('404 Page not found'),
     410 => t('410 Gone'),
-    301 => t('301 Redirect'),
+    301 => t('301 Permanent redirect'),
+    302 => t('302 Temporary redirect'),
   );
 }
 
@@ -119,7 +120,7 @@ function page_manager_http_response_admin_summary($handler, $task, $subtask, $pa
   ctools_include('context');
   ctools_include('context-task-handler');
 
-  // Get the operations
+  // Get the operations.
   $operations = page_manager_get_operations($page);
 
   // Get operations for just this handler.
@@ -188,7 +189,7 @@ function page_manager_http_response_admin_summary($handler, $task, $subtask, $pa
 
   $output .= '<div class="clearfix">';
   if ($show_title) {
-  $output .= '<div class="handler-title clearfix">';
+    $output .= '<div class="handler-title clearfix">';
     $output .= '<div class="actions handler-actions">' . $rendered_operations['actions'] . '</div>';
     $output .= '<span class="title-label">' . $title . '</span>';
   }
@@ -213,9 +214,12 @@ function page_manager_http_response_title($handler, $task, $subtask) {
 }
 
 /**
- * General settings for the panel
+ * General settings for the panel.
  */
 function page_manager_http_response_edit_settings($form, &$form_state) {
+  ctools_include('page_manager.admin', 'page_manager', '');
+  ctools_include('export', 'ctools');
+
   $conf = $form_state['handler']->conf;
   $form['title'] = array(
     '#type' => 'textfield',
@@ -224,6 +228,23 @@ function page_manager_http_response_edit_settings($form, &$form_state) {
     '#description' => t('Administrative title of this variant.'),
   );
 
+  $name = isset($conf['name']) ? $conf['name'] : FALSE;
+  $form['name'] = array(
+    '#type' => 'machine_name',
+    '#title' => t('Machine name'),
+    '#required' => FALSE,
+    '#default_value' => $name,
+    '#description' => t("A unique machine-readable name for this variant. It must only contain lowercase letters, numbers, and underscores. This name will be used when exporting the variant. If left empty the variant's name will be used instead."),
+    '#size' => 32,
+    '#maxlength' => 32,
+    '#machine_name' => array(
+      'exists' => 'page_manager_handler_check_machine_name',
+      'source' => array('title'),
+    ),
+    '#field_prefix' => '<span dir="ltr">' . $form_state['task_name'] . '__',
+    '#field_suffix' => '</span>&lrm;',
+  );
+
   $form['code'] = array(
     '#title' => t('Response code'),
     '#type' => 'select',
@@ -236,7 +257,7 @@ function page_manager_http_response_edit_settings($form, &$form_state) {
     '#type' => 'textfield',
     '#title' => t('Redirect destination'),
     '#default_value' => $conf['destination'],
-    '#dependency' => array('edit-code' => array(301)),
+    '#dependency' => array('edit-code' => array(301, 302)),
     '#description' => t('Enter the path to redirect to. You may use keyword substitutions from contexts. You can use external urls (http://www.example.com/foo) or internal urls (node/1).'),
   );
 
@@ -244,7 +265,33 @@ function page_manager_http_response_edit_settings($form, &$form_state) {
 }
 
 function page_manager_http_response_edit_settings_submit($form, &$form_state) {
+  $machine_name = $form_state['handler']->name;
+  $name = $form_state['task_name'] . '__' . $form_state['values']['name'];
+
+  // If new name doesn't equal machine name, we need to update and redirect.
+  if ($machine_name !== $name) {
+    $form_state['handler']->name = $name;
+    // If there's a trail, we need to replace it for redirection.
+    if (isset($form_state['trail'])) {
+      $form_state['new trail'] = $form_state['trail'];
+      $delta = array_search($machine_name, $form_state['new trail']);
+      $form_state['new trail'][$delta] = $name;
+    }
+    // If handler id is set, replace it.
+    if ($form_state['handler_id']) {
+      $form_state['handler_id'] = $name;
+    }
+    // If we're defining a new custom handler, move page handler to new name.
+    if (isset($form_state['page']->handlers[$machine_name]) && isset($form_state['page']->handler_info[$machine_name])) {
+      $form_state['page']->handlers[$name] = $form_state['page']->handlers[$machine_name];
+      unset($form_state['page']->handlers[$machine_name]);
+      $form_state['page']->handler_info[$name] = $form_state['page']->handler_info[$machine_name];
+      unset($form_state['page']->handler_info[$machine_name]);
+    }
+  }
+
   $form_state['handler']->conf['title'] = $form_state['values']['title'];
+  $form_state['handler']->conf['name'] = $form_state['values']['name'];
   $form_state['handler']->conf['code'] = $form_state['values']['code'];
   $form_state['handler']->conf['destination'] = $form_state['values']['destination'];
 }
@@ -254,7 +301,7 @@ function page_manager_http_response_render($handler, $base_contexts, $args, $tes
   ctools_include('context');
   ctools_include('context-task-handler');
 
-  // Add my contexts
+  // Add my contexts.
   $contexts = ctools_context_handler_get_handler_contexts($base_contexts, $handler);
 
   // Test.
@@ -267,7 +314,7 @@ function page_manager_http_response_render($handler, $base_contexts, $args, $tes
   }
 
   $info['response code'] = $handler->conf['code'];
-  if ($info['response code'] == 301) {
+  if ($info['response code'] == 301 || $info['response code'] == 302) {
     $path = ctools_context_keyword_substitute($handler->conf['destination'], array(), $contexts);
     $url = parse_url($path);
     if (isset($url['query'])) {
diff --git a/page_manager/plugins/tasks/blog.inc b/page_manager/plugins/tasks/blog.inc
index bab2dd28d4014c6f4a87566f1abc6e806fbae141..f20da0be6d0b5bc419ed07120cc33a69e02ac825 100644
--- a/page_manager/plugins/tasks/blog.inc
+++ b/page_manager/plugins/tasks/blog.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
@@ -10,7 +14,7 @@ function page_manager_blog_page_manager_tasks() {
   }
 
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
 
     'title' => t('All blogs'),
@@ -68,7 +72,7 @@ function page_manager_blog_menu_alter(&$items, $task) {
  * node edit, which is node_page_edit().
  */
 function page_manager_blog() {
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('blog');
 
   ctools_include('context');
@@ -113,6 +117,7 @@ function page_manager_blog_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/blog_user.inc b/page_manager/plugins/tasks/blog_user.inc
index 351e4de09b7b857261d329b8dee6fa1cca75b481..e75629821de046d1ee699085343133975b4bafa1 100644
--- a/page_manager/plugins/tasks/blog_user.inc
+++ b/page_manager/plugins/tasks/blog_user.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
@@ -10,7 +14,7 @@ function page_manager_blog_user_page_manager_tasks() {
   }
 
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
     'title' => t('User blog'),
     'admin title' => t('User blog'),
@@ -53,7 +57,7 @@ function page_manager_blog_user_menu_alter(&$items, $task) {
     $items['blog/%user_uid_optional']['file'] = $task['file'];
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_blog_user_disabled', TRUE);
     if (!empty($GLOBALS['page_manager_enabling_blog_user'])) {
       drupal_set_message(t('Page manager module is unable to enable blog/%user because some other module already has overridden with %callback.', array('%callback' => $items['blog/%user']['page callback'])), 'error');
@@ -143,6 +147,7 @@ function page_manager_blog_user_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/comment_reply.inc b/page_manager/plugins/tasks/comment_reply.inc
index 0fcf9e2a725d56a2a637d025f5ac37077ac053c2..c250423508b25ae4a15c13ac4369a2e281b6f1d1 100644
--- a/page_manager/plugins/tasks/comment_reply.inc
+++ b/page_manager/plugins/tasks/comment_reply.inc
@@ -1,4 +1,9 @@
 <?php
+
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
@@ -9,7 +14,7 @@ function page_manager_comment_reply_page_manager_tasks() {
   }
 
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
 
     'title' => t('Comment Reply page'),
@@ -45,13 +50,11 @@ function page_manager_comment_reply_enable($cache, $status) {
   }
 }
 
-
 /**
  * Entry point for our overridden comment.
- *
  */
-function page_manager_comment_reply_page($node, $pid = NULL){
-    // Load my task plugin
+function page_manager_comment_reply_page($node, $pid = NULL) {
+  // Load my task plugin.
   $task = page_manager_get_task('comment_reply');
 
   // Load the node into a context.
@@ -67,7 +70,7 @@ function page_manager_comment_reply_page($node, $pid = NULL){
   }
 
   $output = ctools_context_handler_render($task, '', $contexts, array($node, $pid));
-  if ($output != FALSE) {
+  if ($output !== FALSE) {
     return $output;
   }
 
@@ -134,7 +137,7 @@ function page_manager_comment_reply_menu_alter(&$items, $task) {
     $items['comment/reply/%node']['file'] = $task['file'];
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_comment_reply_disabled', TRUE);
     if (!empty($GLOBALS['page_manager_enabling_comment_reply'])) {
       drupal_set_message(t('Page manager module is unable to enable comment/reply/%node because some other module already has overridden with %callback.', array('%callback' => $callback)), 'error');
@@ -153,6 +156,7 @@ function page_manager_comment_reply_menu_alter(&$items, $task) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/contact_site.inc b/page_manager/plugins/tasks/contact_site.inc
index f8718697cb7f018a01c2fa8eb445930d90a5631a..e9716c493d823ba28e0bb251fc141dc18a4cc939 100644
--- a/page_manager/plugins/tasks/contact_site.inc
+++ b/page_manager/plugins/tasks/contact_site.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
@@ -10,7 +14,7 @@ function page_manager_contact_site_page_manager_tasks() {
   }
 
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
 
     'title' => t('Site contact page'),
@@ -72,7 +76,7 @@ function page_manager_contact_site_menu_alter(&$items, $task) {
  * node edit, which is node_page_edit().
  */
 function page_manager_contact_site() {
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('contact_site');
 
   ctools_include('context');
@@ -121,6 +125,7 @@ function page_manager_contact_site_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/contact_user.inc b/page_manager/plugins/tasks/contact_user.inc
index 5c868161b9d5ebbeb3da4fe6b61f23e1e17383a1..96daec8b50fa5e2e7d6f18e6b45cb0c1069c1fd7 100644
--- a/page_manager/plugins/tasks/contact_user.inc
+++ b/page_manager/plugins/tasks/contact_user.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
@@ -9,7 +13,7 @@ function page_manager_contact_user_page_manager_tasks() {
     return;
   }
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
     'title' => t('User contact'),
     'admin title' => t('User contact'),
@@ -56,7 +60,7 @@ function page_manager_contact_user_menu_alter(&$items, $task) {
     $items['user/%user/contact']['file'] = $task['file'];
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_contact_user_disabled', TRUE);
     if (!empty($GLOBALS['page_manager_enabling_contact_user'])) {
       drupal_set_message(t('Page manager module is unable to enable user/%user/contact because some other module already has overridden with %callback.', array('%callback' => $callback)), 'error');
@@ -146,6 +150,7 @@ function page_manager_contact_user_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/node_edit.inc b/page_manager/plugins/tasks/node_edit.inc
index 844cd5b317d372ac442a71512344882441b9a790..2d27449182e9f1c74f589a05917508c11f906b39 100644
--- a/page_manager/plugins/tasks/node_edit.inc
+++ b/page_manager/plugins/tasks/node_edit.inc
@@ -1,12 +1,16 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
  */
 function page_manager_node_edit_page_manager_tasks() {
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
 
     'title' => t('Node add/edit form'),
@@ -83,7 +87,7 @@ function page_manager_node_edit_menu_alter(&$items, $task) {
  * node edit, which is node_page_edit().
  */
 function page_manager_node_edit($node) {
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('node_edit');
 
   // Load the node into a context.
@@ -91,13 +95,28 @@ function page_manager_node_edit($node) {
   ctools_include('context-task-handler');
   $contexts = ctools_context_handler_get_task_contexts($task, '', array($node));
 
+  // Set the default title for the node add/edit form. If the page has a custom
+  // title it'll override this.
+  $types = node_type_get_types();
+  $context = reset($contexts);
+  if (empty($context->data->nid)) {
+    drupal_set_title(t('Create @name', array(
+      '@name' => $types[$context->data->type]->name
+    )), PASS_THROUGH);
+  }
+  else {
+    drupal_set_title(t('<em>Edit @type</em> @title', array(
+      '@type' => $types[$context->node_type]->name,
+      '@title' => $context->data->title
+    )), PASS_THROUGH);
+  }
+
   $arg = array(isset($node->nid) ? $node->nid : $node->type);
   $output = ctools_context_handler_render($task, '', $contexts, $arg);
   if ($output === FALSE) {
     // Fall back!
     // We've already built the form with the context, so we can't build it again, or
     // form_clean_id will mess up our ids. But we don't really need to, either:
-    $context = reset($contexts);
     $output = $context->form;
   }
 
@@ -108,7 +127,7 @@ function page_manager_node_edit($node) {
  * Callback to handle the process of adding a node.
  *
  * This creates a basic $node and passes that off to page_manager_node_edit().
- * It is modeled after Drupal's node_add() function.
+ * It is modelled after Drupal's node_add() function.
  *
  * Unlike node_add() we do not need to check node_access because that was
  * already checked by the menu system.
@@ -126,7 +145,7 @@ function page_manager_node_add($type) {
     'language' => LANGUAGE_NONE,
   );
 
-  drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)));
+  drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
   return page_manager_node_edit($node);
 }
 
@@ -176,6 +195,7 @@ function page_manager_node_edit_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/node_view.inc b/page_manager/plugins/tasks/node_view.inc
index b8a7e0c96d4b38944bcf351dd5c5ec4ea72515d5..6de28ad5b9d2133d7f3441492737a97b3eb6356d 100644
--- a/page_manager/plugins/tasks/node_view.inc
+++ b/page_manager/plugins/tasks/node_view.inc
@@ -15,7 +15,7 @@
  */
 function page_manager_node_view_page_manager_tasks() {
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
 
     'title' => t('Node template'),
@@ -60,7 +60,7 @@ function page_manager_node_view_menu_alter(&$items, $task) {
     $items['node/%node']['file'] = $task['file'];
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_node_view_disabled', TRUE);
     if (!empty($GLOBALS['page_manager_enabling_node_view'])) {
       drupal_set_message(t('Page manager module is unable to enable node/%node because some other module already has overridden with %callback.', array('%callback' => $callback)), 'error');
@@ -78,39 +78,53 @@ function page_manager_node_view_menu_alter(&$items, $task) {
  * node view, which is node_page_view().
  */
 function page_manager_node_view_page($node) {
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('node_view');
 
   // Load the node into a context.
   ctools_include('context');
   ctools_include('context-task-handler');
 
-  // We need to mimic Drupal's behavior of setting the node title here.
-  drupal_set_title($node->title);
   $uri = entity_uri('node', $node);
-  // Set the node path as the canonical URL to prevent duplicate content.
-  drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
-  // Set the non-aliased path as a default shortlink.
-  drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);
+  if (isset($uri['path'])) {
+    // Set the node path as the canonical URL to prevent duplicate content.
+    $meta_canon = array(
+      'rel' => 'canonical',
+      'href' => url($uri['path'], $uri['options']),
+    );
+    drupal_add_html_head_link($meta_canon, TRUE);
+
+    // Set the non-aliased path as a default shortlink.
+    $meta_short = array(
+      'rel' => 'shortlink',
+      'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE))),
+    );
+    drupal_add_html_head_link($meta_short, TRUE);
+  }
+
+  // Load all contexts.
   $contexts = ctools_context_handler_get_task_contexts($task, '', array($node));
 
+  // Build the full output using the configured CTools plugin.
   $output = ctools_context_handler_render($task, '', $contexts, array($node->nid));
-  if ($output != FALSE) {
+  if ($output !== FALSE) {
     node_tag_new($node);
     return $output;
   }
 
-  $function = 'node_page_view';
+  // Try loading an override plugin.
   foreach (module_implements('page_manager_override') as $module) {
     $call = $module . '_page_manager_override';
     if (($rc = $call('node_view')) && function_exists($rc)) {
-      $function = $rc;
-      break;
+      return $rc($node);
     }
   }
 
-  // Otherwise, fall back.
-  return $function($node);
+  // Prepare the node to be displayed so all of the regular hooks are triggered.
+  $default_output = node_page_view($node);
+
+  // Otherwise, fall back to the default output generated by node_page_view().
+  return $default_output;
 }
 
 /**
@@ -160,6 +174,7 @@ function page_manager_node_view_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/page.admin.inc b/page_manager/plugins/tasks/page.admin.inc
index 88d46c5b6d738a53ffb176d744d224be8923fa18..13cc632286bae86f695fd7fff216a9ebbe4709f1 100644
--- a/page_manager/plugins/tasks/page.admin.inc
+++ b/page_manager/plugins/tasks/page.admin.inc
@@ -38,7 +38,7 @@ function page_manager_page_menu(&$items, $task) {
   ) + $base;
   if ($access_callback == 'user_access') {
     $items['admin/structure/pages/import']['access callback'] = 'ctools_access_multiperm';
-    $items['admin/structure/pages/import']['access arguments'][] = 'use PHP for settings';
+    $items['admin/structure/pages/import']['access arguments'][] = 'use ctools import';
   }
 
   // AJAX callbacks for argument modal.
@@ -47,7 +47,7 @@ function page_manager_page_menu(&$items, $task) {
     'type' => MENU_CALLBACK,
   ) + $base;
 
-  // Add menu entries for each subtask
+  // Add menu entries for each subtask.
   foreach (page_manager_page_load_all() as $subtask_id => $subtask) {
     if (!empty($subtask->disabled)) {
       continue;
@@ -61,7 +61,7 @@ function page_manager_page_menu(&$items, $task) {
     }
 
     $path             = array();
-    $page_arguments   = array($subtask_id);
+    $page_arguments   = array((string) $subtask_id);
     $access_arguments = array($subtask->access);
     $load_arguments   = array($subtask_id, '%index', '%map');
 
@@ -102,12 +102,12 @@ function page_manager_page_menu(&$items, $task) {
         $page_arguments[]   = $position;
         $access_arguments[] = $position;
       }
-      else if ($bit[0] != '!') {
+      elseif ($bit[0] != '!') {
         $path[] = $bit;
       }
 
       // Increment position. We do it like this to skip empty items that
-      // could happen from erroneous paths like: this///that
+      // could happen from erroneous paths like: this///that.
       $position++;
     }
 
@@ -171,7 +171,7 @@ function page_manager_page_menu_item($task, $menu, $access_arguments, $page_argu
 
     case 'normal':
       $item['type'] = MENU_NORMAL_ITEM;
-      // Insert item into the proper menu
+      // Insert item into the proper menu.
       $item['menu_name'] = $menu['name'];
       break;
 
@@ -261,10 +261,10 @@ function page_manager_page_add_subtask($task_name = NULL, $step = NULL) {
         if (isset($form_info['add order'][$id])) {
           $form_info['order'][$id] = $form_info['add order'][$id];
         }
-        else if (isset($handler_plugin['add features'][$id])) {
+        elseif (isset($handler_plugin['add features'][$id])) {
           $form_info['order'][$id] = $handler_plugin['add features'][$id];
         }
-        else if (isset($handler_plugin['required forms'][$id])) {
+        elseif (isset($handler_plugin['required forms'][$id])) {
           $form_info['order'][$id] = $handler_plugin['required forms'][$id];
         }
       }
@@ -279,7 +279,7 @@ function page_manager_page_add_subtask($task_name = NULL, $step = NULL) {
     // our questions determined would be next.
     if ($step == 'next') {
       $keys = array_keys($form_info['order']);
-      // get rid of 'basic' from the list of forms.
+      // Get rid of 'basic' from the list of forms.
       array_shift($keys);
       $step = array_shift($keys);
 
@@ -416,7 +416,7 @@ function page_manager_page_form_basic($form, &$form_state) {
     '#default_value' => $page->admin_description,
   );
 
-  // path
+  // Path.
   $form['path'] = array(
     '#type' => 'textfield',
     '#title' => t('Path'),
@@ -452,7 +452,7 @@ function page_manager_page_form_basic($form, &$form_state) {
       '#description' => t('Admin overlays are used in many places in Drupal 7 and administrative custom pages should probably utilize this feature.'),
     );
   }
-  else if ($path == $frontpage) {
+  elseif ($path == $frontpage) {
     $form['frontpage_markup'] = array(
       '#value' => '<b>' . t('This page is currently set to be your site home page. This can be modified on the !siteinfo configuration form.', array('!siteinfo' => l(t('Site Information'), 'admin/settings/site-information'))) . '</b>',
     );
@@ -516,7 +516,7 @@ function page_manager_page_form_basic_validate(&$form, &$form_state) {
   $path = array();
   if (empty($form_state['values']['path'])) {
     form_error($form['path'], t('Path is required.'));
-    // stop processing here if there is no path.
+    // Stop processing here if there is no path.
     return;
   }
 
@@ -542,7 +542,7 @@ function page_manager_page_form_basic_validate(&$form, &$form_state) {
 
       $path[] = '%';
     }
-    else if ($bit[0] == '!') {
+    elseif ($bit[0] == '!') {
       $found = TRUE;
     }
     else {
@@ -566,7 +566,7 @@ function page_manager_page_form_basic_validate(&$form, &$form_state) {
   if (strpos($path, '%') === FALSE) {
     $alias = db_query('SELECT alias, source FROM {url_alias} WHERE alias = :path', array(':path' => $path))->fetchObject();
     if ($alias) {
-      form_error($form['path'], t('That path is currently assigned to be an alias for @alias. This system cannot override existing aliases.', array('@alias' => $alias->src)));
+      form_error($form['path'], t('That path is currently assigned to be an alias for @alias. This system cannot override existing aliases.', array('@alias' => $alias->source)));
     }
   }
   else {
@@ -620,9 +620,10 @@ function page_manager_page_form_basic_submit(&$form, &$form_state) {
     $title = !empty($form_state['values']['title']) ? $form_state['values']['title'] : $plugin['title'];
     page_manager_handler_add_to_page($cache, $handler, $title);
 
-    // Figure out which forms to present them with
+    // Figure out which forms to present them with.
     $cache->forms = array();
-    $cache->forms[] = 'basic'; // This one is always there.
+    // This one is always there.
+    $cache->forms[] = 'basic';
     if (!empty($form_state['arguments'])) {
       $cache->forms[] = 'argument';
     }
@@ -698,7 +699,7 @@ function page_manager_page_form_menu($form, &$form_state) {
     '#title' => t('Title'),
     '#type' => 'textfield',
     '#default_value' => $menu['title'],
-    '#description' => t('If set to normal or tab, enter the text to use for the menu item.'),
+    '#description' => t('If set to normal or tab, enter the text to use for the menu item. Renaming the menu item using the Drupal menu system (admin/structure/menu) will override this, even if it is renamed again here.'),
     '#dependency' => array('radio:menu[type]' => array('normal', 'tab', 'default tab', 'action')),
   );
 
@@ -769,12 +770,12 @@ function page_manager_page_form_menu($form, &$form_state) {
     );
   }
   $form['menu']['parent']['weight'] = array(
-    '#title' => t('Tab weight'),
+    '#title' => t('Parent weight'),
     '#type' => 'textfield',
     '#default_value' => $menu['parent']['weight'],
     '#size' => 5,
-    '#description' => t('If the parent menu item is a tab, enter the weight of the tab. The lower the number, the more to the left it will be.'),
-    '#dependency' => array('radio:menu[type]' => array('default tab'), 'radio:menu[parent][type]' => array('tab')),
+    '#description' => t('Enter the weight of the parent item. The lower the number, the more to the left it will be.'),
+    '#dependency' => array('radio:menu[type]' => array('default tab'), 'radio:menu[parent][type]' => array('tab', 'normal')),
     '#dependency_count' => 2,
   );
 
@@ -787,7 +788,6 @@ function page_manager_page_form_menu($form, &$form_state) {
 function page_manager_page_form_menu_validate(&$form, &$form_state) {
   // If setting a 'normal' menu entry, make sure that any placeholders
   // support the to_arg stuff.
-
   if ($form_state['values']['menu']['type'] == 'normal') {
     $page = $form_state['page']->subtask['subtask'];
 
@@ -876,7 +876,7 @@ function page_manager_page_form_argument($form, &$form_state) {
     if (isset($page->temporary_arguments[$keyword]) && !empty($form_state['allow temp'])) {
       $conf = $page->temporary_arguments[$keyword];
     }
-    else if (isset($page->arguments[$keyword])) {
+    elseif (isset($page->arguments[$keyword])) {
       $conf = $page->arguments[$keyword];
     }
 
@@ -896,7 +896,7 @@ function page_manager_page_form_argument($form, &$form_state) {
     $form['table']['argument'][$keyword]['#position'] = $position;
     $form['table']['argument'][$keyword]['#context'] = $context;
 
-    // The URL for this ajax button
+    // The URL for this ajax button.
     $form['table']['argument'][$keyword]['change-url'] = array(
       '#attributes' => array('class' => array("page-manager-context-$keyword-change-url")),
       '#type' => 'hidden',
@@ -913,7 +913,7 @@ function page_manager_page_form_argument($form, &$form_state) {
 
     // Only show the button if this has a settings form available:
     if (!empty($plugin)) {
-      // The URL for this ajax button
+      // The URL for this ajax button.
       $form['table']['argument'][$keyword]['settings-url'] = array(
         '#attributes' => array('class' => array("page-manager-context-$keyword-settings-url")),
         '#type' => 'hidden',
@@ -970,7 +970,7 @@ function theme_page_manager_page_form_argument_table($vars) {
 }
 
 /**
- * Ajax entry point to edit an item
+ * Ajax entry point to edit an item.
  */
 function page_manager_page_subtask_argument_ajax($step = NULL, $task_name = NULL, $keyword = NULL) {
   ctools_include('ajax');
@@ -995,7 +995,7 @@ function page_manager_page_subtask_argument_ajax($step = NULL, $task_name = NULL
     return ctools_ajax_render_error(t('Invalid keyword.'));
   }
 
-  // Set up wizard info
+  // Set up wizard info.
   $form_info = array(
     'id' => 'page_manager_page_argument',
     'path' => "admin/structure/pages/argument/%step/$task_name/$keyword",
@@ -1032,7 +1032,7 @@ function page_manager_page_subtask_argument_ajax($step = NULL, $task_name = NULL
   if (!empty($form_state['cancel'])) {
     $commands = array(ctools_modal_command_dismiss());
   }
-  else if (!empty($form_state['complete'])) {
+  elseif (!empty($form_state['complete'])) {
     if (isset($page->temporary_arguments[$keyword])) {
       $page->arguments[$keyword] = $page->temporary_arguments[$keyword];
     }
@@ -1051,7 +1051,6 @@ function page_manager_page_subtask_argument_ajax($step = NULL, $task_name = NULL
     // fully processed, but is guaranteed to produce the same form we
     // started with so we don't have to do crazy stuff to rerender
     // just part of it.
-
     // @todo should there be a tool to do this?
 
     $clone_state = $form_state;
@@ -1174,7 +1173,7 @@ function page_manager_page_argument_form_change_submit(&$form, &$form_state) {
     if (is_array($plugin['default'])) {
       $settings = $plugin['default'];
     }
-    else if (function_exists($plugin['default'])) {
+    elseif (function_exists($plugin['default'])) {
       $settings = $plugin['default']();
     }
   }
@@ -1201,7 +1200,7 @@ function page_manager_page_argument_form_settings($form, &$form_state) {
   if (isset($page->temporary_arguments[$keyword])) {
     $conf = $page->temporary_arguments[$keyword];
   }
-  else if (isset($page->arguments[$keyword])) {
+  elseif (isset($page->arguments[$keyword])) {
     $conf = $page->temporary_arguments[$keyword] = $page->arguments[$keyword];
   }
 
@@ -1271,7 +1270,7 @@ function page_manager_page_argument_form_settings_submit(&$form, &$form_state) {
 }
 
 /**
- * Import a task handler from cut & paste
+ * Import a task handler from cut & paste.
  */
 function page_manager_page_import_subtask($form, &$form_state, $task_name) {
   $form_state['task'] = page_manager_get_task($task_name);
@@ -1414,7 +1413,7 @@ function page_manager_page_form_clone($form, &$form_state) {
     '#description' => t('Enter the name to the new page It must be unique and contain only alphanumeric characters and underscores.'),
   );
 
-  // path
+  // Path.
   $form['path'] = array(
     '#type' => 'textfield',
     '#title' => t('Path'),
@@ -1449,7 +1448,7 @@ function page_manager_page_form_clone_validate(&$form, &$form_state) {
 }
 
 /**
- * submit clone page form.
+ * Submit clone page form.
  *
  * Load the page, change the name(s) to protect the innocent, and if
  * requested, load all the task handlers so that they get saved properly too.
@@ -1462,6 +1461,15 @@ function page_manager_page_form_clone_submit(&$form, &$form_state) {
   $original->path = $form_state['values']['path'];
 
   $handlers = !empty($form_state['values']['handlers']) ? $form_state['page']->handlers : FALSE;
+  // Ensure the handler uuids are re-generated.
+  if ($handlers) {
+    foreach ($handlers as &$handler) {
+      if (isset($handler->conf['display']) && method_exists($handler->conf['display'], 'clone_display')) {
+        $handler->conf['display'] = $handler->conf['display']->clone_display();
+      }
+    }
+  }
+
   // Export the handler, which is a fantastic way to clean database IDs out of it.
   $export = page_manager_page_export($original, $handlers);
   ob_start();
diff --git a/page_manager/plugins/tasks/page.inc b/page_manager/plugins/tasks/page.inc
index 6a8545d1a2f87d69613c6f3093939c98a320c781..100dfd8176bb796329ba04e1a1a655da1a52dfb9 100644
--- a/page_manager/plugins/tasks/page.inc
+++ b/page_manager/plugins/tasks/page.inc
@@ -32,7 +32,7 @@ function page_manager_page_page_manager_tasks() {
       'function' => 'page_manager_page_menu',
     ),
     'hook theme' => 'page_manager_page_theme',
-    // page only items
+    // Page only items.
     'task type' => 'page',
     'page operations' => array(
       array(
@@ -49,7 +49,7 @@ function page_manager_page_page_manager_tasks() {
     ),
     'page type' => 'custom',
 
-    // context only items
+    // Context only items.
     'handler type' => 'context',
     'get arguments' => array(
       'file' => 'page.admin.inc',
@@ -112,7 +112,7 @@ function page_manager_page_save_subtask($subtask) {
     }
   }
   page_manager_page_recalculate_arguments($page);
-  // Create a real object from the cache
+  // Create a real object from the cache.
   page_manager_page_save($page);
 
   // Check to see if we should make this the site frontpage.
@@ -191,7 +191,7 @@ function page_manager_page_build_subtask($task, $page) {
       'form' => 'page_manager_page_form_delete',
     );
   }
-  else if ($page->export_type != EXPORT_IN_CODE) {
+  elseif ($page->export_type != EXPORT_IN_CODE) {
     $operations['actions']['children']['delete'] = array(
       'title' => t('Delete'),
       'description' => t('Remove this page from your system completely.'),
@@ -216,11 +216,11 @@ function page_manager_page_build_subtask($task, $page) {
     'row class' => empty($page->disabled) ? 'page-manager-enabled' : 'page-manager-disabled',
     'storage' => $page->type == t('Default') ? t('In code') : $page->type,
     'disabled' => !empty($page->disabled),
-    // This works for both enable AND disable
+    // This works for both enable AND disable.
     'enable callback' => 'page_manager_page_enable',
   );
 
-  // default handlers may appear from a default subtask.
+  // Default handlers may appear from a default subtask.
   if (isset($page->default_handlers)) {
     $subtask['default handlers'] = $page->default_handlers;
   }
@@ -247,8 +247,7 @@ function page_manager_page_theme(&$items, $task) {
 }
 
 // --------------------------------------------------------------------------
-// Page execution functions
-
+// Page execution functions.
 /**
  * Execute a page task.
  *
@@ -262,6 +261,7 @@ function page_manager_page_theme(&$items, $task) {
  *   creating named arguments in the path.
  */
 function page_manager_page_execute($subtask_id) {
+  $func_args = func_get_args();
   $page = page_manager_page_load($subtask_id);
   $task = page_manager_get_task($page->task);
   $subtask = page_manager_get_task_subtask($task, $subtask_id);
@@ -269,12 +269,12 @@ function page_manager_page_execute($subtask_id) {
   // Turn the contexts into a properly keyed array.
   $contexts = array();
   $args = array();
-  foreach (func_get_args() as $count => $arg) {
+  foreach ($func_args as $count => $arg) {
     if (is_object($arg) && get_class($arg) == 'ctools_context') {
       $contexts[$arg->id] = $arg;
       $args[] = $arg->original_argument;
     }
-    else if ($count) {
+    elseif ($count) {
       $args[] = $arg;
     }
   }
@@ -302,9 +302,9 @@ function page_manager_page_execute($subtask_id) {
           $context = ctools_context_get_context_from_argument($argument, $value);
         }
         else {
-          // make sure there is a placeholder context for missing optional contexts.
+          // Make sure there is a placeholder context for missing optional contexts.
           $context = ctools_context_get_context_from_argument($argument, NULL, TRUE);
-          // Force the title to blank for replacements
+          // Force the title to blank for replacements.
         }
         if ($context) {
           $contexts[$context->id] = $context;
@@ -328,8 +328,7 @@ function page_manager_page_execute($subtask_id) {
 }
 
 // --------------------------------------------------------------------------
-// Context type callbacks
-
+// Context type callbacks.
 /**
  * Return a list of arguments used by this task.
  */
@@ -432,7 +431,7 @@ function page_manager_page_save(&$page) {
 /**
  * Remove a page subtask.
  */
-function page_manager_page_delete($page) {
+function page_manager_page_delete($page, $skip_menu_rebuild = FALSE) {
   $task = page_manager_get_task($page->task);
   if ($function = ctools_plugin_get_function($task, 'delete')) {
     $function($page);
@@ -450,7 +449,11 @@ function page_manager_page_delete($page) {
   // rebuild this page again.
   ctools_include('export');
   ctools_export_load_object_reset('page_manager_pages');
-  menu_rebuild();
+  // Allow menu rebuild to be skipped when calling code is deleting multiple
+  // pages.
+  if (!$skip_menu_rebuild) {
+    menu_rebuild();
+  }
 }
 
 /**
@@ -500,7 +503,7 @@ function page_manager_page_get_named_arguments($path) {
   $bits = explode('/', $path);
   foreach ($bits as $position => $bit) {
     if ($bit && ($bit[0] == '%' || $bit[0] == '!')) {
-      // special handling for duplicate path items and substr to remove the %
+      // Special handling for duplicate path items and substr to remove the %.
       $arguments[substr($bit, 1)] = isset($arguments[$bit]) ? -1 : $position;
     }
   }
@@ -547,7 +550,7 @@ function _pm_arg_load($value, $subtask, $argument) {
   ctools_include('context');
   $context = ctools_context_get_context_from_argument($page->arguments[$keyword], $value);
 
-  // convert false equivalents to false.
+  // Convert false equivalents to false.
   return $context ? $context : FALSE;
 }
 
@@ -583,7 +586,6 @@ function page_manager_page_admin_summary($task, $subtask) {
     array('class' => array('page-summary-operation'), 'data' => $link),
   );
 
-
   $path = array();
   foreach (explode('/', $page->path) as $bit) {
     if ($bit[0] != '!') {
@@ -599,7 +601,7 @@ function page_manager_page_admin_summary($task, $subtask) {
   if ($path == $front) {
     $message = t('This is your site home page.');
   }
-  else if (!empty($page->make_frontpage)) {
+  elseif (!empty($page->make_frontpage)) {
     $message = t('This page is set to become your site home page.');
   }
 
@@ -660,6 +662,7 @@ function page_manager_page_admin_summary($task, $subtask) {
         case 'default tab':
           $menu .= ' ' . t('Parent title: %title.', array('%title' => $page->menu['parent']['title']));
           break;
+
         case 'normal':
           if (module_exists('menu')) {
             $menus = menu_get_menus();
@@ -750,7 +753,7 @@ function page_manager_page_new_page_cache(&$page, &$cache) {
   $cache->subtask = page_manager_page_build_subtask($cache->task, $page);
 
   if (isset($cache->handlers)) {
-    foreach($cache->handlers as $id => $handler) {
+    foreach ($cache->handlers as $id => $handler) {
       $cache->handler_info[$id]['changed'] = PAGE_MANAGER_CHANGED_DELETED;
     }
   }
@@ -778,6 +781,7 @@ function page_manager_page_new_page_cache(&$page, &$cache) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/poll.inc b/page_manager/plugins/tasks/poll.inc
index 073ee0c60eb49c2f7e291466bb54c56f920ae994..926c7671e9d70bb67dbe399bb8c66cb2f0f3530a 100644
--- a/page_manager/plugins/tasks/poll.inc
+++ b/page_manager/plugins/tasks/poll.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
  * more information.
@@ -10,7 +14,7 @@ function page_manager_poll_page_manager_tasks() {
   }
 
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
 
     'title' => t('All polls'),
@@ -68,7 +72,7 @@ function page_manager_poll_menu_alter(&$items, $task) {
  * node edit, which is node_page_edit().
  */
 function page_manager_poll() {
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('poll');
 
   ctools_include('context');
@@ -113,6 +117,7 @@ function page_manager_poll_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/search.inc b/page_manager/plugins/tasks/search.inc
index efd7415c46004a59991e9944becc6ffb4e162e4c..e561c71791a5b396322b51f9a42cc578d9760dfa 100644
--- a/page_manager/plugins/tasks/search.inc
+++ b/page_manager/plugins/tasks/search.inc
@@ -10,8 +10,9 @@
  */
 
 /**
- * Specialized implementation of hook_page_manager_task_tasks(). See api-task.html for
- * more information.
+ * Specialized implementation of hook_page_manager_task_tasks().
+ *
+ * See api-task.html for more information.
  */
 function page_manager_search_page_manager_tasks() {
   if (!module_exists('search')) {
@@ -19,7 +20,7 @@ function page_manager_search_page_manager_tasks() {
   }
 
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
     'title' => t('Search'),
 
@@ -38,7 +39,6 @@ function page_manager_search_page_manager_tasks() {
     'get arguments' => 'page_manager_search_get_arguments',
     'get context placeholders' => 'page_manager_search_get_contexts',
     'access callback' => 'page_manager_search_access_check',
-
   );
 }
 
@@ -59,7 +59,6 @@ function page_manager_search_menu_alter(&$items, $task) {
   // keywords. A second set is for searching *with* keywords. This
   // is necessary because search/node/% and search/node need to be
   // different due to the way the search menu items function.
-
   $default_info = search_get_default_module_info();
   if (empty($default_info)) {
     // Nothing to do.
@@ -85,7 +84,7 @@ function page_manager_search_menu_alter(&$items, $task) {
       $items["$path/%menu_tail"]['file'] = $task['file'];
     }
     else {
-      // automatically disable this task if it cannot be enabled.
+      // Automatically disable this task if it cannot be enabled.
       variable_set('page_manager_search_disabled_' . $module, TRUE);
       if (!empty($GLOBALS['page_manager_enabling_search'])) {
         drupal_set_message(t('Page manager module is unable to enable @path because some other module already has overridden with %callback.', array('%callback' => $callback, '@path' => $path)), 'error');
@@ -96,14 +95,11 @@ function page_manager_search_menu_alter(&$items, $task) {
 
 /**
  * Entry point for our overridden search page.
- *
  */
 function page_manager_search_page($type) {
-  ctools_include('menu');
-//  menu_set_active_trail(ctools_get_menu_trail('search/' . $type));
-
   // Get the arguments and construct a keys string out of them.
   $args = func_get_args();
+  ctools_include('menu');
 
   // We have to remove the $type.
   array_shift($args);
@@ -111,10 +107,10 @@ function page_manager_search_page($type) {
   // And implode() it all back together.
   $keys = $args ? implode('/', $args) : '';
 
-  // Allow other modules to alter the search keys
-  drupal_alter(array('search_keys', 'search_'. $type .'_keys'), $keys);
+  // Allow other modules to alter the search keys.
+  drupal_alter(array('search_keys', 'search_' . $type . '_keys'), $keys);
 
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('search');
   $subtask = page_manager_get_task_subtask($task, $type);
 
@@ -138,7 +134,6 @@ function page_manager_search_page($type) {
   }
 
   // Otherwise, fall back.
-
   // Put the $type back on the arguments.
   module_load_include('inc', 'search', 'search.pages');
   array_unshift($args, $type);
@@ -224,7 +219,7 @@ function page_manager_search_build_subtask($task, $module) {
     'row class' => empty($page->disabled) ? 'page-manager-enabled' : 'page-manager-disabled',
     'storage' => t('In code'),
     'disabled' => variable_get('page_manager_search_disabled_' . $module, TRUE),
-    // This works for both enable AND disable
+    // This works for both enable AND disable.
     'enable callback' => 'page_manager_search_enable',
   );
 
@@ -240,6 +235,7 @@ function page_manager_search_build_subtask($task, $module) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/term_view.inc b/page_manager/plugins/tasks/term_view.inc
index 4be1150e88c495d678ecf2f3570e412359d103bc..101b6744259209f405d99098fdfb8441530b09d9 100644
--- a/page_manager/plugins/tasks/term_view.inc
+++ b/page_manager/plugins/tasks/term_view.inc
@@ -16,12 +16,12 @@
 function page_manager_term_view_page_manager_tasks() {
   if (module_exists('taxonomy')) {
     return array(
-      // This is a 'page' task and will fall under the page admin UI
+      // This is a 'page' task and will fall under the page admin UI.
       'task type' => 'page',
 
       'title' => t('Taxonomy term template'),
       'admin title' => t('Taxonomy term template'),
-      'admin description' => t('When enabled, this overrides the default Drupal behavior for displaying taxonomy terms at <em>taxonomy/term/%term</em>. If you add variants, you may use selection criteria such as vocabulary or user access to provide different displays of the taxonomy term and associated nodes. If no variant is selected, the default Drupal taxonomy term display will be used. This page only affects items actually displayed ad taxonomy/term/%term. Some taxonomy terms, such as forums, have their displays moved elsewhere. Also please note that if you are using pathauto, aliases may make a taxonomy terms appear somewhere else, but as far as Drupal is concerned, they are still at taxonomy/term/%term.'),
+      'admin description' => t('When enabled, this overrides the default Drupal behavior for displaying taxonomy terms at <em>taxonomy/term/%term</em>. If you add variants, you may use selection criteria such as vocabulary or user access to provide different displays of the taxonomy term and associated nodes. If no variant is selected, the default Drupal taxonomy term display will be used. This page only affects items actually displayed at taxonomy/term/%term. Some taxonomy terms, such as forums, have their displays moved elsewhere. Also please note that if you are using pathauto, aliases may make a taxonomy terms appear somewhere else, but as far as Drupal is concerned, they are still at taxonomy/term/%term.'),
       'admin path' => 'taxonomy/term/%taxonomy_term',
       'admin summary' => 'page_manager_term_view_admin_summary',
 
@@ -29,7 +29,7 @@ function page_manager_term_view_page_manager_tasks() {
       'hook menu' => 'page_manager_term_view_menu',
       'hook menu alter' => 'page_manager_term_view_menu_alter',
 
-      // Provide a setting to the primary settings UI for Panels
+      // Provide a setting to the primary settings UI for Panels.
       'admin settings' => 'page_manager_term_view_admin_settings',
       // Even though we don't have subtasks, this allows us to save our settings.
       'save subtask callback' => 'page_manager_term_view_save',
@@ -48,7 +48,7 @@ function page_manager_term_view_page_manager_tasks() {
       'enable callback' => 'page_manager_term_view_enable',
       'access callback' => 'page_manager_term_view_access_check',
 
-      // Allow additional operations
+      // Allow additional operations.
       'operations' => array(
         'settings' => array(
           'title' => t('Settings'),
@@ -79,7 +79,7 @@ function page_manager_term_view_menu_alter(&$items, $task) {
     $items['taxonomy/term/%taxonomy_term']['file'] = $task['file'];
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_term_view_disabled', TRUE);
 
     if (isset($items['taxonomy/term/%taxonomy_term']['page callback'])) {
@@ -87,7 +87,7 @@ function page_manager_term_view_menu_alter(&$items, $task) {
     }
     // Because Views changes %taxonomy_term to %views_arg, check to see if that
     // is why we can't enable:
-    else if (isset($items['taxonomy/term/%views_arg']['page callback'])) {
+    elseif (isset($items['taxonomy/term/%views_arg']['page callback'])) {
       $callback = $items['taxonomy/term/%views_arg']['page callback'];
     }
     else {
@@ -112,7 +112,6 @@ function page_manager_term_view_page($term, $depth = NULL) {
   // potentially load nodes that were not necessary, execute some of the code
   // prior to identifying the correct CTools or Page Manager task handler and
   // only proceed with the rest of the code if necessary.
-
   // Assign the term name as the page title.
   drupal_set_title($term->name);
 
@@ -126,10 +125,10 @@ function page_manager_term_view_page($term, $depth = NULL) {
   // Set the non-aliased path as a default shortlink.
   drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);
 
-  // Trigger the main
+  // Trigger the main.
   $build = taxonomy_term_show($term);
 
-  // Load my task plugin
+  // Load my task plugin.
   $task = page_manager_get_task('term_view');
 
   // Load the term into a context.
@@ -151,13 +150,12 @@ function page_manager_term_view_page($term, $depth = NULL) {
   foreach (module_implements('page_manager_override') as $module) {
     $call = $module . '_page_manager_override';
     if (($rc = $call('term_view')) && function_exists($rc)) {
-      return $rc($node);
+      return $rc($term, $depth);
     }
   }
 
   // Otherwise, fall back to replicating the output normally generated by
   // taxonomy_term_page().
-
   // Build breadcrumb based on the hierarchy of the term.
   $current = (object) array(
     'tid' => $term->tid,
@@ -296,7 +294,6 @@ function page_manager_term_view_enable($cache, $status) {
 }
 
 function page_manager_term_view_get_type() {
-//  $view_type = variable_get('page_manager_term_view_type', 'multiple');
   // Revert to just allowing single.
   $view_type = 'single';
 
@@ -369,7 +366,8 @@ function page_manager_term_view_admin_summary($task, $subtask) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
- * @return
+ *
+ * @return bool
  *   TRUE if the current user can access the page.
  */
 function page_manager_term_view_access_check($task, $subtask_id, $contexts) {
diff --git a/page_manager/plugins/tasks/user_edit.inc b/page_manager/plugins/tasks/user_edit.inc
index 6d0135dee5e4583648966bb16469e23f115659ca..3054056f1721e4445334dc8736bff34d8afa61c7 100644
--- a/page_manager/plugins/tasks/user_edit.inc
+++ b/page_manager/plugins/tasks/user_edit.inc
@@ -9,7 +9,7 @@
  */
 function page_manager_user_edit_page_manager_tasks() {
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
     'title' => t('User Edit Template'),
     'admin title' => t('User edit template'),
@@ -65,7 +65,7 @@ function page_manager_user_edit_menu_alter(&$items, $task) {
     }
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_user_edit_disabled', TRUE);
     if (!empty($GLOBALS['page_manager_enabling_user_edit'])) {
       drupal_set_message(t('Page manager module is unable to enable user/%user/edit because some other module already has overridden with %callback.', array('%callback' => $items['user/%user']['page callback'])), 'error');
@@ -97,8 +97,8 @@ function page_manager_user_edit_page($account, $category = 'account') {
   $output = ctools_context_handler_render($task, '', $contexts, array($account->uid));
   if (is_array($output)) {
     $output = drupal_render($output);
-  }  
-  if ($output != FALSE) {
+  }
+  if ($output !== FALSE) {
     return $output;
   }
 
@@ -114,21 +114,20 @@ function page_manager_user_edit_page($account, $category = 'account') {
   // Otherwise, fall back.
   if ($function == 'drupal_get_form') {
 
-    //In order to ajax fields to work we need to run form_load_include.
-    //Hence we eschew drupal_get_form and manually build the info and
-    //call drupal_build_form.
+    // In order to ajax fields to work we need to run form_load_include.
+    // Hence we eschew drupal_get_form and manually build the info and
+    // call drupal_build_form.
     $form_state = array();
     $form_id = 'user_profile_form';
-    $args = array($account);
+    $args = array($account, $category);
     $form_state['build_info']['args'] = $args;
     form_load_include($form_state, 'inc', 'user', 'user.pages');
     $output = drupal_build_form($form_id, $form_state);
     return $output;
   }
-  //fire off "view" op so that triggers still work
+  // Fire off "view" op so that triggers still work.
   // @todo -- this doesn't work anymore, and the alternatives seem bad.
   // will have to figure out how to fix this.
-  // user_module_invoke('view', $array = array(), $account);
   return $function($account);
 }
 
@@ -178,6 +177,7 @@ function page_manager_user_edit_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/plugins/tasks/user_view.inc b/page_manager/plugins/tasks/user_view.inc
index dfb4081792635ce9a45fa16b33528ab94a92ffa6..3a531c7b42385fd8002ff8c9b2b652a9a610a782 100644
--- a/page_manager/plugins/tasks/user_view.inc
+++ b/page_manager/plugins/tasks/user_view.inc
@@ -9,7 +9,7 @@
  */
 function page_manager_user_view_page_manager_tasks() {
   return array(
-    // This is a 'page' task and will fall under the page admin UI
+    // This is a 'page' task and will fall under the page admin UI.
     'task type' => 'page',
     'title' => t('User profile template'),
     'admin title' => t('User profile template'),
@@ -53,7 +53,7 @@ function page_manager_user_view_menu_alter(&$items, $task) {
     $items['user/%user']['file'] = $task['file'];
   }
   else {
-    // automatically disable this task if it cannot be enabled.
+    // Automatically disable this task if it cannot be enabled.
     variable_set('page_manager_user_view_disabled', TRUE);
     if (!empty($GLOBALS['page_manager_enabling_user_view'])) {
       drupal_set_message(t('Page manager module is unable to enable user/%user because some other module already has overridden with %callback.', array('%callback' => $items['user/%user']['page callback'])), 'error');
@@ -81,7 +81,7 @@ function page_manager_user_view_page($account) {
   user_build_content($account);
 
   $output = ctools_context_handler_render($task, '', $contexts, array($account->uid));
-  if ($output != FALSE) {
+  if ($output !== FALSE) {
     return $output;
   }
 
@@ -98,10 +98,9 @@ function page_manager_user_view_page($account) {
   if ($function == 'user_view') {
     module_load_include('inc', 'user', 'user.pages');
   }
-  //fire off "view" op so that triggers still work
+  // Fire off "view" op so that triggers still work.
   // @todo -- this doesn't work anymore, and the alternatives seem bad.
   // will have to figure out how to fix this.
-//  user_module_invoke('view', $array = array(), $account);
   return $function($account);
 }
 
@@ -152,6 +151,7 @@ function page_manager_user_view_enable($cache, $status) {
  *   The subtask id
  * @param $contexts
  *   The contexts loaded for the task.
+ *
  * @return
  *   TRUE if the current user can access the page.
  */
diff --git a/page_manager/tests/head_links.test b/page_manager/tests/head_links.test
new file mode 100644
index 0000000000000000000000000000000000000000..3a88e295bbba3ca7a601b3d6a831c170b6ecf1e6
--- /dev/null
+++ b/page_manager/tests/head_links.test
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Tests the head links for page manager pages.
+ */
+
+/**
+ * Test the head links.
+ */
+class HeadLinksTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Head links test',
+      'description' => 'Checks that the shortlink and canonical links are present on a node page overriden by Page manager',
+      'group' => 'ctools',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp('page_manager');
+
+    // First add an override for "node/%node".
+    variable_set('page_manager_node_view_disabled', FALSE);
+
+    $record = (object) array(
+      'name' => 'node_view__http_response_707659df-062d-4252-8c2a-22a8e0289cd4',
+      'task' => 'node_view',
+      'subtask' => '',
+      'handler' => 'http_response',
+      'weight' => '1',
+      'conf' => array(
+        'title' => 'Test',
+        'contexts' => array(
+          0 => array(
+            'identifier' => 'String',
+            'keyword' => 'string',
+            'name' => 'string',
+            'string' => 'Test',
+            'id' => 1,
+          ),
+        ),
+        'relationships' => array(),
+        'code' => '404',
+        'destination' => '',
+        'name' => '',
+      ),
+    );
+
+    page_manager_save_task_handler($record);
+
+    menu_rebuild();
+  }
+
+  /**
+   * Test the presence of the head links.
+   */
+  public function testHeadLinks() {
+    $node = $this->drupalCreateNode();
+    $url = 'node/' . $node->nid;
+    $this->drupalGet($url);
+
+    $shortlink = $this->xpath('//head//link[@rel="shortlink"]');
+    $this->assertEqual(url($url), (string) $shortlink[0]['href'], 'shortlink url found');
+
+    $canonical = $this->xpath('//head//link[@rel="canonical"]');
+    $this->assertEqual(url($url), (string) $canonical[0]['href'], 'canonical url found');
+  }
+
+}
diff --git a/page_manager/theme/page-manager-edit-page.tpl.php b/page_manager/theme/page-manager-edit-page.tpl.php
index 85510cd93f9e9b53003546cfbe4534804b76c127..2ea065c8abeefd4277bd3cf32290ea9b4e7db269 100644
--- a/page_manager/theme/page-manager-edit-page.tpl.php
+++ b/page_manager/theme/page-manager-edit-page.tpl.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Template for the page manager page editor.
@@ -42,7 +43,7 @@
               <div class="description">
                 <?php print $content['description']; ?>
               </div>
-              <?php endif; ?>
+            <?php endif; ?>
             <?php print $content['content']; ?>
           </div>
         </div>
@@ -50,4 +51,4 @@
     </div>
   </div>
   <?php print $save; ?>
-</div>
\ No newline at end of file
+</div>
diff --git a/page_manager/theme/page_manager.theme.inc b/page_manager/theme/page_manager.theme.inc
index 6435d1ce5984d64f4a97a81c815ddbd2e826852a..3df55a89b13b161a4fc8e59f694c0c55a71c93ea 100644
--- a/page_manager/theme/page_manager.theme.inc
+++ b/page_manager/theme/page_manager.theme.inc
@@ -27,10 +27,10 @@ function template_preprocess_page_manager_edit_page(&$vars) {
     $vars['locked'] = theme('page_manager_lock', array('page' => $page));
     $vars['changed'] = theme('page_manager_changed', array('text' => t('Locked'), 'description' => t('This page is being edited by another user and you cannot make changes to it.')));
   }
-  else if (!empty($page->new)) {
+  elseif (!empty($page->new)) {
     $vars['changed'] = theme('page_manager_changed', array('text' => t('New'), 'description' => t('This page is newly created and has not yet been saved to the database. It will not be available until you save it.')));
   }
-  else if (!empty($page->changed)) {
+  elseif (!empty($page->changed)) {
     $vars['changed'] = theme('page_manager_changed', array('text' => t('Changed'), 'description' => t('This page has been modified, but these modifications are not yet live. While modifying this page, it is locked from modification by other users.')));
   }
 
@@ -49,9 +49,9 @@ function template_preprocess_page_manager_edit_page(&$vars) {
  */
 function theme_page_manager_handler_rearrange($vars) {
   $form = &$vars['form'];
-  // Assemble the data for a table from everything in $form['handlers']
+  // Assemble the data for a table from everything in $form['handlers'].
   foreach (element_children($form['handlers']) as $id) {
-    // provide a reference shortcut.
+    // Provide a reference shortcut.
     $element = &$form['handlers'][$id];
     if (isset($element['title'])) {
       $row = array();
diff --git a/plugins/access/book.inc b/plugins/access/book.inc
new file mode 100644
index 0000000000000000000000000000000000000000..4b4f7eaaef85e3c8d22892f4742afc8e44545227
--- /dev/null
+++ b/plugins/access/book.inc
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * Plugin to provide access control based on whether a node belongs to a book.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+if (module_exists('book')) {
+  $plugin = array(
+    'title' => t("Book: node is in a book"),
+    'description' => t('Control access based upon a node belonging to a book.'),
+    'callback' => 'ctools_book_node_ctools_access_check',
+    'default' => array('book' => array()),
+    'settings form' => 'ctools_book_node_ctools_access_settings',
+    'settings form submit' => 'ctools_book_node_ctools_access_settings_submit',
+    'summary' => 'ctools_book_node_ctools_access_summary',
+    'required context' => new ctools_context_required(t('Node'), 'node'),
+  );
+}
+
+/**
+ * Settings form for the 'by book_node' access plugin.
+ */
+function ctools_book_node_ctools_access_settings($form, &$form_state, $conf) {
+  $options = array(
+    'any' => t('In any book'),
+  );
+  $books = book_get_books();
+  foreach ($books as $bid => $book) {
+    $options[$bid] = $book['title'];
+  }
+  $form['settings']['book'] = array(
+    '#title' => t('Book'),
+    '#type' => 'checkboxes',
+    '#options' => $options,
+    '#description' => t('Pass only if the node belongs to one of the selected books'),
+    '#default_value' => $conf['book'],
+    '#required' => TRUE,
+  );
+  return $form;
+}
+
+/**
+ * Check for access.
+ */
+function ctools_book_node_ctools_access_check($conf, $context) {
+  // As far as I know there should always be a context at this point, but this
+  // is safe.
+  if (empty($context) || empty($context->data) || empty($context->data->book)) {
+    return FALSE;
+  }
+
+  if ($conf['book']['any']) {
+    return !empty($context->data->book);
+  }
+
+  foreach ($conf['book'] as $bid => $value) {
+    if ($bid == 'any') {
+      continue;
+    }
+    if ($value && ($bid == $context->data->book['bid'])) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ * Provide a summary description based upon the checked node_languages.
+ */
+function ctools_book_node_ctools_access_summary($conf, $context) {
+  if ($conf['book']['any']) {
+    return t('@identifier belongs to a book', array('@identifier' => $context->identifier));
+  }
+
+  $books = array();
+  foreach ($conf['book'] as $bid => $value) {
+    if ($value) {
+      $node = node_load($bid);
+      $books[] = $node->title;
+    }
+  }
+
+  if (count($books) == 1) {
+    return t('@identifier belongs to the book "@book"', array('@book' => $books[0], '@identifier' => $context->identifier));
+  }
+
+  return t('@identifier belongs in multiple books', array('@identifier' => $context->identifier));
+}
diff --git a/plugins/access/compare_users.inc b/plugins/access/compare_users.inc
index c271ff4e3cdafcd528455e623e75c820deab43d5..e0a7f1b456ba57da386c4cfc97fa500325c1463a 100644
--- a/plugins/access/compare_users.inc
+++ b/plugins/access/compare_users.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Ctools access plugin to provide access/visiblity if two user contexts are equal.
+ * CTools access plugin to provide access/visiblity if two user contexts are equal.
  */
 
 /**
@@ -20,12 +20,12 @@ $plugin = array(
   'summary' => 'ctools_compare_users_ctools_access_summary',
   'required context' => array(
     new ctools_context_required(t('First User'), 'user'),
-    new ctools_context_required(t("Second User"), 'user')
+    new ctools_context_required(t("Second User"), 'user'),
   ),
 );
 
 /**
- * Settings form for the 'by perm' access plugin
+ * Settings form for the 'by perm' access plugin.
  */
 function ctools_compare_users_settings($form, &$form_state, $conf) {
 
diff --git a/plugins/access/context_exists.inc b/plugins/access/context_exists.inc
index aabc62dd9eece9f8be3ee7cf0b6d23870c097263..e5d2b5e27c02127194998c72530b3a15ff4bea05 100644
--- a/plugins/access/context_exists.inc
+++ b/plugins/access/context_exists.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Plugin to provide access control/visibility based on existence of a specified context
+ * Plugin to provide access control/visibility based on existence of a specified context.
  */
 
 $plugin = array(
@@ -16,7 +16,7 @@ $plugin = array(
 );
 
 /**
- * Settings form
+ * Settings form.
  */
 function ctools_context_exists_ctools_access_settings($form, &$form_state, $conf) {
   $form['settings']['exists'] = array(
@@ -29,17 +29,17 @@ function ctools_context_exists_ctools_access_settings($form, &$form_state, $conf
 }
 
 /**
- * Check for access
+ * Check for access.
  */
 function ctools_context_exists_ctools_access_check($conf, $context) {
-  // xor returns false if the two bools are the same, and true if they are not.
+  // Xor returns false if the two bools are the same, and true if they are not.
   // i.e, if we asked for context_exists and it does, return true.
   // If we asked for context does not exist and it does, return false.
   return (empty($context->data) xor !empty($conf['exists']));
 }
 
 /**
- * Provide a summary description based upon the specified context
+ * Provide a summary description based upon the specified context.
  */
 function ctools_context_exists_ctools_access_summary($conf, $context) {
   if (!empty($conf['exists'])) {
diff --git a/plugins/access/entity_bundle.inc b/plugins/access/entity_bundle.inc
index e07a048decc74700dacb03306a3f9ef81d63fc9b..fce34197d54e3c2fb729112f01678a0caaae2ec5 100644
--- a/plugins/access/entity_bundle.inc
+++ b/plugins/access/entity_bundle.inc
@@ -43,7 +43,7 @@ function ctools_entity_bundle_ctools_access_get_children($plugin, $parent) {
 }
 
 /**
- * Settings form for the 'by entity_bundle' access plugin
+ * Settings form for the 'by entity_bundle' access plugin.
  */
 function ctools_entity_bundle_ctools_access_settings($form, &$form_state, $conf) {
   $plugin = $form_state['plugin'];
@@ -133,4 +133,3 @@ function ctools_entity_bundle_ctools_access_summary($conf, $context, $plugin) {
 
   return format_plural(count($names), '@identifier is bundle "@types"', '@identifier bundle is one of "@types"', array('@types' => implode(', ', $names), '@identifier' => $context->identifier));
 }
-
diff --git a/plugins/access/entity_field_value.inc b/plugins/access/entity_field_value.inc
index ab36ca9a4e7f23d66b60f25dadad05afcd774ffb..60d2c2e020a0c8dd8e1b4579a1e339893d4f5f52 100644
--- a/plugins/access/entity_field_value.inc
+++ b/plugins/access/entity_field_value.inc
@@ -16,8 +16,8 @@ $plugin = array(
   'get child' => 'ctools_entity_field_value_ctools_access_get_child',
   'get children' => 'ctools_entity_field_value_ctools_access_get_children',
 );
-function ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $child) {
 
+function ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $child) {
   $plugins = &drupal_static(__FUNCTION__, array());
   if (empty($plugins[$parent . ':' . $child])) {
     list($entity_type, $bundle_type, $field_name) = explode(':', $child);
@@ -48,8 +48,7 @@ function ctools_entity_field_value_ctools_access_get_children($plugin, $parent)
 }
 
 function _ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $entity_type, $bundle_type, $field_name, $entity = NULL, $bundle = NULL, $field = NULL) {
-
-  // check that the entity, bundle and field arrays have a value.
+  // Check that the entity, bundle and field arrays have a value.
   // If not, load theme using machine names.
   if (empty($entity)) {
     $entity = entity_get_info($entity_type);
@@ -69,14 +68,14 @@ function _ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $e
   $plugin['description'] = t('Control access by @entity entity bundle.', array('@entity' => $entity_type));
   $plugin['name'] = $parent . ':' . $entity_type . ':' . $bundle_type . ':' . $field_name;
   $plugin['required context'] = new ctools_context_required(t(ucfirst($entity_type)), $entity_type, array(
-      'type' => $bundle_type,
-    ));
+    'type' => $bundle_type,
+  ));
 
   return $plugin;
 }
 
 /**
- * Settings form for the 'by entity_bundle' access plugin
+ * Settings form for the 'by entity_bundle' access plugin.
  */
 function ctools_entity_field_value_ctools_access_settings($form, &$form_state, $conf) {
   $plugin = $form_state['plugin'];
@@ -86,39 +85,44 @@ function ctools_entity_field_value_ctools_access_settings($form, &$form_state, $
   $instance    = $instances[$field_name];
   $field       = field_info_field_by_id($instance['field_id']);
   foreach ($field['columns'] as $column => $attributes) {
-    $columns[] = _field_sql_storage_columnname($field_name, $column);
+    $columns[$column] = _field_sql_storage_columnname($field_name, $column);
   }
   ctools_include('fields');
-  $entity = (object)array(
+  $entity = (object) array(
     $entity_info['entity keys']['bundle'] => $bundle_type,
   );
-  $langcode = field_valid_language(NULL);
-  $form['settings'] += (array) ctools_field_invoke_field($instance, 'form', $entity_type, $entity, $form, $form_state, array('default' => TRUE, 'language' => $langcode));
-  // weight is really not important once this is populated and will only interfere with the form layout.
-  foreach (element_children($form['settings']) as $element) {
-    unset($form['settings'][$element]['#weight']);
-  }
 
-  // Need more logic here to handle compound fields.
-  foreach ($columns as $column) {
-    if (isset($conf[$column]) && is_array($conf[$column])) {
-      foreach ($conf[$column] as $delta => $conf_value) {
-        if (is_numeric($delta) && is_array($conf_value)) {
-          $form['settings'][$field_name][LANGUAGE_NONE][$delta]['value']['#default_value'] = $conf_value['value'];
+  foreach ($columns as $column => $sql_column) {
+    if (isset($conf[$sql_column])) {
+      if (is_array($conf[$sql_column])) {
+        foreach ($conf[$sql_column] as $delta => $conf_value) {
+          if (is_numeric($delta)) {
+            if (is_array($conf_value)) {
+              $entity->{$field_name}[LANGUAGE_NONE][$delta][$column] = $conf_value[$column];
+            }
+            else {
+              $entity->{$field_name}[LANGUAGE_NONE][$delta][$column] = $conf_value;
+            }
+          }
         }
       }
+      else {
+        $entity->{$field_name}[LANGUAGE_NONE][0][$column] = $conf[$sql_column];
+      }
     }
-    else {
-      $form['settings'][$field_name][LANGUAGE_NONE]['#default_value'] = $conf[$column];
-    }
+  }
+
+  $form['#parents'] = array('settings');
+  $langcode = field_valid_language(NULL);
+  $form['settings'] += (array) ctools_field_invoke_field($instance, 'form', $entity_type, $entity, $form, $form_state, array('default' => TRUE, 'language' => $langcode));
+  // Weight is really not important once this is populated and will only interfere with the form layout.
+  foreach (element_children($form['settings']) as $element) {
+    unset($form['settings'][$element]['#weight']);
   }
 
   return $form;
 }
 
-/**
- * Compress the entity bundles allowed to the minimum.
- */
 function ctools_entity_field_value_ctools_access_settings_submit($form, &$form_state) {
   $plugin = $form_state['plugin'];
   list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']);
@@ -128,18 +132,78 @@ function ctools_entity_field_value_ctools_access_settings_submit($form, &$form_s
   $instance  = $instances[$field_name];
   $field     = field_info_field_by_id($instance['field_id']);
   foreach ($field['columns'] as $column => $attributes) {
-    $columns[] = _field_sql_storage_columnname($field_name, $column);
+    $columns[$column] = _field_sql_storage_columnname($field_name, $column);
+  }
+  $items = _ctools_entity_field_value_get_proper_form_items($field, $form_state['values']['settings'][$field_name][$langcode], array_keys($columns));
+  foreach ($columns as $column => $sql_column) {
+    $column_items = _ctools_entity_field_value_filter_items_by_column($items, $column);
+    $form_state['values']['settings'][$sql_column] = $column_items;
   }
+  $form_state['values']['settings'][$field_name][$langcode] = $items;
+}
+
+function _ctools_entity_field_value_get_proper_form_items($field, $form_items, $columns) {
+  $items = array();
+
+  // Single value item.
+  if (!is_array($form_items)) {
+    foreach ($columns as $column) {
+      $items[0][$column] = $form_items;
+    }
+    return $items;
+  }
+
+  foreach ($form_items as $delta => $value) {
+    $item = array();
+    if (is_numeric($delta)) { // Array of field values.
+      if (!is_array($value)) {  // Single value in array.
+        foreach ($columns as $column) {
+          $item[$column] = $value;
+        }
+      }
+      else { // Value has colums.
+        foreach ($columns as $column) {
+          $item[$column] = isset($value[$column]) ? $value[$column] : '';
+        }
+      }
+    }
+    $items[] = $item;
+  }
+
+  // Check if $form_items is an array of columns.
+  $item = array();
+  $has_columns = FALSE;
   foreach ($columns as $column) {
-    $form_state['values']['settings'][$column] = $form_state['input']['settings'][$field_name][$langcode];
+    if (isset($form_items[$column])) {
+      $has_columns = TRUE;
+      $item[$column] = $form_items[$column];
+    }
+    else {
+      $item[$column] = '';
+    }
+  }
+  if ($has_columns) {
+    $items[] = $item;
+  }
+
+  // Remove empty values.
+  $items = _field_filter_items($field, $items);
+  return $items;
+}
+
+function _ctools_entity_field_value_filter_items_by_column($items, $column) {
+  $column_items = array();
+  foreach ($items as $delta => $values) {
+    $column_items[$delta] = isset($values[$column]) ? $values[$column] : '';
   }
+  return $column_items;
 }
 
 /**
  * Check for access.
  */
 function ctools_entity_field_value_ctools_access_check($conf, $context, $plugin) {
-  if (!isset($context->data)) {
+  if ((!is_object($context)) || (empty($context->data))) {
     // If the context doesn't exist -- for example, a newly added entity
     // reference is used as a pane visibility criteria -- we deny access.
     return FALSE;
@@ -166,16 +230,27 @@ function ctools_entity_field_value_ctools_access_check($conf, $context, $plugin)
 
       // Check field value.
       foreach ($field_items as $field_value) {
-        foreach ($field_value as $field_column => $value) {
-          // Iterate through config values.
-          foreach ($conf_value_array as $conf_value) {
+        // Iterate through config values.
+        foreach ($conf_value_array as $conf_value) {
+          $match = FALSE;
+          foreach ($field_value as $field_column => $value) {
             // Check access only for stored in config column values.
-            if (isset($conf_value[$field_column]) && $value == $conf_value[$field_column]) {
-              return TRUE;
+            if (isset($conf_value[$field_column])) {
+              if ($value == $conf_value[$field_column]) {
+                $match = TRUE;
+              }
+              else {
+                $match = FALSE;
+                break;
+              }
             }
           }
+          if ($match) {
+            return TRUE;
+          }
         }
       }
+      return FALSE;
     }
   }
 
@@ -184,7 +259,7 @@ function ctools_entity_field_value_ctools_access_check($conf, $context, $plugin)
 
 function _ctools_entity_field_value_ctools_access_get_conf_field_values($values, $langcode = LANGUAGE_NONE) {
   if (!is_array($values) || !isset($values[$langcode])) {
-    return;
+    return NULL;
   }
   $conf_values = array();
 
@@ -207,41 +282,130 @@ function ctools_entity_field_value_ctools_access_summary($conf, $context, $plugi
   $entity      = (object)array(
     $entity_info['entity keys']['bundle'] => $bundle_type,
   );
-  $string = '';
   $keys   = array();
-  $values = array();
+  $value_keys = array();
+  $keyed_elements = array();
   foreach ($field['columns'] as $column => $attributes) {
     $conf_key = _field_sql_storage_columnname($field_name, $column);
-    if (count($field['columns']) > 1) {
-      // Add some sort of handling for compound fields
-    }
-    else {
-      if (isset($conf[$conf_key])) {
-        $entity->{$field_name}[LANGUAGE_NONE][] = array($column => $conf[$conf_key]);
+    $keyed_elements["@{$column}_value"] = array();
+
+    if (isset($conf[$conf_key])) {
+      if (is_array($conf[$conf_key])) {
+        $i = 0;
+        foreach ($conf[$conf_key] as $conf_value) {
+          if (!is_array($conf_value)) {
+            $entity->{$field_name}[LANGUAGE_NONE][$i][$column] = $conf_value;
+            $keyed_elements["@{$column}_value"][$i] = array('#markup' => $conf_value);
+          }
+          elseif (isset($conf_value[$column])) {
+            $entity->{$field_name}[LANGUAGE_NONE][$i][$column] = $conf_value[$column];
+            $keyed_elements["@{$column}_value"][$i] = array('#markup' => $conf_value[$column]);
+          }
+          $i++;
+        }
+      }
+      else {
+        $entity->{$field_name}[LANGUAGE_NONE][0][$column] = $conf[$conf_key];
+        $keyed_elements["@{$column}_value"][0] = array('#markup' => $conf[$conf_key]);
       }
     }
-    $string .= " @{$column} equals @{$column}_value";
+
     $keys['@' . $column] = $column;
-    $values["@{$column}_value"] = $conf[$conf_key];
+    $value_keys[] = "@{$column}_value";
   }
+  $elements = array();
+  $items = isset($entity->{$field_name}[LANGUAGE_NONE]) ? $entity->{$field_name}[LANGUAGE_NONE] : array();
   $view_mode = 'full';
-  $null      = NULL;
-  $options   = array('language' => LANGUAGE_NONE);
   ctools_include('fields');
-  $display         = field_get_display($instance, $view_mode, $entity);
+  $display = field_get_display($instance, $view_mode, $entity);
+  if (!isset($display['module'])) {
+    $display['module'] = $field['module'];
+  }
   if (isset($display['module'])) {
-    $display['type'] = 'list_default';
-    $function        = $display['module'] . '_field_formatter_view';
-    $items           = isset($entity->{$field_name}[LANGUAGE_NONE]) ? $entity->{$field_name}[LANGUAGE_NONE] : array();
+    // Choose simple formatter for well known cases.
+    switch ($display['module']) {
+      case 'text':
+        $display['type'] = 'text_default';
+        break;
+
+      case 'list':
+        $display['type'] = 'list_default';
+        if ($field['type'] == 'list_boolean') {
+          $allowed_values = list_allowed_values($field, $instance, $entity_type, $entity);
+          foreach ($items as $item) {
+            if (isset($allowed_values[$item['value']])) {
+              if ($allowed_values[$item['value']] == '') {
+                $display['type'] = 'list_key';
+                break;
+              }
+            }
+            else {
+              $display['type'] = 'list_key';
+            }
+          }
+        }
+        break;
+
+      case 'taxonomy':
+        $display['type'] = 'taxonomy_term_reference_plain';
+        break;
+
+      case 'entityreference':
+        $display['type'] = 'entityreference_label';
+        break;
+
+      default:
+        // Use field instance formatter setting.
+        break;
+    }
+
+    $function = $display['module'] . '_field_formatter_view';
     if (function_exists($function)) {
-      $elements = $function($entity_type, $entity, $field, $instance, LANGUAGE_NONE, $items, $display);
+      $entity_group = array(0 => $entity);
+      $item_group = array(0 => $items);
+      $instance_group = array(0 => $instance);
+      field_default_prepare_view($entity_type, $entity_group, $field, $instance_group, LANGUAGE_NONE, $item_group, $display);
+      $elements = $function($entity_type, $entity, $field, $instance, LANGUAGE_NONE, $item_group[0], $display);
     }
-    $value_keys = array_keys($values);
-    foreach ($value_keys as $key => $value) {
-      $values[$value] = isset($elements[$key]['#markup']) ? $elements[$key]['#markup'] : '';
+  }
+  if (count($elements) > 0) {
+    foreach ($field['columns'] as $column => $attributes) {
+      if (count($field['columns']) == 1) {
+        $keyed_elements["@{$column}_value"] = $elements;
+      }
     }
   }
-  $values = array_merge($keys, $values);
-  return t($string, $values);
+  $values = array();
+  foreach ($value_keys as $key) {
+    $output = array();
+    $elements = $keyed_elements[$key];
+    if (is_array($elements)) {
+      foreach ($elements as $element_key => $element) {
+        if (is_numeric($element_key)) {
+          $value_str = strip_tags(drupal_render($element));
+          if (strlen($value_str) > 0) {
+            $output[] = $value_str;
+          }
+        }
+      }
+    }
+    else {
+      $value_str = strip_tags(drupal_render($elements));
+      if (strlen($value_str) > 0) {
+        $output[] = $value_str;
+      }
+    }
+    $value = implode(', ', $output);
+    if ($value !== '') {
+      $values[$key] = implode(', ', $output);
+    }
+  }
+  $string = '';
+  $value_count = count($values);
+  foreach ($keys as $key_name => $column) {
+    if (isset($values[$key_name . '_value'])) {
+      $string .= ($value_count > 1) ? " @{$column} = @{$column}_value" : "@{$column}_value";
+    }
+  }
+  return t('@field is set to "!value"', array('@field' => $instance['label'], '!value' => format_string($string, array_merge($keys, $values))));
 }
-
diff --git a/plugins/access/front.inc b/plugins/access/front.inc
index 1bbc6e057bb4ca579baec42015d10f39a23eb9fa..8718a143c3af96d16fad4a5a4a261cb65959cb60 100644
--- a/plugins/access/front.inc
+++ b/plugins/access/front.inc
@@ -19,7 +19,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by parent term' access plugin
+ * Settings form for the 'by parent term' access plugin.
  */
 function ctools_front_ctools_access_settings($form, &$form_state, $conf) {
   // No additional configuration necessary.
diff --git a/plugins/access/node.inc b/plugins/access/node.inc
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/plugins/access/node_access.inc b/plugins/access/node_access.inc
index fcd275d94c11265df1ebe05d7469bcfd7f4f3d5c..c153cc5a985fc1cfd0844a9f7dea854e8bbd4ec3 100644
--- a/plugins/access/node_access.inc
+++ b/plugins/access/node_access.inc
@@ -24,7 +24,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by node_access' access plugin
+ * Settings form for the 'by node_access' access plugin.
  */
 function ctools_node_access_ctools_access_settings($form, &$form_state, $conf) {
   $form['settings']['type'] = array(
@@ -86,4 +86,3 @@ function ctools_node_access_ctools_access_summary($conf, $context) {
       return t('@user can create nodes of the same type as @node.', $replacement);
   }
 }
-
diff --git a/plugins/access/node_comment.inc b/plugins/access/node_comment.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6cebdaf8e4f59b43ac7cce7d5ccad40ae0b3dda0
--- /dev/null
+++ b/plugins/access/node_comment.inc
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Plugin to provide access control based upon node comment status.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t("Node: comments are open"),
+  'description' => t('Control access by the nodes comment status.'),
+  'callback' => 'ctools_node_comment_ctools_access_check',
+  'summary' => 'ctools_node_comment_ctools_access_summary',
+  'required context' => new ctools_context_required(t('Node'), 'node'),
+);
+
+/**
+ * Checks for access.
+ */
+function ctools_node_comment_ctools_access_check($conf, $context) {
+  return (!empty($context->data) && $context->data->comment == 2);
+}
+
+/**
+ * Provides a summary description based upon the checked node_status.
+ */
+function ctools_node_comment_ctools_access_summary($conf, $context) {
+  return t('Returns true if the nodes comment status is "open".');
+}
diff --git a/plugins/access/node_language.inc b/plugins/access/node_language.inc
index 0fdcfc66a533ef9d2318e01b6e5b6b507f60f1e2..b824331868cd44721d237114ad4388b7897d6c74 100644
--- a/plugins/access/node_language.inc
+++ b/plugins/access/node_language.inc
@@ -23,7 +23,7 @@ if (module_exists('locale')) {
 }
 
 /**
- * Settings form for the 'by node_language' access plugin
+ * Settings form for the 'by node_language' access plugin.
  */
 function ctools_node_language_ctools_access_settings($form, &$form_state, $conf) {
   $options = array(
@@ -111,4 +111,3 @@ function ctools_node_language_ctools_access_summary($conf, $context) {
 
   return format_plural(count($names), '@identifier language is "@languages"', '@identifier language is one of "@languages"', array('@languages' => implode(', ', $names), '@identifier' => $context->identifier));
 }
-
diff --git a/plugins/access/node_status.inc b/plugins/access/node_status.inc
index ad5ba4009dcf0f4f409d394fa7d63cfddc3c498b..519619bec0a1d5d521f76416693b53d5a6ed79e0 100644
--- a/plugins/access/node_status.inc
+++ b/plugins/access/node_status.inc
@@ -21,7 +21,7 @@ $plugin = array(
  * Check for access.
  */
 function ctools_node_status_ctools_access_check($conf, $context) {
-  return (!empty($context->data) && $context->data->status);
+  return (!empty($context->data->status) && $context->data->status);
 }
 
 /**
@@ -30,4 +30,3 @@ function ctools_node_status_ctools_access_check($conf, $context) {
 function ctools_node_status_ctools_access_summary($conf, $context) {
   return t('Returns true if the nodes status is "published".');
 }
-
diff --git a/plugins/access/node_type.inc b/plugins/access/node_type.inc
index 23a38453a7ffa9f4c1c6c5943095dd3abb58d048..d89532aea4886c15590026141c9c66df2f286cfb 100644
--- a/plugins/access/node_type.inc
+++ b/plugins/access/node_type.inc
@@ -22,7 +22,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by node_type' access plugin
+ * Settings form for the 'by node_type' access plugin.
  */
 function ctools_node_type_ctools_access_settings($form, &$form_state, $conf) {
   $types = node_type_get_types();
@@ -114,4 +114,3 @@ function ctools_node_type_ctools_access_summary($conf, $context) {
 
   return format_plural(count($names), '@identifier is type "@types"', '@identifier type is one of "@types"', array('@types' => implode(', ', $names), '@identifier' => $context->identifier));
 }
-
diff --git a/plugins/access/path_visibility.inc b/plugins/access/path_visibility.inc
index 60b86124e49eedcfd98699f59f8a78098450fc87..1612e1c3eab0302f863b856a137e350eaff85c40 100644
--- a/plugins/access/path_visibility.inc
+++ b/plugins/access/path_visibility.inc
@@ -11,12 +11,12 @@ $plugin = array(
   'callback' => 'ctools_path_visibility_ctools_access_check',
   'settings form' => 'ctools_path_visibility_ctools_access_settings',
   'summary' => 'ctools_path_visibility_ctools_access_summary',
-  'required context' =>  new ctools_context_optional(t('Path'), 'string'),
+  'required context' => new ctools_context_optional(t('Path'), 'string'),
   'default' => array('visibility_setting' => 1, 'paths' => ''),
 );
 
 /**
- * Settings form
+ * Settings form.
  */
 function ctools_path_visibility_ctools_access_settings($form, &$form_state, $conf) {
   $form['settings']['note'] = array(
diff --git a/plugins/access/perm.inc b/plugins/access/perm.inc
index 67516faf6f34233fea6dafc94690df9d746558d6..cb2bb81e9645eddfb1bc8012742ec3734d3a5028 100644
--- a/plugins/access/perm.inc
+++ b/plugins/access/perm.inc
@@ -20,11 +20,11 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by perm' access plugin
+ * Settings form for the 'by perm' access plugin.
  */
 function ctools_perm_ctools_access_settings($form, &$form_state, $conf) {
   $perms = array();
-  // Get list of permissions
+  // Get list of permissions.
   foreach (module_list(FALSE, FALSE, TRUE) as $module) {
     // By keeping them keyed by module we can use optgroups with the
     // 'select' type.
@@ -70,4 +70,3 @@ function ctools_perm_ctools_access_summary($conf, $context) {
   $permissions = module_invoke_all('permission');
   return t('@identifier has "@perm"', array('@identifier' => $context->identifier, '@perm' => $permissions[$conf['perm']]['title']));
 }
-
diff --git a/plugins/access/php.inc b/plugins/access/php.inc
index 35da86d9a593b1446f1ca22b30cb0815d158ef3a..4e9d05656e12cdf51933be19d53bc50120bc0243 100644
--- a/plugins/access/php.inc
+++ b/plugins/access/php.inc
@@ -20,7 +20,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by perm' access plugin
+ * Settings form for the 'by perm' access plugin.
  *
  * @todo Need a way to provide a list of all available contexts to be used by
  *       the eval-ed PHP.
@@ -38,7 +38,7 @@ function ctools_php_ctools_access_settings($form, &$form_state, $conf) {
     '#type' => 'textarea',
     '#title' => t('PHP Code'),
     '#default_value' => $conf['php'],
-    '#description' =>  t('Access will be granted if the following PHP code returns <code>TRUE</code>. Do not include &lt;?php ?&gt;. Note that executing incorrect PHP-code can break your Drupal site. All contexts will be available in the <em>$contexts</em> variable.'),
+    '#description' => t('Access will be granted if the following PHP code returns <code>TRUE</code>. Do not include &lt;?php ?&gt;. Note that executing incorrect PHP-code can break your Drupal site. All contexts will be available in the <em>$contexts</em> variable.'),
   );
   if (!user_access('use PHP for settings')) {
     $form['settings']['php']['#disabled'] = TRUE;
diff --git a/plugins/access/query_string_exists.inc b/plugins/access/query_string_exists.inc
new file mode 100644
index 0000000000000000000000000000000000000000..fb3b4334caefd283de87438d0391d00ecf439075
--- /dev/null
+++ b/plugins/access/query_string_exists.inc
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Plugin for controlling access based on the existence of a query string.
+ */
+
+$plugin = array(
+  'title' => t('Query string exists'),
+  'description' => t('Control access by whether or not a query string exists.'),
+  'callback' => 'ctools_query_string_exists_ctools_access_check',
+  'settings form' => 'ctools_query_string_exists_ctools_access_settings',
+  'summary' => 'ctools_query_string_exists_ctools_access_summary',
+  'defaults' => array('key' => ''),
+);
+
+/**
+ * Settings form.
+ */
+function ctools_query_string_exists_ctools_access_settings($form, &$form_state, $config) {
+  $form['settings']['key'] = array(
+    '#title' => t('Query string key'),
+    '#description' => t('Enter the key of the query string.'),
+    '#type' => 'textfield',
+    '#required' => TRUE,
+    '#default_value' => $config['key'],
+  );
+
+  return $form;
+}
+
+/**
+ * Check for access.
+ */
+function ctools_query_string_exists_ctools_access_check($config, $context) {
+  return isset($_GET[$config['key']]);
+}
+
+/**
+ * Provide a summary description.
+ */
+function ctools_query_string_exists_ctools_access_summary($config, $context) {
+  return t('@identifier exists', array('@identifier' => $config['key']));
+}
diff --git a/plugins/access/role.inc b/plugins/access/role.inc
index b6332544fee5d8b33fa582cfe093ba6306b26e9c..4d8cbae12c786d1269f54b72990c186f95333f8e 100644
--- a/plugins/access/role.inc
+++ b/plugins/access/role.inc
@@ -21,7 +21,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by role' access plugin
+ * Settings form for the 'by role' access plugin.
  */
 function ctools_role_ctools_access_settings($form, &$form_state, $conf) {
   $form['settings']['rids'] = array(
@@ -76,4 +76,3 @@ function ctools_role_ctools_access_summary($conf, $context) {
 
   return format_plural(count($names), '@identifier has role "@roles"', '@identifier has one of "@roles"', array('@roles' => implode(', ', $names), '@identifier' => $context->identifier));
 }
-
diff --git a/plugins/access/site_language.inc b/plugins/access/site_language.inc
index 9ff2f70c8f144a57c5a0e33bc6651021878bfdbf..5b7b724ca089eca6b9d80ea1690618527d3b3a59 100644
--- a/plugins/access/site_language.inc
+++ b/plugins/access/site_language.inc
@@ -22,7 +22,7 @@ if (module_exists('locale')) {
 }
 
 /**
- * Settings form for the 'by site_language' access plugin
+ * Settings form for the 'by site_language' access plugin.
  */
 function ctools_site_language_ctools_access_settings($form, &$form_state, $conf) {
   $options = array(
@@ -84,4 +84,3 @@ function ctools_site_language_ctools_access_summary($conf, $context) {
 
   return format_plural(count($names), 'Site language is "@languages"', 'Site language is one of "@languages"', array('@languages' => implode(', ', $names)));
 }
-
diff --git a/plugins/access/string_equal.inc b/plugins/access/string_equal.inc
index ad1c88d82f3251f7f451f8c3b5d325a5f39da345..feb48e9c31d1d211e3e3f7a36e5f42ad62ff329d 100644
--- a/plugins/access/string_equal.inc
+++ b/plugins/access/string_equal.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Plugin to provide access control/visibility based on specified context string matching user-specified string
+ * Plugin to provide access control/visibility based on specified context string matching user-specified string.
  */
 
 $plugin = array(
@@ -16,7 +16,7 @@ $plugin = array(
 );
 
 /**
- * Settings form
+ * Settings form.
  */
 function ctools_string_equal_ctools_access_settings($form, &$form_state, $conf) {
   $form['settings']['operator'] = array(
@@ -47,7 +47,7 @@ function ctools_string_equal_ctools_access_settings($form, &$form_state, $conf)
 }
 
 /**
- * Check for access
+ * Check for access.
  */
 function ctools_string_equal_ctools_access_check($conf, $context) {
   if (empty($context) || empty($context->data)) {
@@ -66,29 +66,34 @@ function ctools_string_equal_ctools_access_check($conf, $context) {
   switch ($conf['operator']) {
     case '=':
       return $string === $value;
+
     case '!=':
       return $string !== $value;
+
     case 'regex':
       return preg_match($value, $string);
+
     case '!regex':
       return !preg_match($value, $string);
   }
 }
 
 /**
- * Provide a summary description based upon the specified context
+ * Provide a summary description based upon the specified context.
  */
 function ctools_string_equal_ctools_access_summary($conf, $context) {
   $values = array('@identifier' => $context->identifier, '@value' => $conf['value']);
   switch ($conf['operator']) {
     case '=':
       return t('@identifier is "@value"', $values);
+
     case '!=':
       return t('@identifier is not "@value"', $values);
+
     case 'regex':
       return t('@identifier matches "@value"', $values);
+
     case '!regex':
       return t('@identifier does not match "@value"', $values);
   }
 }
-
diff --git a/plugins/access/string_length.inc b/plugins/access/string_length.inc
index 2bad6afb17a9e5f84764188cc9321c67d1657b66..3af504b9eddf6c23c3401f1d1f288252f86dbcfe 100644
--- a/plugins/access/string_length.inc
+++ b/plugins/access/string_length.inc
@@ -57,17 +57,24 @@ function ctools_string_length_ctools_access_check($conf, $context) {
   switch ($conf['operator']) {
     case '<':
       return $length < $conf['length'];
+
     case '<=':
       return $length <= $conf['length'];
-    case '==':
+
+    case '=':
       return $length == $conf['length'];
+
     case '!=':
       return $length != $conf['length'];
+
     case '>':
       return $length > $conf['length'];
+
     case '>=':
       return $length >= $conf['length'];
   }
+  // Invalid Operator sent, return FALSE.
+  return FALSE;
 }
 
 /**
diff --git a/plugins/access/term.inc b/plugins/access/term.inc
index 36e70de47662c9e891656fb97d2ec8c2045da68d..224a00c6f84d8b7728d941902e2bb844c27994c5 100644
--- a/plugins/access/term.inc
+++ b/plugins/access/term.inc
@@ -15,14 +15,14 @@ $plugin = array(
   'callback' => 'ctools_term_ctools_access_check',
   'default' => array('vids' => array()),
   'settings form' => 'ctools_term_ctools_access_settings',
-  'settings form validation' => 'ctools_term_ctools_access_settings_validate',
+  'settings form validate' => 'ctools_term_ctools_access_settings_validate',
   'settings form submit' => 'ctools_term_ctools_access_settings_submit',
   'summary' => 'ctools_term_ctools_access_summary',
   'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')),
 );
 
 /**
- * Settings form for the 'by term' access plugin
+ * Settings form for the 'by term' access plugin.
  */
 function ctools_term_ctools_access_settings($form, &$form_state, $conf) {
   // If no configuration was saved before, set some defaults.
@@ -51,7 +51,6 @@ function ctools_term_ctools_access_settings($form, &$form_state, $conf) {
   // A note: Dependency works strangely on these forms as they have never been
   // updated to a more modern system so they are not individual forms of their
   // own like the content types.
-
   $form['settings']['#tree'] = TRUE;
 
   // Loop over each of the configured vocabularies.
@@ -124,6 +123,8 @@ function ctools_term_ctools_access_summary($conf, $context) {
   return format_plural(count($terms),
     '@term can be the term "@terms"',
     '@term can be one of these terms: @terms',
-    array('@terms' => implode(', ', $terms),
-      '@term' => $context->identifier));
+    array(
+      '@terms' => implode(', ', $terms),
+      '@term' => $context->identifier,
+    ));
 }
diff --git a/plugins/access/term_has_parent.inc b/plugins/access/term_has_parent.inc
index a079e92af7d377d01d8eb543bb4a0ffcf4772fa1..fd9351d9cacabb4d6ef192d51281b1e252f79668 100644
--- a/plugins/access/term_has_parent.inc
+++ b/plugins/access/term_has_parent.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Plugin to provide access control based upon a parent term.
@@ -20,7 +21,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by parent term' access plugin
+ * Settings form for the 'by parent term' access plugin.
  */
 function ctools_term_has_parent_ctools_access_settings($form, &$form_state, $conf) {
   // If no configuration was saved before, set some defaults.
@@ -37,7 +38,7 @@ function ctools_term_has_parent_ctools_access_settings($form, &$form_state, $con
     '#title' => t('Vocabulary'),
     '#type' => 'select',
     '#options' => array(),
-    '#description' => t('Select the vocabulary for this form.'),
+    '#description' => t('Select the vocabulary your parent term belongs to.'),
     '#id' => 'ctools-select-vid',
     '#default_value' => $conf['vid'],
     '#required' => TRUE,
@@ -49,7 +50,6 @@ function ctools_term_has_parent_ctools_access_settings($form, &$form_state, $con
   // A note: Dependency works strangely on these forms as they have never been
   // updated to a more modern system so they are not individual forms of their
   // own like the content types.
-
   $form['settings']['#tree'] = TRUE;
 
   // Loop over each of the configured vocabularies.
@@ -57,12 +57,12 @@ function ctools_term_has_parent_ctools_access_settings($form, &$form_state, $con
     $options[$vid] = $vocabulary->name;
     $form['settings']['vid_' . $vid] = array(
       '#title' => t('Terms'),
-      '#description' => t('Select a term or terms from @vocabulary.', array('@vocabulary' => $vocabulary->name)),
+      '#description' => t('Select a parent term (or terms) from the @vocabulary vocabulary.', array('@vocabulary' => $vocabulary->name)),
       '#dependency' => array('ctools-select-vid' => array($vocabulary->vid)),
       '#default_value' => !empty($conf['vid_' . $vid]) ? $conf['vid_' . $vid] : '',
       '#size' => 10,
       '#multiple' => TRUE,
-      //@todo: Remove the following workaround when the following patch is in core. {@see:http://drupal.org/node/1117526}
+      // @todo: Remove the following workaround when the following patch is in core. {@see:http://drupal.org/node/1117526}
       '#name' => sprintf("settings[%u][]", $vid),
       '#attributes' => array('multiple' => 'multiple'),
     );
@@ -71,15 +71,14 @@ function ctools_term_has_parent_ctools_access_settings($form, &$form_state, $con
     foreach (taxonomy_get_tree($vocabulary->vid) as $term) {
       $terms[$term->tid] = str_repeat('-', $term->depth) . ($term->depth ? ' ' : '') . $term->name;
     }
-    //$form['settings']['vid_' . $vid]['#type'] = 'select';
     $form['settings']['vid_' . $vid]['#type'] = 'checkboxes';
     $form['settings']['vid_' . $vid]['#options'] = $terms;
     unset($terms);
   }
   $form['settings']['vid']['#options'] = $options;
   $form['settings']['include_self'] = array(
-    '#title' => t('Include these term(s) as candidates?'),
-    '#description' => t('When this rule is evaluated, should the term(s) you select be included as candidates for access?'),
+    '#title' => t('Include these parent term(s)?'),
+    '#description' => t('Should the term(s) you selected above be included in addition to their children?'),
     '#default_value' => !empty($conf['include_self']) ? $conf['include_self'] : FALSE,
     '#type' => 'checkbox',
   );
@@ -116,37 +115,36 @@ function ctools_term_has_parent_ctools_access_check($conf, $context) {
   // we'll start looking up the hierarchy from our context term id.
   $current_term = $context->data->tid;
 
-  $term='';
+  $term = '';
 
-  // scan up the tree.
-  while (true) {
-    // select parent as term_parent to avoid PHP5 complications with the parent keyword
-    //@todo: Find a way to reduce the number of queries required for really deep hierarchies.
-    $term = db_query("SELECT parent AS term_parent, tid AS tid FROM {taxonomy_term_hierarchy} th WHERE th.tid = :tid", array(':tid'=>$current_term))->fetchObject();
+  // Scan up the tree.
+  while (TRUE) {
+    // Select parent as term_parent to avoid PHP5 complications with the parent keyword.
+    // @todo: Find a way to reduce the number of queries required for really deep hierarchies.
+    $term = db_query("SELECT parent AS term_parent, tid AS tid FROM {taxonomy_term_hierarchy} th WHERE th.tid = :tid", array(':tid' => $current_term))->fetchObject();
 
-    // if no term is found, get out of the loop
+    // If no term is found, get out of the loop.
     if (!$term || empty($term->tid)) {
       break;
     }
 
-    // check the term selected, if the user asked it to.
+    // Check the term selected, if the user asked it to.
     if (!empty($conf['include_self']) && isset($conf['vid_' . $vid][$term->tid])) {
       return TRUE;
     }
 
-    // did we find the parent TID we were looking for?
+    // Did we find the parent TID we were looking for?
     if (isset($conf['vid_' . $vid][$term->tid])) {
       // YES, we're done!
       return TRUE;
     }
     // Nope, we didn't find it.
-
     // If this is the top of the hierarchy, stop scanning.
-    if ($term->term_parent==0) {
+    if ($term->term_parent == 0) {
       break;
     }
 
-    // update the parent, and keep scanning.
+    // Update the parent, and keep scanning.
     $current_term = $term->term_parent;
   }
 
@@ -157,7 +155,7 @@ function ctools_term_has_parent_ctools_access_check($conf, $context) {
  * Provide a summary description based upon the checked terms.
  */
 function ctools_term_has_parent_ctools_access_summary($conf, $context) {
-  $vid = (int)$conf['vid'];
+  $vid = (int) $conf['vid'];
   $terms = array();
   foreach ($conf['vid_' . $vid] as $tid) {
     $term = taxonomy_term_load($tid);
@@ -167,6 +165,8 @@ function ctools_term_has_parent_ctools_access_summary($conf, $context) {
   return format_plural(count($terms),
     '@term can have the parent "@terms"',
     '@term can have one of these parents: @terms',
-    array('@terms' => implode(', ', $terms),
-      '@term' => $context->identifier));
+    array(
+      '@terms' => implode(', ', $terms),
+      '@term' => $context->identifier,
+    ));
 }
diff --git a/plugins/access/term_parent.inc b/plugins/access/term_parent.inc
index acbaf8720e1de6d45c900ca4f50476ae4bfbabb9..0fddc020df181159745b567aaad22f1241185507 100644
--- a/plugins/access/term_parent.inc
+++ b/plugins/access/term_parent.inc
@@ -15,14 +15,14 @@ $plugin = array(
   'callback' => 'ctools_term_parent_ctools_access_check',
   'default' => array('vid' => array(), 'negate' => 0),
   'settings form' => 'ctools_term_parent_ctools_access_settings',
-  'settings form validation' => 'ctools_term_parent_ctools_access_settings_validate',
+  'settings form validate' => 'ctools_term_parent_ctools_access_settings_validate',
   'settings form submit' => 'ctools_term_parent_ctools_access_settings_submit',
   'summary' => 'ctools_term_parent_ctools_access_summary',
   'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')),
 );
 
 /**
- * Settings form for the 'by parent term' access plugin
+ * Settings form for the 'by parent term' access plugin.
  */
 function ctools_term_parent_ctools_access_settings($form, &$form_state, $conf) {
   // If no configuration was saved before, set some defaults.
diff --git a/plugins/access/term_vocabulary.inc b/plugins/access/term_vocabulary.inc
index b003138dffdd3dd46bd680d2fd096e6e92f7e8c8..8e9a0cafbdb4c7356b639dd3aedaed43c7603f89 100644
--- a/plugins/access/term_vocabulary.inc
+++ b/plugins/access/term_vocabulary.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Plugin to provide access control based upon term vocabulary
+ * Plugin to provide access control based upon term vocabulary.
  */
 
 /**
@@ -20,12 +20,12 @@ $plugin = array(
   'required context' => new ctools_context_required(t('Vocabulary'), array(
     'taxonomy_term',
     'terms',
-    'taxonomy_vocabulary'
+    'taxonomy_vocabulary',
   )),
 );
 
 /**
- * Settings form for the 'by term_vocabulary' access plugin
+ * Settings form for the 'by term_vocabulary' access plugin.
  */
 function ctools_term_vocabulary_ctools_access_settings($form, &$form_state, $conf) {
   $options = array();
@@ -101,7 +101,7 @@ function ctools_term_vocabulary_ctools_access_summary($conf, $context) {
 
   return format_plural(count($names), '@identifier vocabulary is "@machine_names"', '@identifier vocabulary is one of "@machine_names"', array(
     '@machine_names' => implode(', ', $names),
-    '@identifier' => $context->identifier
+    '@identifier' => $context->identifier,
   ));
 }
 
@@ -123,5 +123,3 @@ function _ctools_term_vocabulary_ctools_access_map_vids(&$conf) {
     }
   }
 }
-
-
diff --git a/plugins/access/theme.inc b/plugins/access/theme.inc
index 4f4be6ded916560a7da8873db4d1237aa4cc580d..67e3e6f07461df164faa3ba0355d624d5ad92471 100644
--- a/plugins/access/theme.inc
+++ b/plugins/access/theme.inc
@@ -19,7 +19,7 @@ $plugin = array(
 );
 
 /**
- * Settings form for the 'by theme' access plugin
+ * Settings form for the 'by theme' access plugin.
  */
 function ctools_theme_ctools_access_settings($form, &$form_state, $conf) {
   $themes = array();
@@ -44,10 +44,10 @@ function ctools_theme_ctools_access_check($conf, $context) {
   if (!empty($GLOBALS['theme'])) {
     $theme = $GLOBALS['theme'];
   }
-  else if (!empty($GLOBALS['custom_theme'])) {
+  elseif (!empty($GLOBALS['custom_theme'])) {
     $theme = $GLOBALS['custom_theme'];
   }
-  else if (!empty($GLOBALS['user']->theme)) {
+  elseif (!empty($GLOBALS['user']->theme)) {
     $theme = $GLOBALS['user']->theme;
   }
   else {
diff --git a/plugins/arguments/entity_id.inc b/plugins/arguments/entity_id.inc
index 451d444cbe9fd9564727d552425e8bc1a29b2b2c..73bfe1e1bc63209cf2fcf478b5feee3e09016924 100644
--- a/plugins/arguments/entity_id.inc
+++ b/plugins/arguments/entity_id.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for all entity ids
+ * Plugin to provide an argument handler for all entity ids.
  */
 
 /**
@@ -16,6 +15,10 @@ $plugin = array(
   'context' => 'ctools_argument_entity_id_context',
   'get child' => 'ctools_argument_entity_id_get_child',
   'get children' => 'ctools_argument_entity_id_get_children',
+  'default' => array(
+    'entity_id' => '',
+  ),
+  'placeholder form' => 'ctools_argument_entity_id_ctools_argument_placeholder',
 );
 
 function ctools_argument_entity_id_get_child($plugin, $parent, $child) {
@@ -37,6 +40,7 @@ function ctools_argument_entity_id_get_children($original_plugin, $parent) {
     $plugins[$plugin_id] = $plugin;
   }
   drupal_alter('ctools_entity_contexts', $plugins);
+
   return $plugins;
 }
 
@@ -56,15 +60,87 @@ function ctools_argument_entity_id_context($arg = NULL, $conf = NULL, $empty = F
     return ctools_context_create('entity:' . $entity_type, $arg);
   }
 
+  // Trim spaces and other garbage.
+  $arg = trim($arg);
+
   if (!is_numeric($arg)) {
+    $preg_matches = array();
+    $match = preg_match('/\[id: (\d+)\]/', $arg, $preg_matches);
+    if (!$match) {
+      $match = preg_match('/^id: (\d+)/', $arg, $preg_matches);
+    }
+
+    if ($match) {
+      $id = $preg_matches[1];
+    }
+    if (isset($id) && is_numeric($id)) {
+      return ctools_context_create('entity:' . $entity_type, $id);
+    }
     return FALSE;
   }
 
-  $entity = entity_load($entity_type, array($arg));
-  if (!$entity) {
+  $entities = entity_load($entity_type, array($arg));
+  if (empty($entities)) {
     return FALSE;
   }
 
-  return ctools_context_create('entity:' . $entity_type, $entity[$arg]);
+  return ctools_context_create('entity:' . $entity_type, reset($entities));
 }
 
+function ctools_argument_entity_id_settings_form(&$form, &$form_state, $conf) {
+  $plugin = &$form_state['plugin'];
+
+  $form['settings']['entity'] = array(
+    '#title' => t('Enter the title or ID of a @entity entity', array('@entity' => $plugin['keyword'])),
+    '#type' => 'textfield',
+    '#maxlength' => 512,
+    '#autocomplete_path' => 'ctools/autocomplete/' . $plugin['keyword'],
+    '#weight' => -10,
+  );
+
+  if (!empty($conf['entity_id'])) {
+    $info = entity_load($plugin['keyword'], array($conf['entity_id']));
+    $info = $info[$conf['entity_id']];
+    if ($info) {
+      $entity = entity_get_info($plugin['keyword']);
+      $uri = entity_uri($plugin['keyword'], $info);
+      if (is_array($uri) && $entity['entity keys']['label']) {
+        $link = l(t("'%title' [%type id %id]", array('%title' => $info->{$entity['entity keys']['label']}, '%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), $uri['path'], array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE));
+      }
+      elseif (is_array($uri)) {
+        $link = l(t("[%type id %id]", array('%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), $uri['path'], array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE));
+      }
+      elseif ($entity['entity keys']['label']) {
+        $link = l(t("'%title' [%type id %id]", array('%title' => $info->{$entity['entity keys']['label']}, '%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), file_create_url($uri), array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE));
+      }
+      else {
+        $link = t("[%type id %id]", array('%type' => $plugin['keyword'], '%id' => $conf['entity_id']));
+      }
+      $form['settings']['entity']['#description'] = t('Currently set to !link', array('!link' => $link));
+    }
+  }
+
+  $form['settings']['entity_id'] = array(
+    '#type' => 'value',
+    '#value' => isset($conf['entity_id']) ? $conf['entity_id'] : '',
+  );
+
+  $form['settings']['entity_type'] = array(
+    '#type' => 'value',
+    '#value' => $plugin['keyword'],
+  );
+
+  return $form;
+}
+
+function ctools_argument_entity_id_ctools_argument_placeholder($conf) {
+  $conf = array(
+    '#title' => t('Enter the title or ID of a @entity entity', array('@entity' => $conf['keyword'])),
+    '#type' => 'textfield',
+    '#maxlength' => 512,
+    '#autocomplete_path' => 'ctools/autocomplete/' . $conf['keyword'],
+    '#weight' => -10,
+  );
+
+  return $conf;
+}
diff --git a/plugins/arguments/nid.inc b/plugins/arguments/nid.inc
index 9aaec0e1fa056babfb459ef53360791d74cc4f12..cbb56d3ebfa2d9ce36f46846408d4098e60245ad 100644
--- a/plugins/arguments/nid.inc
+++ b/plugins/arguments/nid.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a node id
+ * Plugin to provide an argument handler for a node id.
  */
 
 /**
@@ -47,4 +46,3 @@ function ctools_argument_nid_context($arg = NULL, $conf = NULL, $empty = FALSE)
 
   return ctools_context_create('node', $node);
 }
-
diff --git a/plugins/arguments/node_add.inc b/plugins/arguments/node_add.inc
index c811311b0207a76887dc319f4571e7b0edb41c70..f249a945c57f318d6abfb6189923dee9c1841e7a 100644
--- a/plugins/arguments/node_add.inc
+++ b/plugins/arguments/node_add.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a Node add form
+ * Plugin to provide an argument handler for a Node add form.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("Node add form: node type"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'node_type',
   'description' => t('Creates a node add form context from a node type argument.'),
   'context' => 'ctools_node_add_context',
@@ -29,4 +28,3 @@ function ctools_node_add_context($arg = NULL, $conf = NULL, $empty = FALSE) {
 
   return ctools_context_create('node_add_form', $arg);
 }
-
diff --git a/plugins/arguments/node_edit.inc b/plugins/arguments/node_edit.inc
index c7cdf29e83e8ff1fc3b289ee3331292dae32b2a7..8bd076895a01887e11a14518d68d7460ca0684be 100644
--- a/plugins/arguments/node_edit.inc
+++ b/plugins/arguments/node_edit.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a Node edit form
+ * Plugin to provide an argument handler for a Node edit form.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("Node edit form: node ID"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'node',
   'description' => t('Creates a node edit form context from a node ID argument.'),
   'context' => 'ctools_node_edit_context',
@@ -48,4 +47,3 @@ function ctools_node_edit_context($arg = NULL, $conf = NULL, $empty = FALSE) {
   // This will perform a node_access check, so we don't have to.
   return ctools_context_create('node_edit_form', $node);
 }
-
diff --git a/plugins/arguments/rid.inc b/plugins/arguments/rid.inc
index 2661153b24946fbf2f33b472338962e486f401ed..d0cc30c40306f89a56651944988a81df4bc5ed0a 100644
--- a/plugins/arguments/rid.inc
+++ b/plugins/arguments/rid.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a node revision id
+ * Plugin to provide an argument handler for a node revision id.
  */
 
 /**
@@ -47,4 +46,3 @@ function ctools_argument_rid_context($arg = NULL, $conf = NULL, $empty = FALSE)
 
   return ctools_context_create('node', $node);
 }
-
diff --git a/plugins/arguments/string.inc b/plugins/arguments/string.inc
index ed4ffbb63a47cfe290667dd67aeaf6d9ad8a2ad3..005e40eab31acf5ec5b4ac642c26efdc2754e0ab 100644
--- a/plugins/arguments/string.inc
+++ b/plugins/arguments/string.inc
@@ -2,16 +2,16 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a raw string
+ * Plugin to provide an argument handler for a raw string.
  */
+
 /**
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
 $plugin = array(
   'title' => t("String"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'string',
   'description' => t('A string is a minimal context that simply holds a string that can be used for some other purpose.'),
   'settings form' => 'ctools_string_settings_form',
@@ -20,7 +20,8 @@ $plugin = array(
     '#type' => 'textfield',
     '#description' => t('Enter a value for this argument'),
   ),
-  'path placeholder' => 'ctools_string_path_placeholder', // This is in pagemanager.
+// This is in pagemanager.
+  'path placeholder' => 'ctools_string_path_placeholder',
 );
 
 /**
@@ -39,7 +40,7 @@ function ctools_string_context($arg = NULL, $conf = NULL, $empty = FALSE) {
 }
 
 /**
- * Settings form for the argument
+ * Settings form for the argument.
  */
 function ctools_string_settings_form(&$form, &$form_state, $conf) {
   $form['settings']['use_tail'] = array(
@@ -48,7 +49,6 @@ function ctools_string_settings_form(&$form, &$form_state, $conf) {
     '#default_value' => !empty($conf['use_tail']),
     '#description' => t('If checked, this string will include all arguments. For example, if the path is "path/%" and the user visits "path/foo/bar", if this is not checked the string will be "foo". If it is checked the string will be "foo/bar".'),
   );
-//  return $form;
 }
 
 /**
@@ -61,4 +61,4 @@ function ctools_string_path_placeholder($argument) {
   else {
     return '%pm_arg_tail';
   }
-}
\ No newline at end of file
+}
diff --git a/plugins/arguments/term.inc b/plugins/arguments/term.inc
index 868c8aa5ee5c90a325789d9113bedf2b083d0a3b..f72e93da62f418f16c41aba72306f68cc26a40f5 100644
--- a/plugins/arguments/term.inc
+++ b/plugins/arguments/term.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a Taxonomy term
+ * Plugin to provide an argument handler for a Taxonomy term.
  */
 
 /**
@@ -12,12 +11,13 @@
  */
 $plugin = array(
   'title' => t("Taxonomy term: ID"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'term',
   'description' => t('Creates a single taxonomy term from a taxonomy ID or taxonomy term name.'),
   'context' => 'ctools_term_context',
   'default' => array('input_form' => 'tid', 'breadcrumb' => TRUE, 'transform' => FALSE),
   'settings form' => 'ctools_term_settings_form',
+  'settings form validate' => 'ctools_term_settings_form_validate',
   'placeholder form' => 'ctools_term_ctools_argument_placeholder',
   'breadcrumb' => 'ctools_term_breadcrumb',
 );
@@ -31,6 +31,16 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
     return ctools_context_create_empty('entity:taxonomy_term');
   }
 
+  if (isset($conf['vocabularies'])) {
+    $vocabularies = $conf['vocabularies'];
+  }
+  else {
+    $vids = isset($conf['vids']) ? $conf['vids'] : array();
+
+    // Convert legacy use of vids to machine names.
+    $vocabularies = _ctools_term_vocabulary_machine_name_convert($vids);
+  }
+
   if (is_object($arg)) {
     $term = $arg;
   }
@@ -50,14 +60,13 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
         }
 
         $terms = taxonomy_get_term_by_name($arg);
-
-        $conf['vids'] = is_array($conf['vids']) ? array_filter($conf['vids']) : NULL;
-        if ((count($terms) > 1) && isset($conf['vids'])) {
+        // If only one term is found, fall through to vocabulary check below.
+        if ((count($terms) > 1) && $vocabularies) {
           foreach ($terms as $potential) {
-            foreach ($conf['vids'] as $vid => $active) {
-              if ($active && $potential->vid == $vid) {
+            foreach ($vocabularies as $machine_name) {
+              if ($potential->vocabulary_machine_name == $machine_name) {
                 $term = $potential;
-                // break out of the foreaches AND the case
+                // Break out of the foreaches AND the case.
                 break 3;
               }
             }
@@ -72,7 +81,7 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
     }
   }
 
-  if (!empty($conf['vids']) && array_filter($conf['vids']) && empty($conf['vids'][$term->vid])) {
+  if ($vocabularies && !isset($vocabularies[$term->vocabulary_machine_name])) {
     return NULL;
   }
 
@@ -82,7 +91,7 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
 }
 
 /**
- * Settings form for the argument
+ * Settings form for the argument.
  */
 function ctools_term_settings_form(&$form, &$form_state, $conf) {
   // @todo allow synonym use like Views does.
@@ -98,13 +107,20 @@ function ctools_term_settings_form(&$form, &$form_state, $conf) {
   $vocabularies = taxonomy_get_vocabularies();
   $options = array();
   foreach ($vocabularies as $vid => $vocab) {
-    $options[$vid] = $vocab->name;
+    $options[$vocab->machine_name] = $vocab->name;
   }
-  $form['settings']['vids'] = array(
+
+  // Fallback on legacy 'vids', when no vocabularies are available.
+  if (empty($conf['vocabularies']) && !empty($conf['vids'])) {
+    $conf['vocabularies'] = _ctools_term_vocabulary_machine_name_convert(array_filter($conf['vids']));
+    unset($conf['vids']);
+  }
+
+  $form['settings']['vocabularies'] = array(
     '#title' => t('Limit to these vocabularies'),
     '#type' => 'checkboxes',
     '#options' => $options,
-    '#default_value' => !empty($conf['vids']) ? $conf['vids'] : array(),
+    '#default_value' => !empty($conf['vocabularies']) ? $conf['vocabularies'] : array(),
     '#description' => t('If no vocabularies are checked, terms from all vocabularies will be accepted.'),
   );
 
@@ -120,7 +136,12 @@ function ctools_term_settings_form(&$form, &$form_state, $conf) {
     '#type' => 'checkbox',
     '#default_value' => !empty($conf['transform']),
   );
-//  return $form;
+}
+
+function ctools_term_settings_form_validate(&$form, &$form_state) {
+  // Filter the selected vocabularies to avoid storing redundant data.
+  $vocabularies = array_filter($form_state['values']['settings']['vocabularies']);
+  form_set_value($form['settings']['vocabularies'], $vocabularies, $form_state);
 }
 
 /**
@@ -134,6 +155,7 @@ function ctools_term_ctools_argument_placeholder($conf) {
         '#type' => 'textfield',
         '#description' => t('Enter a taxonomy term ID.'),
       );
+
     case 'term':
       return array(
         '#type' => 'textfield',
@@ -161,3 +183,21 @@ function ctools_term_breadcrumb($conf, $context) {
   $breadcrumb = array_merge(drupal_get_breadcrumb(), array_reverse($breadcrumb));
   drupal_set_breadcrumb($breadcrumb);
 }
+
+/**
+ * Helper function to convert convert legacy vocabulary ids into machine names.
+ *
+ * @param array $vids
+ *   Array of either vids.
+ *
+ * @return array
+ *   A keyed array of machine names.
+ */
+function _ctools_term_vocabulary_machine_name_convert($vids) {
+  $vocabularies = taxonomy_vocabulary_load_multiple($vids);
+  $return = array();
+  foreach ($vocabularies as $vocabulary) {
+    $return[$vocabulary->machine_name] = $vocabulary->machine_name;
+  }
+  return $return;
+}
diff --git a/plugins/arguments/terms.inc b/plugins/arguments/terms.inc
index 4298ea91dd388a7e6c5f7e75d9a830400484513a..b816e1cbe4d61b8642c77fea31b741089a48ac7f 100644
--- a/plugins/arguments/terms.inc
+++ b/plugins/arguments/terms.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a Taxonomy term
+ * Plugin to provide an argument handler for a Taxonomy term.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("Taxonomy term (multiple): ID"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'term',
   'description' => t('Creates a group of taxonomy terms from a list of tids separated by a comma or a plus sign. In general the first term of the list will be used for panes.'),
   'context' => 'ctools_terms_context',
@@ -45,7 +44,7 @@ function ctools_terms_context($arg = NULL, $conf = NULL, $empty = FALSE) {
 }
 
 /**
- * Settings form for the argument
+ * Settings form for the argument.
  */
 function ctools_terms_settings_form(&$form, &$form_state, $conf) {
   $form['settings']['breadcrumb'] = array(
@@ -54,7 +53,6 @@ function ctools_terms_settings_form(&$form, &$form_state, $conf) {
     '#default_value' => !empty($conf['breadcrumb']),
     '#description' => t('If checked, taxonomy term parents will appear in the breadcrumb trail.'),
   );
-//  return $form;
 }
 
 /**
@@ -65,6 +63,7 @@ function ctools_terms_breadcrumb($conf, $context) {
     return;
   }
 
+  $current = new stdClass();
   $current->tid = $context->tids[0];
   $breadcrumb = array();
   while ($parents = taxonomy_get_parents($current->tid)) {
diff --git a/plugins/arguments/uid.inc b/plugins/arguments/uid.inc
index f9d5315cc326f79e87ba519de20b054971250289..c6ca3cccb64858881a3a3e91d9f2b1b7aaa556f1 100644
--- a/plugins/arguments/uid.inc
+++ b/plugins/arguments/uid.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a user id
+ * Plugin to provide an argument handler for a user id.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("User: ID"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'user',
   'description' => t('Creates a user context from a user ID argument.'),
   'context' => 'ctools_argument_uid_context',
@@ -21,7 +20,8 @@ $plugin = array(
     '#description' => t('Enter the user ID of a user for this argument'),
   ),
   'default' => array('to_arg' => TRUE),
-  'path placeholder' => '%pm_uid_arg', // This is in pagemanager.
+// This is in pagemanager.
+  'path placeholder' => '%pm_uid_arg',
   'path placeholder to_arg' => TRUE,
   'no ui' => TRUE,
 );
diff --git a/plugins/arguments/user_edit.inc b/plugins/arguments/user_edit.inc
index 32b2b812abca85465df138b4474321e9f7b4eebb..9c52b589c8083dfd010701272b71681152f2ca40 100644
--- a/plugins/arguments/user_edit.inc
+++ b/plugins/arguments/user_edit.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a Taxonomy term
+ * Plugin to provide an argument handler for a Taxonomy term.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("User edit form: User ID"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'user',
   'description' => t('Creates a user edit form context from a user ID argument.'),
   'context' => 'ctools_user_edit_context',
@@ -30,18 +29,18 @@ function ctools_user_edit_context($arg = NULL, $conf = NULL, $empty = FALSE) {
   if ($empty) {
     return ctools_context_create_empty('user_edit_form');
   }
-  if(is_object($arg)){
+  if (is_object($arg)) {
     return ctools_context_create('user_edit_form', $arg);
   }
   if (!is_numeric($arg)) {
     return FALSE;
   }
 
-  $account= user_load($arg);
+  $account = user_load($arg);
   if (!$account) {
     return NULL;
   }
 
   // This will perform a node_access check, so we don't have to.
   return ctools_context_create('user_edit_form', $account);
-}
\ No newline at end of file
+}
diff --git a/plugins/arguments/user_name.inc b/plugins/arguments/user_name.inc
index f6f3b4635c5015903f6ab2510e66c8a88ba76208..ed74d9d846013be6059c5118fe152413a1cf3dfb 100644
--- a/plugins/arguments/user_name.inc
+++ b/plugins/arguments/user_name.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a username
+ * Plugin to provide an argument handler for a username.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("User: name"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'user',
   'description' => t('Creates a user context from a user name.'),
   'context' => 'ctools_argument_user_name_context',
@@ -42,6 +41,3 @@ function ctools_argument_user_name_context($arg = NULL, $conf = NULL, $empty = F
   }
   return ctools_context_create('user', $account);
 }
-
-
-
diff --git a/plugins/arguments/vid.inc b/plugins/arguments/vid.inc
index 064b22d0a7be6b6ec4f938281402e18d16084619..db68acd787827cb403cfa90e76deac18a379a811 100644
--- a/plugins/arguments/vid.inc
+++ b/plugins/arguments/vid.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide an argument handler for a vocabulary id
+ * Plugin to provide an argument handler for a vocabulary id.
  */
 
 /**
@@ -12,7 +11,7 @@
  */
 $plugin = array(
   'title' => t("Vocabulary: ID"),
-  // keyword to use for %substitution
+  // Keyword to use for %substitution.
   'keyword' => 'vocabulary',
   'description' => t('Creates a vocabulary context from a vocabulary ID argument.'),
   'context' => 'ctools_vid_context',
@@ -43,4 +42,3 @@ function ctools_vid_context($arg = NULL, $conf = NULL, $empty = FALSE) {
 
   return ctools_context_create('vocabulary', $vocabulary);
 }
-
diff --git a/plugins/cache/export_ui.inc b/plugins/cache/export_ui.inc
index 53483a53535de1bd617c08e576ae639c998ed8b2..f21af10094bac0808907cfa881d4abc49dbd85d9 100644
--- a/plugins/cache/export_ui.inc
+++ b/plugins/cache/export_ui.inc
@@ -6,7 +6,7 @@
  */
 
 $plugin = array(
-  // cache plugins are the rare plugin types that have no real UI but
+  // Cache plugins are the rare plugin types that have no real UI but
   // we're providing a title just in case.
   'title' => t('Export UI wizard cache'),
   'cache get' => 'ctools_cache_export_ui_cache_get',
diff --git a/plugins/cache/simple.inc b/plugins/cache/simple.inc
index 570398ba051e894302fc7ee4cc95d8e36c028451..c44d7983cca60ded9947c136db8e98558ae6befd 100644
--- a/plugins/cache/simple.inc
+++ b/plugins/cache/simple.inc
@@ -6,7 +6,7 @@
  */
 
 $plugin = array(
-  // cache plugins are the rare plugin types that have no real UI but
+  // Cache plugins are the rare plugin types that have no real UI but
   // we're providing a title just in case.
   'title' => t('Simple'),
   'cache get' => 'ctools_cache_simple_cache_get',
diff --git a/plugins/content_types/block/block.inc b/plugins/content_types/block/block.inc
index 7c551b9a97b787d0b885ec9debb58e0455ad58e8..ee5ce57641741f77ed0ab9967bfcbd6ac9aab569 100644
--- a/plugins/content_types/block/block.inc
+++ b/plugins/content_types/block/block.inc
@@ -51,7 +51,7 @@ function ctools_block_content_type_content_types() {
     if ($module_blocks) {
       foreach ($module_blocks as $delta => $block) {
         $info = _ctools_block_content_type_content_type($module, $delta, $block);
-        // this check means modules can remove their blocks; particularly useful
+        // This check means modules can remove their blocks; particularly useful
         // if they offer the block some other way (like we do for views)
         if ($info) {
           $types["$module-$delta"] = $info;
@@ -148,16 +148,19 @@ function ctools_block_content_type_render($subtype, $conf) {
   $block = module_invoke($module, 'block_view', $delta);
 
   if (!empty($info)) {
+    // Valid PHP function names cannot contain hyphens.
+    $block_delta = str_replace('-', '_', $delta);
+
     // Allow modules to modify the block before it is viewed, via either
     // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
-    drupal_alter(array('block_view', "block_view_{$module}_{$delta}"), $block, $info);
+    drupal_alter(array('block_view', "block_view_{$module}_{$block_delta}"), $block, $info);
   }
-  $block = (object) $block;
 
   if (empty($block)) {
     return;
   }
 
+  $block = (object) $block;
   $block->module = $module;
   $block->delta = $delta;
 
@@ -165,7 +168,7 @@ function ctools_block_content_type_render($subtype, $conf) {
     if ($module == 'block' && !empty($info) && isset($info->title)) {
       $block->title = $info->title;
     }
-    else if (isset($block->subject)) {
+    elseif (isset($block->subject)) {
       $block->title = $block->subject;
     }
     else {
@@ -205,70 +208,6 @@ function ctools_block_content_type_edit_form_submit($form, &$form_state) {
   }
 }
 
-/**
- * Returns an edit form for a block.
- */
-//function ctools_block_content_type_edit_form($id, $parents, $conf) {
-//  if (user_access('administer advanced pane settings')) {
-//    $form['block_visibility'] = array(
-//      '#type' => 'checkbox',
-//      '#title' => t('Use block visibility settings (see block config)'),
-//      '#default_value' => !empty($conf['block_visibility']),
-//      '#description' => t('If checked, the block visibility settings for this block will apply to this block.'),
-//    );
-//    // Module-specific block configurations.
-//    if ($settings = module_invoke($module, 'block', 'configure', $delta)) {
-//      // Specifically modify a couple of core block forms.
-//      if ($module == 'block') {
-//        unset($settings['submit']);
-//        $settings['info']['#type'] = 'value';
-//        $settings['info']['#value'] = $settings['info']['#default_value'];
-//      }
-//      ctools_admin_fix_block_tree($settings);
-//      $form['block_settings'] = array(
-//        '#type' => 'fieldset',
-//        '#title' => t('Block settings'),
-//        '#description' => t('Settings in this section are global and are for all blocks of this type, anywhere in the system.'),
-//        '#tree' => FALSE,
-//      );
-//
-//
-//      $form['block_settings'] += $settings;
-//    }
-//  }
-//
-//  return $form;
-//}
-
-//function ctools_admin_submit_block(&$form_values) {
-//  if (!empty($form_values['block_settings'])) {
-//    module_invoke($form_values['module'], 'block', 'save', $form_values['delta'], $form_values['block_settings']);
-//  }
-//}
-//
-///**
-// * Because form api cannot collapse just part of a tree, and the block settings
-// * assume no tree, we have to collapse the tree ourselves.
-// */
-//function ctools_admin_fix_block_tree(&$form, $key = NULL) {
-//  if ($key) {
-//    if (!empty($form['#parents'])) {
-//      $form['#parents'] = array_merge(array('configuration', 'block_settings'), $form['#parents']);
-//    }
-//    else if (empty($form['#tree'])) {
-//      $form['#parents'] = array('configuration', 'block_settings', $key);
-//    }
-//  }
-//
-//  if (isset($form['#type']) && $form['#type'] == 'textarea' && !empty($form['#rows']) && $form['#rows'] > 10) {
-//    $form['#rows'] = 10;
-//  }
-//
-//  foreach (element_children($form) as $key) {
-//    ctools_admin_fix_block_tree($form[$key], $key);
-//  }
-//}
-
 /**
  * Returns the administrative title for a type.
  */
@@ -335,8 +274,10 @@ function ctools_default_block_info($module, $delta, &$info) {
   }
 }
 
-// These are all on behalf of modules that don't implement ctools but that
-// we care about.
+/**
+ * These are all on behalf of modules that don't implement ctools but that
+ * we care about.
+ */
 function menu_ctools_block_info($module, $delta, &$info) {
   $info['icon'] = 'icon_core_block_menu.png';
   $info['category'] = t('Menus');
@@ -357,7 +298,7 @@ function forum_ctools_block_info($module, $delta, &$info) {
       break;
 
     default:
-      // safety net
+      // Safety net.
       ctools_default_block_info($module, $delta, $info);
   }
 }
@@ -369,9 +310,9 @@ function profile_ctools_block_info($module, $delta, &$info) {
 }
 
 function book_ctools_block_info($module, $delta, &$info) {
-  // Hide the book navigation block which isn't as rich as what we can
-  // do with context.
-  $info = NULL;
+  $info['title'] = t('Book navigation menu');
+  $info['icon'] = 'icon_core_block_menu.png';
+  $info['category'] = t('Node');
 }
 
 function blog_ctools_block_info($module, $delta, &$info) {
@@ -411,7 +352,7 @@ function block_ctools_block_info($module, $delta, &$info) {
   // The title of custom blocks from the block module is stored in the
   // {block} table. Look for it in the default theme as a reasonable
   // default value for the title.
-  $block_info_cache = drupal_static(__FUNCTION__);
+  $block_info_cache = &drupal_static(__FUNCTION__);
   if (!isset($block_info_cache)) {
     $block_info_cache = db_select('block', 'b')
       ->fields('b')
@@ -452,7 +393,7 @@ function user_ctools_block_info($module, $delta, &$info) {
       break;
 
     default:
-      // safety net
+      // Safety net.
       ctools_default_block_info($module, $delta, $info);
   }
 }
@@ -505,7 +446,7 @@ function ctools_user_login_pane_render($subtype, $conf, $panel_args, $contexts)
     return;
   }
 
-  $info = new stdClass;
+  $info = new stdClass();
   $info->module = $module;
   $info->delta = $delta;
 
@@ -534,7 +475,7 @@ function ctools_user_login_pane_render($subtype, $conf, $panel_args, $contexts)
   if ($module == 'block') {
     $block->title = $info->title;
   }
-  else if (isset($block->subject)) {
+  elseif (isset($block->subject)) {
     $block->title = $block->subject;
   }
   else {
diff --git a/plugins/content_types/comment/comment_created.inc b/plugins/content_types/comment/comment_created.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b3f454a61447b7783332ddde29c54efba3813e21
--- /dev/null
+++ b/plugins/content_types/comment/comment_created.inc
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+
+$plugin = array(
+  'single' => TRUE,
+  'title' => t('Comment created date'),
+  'icon' => 'icon_comment.png',
+  'description' => t('The date the referenced comment was created.'),
+  'required context' => new ctools_context_required(t('Comment'), 'entity:comment'),
+  'category' => t('Comment'),
+  'defaults' => array(
+    'format' => 'small',
+  ),
+);
+
+/**
+ * Render the custom content type.
+ */
+function ctools_comment_created_content_type_render($subtype, $conf, $panel_args, $context) {
+  if (empty($context) || empty($context->data)) {
+    return;
+  }
+
+  // Get a shortcut to the comment.
+  $comment = $context->data;
+
+  // Build the content type block.
+  $block          = new stdClass();
+  $block->module  = 'comment_created';
+  $block->title   = t('Created date');
+  $block->content = format_date($comment->created, $conf['format']);
+  $block->delta   = $comment->cid;
+
+  return $block;
+}
+
+/**
+ * Returns an edit form for custom type settings.
+ */
+function ctools_comment_created_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+  $date_types = array();
+
+  foreach (system_get_date_types() as $date_type => $definition) {
+    $date_types[$date_type] = format_date(REQUEST_TIME, $date_type);
+  }
+  $form['format'] = array(
+    '#title' => t('Date format'),
+    '#type' => 'select',
+    '#options' => $date_types,
+    '#default_value' => $conf['format'],
+  );
+  return $form;
+}
+
+/**
+ * Submit handler for the custom type settings form.
+ */
+function ctools_comment_created_content_type_edit_form_submit($form, &$form_state) {
+  // Copy everything from our defaults.
+  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
+    $form_state['conf'][$key] = $form_state['values'][$key];
+  }
+}
+
+/**
+ * Returns the administrative title for a type.
+ */
+function ctools_comment_created_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" created date', array('@s' => $context->identifier));
+}
diff --git a/plugins/content_types/comment/comment_links.inc b/plugins/content_types/comment/comment_links.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ed454f9408063499e6a41b4947c310e04a8e4f73
--- /dev/null
+++ b/plugins/content_types/comment/comment_links.inc
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+
+$plugin = array(
+  'single' => TRUE,
+  'title' => t('Comment links'),
+  'icon' => 'icon_comment.png',
+  'description' => t('Comment links of the referenced comment.'),
+  'required context' => new ctools_context_required(t('Comment'), 'entity:comment'),
+  'category' => t('Comment'),
+  'defaults' => array(
+    'override_title' => FALSE,
+    'override_title_text' => '',
+    'build_mode' => '',
+  ),
+);
+
+/**
+ * Output function for the comment links.
+ */
+function ctools_comment_links_content_type_render($subtype, $conf, $panel_args, $context) {
+  if (!empty($context) && empty($context->data)) {
+    return;
+  }
+
+  $comment = isset($context->data) ? clone $context->data : NULL;
+  $block = new stdClass();
+  $block->module = 'comment';
+  $block->delta = $comment->cid;
+
+  if (empty($comment)) {
+    $block->delta   = 'placeholder';
+    $block->subject = t('Comment subject.');
+    $block->content = t('Comment links go here.');
+  }
+  else {
+    $node = node_load($comment->nid);
+    $block->subject = $comment->subject;
+    comment_build_content($comment, $node, $conf['build_mode']);
+    $block->content = $comment->content['links'];
+  }
+  return $block;
+}
+
+/**
+ * Returns an edit form for the custom type.
+ */
+function ctools_comment_links_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+
+  $entity = entity_get_info('comment');
+  $build_mode_options = array();
+  foreach ($entity['view modes'] as $mode => $option) {
+    $build_mode_options[$mode] = $option['label'];
+  }
+
+  $form['build_mode'] = array(
+    '#title' => t('Build mode'),
+    '#type' => 'select',
+    '#description' => t('Select a build mode for this comment.'),
+    '#options' => $build_mode_options,
+    '#default_value' => $conf['build_mode'],
+  );
+
+  return $form;
+}
+
+function ctools_comment_links_content_type_edit_form_submit($form, &$form_state) {
+  // Copy everything from our defaults.
+  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
+    $form_state['conf'][$key] = $form_state['values'][$key];
+  }
+}
+
+function ctools_comment_links_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" links', array('@s' => $context->identifier));
+}
diff --git a/plugins/content_types/comment/comment_reply_form.inc b/plugins/content_types/comment/comment_reply_form.inc
index c05effb60ffac52a41c0446e1c43612ea1d80210..a18ece9a3ae56132999108140d733582b8987814 100644
--- a/plugins/content_types/comment/comment_reply_form.inc
+++ b/plugins/content_types/comment/comment_reply_form.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Ctools content-type plugin to provide a comment-reply form (replying either
+ * CTools content-type plugin to provide a comment-reply form (replying either
  * to a node or to another comment).
  */
 
@@ -14,21 +14,23 @@ if (module_exists('comment')) {
     'icon' => 'icon_comment.png',
     'description' => t('A form to add a new comment reply.'),
     'required context' => array(
-        new ctools_context_required(t('Node'), 'node'),
-        new ctools_context_optional(t('Comment'), 'comment'),
-        ),
+      new ctools_context_required(t('Node'), 'node'),
+      new ctools_context_optional(t('Comment'), 'comment'),
+    ),
     'category' => t('Comment'),
     'render callback'  => 'ctools_comment_reply_form_content_type_render',
-    'defaults' => array('anon_links' => false),
+    'defaults' => array('anon_links' => FALSE),
   );
 }
 
 function ctools_comment_reply_form_content_type_render($subtype, $conf, $panel_args, $context) {
 
-  $comment = ($context[1]->identifier == t('No context')) ? NULL : clone($context[1]->data);
+  $comment = ($context[1]->identifier == t('No context')) ? NULL : clone $context[1]->data;
   $block = new stdClass();
   $block->module = 'comments';
-  if ($comment) $block->delta  = $comment->cid;
+  if ($comment) {
+    $block->delta = $comment->cid;
+  }
   $block->title = t('Add comment');
   $node = $context[0]->data;
 
diff --git a/plugins/content_types/contact/contact.inc b/plugins/content_types/contact/contact.inc
index 63283f598d46d1b9f90b16461e0763f93c6347c0..bac30c475092a0fd3bcce335ef66805386e1d73d 100644
--- a/plugins/content_types/contact/contact.inc
+++ b/plugins/content_types/contact/contact.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('contact')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -22,10 +26,10 @@ function ctools_contact_content_type_render($subtype, $conf, $panel_args, $conte
     return;
   }
   // Build the content type block.
-  $block = new stdClass();
-  $block->module  = 'contact';
-  $block->delta   = 'form';
-  $block->title   = t('Contact');
+  $block         = new stdClass();
+  $block->module = 'contact';
+  $block->delta  = 'form';
+  $block->title  = t('Contact');
 
   module_load_include('inc', 'contact', 'contact.pages');
   $block->content = drupal_get_form('contact_site_form');
@@ -45,11 +49,6 @@ function ctools_contact_content_type_edit_form($form, &$form_state) {
  */
 function ctools_contact_content_type_edit_form_submit($form, &$form_state) {
   // Copy everything from our defaults.
-/*
-  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
-    $form_state['conf'][$key] = $form_state['values'][$key];
-  }
-*/
 }
 
 /**
diff --git a/plugins/content_types/contact/user_contact.inc b/plugins/content_types/contact/user_contact.inc
index 9b3726ab8a018e389bfde04cb81b69a099f59689..5bd36572c13542c46858d271a280ff80900eb69a 100644
--- a/plugins/content_types/contact/user_contact.inc
+++ b/plugins/content_types/contact/user_contact.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('contact')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -28,10 +32,10 @@ function ctools_user_contact_content_type_render($subtype, $conf, $panel_args, $
   }
 
   // Build the content type block.
-  $block = new stdClass();
-  $block->module  = 'contact';
-  $block->delta   = 'form';
-  $block->title   = t('Contact @name', array('@name' => $context->data->name));
+  $block         = new stdClass();
+  $block->module = 'contact';
+  $block->delta  = 'form';
+  $block->title  = t('Contact @name', array('@name' => $context->data->name));
 
   module_load_include('inc', 'contact', 'contact.pages');
   $block->content = drupal_get_form('contact_personal_form', $context->data);
@@ -51,11 +55,6 @@ function ctools_user_contact_content_type_edit_form($form, &$form_state) {
  */
 function ctools_user_contact_content_type_edit_form_submit(&$form, &$form_state) {
   // Copy everything from our defaults.
-/*
-  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
-    $form_state['conf'][$key] = $form_state['values'][$key];
-  }
-*/
 }
 
 /**
diff --git a/plugins/content_types/custom/custom.inc b/plugins/content_types/custom/custom.inc
index ac2f2a3ff253d9a3da3174c31ff77d926c5f6049..84fe3c551a227ba155b69757a7cd10f2c2e52e0c 100644
--- a/plugins/content_types/custom/custom.inc
+++ b/plugins/content_types/custom/custom.inc
@@ -16,7 +16,7 @@
 $plugin = array(
   'title' => t('Custom content'),
   'no title override' => TRUE,
-  'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE),
+  'defaults' => array('admin_title' => '', 'title' => '', 'title_heading' => 'h2', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE),
   'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
   // Make sure the edit form is only used for some subtypes.
   'edit form' => '',
@@ -135,6 +135,7 @@ function ctools_custom_content_type_get_conf($subtype, $conf) {
         $settings = array(
           'admin_title' => t('Missing/deleted content'),
           'title' => '',
+          'title_heading' => '',
           'body' => '',
           'format' => filter_default_format(),
           'substitute' => TRUE,
@@ -177,9 +178,10 @@ function ctools_custom_content_type_render($subtype, $conf, $args, $contexts) {
 
   static $delta = 0;
 
-  $block          = new stdClass();
-  $block->subtype = ++$delta;
-  $block->title   = filter_xss_admin($settings['title']);
+  $block                = new stdClass();
+  $block->subtype       = ++$delta;
+  $block->title         = filter_xss_admin($settings['title']);
+  $block->title_heading = isset($settings['title_heading']) ? $settings['title_heading'] : 'h2';
 
   // Add keyword substitutions if we were configured to do so.
   $content = $settings['body'];
@@ -267,7 +269,8 @@ function ctools_custom_content_type_edit_form($form, &$form_state) {
   $form_state['settings'] = $settings;
 
   if ($settings['custom_type'] == 'fixed') {
-    return $form; // no form for this case.
+    // No form for this case.
+    return $form;
   }
 
   $form['admin_title'] = array(
@@ -277,10 +280,36 @@ function ctools_custom_content_type_edit_form($form, &$form_state) {
     '#description' => t('This title will be used administratively to identify this pane. If blank, the regular title will be used.'),
   );
 
+  // Copy over the title override settings for a title heading.
+  $form['aligner_start'] = array(
+    '#markup' => '<div class="option-text-aligner clearfix">',
+  );
+
   $form['title'] = array(
     '#type' => 'textfield',
     '#default_value' => $settings['title'],
     '#title' => t('Title'),
+    '#id' => 'override-title-textfield',
+  );
+
+  $form['title_heading'] = array(
+    '#type' => 'select',
+    '#default_value' => isset($settings['title_heading']) ? $settings['title_heading'] : 'h2',
+    '#options' => array(
+      'h1' => t('h1'),
+      'h2' => t('h2'),
+      'h3' => t('h3'),
+      'h4' => t('h4'),
+      'h5' => t('h5'),
+      'h6' => t('h6'),
+      'div' => t('div'),
+      'span' => t('span'),
+    ),
+    '#id' => 'override-title-heading',
+  );
+
+  $form['aligner_stop'] = array(
+    '#markup' => '</div>',
   );
 
   $form['body'] = array(
@@ -291,7 +320,7 @@ function ctools_custom_content_type_edit_form($form, &$form_state) {
   );
 
   if (!empty($form_state['contexts'])) {
-    // Set extended description if both CCK and Token modules are enabled, notifying of unlisted keywords
+    // Set extended description if both CCK and Token modules are enabled, notifying of unlisted keywords.
     if (module_exists('content') && module_exists('token')) {
       $description = t('If checked, context keywords will be substituted in this content. Note that CCK fields may be used as keywords using patterns like <em>%node:field_name-formatted</em>.');
     }
@@ -388,7 +417,7 @@ function ctools_custom_content_type_edit_form_validate(&$form, &$form_state) {
       form_error($form['name'], t('Name is required.'));
     }
 
-    // Check for string identifier sanity
+    // Check for string identifier sanity.
     if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['name'])) {
       form_error($form['name'], t('The name can only consist of lowercase letters, underscores, and numbers.'));
       return;
@@ -398,7 +427,7 @@ function ctools_custom_content_type_edit_form_validate(&$form, &$form_state) {
       return;
     }
 
-    // Check for name collision
+    // Check for name collision.
     if ($form_state['values']['name'] == 'custom' || (ctools_export_crud_load('ctools_custom_content', $form_state['values']['name']))) {
       form_error($form['name'], t('Content with this name already exists. Please choose another name or delete the existing item before creating a new one.'));
     }
@@ -418,7 +447,7 @@ function ctools_custom_content_type_edit_form_submit($form, &$form_state) {
   }
   // If the 'reusable' checkbox was checked, we will create a new
   // custom content and give it the proper values.
-  else if (!empty($form_state['values']['reusable'])) {
+  elseif (!empty($form_state['values']['reusable'])) {
     $content = ctools_export_crud_new('ctools_custom_content');
     $content->name = $form_state['values']['name'];
     _ctools_custom_content_type_edit_save($content, $form_state);
@@ -426,7 +455,6 @@ function ctools_custom_content_type_edit_form_submit($form, &$form_state) {
   }
   else {
     // Otherwise, just save values into $conf normally.
-
     foreach (array_keys($form_state['plugin']['defaults']) as $key) {
       $form_state['conf'][$key] = isset($form_state['values'][$key]) ? $form_state['values'][$key] : $form_state['plugin']['defaults'][$key];
     }
diff --git a/plugins/content_types/entity_context/entity_field.inc b/plugins/content_types/entity_context/entity_field.inc
index d7d6319c7ab66ad11cda8add6449940b8771c99d..80d24ef1f06cee9167f7725024f7ca3ac7b870b0 100644
--- a/plugins/content_types/entity_context/entity_field.inc
+++ b/plugins/content_types/entity_context/entity_field.inc
@@ -34,6 +34,14 @@ function ctools_entity_field_content_type_content_types() {
     return $types;
   }
 
+  $cache_key = 'ctools_entity_field_content_type_content_types';
+  if ($cache = cache_get($cache_key)) {
+    $types = $cache->data;
+    if (!empty($types)) {
+      return $types;
+    }
+  }
+
   // This will hold all the individual field content types.
   $context_types = array();
   $entities = entity_get_info();
@@ -82,12 +90,14 @@ function ctools_entity_field_content_type_content_types() {
     unset($context_types[$key]['types']);
   }
 
+  cache_set($cache_key, $types);
+
   return $types;
 }
 
 /**
-* Render the custom content type.
-*/
+ * Render the custom content type.
+ */
 function ctools_entity_field_content_type_render($subtype, $conf, $panel_args, $context) {
   if (empty($context) || empty($context->data)) {
     return;
@@ -118,6 +128,8 @@ function ctools_entity_field_content_type_render($subtype, $conf, $panel_args, $
   $field_settings = array(
     'label' => $label,
     'type' => $conf['formatter'],
+    // Pass all entity field panes settings to field display settings.
+    'pane_settings' => $conf,
   );
 
   // Get the field output, and the title.
@@ -125,48 +137,37 @@ function ctools_entity_field_content_type_render($subtype, $conf, $panel_args, $
     $field_settings['settings'] = $conf['formatter_settings'];
   }
 
+  $clone = clone $entity;
   $all_values = field_get_items($entity_type, $entity, $field_name, $language);
-  if (!is_array($all_values)) {
-    $all_values = array();
-  }
 
-  // Reverse values.
-  if (isset($conf['delta_reversed']) && $conf['delta_reversed']) {
-    $all_values = array_reverse($all_values);
-  }
-
-  if (isset($conf['delta_limit'])) {
-    $delta_limit = $conf['delta_limit'];
-    $offset = intval($conf['delta_offset']);
-    $total = count($all_values);
-
-    if ($delta_limit == 0) {
-      $delta_limit = $total - $offset;
+  if (is_array($all_values)) {
+    // Reverse values.
+    if (isset($conf['delta_reversed']) && $conf['delta_reversed']) {
+      $all_values = array_reverse($all_values, TRUE);
     }
 
-    $new_values = array();
-    for ($i = 0; $i < $delta_limit; $i++) {
-      $new_delta = $offset + $i;
-
-      if (isset($all_values[$new_delta])) {
-        $new_values[] = $all_values[$new_delta];
-      }
+    if (isset($conf['delta_limit'])) {
+      $offset = intval($conf['delta_offset']);
+      $limit = !empty($conf['delta_limit']) ? $conf['delta_limit'] : NULL;
+      $all_values = array_slice($all_values, $offset, $limit, TRUE);
     }
 
-    $all_values = $new_values;
+    $clone->{$field_name}[$language] = $all_values;
   }
 
-  $clone = clone $entity;
-  $clone->{$field_name}[$language] = $all_values;
   $field_output = field_view_field($entity_type, $clone, $field_name, $field_settings, $language);
 
-  if (!empty($field_output) && !empty($conf['override_title'])) {
-    $field_output['#title'] = filter_xss_admin($conf['override_title_text']);
+  if (!empty($field_output)) {
+    if (!empty($conf['override_title'])) {
+      $field_output['#title'] = filter_xss_admin($conf['override_title_text']);
+    }
+    $field_output['#ctools_context'] = $context;
+    $field_output['#post_render'][] = 'ctools_entity_field_content_type_substitute_keywords';
   }
 
   // Build the content type block.
   $block = new stdClass();
-  $block->module  = 'entity_field';
+  $block->module = 'entity_field';
   if ($conf['label'] == 'title' && isset($field_output['#title'])) {
     $block->title = $field_output['#title'];
   }
@@ -178,8 +179,15 @@ function ctools_entity_field_content_type_render($subtype, $conf, $panel_args, $
 }
 
 /**
-* Returns an edit form for custom type settings.
-*/
+ * Replace context keywords.
+ */
+function ctools_entity_field_content_type_substitute_keywords($markup, array $element) {
+  return ctools_context_keyword_substitute($markup, array(), array($element['#ctools_context']));
+}
+
+/**
+ * Returns an edit form for custom type settings.
+ */
 function ctools_entity_field_content_type_formatter_options($form, &$form_state) {
   if (empty($form_state['conf']['formatter_settings'])) {
     $form_state['conf']['formatter_settings'] = array();
@@ -233,6 +241,11 @@ function ctools_entity_field_content_type_formatter_styles($form, &$form_state)
   ctools_form_include($form_state, 'field_ui.admin', 'field_ui', '');
   ctools_form_include($form_state, 'fields');
 
+  $form['ctools_keywords'] = array(
+    '#type' => 'item',
+    '#description' => t('You may use keywords for substitutions.'),
+  );
+
   $form['ctools_field_list'] = array(
     '#type' => 'value',
     '#value' => array(),
@@ -263,10 +276,18 @@ function ctools_entity_field_content_type_formatter_styles_submit($form, &$form_
 }
 
 /**
-* Returns the administrative title for a type.
-*/
+ * Returns the administrative title for a type.
+ */
 function ctools_entity_field_content_type_admin_title($subtype, $conf, $context) {
   list($bundle, $field_name) = explode(':', $subtype);
   ctools_include('fields');
-  return t('"@s" @field', array('@s' => $context->identifier, '@field' => ctools_field_label($field_name)));
+  if (is_object($context) && isset($context->identifier)) {
+    $identifier = $context->identifier;
+  }
+  else {
+    watchdog('ctools_entity_field_content_type_admin_title', 'Context is missing for field: @name', array('@name' => $subtype), WATCHDOG_NOTICE);
+    $identifier = t('Unknown');
+  }
+
+  return t('"@s" @field', array('@s' => $identifier, '@field' => ctools_field_label($field_name)));
 }
diff --git a/plugins/content_types/entity_context/entity_field_extra.inc b/plugins/content_types/entity_context/entity_field_extra.inc
index 6a59ed4c634a9948bc9487a3ac5816ecddbdba34..efc7f4ff6754191aca37c30085630d233f72ff23 100644
--- a/plugins/content_types/entity_context/entity_field_extra.inc
+++ b/plugins/content_types/entity_context/entity_field_extra.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 $plugin = array(
   'title' => t('Entity extra field'),
   'defaults' => array('view_mode' => NULL),
@@ -119,7 +123,7 @@ function ctools_entity_field_extra_content_type_render($subtype, $conf, $panel_a
 
   if (isset($entity->content[$field_name])) {
     // Build the content type block.
-    $block = new stdClass();
+    $block          = new stdClass();
     $block->module  = 'entity_field_extra';
     $block->content = $entity->content[$field_name];
     $block->delta   = $id;
diff --git a/plugins/content_types/form/entity_form_field.inc b/plugins/content_types/form/entity_form_field.inc
index a030f693ee6b2e0c36a57bc74883cb948a8a7a60..c85a1ac374dde004d0194c32128f135afc5f9b6d 100644
--- a/plugins/content_types/form/entity_form_field.inc
+++ b/plugins/content_types/form/entity_form_field.inc
@@ -38,10 +38,13 @@ function ctools_entity_form_field_content_type_content_types() {
   $types = array();
   $content_types = array();
   $entities = entity_get_info();
-
+  $field_instances = field_info_instances();
   foreach ($entities as $entity_type => $entity) {
     foreach ($entity['bundles'] as $type => $bundle) {
-      foreach (field_info_instances($entity_type, $type) as $field_name => $field) {
+      if (!isset($field_instances[$entity_type][$type])) {
+        continue;
+      }
+      foreach ($field_instances[$entity_type][$type] as $field_name => $field) {
         if (!isset($types[$entity_type . ':' . $field_name])) {
           $types[$entity_type . ':' . $field_name] = array(
             'category' => t('Form'),
@@ -57,6 +60,26 @@ function ctools_entity_form_field_content_type_content_types() {
     }
   }
 
+  if (module_exists('field_group')) {
+    foreach ($entities as $entity_type => $entity) {
+      foreach ($entity['bundles'] as $type => $bundle) {
+        if ($group_info = field_group_info_groups($entity_type, $type, "form")) {
+          foreach ($group_info as $group_name => $group) {
+            if (!isset($types[$entity_type . ':' . $group_name])) {
+              $types[$entity_type . ':' . $group_name] = array(
+                'category' => t('Form'),
+                'icon' => 'icon_field.png',
+                'title' => t('Group form: @widget_label', array('@widget_label' => $group->label)),
+                'description' => t('Field group on the referenced entity.'),
+              );
+            }
+            $content_types[$entity_type . ':' . $group_name]['types'][$type] = $bundle['label'];
+          }
+        }
+      }
+    }
+  }
+
   // Create the required context for each field related to the bundle types.
   foreach ($types as $key => $field_content_type) {
     list($entity_type, $field_name) = explode(':', $key, 2);
@@ -70,8 +93,8 @@ function ctools_entity_form_field_content_type_content_types() {
 }
 
 /**
-* Render the custom content type.
-*/
+ * Render the custom content type.
+ */
 function ctools_entity_form_field_content_type_render($subtype, $conf, $panel_args, $context) {
   if (empty($context) || empty($context->data)) {
     return;
@@ -85,16 +108,38 @@ function ctools_entity_form_field_content_type_render($subtype, $conf, $panel_ar
   $ids = entity_extract_ids($entity_type, $entity);
   $field = field_info_instance($entity_type, $field_name, $ids[2]);
 
-  // Do not render if the entity type does not have this field.
-  if (empty($field)) {
+  // Check for field groups.
+  if (empty($field) && module_exists('field_group')) {
+    $groups = field_group_info_groups($entity_type, $entity->type, "form");
+    $group = !empty($groups[$field_name]) ? $groups[$field_name] : NULL;
+  }
+
+  // Do not render if the entity type does not have this field or group.
+  if (empty($field) && empty($group)) {
     return;
   }
-  $block = new stdClass();
 
+  $block = new stdClass();
   if (isset($context->form)) {
     $block->content = array();
-    $block->content[$field_name] = $context->form[$field_name];
-    unset($context->form[$field_name]);
+    if (!empty($field)) {
+      $block->content[$field_name] = $context->form[$field_name];
+      unset($context->form[$field_name]);
+    }
+    else {
+      // Pre-render the form to populate field groups.
+      if (isset($context->form['#pre_render'])) {
+        foreach ($context->form['#pre_render'] as $function) {
+          if (function_exists($function)) {
+            $context->form = $function($context->form);
+          }
+        }
+        unset($context->form['#pre_render']);
+      }
+
+      $block->content[$field_name] = $context->form[$field_name];
+      unset($context->form[$field_name]);
+    }
   }
   else {
     $block->content = t('Entity info.');
@@ -104,13 +149,26 @@ function ctools_entity_form_field_content_type_render($subtype, $conf, $panel_ar
 }
 
 /**
-* Returns the administrative title for a type.
-*/
+ * Returns the administrative title for a type.
+ */
 function ctools_entity_form_field_content_type_admin_title($subtype, $conf, $context) {
+  // Return early because we don't have context to build this field from.
+  if (!$context || !isset($context->identifier)) {
+    watchdog('ctools_entity_form_field_content_type_admin_title', 'Context is missing for field: @name', array('@name' => $subtype), WATCHDOG_NOTICE);
+    return t('Deleted/missing field @name', array('@name' => $subtype));
+  }
+
   list($entity_type, $field_name) = explode(':', $subtype, 2);
 
   if (!empty($context->restrictions)) {
     $field = field_info_instance($entity_type, $field_name, $context->restrictions['type'][0]);
+
+    // Check for field groups.
+    if (empty($field) && module_exists('field_group')) {
+      $groups = field_group_info_groups($entity_type, $context->restrictions['type'][0], 'form');
+      $group = !empty($groups[$field_name]) ? $groups[$field_name] : NULL;
+      $field = array('label' => isset($group->label) ? $group->label : $subtype);
+    }
   }
   else {
     $field = array('label' => $subtype);
@@ -120,6 +178,6 @@ function ctools_entity_form_field_content_type_admin_title($subtype, $conf, $con
 }
 
 function ctools_entity_form_field_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/form/form.inc b/plugins/content_types/form/form.inc
index 73f7c780166e3afa0850b351bc91681d1457a027..ef8cc65ab7c961af526b866323fa517304243196 100644
--- a/plugins/content_types/form/form.inc
+++ b/plugins/content_types/form/form.inc
@@ -1,11 +1,13 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
-  // only provides a single content type
+  // Only provides a single content type.
   'single' => TRUE,
   'render last' => TRUE,
   'title' => t('General form'),
@@ -43,7 +45,7 @@ function ctools_form_content_type_render($subtype, $conf, $panel_args, &$context
     $block->delta = $context->form_id;
   }
   else {
-    $block->title = t('Form');
+    $block->title   = t('Form');
     $block->content = t('Form goes here.');
     $block->delta   = 'unknown';
   }
@@ -56,7 +58,7 @@ function ctools_form_content_type_admin_title($subtype, $conf, $context) {
 }
 
 function ctools_form_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to override title
+  // Provide a blank form so we have a place to override title
   // and stuff.
   return $form;
 }
diff --git a/plugins/content_types/node/node.inc b/plugins/content_types/node/node.inc
index 30e06f041e8c9b3d60c57dc90faef20584afa825..a11412014256f36fe59a07f29e4a0d72fc73bf4f 100644
--- a/plugins/content_types/node/node.inc
+++ b/plugins/content_types/node/node.inc
@@ -11,7 +11,7 @@
  * by the system that includes this file.
  */
 $plugin = array(
-  'title' => t('Node'),
+  'title' => t('Existing node'),
   'single' => TRUE,
   'defaults' => array(
     'nid' => '',
@@ -20,7 +20,6 @@ $plugin = array(
     'identifier' => '',
     'build_mode' => 'teaser',
   ),
-  'title' => t('Existing node'),
   'icon' => 'icon_node.png',
   'description' => t('Add a node from your site as content.'),
   'category' => t('Custom'),
@@ -47,10 +46,10 @@ function ctools_node_content_type_render($subtype, $conf, $panel_args) {
     }
   }
 
-  // Support node translation
+  // Support node translation.
   if (module_exists('translation')) {
     if ($translations = module_invoke('translation', 'node_get_translations', $nid)) {
-      if (isset($translations[$GLOBALS['language']->language]))  {
+      if (isset($translations[$GLOBALS['language']->language])) {
         $nid = $translations[$GLOBALS['language']->language]->nid;
       }
     }
@@ -67,7 +66,7 @@ function ctools_node_content_type_render($subtype, $conf, $panel_args) {
 
   // Don't store viewed node data on the node, this can mess up other
   // views of the node.
-  $node = clone($node);
+  $node = clone $node;
 
   $block->module = 'node';
   $block->delta = $node->nid;
@@ -122,7 +121,6 @@ function ctools_node_content_type_edit_form($form, &$form_state) {
     '#description' => t('Check this box if you would like your pane title to link to the node.'),
   );
 
-
   if ($form_state['op'] == 'add') {
     $form['nid'] = array(
       '#prefix' => '<div class="no-float">',
@@ -180,7 +178,7 @@ function ctools_node_content_type_edit_form($form, &$form_state) {
 /**
  * Validate the node selection.
  */
-function  ctools_node_content_type_edit_form_validate(&$form, &$form_state) {
+function ctools_node_content_type_edit_form_validate(&$form, &$form_state) {
   if ($form_state['op'] != 'add') {
     return;
   }
@@ -206,7 +204,7 @@ function  ctools_node_content_type_edit_form_validate(&$form, &$form_state) {
   }
 
   if (!($node || preg_match('/^[@%]\d+$/', $nid)) ||
-      // Do not allow unpublished nodes to be selected by unprivileged users
+      // Do not allow unpublished nodes to be selected by unprivileged users.
       (empty($node->status) && !user_access('administer nodes'))) {
     form_error($form['nid'], t('Invalid node'));
   }
diff --git a/plugins/content_types/node_context/node_attachments.inc b/plugins/content_types/node_context/node_attachments.inc
index 380e26043db489712bc6f2d2d403ee763497f800..2878e16d90ba7fdc2f6bb78c43688fd39d514c89 100644
--- a/plugins/content_types/node_context/node_attachments.inc
+++ b/plugins/content_types/node_context/node_attachments.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Attached files'),
@@ -14,7 +16,7 @@ $plugin = array(
 );
 
 function ctools_node_attachments_content_type_render($subtype, $conf, $panel_args, $context) {
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  $node = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'attachments';
 
@@ -38,7 +40,6 @@ function ctools_node_attachments_content_type_admin_title($subtype, $conf, $cont
 }
 
 function ctools_node_attachments_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
-
diff --git a/plugins/content_types/node_context/node_author.inc b/plugins/content_types/node_context/node_author.inc
index e98ce5acc90263df28f694487dd3d881c23e9cde..04b387d6603d71c55bc933c6147058223fcf3f4d 100644
--- a/plugins/content_types/node_context/node_author.inc
+++ b/plugins/content_types/node_context/node_author.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node author'),
@@ -29,7 +31,7 @@ function ctools_node_author_content_type_render($subtype, $conf, $panel_args, $c
   $user = user_load($node->uid);
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'node_author';
   $block->title   = t('Author');
   $block->content = !empty($conf['link']) ? theme('username', array('account' => $user, 'link_path' => 'user/' . $node->uid)) : check_plain(format_username($node));
diff --git a/plugins/content_types/node_context/node_body.inc b/plugins/content_types/node_context/node_body.inc
index 3e69560a28a75f6f3ffb4cd58e7054a915a5793f..032bc8e177faa6d84973a24c1579b92674d26f36 100644
--- a/plugins/content_types/node_context/node_body.inc
+++ b/plugins/content_types/node_context/node_body.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node body'),
@@ -28,7 +30,7 @@ function ctools_node_body_content_type_render($subtype, $conf, $panel_args, $con
  * Returns an edit form for custom type settings.
  */
 function ctools_node_body_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
 
diff --git a/plugins/content_types/node_context/node_book_children.inc b/plugins/content_types/node_context/node_book_children.inc
index 5d017c5cde4b60ad5a0d780dd67794c44e753206..21f65428a959cd9514480df0ab09abf6464884dd 100644
--- a/plugins/content_types/node_context/node_book_children.inc
+++ b/plugins/content_types/node_context/node_book_children.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('book')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -16,7 +20,7 @@ if (module_exists('book')) {
 }
 
 function ctools_node_book_children_content_type_render($subtype, $conf, $panel_args, $context) {
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  $node = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'book_children';
 
@@ -38,6 +42,6 @@ function ctools_node_book_children_content_type_admin_title($subtype, $conf, $co
 }
 
 function ctools_node_book_children_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_context/node_book_menu.inc b/plugins/content_types/node_context/node_book_menu.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b68707614ff785779845bb1e6ff44bc4b0648ced
--- /dev/null
+++ b/plugins/content_types/node_context/node_book_menu.inc
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ */
+
+if (module_exists('book')) {
+  /**
+   * Plugins are described by creating a $plugin array which will be used
+   * by the system that includes this file.
+   */
+  $plugin = array(
+    'single' => TRUE,
+    'title' => t('Book navigation menu'),
+    'icon' => drupal_get_path('module', 'ctools') . '/plugins/content_types/block/icon_core_block_menu.png',
+    'description' => t('The book menu belonging to the current book node.'),
+    'required context' => new ctools_context_required(t('Node'), 'node'),
+    'category' => t('Node'),
+  );
+}
+
+function ctools_node_book_menu_content_type_render($subtype, $conf, $panel_args, $context) {
+  $node = isset($context->data) ? clone $context->data : NULL;
+  $block = new stdClass();
+  $block->module = 'book_menu';
+
+  if ($conf['override_title']) {
+    $block->title = t($conf['override_title_text']);
+  }
+  else {
+    $block->title = t('Book navigation menu');
+  }
+  if ($node) {
+    $block->delta = $node->nid;
+    // TODO: the value is not available somehow?!?
+    $book_block_mode = isset($conf['book_block_mode']) ? $conf['book_block_mode'] : 'book pages';
+
+    // Code below is taken from function book_block_view().
+    $current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
+
+    if ($book_block_mode === 'all pages') {
+      $block->subject = t('Book navigation');
+      $book_menus = array();
+      $pseudo_tree = array(0 => array('below' => FALSE));
+      foreach (book_get_books() as $book_id => $book) {
+        if ($book['bid'] === $current_bid) {
+          // If the current page is a node associated with a book, the menu
+          // needs to be retrieved.
+          $book_menus[$book_id] = menu_tree_output(menu_tree_all_data($node->book['menu_name'], $node->book));
+        }
+        else {
+          // Since we know we will only display a link to the top node, there
+          // is no reason to run an additional menu tree query for each book.
+          $book['in_active_trail'] = FALSE;
+          // Check whether user can access the book link.
+          $book_node = node_load($book['nid']);
+          $book['access'] = node_access('view', $book_node);
+          $pseudo_tree[0]['link'] = $book;
+          $book_menus[$book_id] = menu_tree_output($pseudo_tree);
+        }
+      }
+      $book_menus['#theme'] = 'book_all_books_block';
+      $block->content = $book_menus;
+    }
+    elseif ($current_bid) {
+      // Only display this block when the user is browsing a book.
+      $select = db_select('node', 'n')
+        ->fields('n', array('title'))
+        ->condition('n.nid', $node->book['bid'])
+        ->addTag('node_access');
+      $title = $select->execute()->fetchField();
+      // Only show the block if the user has view access for the top-level node.
+      if ($title) {
+        $tree = menu_tree_all_data($node->book['menu_name'], $node->book);
+        // There should only be one element at the top level.
+        $data = array_shift($tree);
+        // TODO: subject is not rendered.
+        $block->subject = theme('book_title_link', array('link' => $data['link']));
+        $block->content = ($data['below']) ? menu_tree_output($data['below']) : '';
+      }
+    }
+  }
+  else {
+    $block->content = t('Book navigation pager goes here.');
+    $block->delta = 'unknown';
+  }
+
+  return $block;
+}
+
+function ctools_node_book_menu_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" book navigation pager', array('@s' => $context->identifier));
+}
+
+function ctools_node_book_menu_content_type_edit_form($form, &$form_state) {
+  // Grab block form from the book module.
+  $block_form = book_block_configure($delta = '');
+  // TODO: this does not work yet.
+  //       See TODO in: ctools_node_book_menu_content_type_render.
+  if (isset($form_state['input']['book_block_mode'])) {
+    $block_form['book_block_mode']['#default_value'] = $form_state['input']['book_block_mode'];
+  }
+  $form += $block_form;
+  return $form;
+}
diff --git a/plugins/content_types/node_context/node_book_nav.inc b/plugins/content_types/node_context/node_book_nav.inc
index 6c0d50df7e329b2eb59fb7bd7677882f3a053fdb..d7a284b614958177c95cc9a95b3e9ac045f908d6 100644
--- a/plugins/content_types/node_context/node_book_nav.inc
+++ b/plugins/content_types/node_context/node_book_nav.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('book')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -7,26 +11,26 @@ if (module_exists('book')) {
    */
   $plugin = array(
     'single' => TRUE,
-    'title' => t('Book navigation'),
-    'icon' => 'icon_node.png',
-    'description' => t('The navigation menu the book the node belongs to.'),
+    'title' => t('Book navigation pager'),
+    'icon' => drupal_get_path('module', 'ctools') . '/plugins/content_types/block/icon_core_booknavigation.png',
+    'description' => t('The navigational pager and sub pages of the current book node.'),
     'required context' => new ctools_context_required(t('Node'), 'node'),
     'category' => t('Node'),
   );
 }
 
 function ctools_node_book_nav_content_type_render($subtype, $conf, $panel_args, $context) {
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  $node = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'book_nav';
 
-  $block->title = t('Book navigation');
+  $block->title = t('Book navigation pager');
   if ($node) {
     $block->content = isset($node->book) ? theme('book_navigation', array('book_link' => $node->book)) : '';
     $block->delta = $node->nid;
   }
   else {
-    $block->content = t('Book navigation goes here.');
+    $block->content = t('Book navigation pager goes here.');
     $block->delta = 'unknown';
   }
 
@@ -34,10 +38,10 @@ function ctools_node_book_nav_content_type_render($subtype, $conf, $panel_args,
 }
 
 function ctools_node_book_nav_content_type_admin_title($subtype, $conf, $context) {
-  return t('"@s" book navigation', array('@s' => $context->identifier));
+  return t('"@s" book navigation pager', array('@s' => $context->identifier));
 }
 
 function ctools_node_book_nav_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_context/node_comment_form.inc b/plugins/content_types/node_context/node_comment_form.inc
index f77b66e416aa7858b420ca395fcf5d9a070f09c7..ff34e4b5281b662f74dbfdee89f51344f95fd62e 100644
--- a/plugins/content_types/node_context/node_comment_form.inc
+++ b/plugins/content_types/node_context/node_comment_form.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('comment')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -17,17 +21,16 @@ if (module_exists('comment')) {
 }
 
 function ctools_node_comment_form_content_type_render($subtype, $conf, $panel_args, $context) {
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  if (empty($context->data->nid)) {
+    return;
+  }
+  $node = clone $context->data;
   $block = new stdClass();
   $block->module = 'comments';
-  $block->delta  = $node->nid;
-
+  $block->delta = $node->nid;
   $block->title = t('Add comment');
 
-  if (empty($node)) {
-    $block->content = t('Comment form here.');
-  }
-  else if ($node->comment == COMMENT_NODE_OPEN) {
+  if ($node->comment == COMMENT_NODE_OPEN) {
     if (user_access('post comments')) {
       $comment = new stdClass();
       $comment->nid = $node->nid;
@@ -43,7 +46,7 @@ function ctools_node_comment_form_content_type_render($subtype, $conf, $panel_ar
       );
       $block->content = drupal_build_form('comment_node_' . $node->type . '_form', $form_state);
     }
-    else if (!empty($conf['anon_links'])) {
+    elseif (!empty($conf['anon_links'])) {
       $block->content = theme('comment_post_forbidden', array('node' => $node));
     }
   }
@@ -76,21 +79,3 @@ function ctools_node_comment_form_content_type_edit_form_submit($form, &$form_st
     $form_state['conf'][$key] = $form_state['values'][$key];
   }
 }
-
-/**
- * Alter the comment form to get a little more control over it.
- */
-function ctools_form_comment_form_alter(&$form, &$form_state) {
-  if (!empty($form_state['ctools comment alter'])) {
-    // Force the form to post back to wherever we are.
-    $form['#action'] = url($_GET['q'], array('fragment' => 'comment-form'));
-    if (empty($form['#submit'])) {
-      $form['#submit'] = array('comment_form_submit');
-    }
-    $form['#submit'][] = 'ctools_node_comment_form_submit';
-  }
-}
-
-function ctools_node_comment_form_submit(&$form, &$form_state) {
-  $form_state['redirect'][0] = $_GET['q'];
-}
diff --git a/plugins/content_types/node_context/node_comment_wrapper.inc b/plugins/content_types/node_context/node_comment_wrapper.inc
new file mode 100644
index 0000000000000000000000000000000000000000..4bdb3fc4da8097553b4f52a027aba5a80cc1852f
--- /dev/null
+++ b/plugins/content_types/node_context/node_comment_wrapper.inc
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ */
+
+if (module_exists('comment')) {
+  /**
+   * Plugins are described by creating a $plugin array which will be used
+   * by the system that includes this file.
+   */
+  $plugin = array(
+    'single' => TRUE,
+    'title' => t('Comments and comment form.'),
+    'icon' => 'icon_node.png',
+    'description' => t('The comments and comment form for the referenced node.'),
+    'required context' => new ctools_context_required(t('Node'), 'node'),
+    'category' => t('Node'),
+    'defaults' => array(
+      'mode' => variable_get('comment_default_mode', COMMENT_MODE_THREADED),
+      'comments_per_page' => variable_get('comment_default_per_page', '50'),
+    ),
+  );
+}
+
+/**
+ * Render the node comments.
+ */
+function ctools_node_comment_wrapper_content_type_render($subtype, $conf, $panel_args, $context) {
+  $node = isset($context->data) ? clone $context->data : NULL;
+  $block = new stdClass();
+  $block->module = 'comments';
+  $block->delta = $node->nid;
+
+  $renderable = array(
+    '#theme' => 'comment_wrapper__node_' . $node->type,
+    '#node' => $node,
+    'comments' => array(),
+    'comment_form' => array(),
+  );
+
+  // Add in the comments.
+  if (($node->comment_count && user_access('access comments')) || user_access('administer comments')) {
+    $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED);
+    $comments_per_page = variable_get('comment_default_per_page_' . $node->type, 50);
+    if ($cids = comment_get_thread($node, $mode, $comments_per_page)) {
+      $comments = comment_load_multiple($cids);
+      comment_prepare_thread($comments);
+      $build = comment_view_multiple($comments, $node);
+      $build['pager']['#theme'] = 'pager';
+      $renderable['comments'] = $build;
+    }
+  }
+
+  // Stuff in the comment form.
+  if ($node->comment == COMMENT_NODE_OPEN) {
+    if (user_access('post comments')) {
+      $comment = new stdClass();
+      $comment->nid = $node->nid;
+      $comment->pid = NULL;
+      $form_state = array(
+        'ctools comment alter' => TRUE,
+        'node' => $node,
+        'build_info' => array(
+          'args' => array(
+            $comment,
+          ),
+        ),
+      );
+      $renderable['comment_form'] = drupal_build_form('comment_node_' . $node->type . '_form', $form_state);
+    }
+    elseif (!empty($conf['anon_links'])) {
+      $renderable['comment_form'] = theme('comment_post_forbidden', array('node' => $node));
+    }
+  }
+
+  $block->content = drupal_render($renderable);
+
+  return $block;
+}
+
+/**
+ * Returns an edit form for the comment wrapper.
+ */
+function ctools_node_comment_wrapper_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+  $form['mode'] = array(
+    '#type' => 'select',
+    '#title' => t('Mode'),
+    '#default_value' => $conf['mode'],
+    '#options' => _comment_get_modes(),
+    '#weight' => 1,
+  );
+  foreach (_comment_per_page() as $i) {
+    $options[$i] = t('!a comments per page', array('!a' => $i));
+  }
+  $form['comments_per_page'] = array(
+    '#type' => 'select',
+    '#title' => t('Pager'),
+    '#default_value' => $conf['comments_per_page'],
+    '#options' => $options,
+    '#weight' => 3,
+  );
+  return $form;
+}
+
+/**
+ * Submit handler for the comment wrapper settings form.
+ */
+function ctools_node_comment_wrapper_content_type_edit_form_submit($form, &$form_state) {
+  // Copy everything from our defaults.
+  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
+    $form_state['conf'][$key] = $form_state['values'][$key];
+  }
+}
+
+/**
+ * Returns the administrative title.
+ */
+function ctools_node_comment_wrapper_content_type_admin_title($subtype, $conf, $context) {
+  return t('Comments and comment form');
+}
diff --git a/plugins/content_types/node_context/node_comments.inc b/plugins/content_types/node_context/node_comments.inc
index 0f0033d2af1a7a13bbb982a69d6afd285ba2d0a7..7453e79629c6a9338a17068acc1145c760cec39b 100644
--- a/plugins/content_types/node_context/node_comments.inc
+++ b/plugins/content_types/node_context/node_comments.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('comment')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -20,19 +24,17 @@ if (module_exists('comment')) {
 }
 
 function ctools_node_comments_content_type_render($subtype, $conf, $panel_args, $context) {
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  if (empty($context->data->nid)) {
+    return;
+  }
+  $node = clone $context->data;
   $block = new stdClass();
   $block->module = 'comments';
-  $block->delta  = $node->nid;
-
+  $block->delta = $node->nid;
   $block->title = t('Comments');
-  if (empty($node)) {
-    $block->content = t('Node comments go here.');
-  }
-  else if ($node->comment) {
+
+  if ($node->comment) {
     $block->content = ctools_comment_render($node, $conf);
-    // Update the history table, stating that this user viewed this node.
-    node_tag_new($node);
   }
 
   return $block;
@@ -50,7 +52,8 @@ function ctools_node_comments_content_type_edit_form($form, &$form_state) {
   foreach (_comment_per_page() as $i) {
     $options[$i] = t('!a comments per page', array('!a' => $i));
   }
-  $form['comments_per_page'] = array('#type' => 'select',
+  $form['comments_per_page'] = array(
+    '#type' => 'select',
     '#title' => t('Pager'),
     '#default_value' => $conf['comments_per_page'],
     '#options' => $options,
diff --git a/plugins/content_types/node_context/node_content.inc b/plugins/content_types/node_context/node_content.inc
index 38c5b574423c8fdbc7f764840180827f1fda1d94..ba873ed78da39e80ebe33c72f4e02e1b03522cd2 100644
--- a/plugins/content_types/node_context/node_content.inc
+++ b/plugins/content_types/node_context/node_content.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node content'),
@@ -27,18 +29,18 @@ $plugin = array(
  * Render the node content.
  */
 function ctools_node_content_content_type_render($subtype, $conf, $panel_args, $context) {
-  if (!empty($context) && empty($context->data)) {
+  if (!empty($context) && (empty($context->data) || empty($context->data->nid))) {
     return;
   }
 
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  $node = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'node';
-  $block->delta  = $node->nid;
+  $block->delta = $node->nid;
 
   if (empty($node)) {
     $block->delta   = 'placeholder';
-    $block->title = t('Node title.');
+    $block->title   = t('Node title.');
     $block->content = t('Node content goes here.');
   }
   else {
@@ -86,7 +88,7 @@ function ctools_node_content_render_node($node, $conf) {
       $links['node-readmore'] = array(
         'title' => t('Read more'),
         'href' => 'node/' . $node->nid,
-        'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title))
+        'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title)),
       );
     }
 
@@ -201,4 +203,3 @@ function ctools_node_content_content_type_edit_form_submit($form, &$form_state)
 function ctools_node_content_content_type_admin_title($subtype, $conf, $context) {
   return t('"@s" content', array('@s' => $context->identifier));
 }
-
diff --git a/plugins/content_types/node_context/node_created.inc b/plugins/content_types/node_context/node_created.inc
index 06d14427b6d0ecae07ef0994dae47f641247c10a..da3fbf8bdc3a68ce6a0eac56ef591b0162de926e 100644
--- a/plugins/content_types/node_context/node_created.inc
+++ b/plugins/content_types/node_context/node_created.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node created date'),
@@ -20,7 +22,7 @@ $plugin = array(
  * Render the custom content type.
  */
 function ctools_node_created_content_type_render($subtype, $conf, $panel_args, $context) {
-  if (empty($context) || empty($context->data)) {
+  if (!empty($context) && (empty($context->data) || empty($context->data->nid))) {
     return;
   }
 
@@ -28,7 +30,7 @@ function ctools_node_created_content_type_render($subtype, $conf, $panel_args, $
   $node = $context->data;
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'node_created';
   $block->title   = t('Created date');
   $block->content = format_date($node->created, $conf['format']);
diff --git a/plugins/content_types/node_context/node_links.inc b/plugins/content_types/node_context/node_links.inc
index 6096a44fb673daf02293f75ed2e621b7ea19114b..384fb639f15fe530374e7528c49ec3796b033a7b 100644
--- a/plugins/content_types/node_context/node_links.inc
+++ b/plugins/content_types/node_context/node_links.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node links'),
@@ -29,10 +31,10 @@ function ctools_node_links_content_type_render($subtype, $conf, $panel_args, $co
     return;
   }
 
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  $node = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'node';
-  $block->delta  = $node->nid;
+  $block->delta = $node->nid;
 
   if (empty($node)) {
     $block->delta   = 'placeholder';
@@ -102,4 +104,3 @@ function ctools_node_links_content_type_edit_form_submit($form, &$form_state) {
 function ctools_node_links_content_type_admin_title($subtype, $conf, $context) {
   return t('"@s" links', array('@s' => $context->identifier));
 }
-
diff --git a/plugins/content_types/node_context/node_terms.inc b/plugins/content_types/node_context/node_terms.inc
index f6e7aec33ab514bdf34915c1dec3a668a355f9a6..e910e4c7c371f806f7490a956709f5d39270d779 100644
--- a/plugins/content_types/node_context/node_terms.inc
+++ b/plugins/content_types/node_context/node_terms.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node terms'),
@@ -30,7 +32,7 @@ function ctools_node_terms_content_type_render($subtype, $conf, $panel_args, $co
   // Get a shortcut to the node.
   $node = $context->data;
 
-  // Load all terms for this node from all vocabularies
+  // Load all terms for this node from all vocabularies.
   $query = db_select('taxonomy_index', 't');
   $result = $query
     ->fields('t')
@@ -38,22 +40,22 @@ function ctools_node_terms_content_type_render($subtype, $conf, $panel_args, $co
     ->execute();
 
   $tids = array();
-  foreach ($result AS $term) {
+  foreach ($result as $term) {
     $tids[] = $term->tid;
   }
 
-  // Get the real term objects
+  // Get the real term objects.
   $term_objects = taxonomy_term_load_multiple($tids);
 
   $terms = array();
 
   if (empty($conf['vid'])) {
     // All terms.
-    foreach ($term_objects AS $term) {
+    foreach ($term_objects as $term) {
       $terms['taxonomy_term_' . $term->tid] = array(
         'title' => check_plain($term->name),
         'href' => 'taxonomy/term/' . $term->tid,
-        'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description))
+        'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description)),
       );
     }
   }
@@ -106,7 +108,7 @@ function ctools_node_terms_content_type_render($subtype, $conf, $panel_args, $co
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'node_terms';
   $block->delta   = $node->nid;
   $block->title   = t('Terms');
diff --git a/plugins/content_types/node_context/node_title.inc b/plugins/content_types/node_context/node_title.inc
index bec8982563230961b86d3307c1769c2f7d2dbb33..6956c2f23acde172b4bb5f58102f370e84c0d9da 100644
--- a/plugins/content_types/node_context/node_title.inc
+++ b/plugins/content_types/node_context/node_title.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node title'),
@@ -23,7 +25,7 @@ $plugin = array(
  * Render the custom content type.
  */
 function ctools_node_title_content_type_render($subtype, $conf, $panel_args, $context) {
-  if (empty($context) || empty($context->data)) {
+  if (!empty($context) && (empty($context->data) || empty($context->data->nid))) {
     return;
   }
 
@@ -33,10 +35,10 @@ function ctools_node_title_content_type_render($subtype, $conf, $panel_args, $co
   // Load information about the node type.
   $type = node_type_get_type($node);
 
-  // Generate the title
+  // Generate the title.
   $content = !empty($conf['link']) ? l($node->title, 'node/' . $node->nid) : check_plain($node->title);
 
-  // Build any surrounding markup if so configured
+  // Build any surrounding markup if so configured.
   if (isset($conf['markup']) && $conf['markup'] != 'none') {
     $markup = '<' . $conf['markup'];
     if (!empty($conf['id'])) {
@@ -50,7 +52,7 @@ function ctools_node_title_content_type_render($subtype, $conf, $panel_args, $co
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'node_title';
   $block->title   = $type->title_label;
   $block->content = $content;
diff --git a/plugins/content_types/node_context/node_type_desc.inc b/plugins/content_types/node_context/node_type_desc.inc
index f2005d08b538cb94b1f006ebbb9a7948515b2bea..0694c539e2ead65d3626fe0599d3e6874b87a7f5 100644
--- a/plugins/content_types/node_context/node_type_desc.inc
+++ b/plugins/content_types/node_context/node_type_desc.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node type description'),
@@ -18,18 +20,18 @@ $plugin = array(
  * based on the module and delta supplied in the configuration.
  */
 function ctools_node_type_desc_content_type_render($subtype, $conf, $panel_args, $context) {
-  $node = isset($context->data) ? clone($context->data) : NULL;
+  $node = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'node_type';
 
   if ($node) {
-    $type = node_type_get_type($node);
-    $block->title = $type->name;
+    $type           = node_type_get_type($node);
+    $block->title   = $type->name;
     $block->content = filter_xss_admin($type->description);
     $block->delta   = $node->type;
   }
   else {
-    $block->title = t('Node type description');
+    $block->title   = t('Node type description');
     $block->content = t('Node type description goes here.');
     $block->delta   = 'unknown';
   }
@@ -42,6 +44,6 @@ function ctools_node_type_desc_content_type_admin_title($subtype, $conf, $contex
 }
 
 function ctools_node_type_desc_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_context/node_updated.inc b/plugins/content_types/node_context/node_updated.inc
index 8b709cdf8492b5b5898b70f3878f72cb398819a9..eb5066917c409d2c36cd204406f9c4465e3aca3d 100644
--- a/plugins/content_types/node_context/node_updated.inc
+++ b/plugins/content_types/node_context/node_updated.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Node last updated date'),
@@ -20,7 +22,7 @@ $plugin = array(
  * Render the custom content type.
  */
 function ctools_node_updated_content_type_render($subtype, $conf, $panel_args, $context) {
-  if (empty($context) || empty($context->data)) {
+  if (empty($context) || empty($context->data) || empty($context->data->nid)) {
     return;
   }
 
@@ -28,7 +30,7 @@ function ctools_node_updated_content_type_render($subtype, $conf, $panel_args, $
   $node = $context->data;
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'node_updated';
   $block->title   = t('Last updated date');
   $block->content = format_date(!empty($node->changed) ? $node->changed : $node->created, $conf['format']);
diff --git a/plugins/content_types/node_form/node_form_attachments.inc b/plugins/content_types/node_form/node_form_attachments.inc
index 1e248f5005c73e93cf87cdc0c13f2e6ed2bdd66a..51c95a5e9deb3a2c0ad646c4c273dbe99e57a68c 100644
--- a/plugins/content_types/node_form/node_form_attachments.inc
+++ b/plugins/content_types/node_form/node_form_attachments.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('upload')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -17,7 +21,7 @@ if (module_exists('upload')) {
 
 function ctools_node_form_attachments_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = t('Attach files');
   $block->delta = 'url-path-options';
@@ -46,6 +50,6 @@ function ctools_node_form_attachments_content_type_admin_title($subtype, $conf,
 }
 
 function ctools_node_form_attachments_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_author.inc b/plugins/content_types/node_form/node_form_author.inc
index 350df40a962d7a2e0f2c5bb42fc56d794ff6e4db..86f3d7314201c620b8872abf708b27f4d40811aa 100644
--- a/plugins/content_types/node_form/node_form_author.inc
+++ b/plugins/content_types/node_form/node_form_author.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'icon' => 'icon_node_form.png',
@@ -15,7 +17,7 @@ $plugin = array(
 
 function ctools_node_form_author_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = t('Authoring information');
   $block->delta = 'author-options';
@@ -47,6 +49,6 @@ function ctools_node_form_author_content_type_admin_title($subtype, $conf, $cont
 }
 
 function ctools_node_form_author_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_book.inc b/plugins/content_types/node_form/node_form_book.inc
index ad19590f1701e254e41e53fb29babeffe5898250..b7ad36bdf2b969ba043b016c1e240cfa101c2a48 100644
--- a/plugins/content_types/node_form/node_form_book.inc
+++ b/plugins/content_types/node_form/node_form_book.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('book')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -17,7 +21,7 @@ if (module_exists('book')) {
 
 function ctools_node_form_book_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = t('Book outline');
   $block->delta = 'book-outline';
@@ -45,6 +49,6 @@ function ctools_node_form_book_content_type_admin_title($subtype, $conf, $contex
 }
 
 function ctools_node_form_book_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_buttons.inc b/plugins/content_types/node_form/node_form_buttons.inc
index b7ac9841dbdfc3b0f01722594b0571ec0f77a50b..ed553a67d3fdc9c5f04890a93fa0b75cb8149527 100644
--- a/plugins/content_types/node_form/node_form_buttons.inc
+++ b/plugins/content_types/node_form/node_form_buttons.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'icon' => 'icon_node_form.png',
@@ -15,7 +17,7 @@ $plugin = array(
 
 function ctools_node_form_buttons_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = '';
   $block->delta = 'buttons';
@@ -38,6 +40,6 @@ function ctools_node_form_buttons_content_type_admin_title($subtype, $conf, $con
 }
 
 function ctools_node_form_buttons_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_comment.inc b/plugins/content_types/node_form/node_form_comment.inc
index d0f137ae7a08fa45a792ae2227b78a3afd68d6cb..eaf5c954c115d4b84c93bd52490d1c18ecaf9d54 100644
--- a/plugins/content_types/node_form/node_form_comment.inc
+++ b/plugins/content_types/node_form/node_form_comment.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('comment')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -17,7 +21,7 @@ if (module_exists('comment')) {
 
 function ctools_node_form_comment_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = t('Comment options');
   $block->delta = 'comment-options';
@@ -45,6 +49,6 @@ function ctools_node_form_comment_content_type_admin_title($subtype, $conf, $con
 }
 
 function ctools_node_form_comment_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_language.inc b/plugins/content_types/node_form/node_form_language.inc
index 2043c1c52f0ade80b96149fc28021a6af66b9b81..dfef295f511a504304091f0ed7efbb2c04dc27b4 100644
--- a/plugins/content_types/node_form/node_form_language.inc
+++ b/plugins/content_types/node_form/node_form_language.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'icon' => 'icon_node_form.png',
@@ -15,7 +17,7 @@ $plugin = array(
 
 function ctools_node_form_language_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->delta = 'language-options';
 
@@ -36,6 +38,6 @@ function ctools_node_form_language_content_type_admin_title($subtype, $conf, $co
 }
 
 function ctools_node_form_language_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
-}
\ No newline at end of file
+}
diff --git a/plugins/content_types/node_form/node_form_log.inc b/plugins/content_types/node_form/node_form_log.inc
index 334ff54004fbc73a6afe888ab5911aad20bcd65b..aac42a6455ca1a67e723362ccaae2ad332b6929c 100644
--- a/plugins/content_types/node_form/node_form_log.inc
+++ b/plugins/content_types/node_form/node_form_log.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'icon' => 'icon_node_form.png',
@@ -15,7 +17,7 @@ $plugin = array(
 
 function ctools_node_form_log_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
   $block->title = t('Revision information');
 
   if (isset($context->form)) {
@@ -42,6 +44,6 @@ function ctools_node_form_log_content_type_admin_title($subtype, $conf, $context
 }
 
 function ctools_node_form_log_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_menu.inc b/plugins/content_types/node_form/node_form_menu.inc
index 906ade4d7d475896643ee607156bbe8fa9777ec2..9b4df43452e22196ecb4c9d4a58d6da580b1c2c1 100644
--- a/plugins/content_types/node_form/node_form_menu.inc
+++ b/plugins/content_types/node_form/node_form_menu.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('menu')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -17,7 +21,7 @@ if (module_exists('menu')) {
 
 function ctools_node_form_menu_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = t('Menu options');
   $block->delta = 'menu-options';
@@ -45,6 +49,6 @@ function ctools_node_form_menu_content_type_admin_title($subtype, $conf, $contex
 }
 
 function ctools_node_form_menu_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_path.inc b/plugins/content_types/node_form/node_form_path.inc
index a1e3cba03db106f137df24951f3b483692b02eca..262851f0ad17e7e3a8031cd14c002c7b5eb20746 100644
--- a/plugins/content_types/node_form/node_form_path.inc
+++ b/plugins/content_types/node_form/node_form_path.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('path')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -17,7 +21,7 @@ if (module_exists('path')) {
 
 function ctools_node_form_path_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->title = t('URL path options');
   $block->delta = 'url-path-options';
@@ -46,6 +50,6 @@ function ctools_node_form_path_content_type_admin_title($subtype, $conf, $contex
 }
 
 function ctools_node_form_path_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_publishing.inc b/plugins/content_types/node_form/node_form_publishing.inc
index e73cff21b600e856b02c515ae2f8511166d39bac..53b584f90908944046645b41376ce3dce82a39eb 100644
--- a/plugins/content_types/node_form/node_form_publishing.inc
+++ b/plugins/content_types/node_form/node_form_publishing.inc
@@ -23,7 +23,7 @@ function ctools_node_form_publishing_content_type_render($subtype, $conf, $panel
   $block = new stdClass();
 
   $block->title = t('Publishing options');
-  $block->module = t('node_form');
+  $block->module = 'node_form';
   $block->delta = 'publishing-options';
 
   if (isset($context->form)) {
@@ -49,6 +49,6 @@ function ctools_node_form_publishing_content_type_admin_title($subtype, $conf, $
 }
 
 function ctools_node_form_publishing_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/node_form/node_form_title.inc b/plugins/content_types/node_form/node_form_title.inc
index f40d274dec52ec83fac948a27e0585f68676e83a..14e79abae89cd4427ba9a2f66ef72d449a770083 100644
--- a/plugins/content_types/node_form/node_form_title.inc
+++ b/plugins/content_types/node_form/node_form_title.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'icon' => 'icon_node_form.png',
@@ -15,7 +17,7 @@ $plugin = array(
 
 function ctools_node_form_title_content_type_render($subtype, $conf, $panel_args, &$context) {
   $block = new stdClass();
-  $block->module = t('node_form');
+  $block->module = 'node_form';
 
   $block->delta = 'title-options';
 
@@ -36,6 +38,6 @@ function ctools_node_form_title_content_type_admin_title($subtype, $conf, $conte
 }
 
 function ctools_node_form_title_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/page/page_help.inc b/plugins/content_types/page/page_help.inc
index da1abe69f5fb5e8967cf49123f2c9067311b1252..dcba97d4803caf3907458949ce15e33de6efcba2 100644
--- a/plugins/content_types/page/page_help.inc
+++ b/plugins/content_types/page/page_help.inc
@@ -30,4 +30,3 @@ function ctools_page_help_content_type_render($subtype, $conf, $panel_args) {
 
   return $block;
 }
-
diff --git a/plugins/content_types/page/page_logo.inc b/plugins/content_types/page/page_logo.inc
index c00ca5e888ba6869d8e17c6620a53a41ed820270..fa7cdaea36c3f1fa786c7686adda74551d7f4f09 100644
--- a/plugins/content_types/page/page_logo.inc
+++ b/plugins/content_types/page/page_logo.inc
@@ -29,7 +29,7 @@ function ctools_page_logo_content_type_render($subtype, $conf, $panel_args) {
   $block = new stdClass();
 
   if (!empty($logo)) {
-    $image = '<img src="' . $logo . '" alt="' . t('Home') . '" />';
+    $image = theme('image', array('path' => $logo, 'alt' => t('Home')));
     $block->content = l($image, '', array('html' => TRUE, 'attributes' => array('rel' => 'home', 'id' => 'logo', 'title' => t('Home'))));
   }
 
diff --git a/plugins/content_types/page/page_messages.inc b/plugins/content_types/page/page_messages.inc
index e2fe37b3574d67dc0e9d6adfe9d238ae5b0357a6..9a8bc74bfab4fee66db3ef649ec902d307517da6 100644
--- a/plugins/content_types/page/page_messages.inc
+++ b/plugins/content_types/page/page_messages.inc
@@ -30,4 +30,3 @@ function ctools_page_messages_content_type_render($subtype, $conf, $panel_args)
 
   return $block;
 }
-
diff --git a/plugins/content_types/page/page_site_name.inc b/plugins/content_types/page/page_site_name.inc
index 99501f2c1f9ef46799a55870cc7aca756d41aec3..cb834316a3a22a5dd548e067f9e30b94fa9aa277 100644
--- a/plugins/content_types/page/page_site_name.inc
+++ b/plugins/content_types/page/page_site_name.inc
@@ -7,18 +7,48 @@
  */
 
 /**
- * Plugins are described by creating a $plugin array which will be used
- * by the system that includes this file.
+ * Plugins are described by creating a $plugin array which will be used by the
+ * system that includes this file.
  */
 $plugin = array(
   'title' => t('Site name'),
   'single' => TRUE,
   'icon' => 'icon_page.png',
-  'description' => t('The name of the site.'),
+  'description' => t('The name of the site, optionally links to the front page.'),
   'category' => t('Page elements'),
   'render last' => TRUE,
+  'defaults' => array(
+    'linked' => FALSE,
+  ),
 );
 
+/**
+ * Settings form for the Site Name pane.
+ */
+function ctools_page_site_name_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+
+  $form['linked'] = array(
+    '#title' => t('Linked'),
+    '#description' => t('Link the site name to the home page.'),
+    '#type' => 'checkbox',
+    '#default_value' => isset($conf['linked']) ? $conf['linked'] : FALSE,
+  );
+
+  return $form;
+}
+
+/**
+ * The submit form stores the data in $conf.
+ */
+function ctools_page_site_name_content_type_edit_form_submit($form, &$form_state) {
+  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
+    if (isset($form_state['values'][$key])) {
+      $form_state['conf'][$key] = $form_state['values'][$key];
+    }
+  }
+}
+
 /**
  * Output function for the 'page_site_name' content type.
  *
@@ -26,7 +56,13 @@ $plugin = array(
  */
 function ctools_page_site_name_content_type_render($subtype, $conf, $panel_args) {
   $block = new stdClass();
+
   $block->content = filter_xss_admin(variable_get('site_name', 'Drupal'));
 
+  // Optionally link the site name to the homepage.
+  if (!empty($conf['linked'])) {
+    $block->content = l($block->content, '<front>', array('html' => TRUE));
+  }
+
   return $block;
 }
diff --git a/plugins/content_types/page/page_tabs.inc b/plugins/content_types/page/page_tabs.inc
index e88acd54fc393806a6fa156a512aa50758e1a8d2..6a2e9a7dc353a98a3f1a6b5ca68b41f8337562be 100644
--- a/plugins/content_types/page/page_tabs.inc
+++ b/plugins/content_types/page/page_tabs.inc
@@ -40,6 +40,7 @@ function ctools_page_tabs_content_type_render($subtype, $conf, $panel_args) {
     case 'primary':
       unset($menus['#secondary']);
       break;
+
     case 'secondary':
       unset($menus['#primary']);
       break;
@@ -54,7 +55,6 @@ function ctools_page_tabs_content_type_render($subtype, $conf, $panel_args) {
   return $block;
 }
 
-
 function ctools_page_tabs_content_type_edit_form($form, &$form_state) {
   $conf = $form_state['conf'];
 
diff --git a/plugins/content_types/page/page_title.inc b/plugins/content_types/page/page_title.inc
index e3032dfbee69e0c9adbbe9785999be7cf5ef7e2c..c32ef7e1c0d687c6f8aae903c24bc7321f0bdfc3 100644
--- a/plugins/content_types/page/page_title.inc
+++ b/plugins/content_types/page/page_title.inc
@@ -29,6 +29,12 @@ $plugin = array(
  * Outputs the page title of the current page.
  */
 function ctools_page_title_content_type_render($subtype, $conf, $panel_args) {
+  // $conf['override_title'] can have one of these three values.
+  // 0 i.e. hide the title, 1 i.e. no title, and 2 i.e. pane title if it's a
+  // panels page.
+  if (!drupal_get_title() && isset($conf['override_title']) && $conf['override_title'] === 1) {
+    return;
+  }
   // TODO: This should have a setting or something for the markup.
   if (empty($conf['markup'])) {
     $conf['markup'] = 'h1';
diff --git a/plugins/content_types/search/search_form.inc b/plugins/content_types/search/search_form.inc
index 2b6a322b1e647ef179ff1eea50a2cd2f095f6268..01671007772a9ba6543144b56246b778cb88de48 100644
--- a/plugins/content_types/search/search_form.inc
+++ b/plugins/content_types/search/search_form.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('search')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -35,10 +39,10 @@ function ctools_search_form_content_type_render($subtype, $conf, $panel_args, $c
   }
 
   // Build the content type block.
-  $block = new stdClass();
-  $block->module  = 'search';
-  $block->delta   = 'form';
-  $block->title   = '';
+  $block         = new stdClass();
+  $block->module = 'search';
+  $block->delta  = 'form';
+  $block->title  = '';
 
   switch ($conf['path_type']) {
     default:
@@ -49,6 +53,7 @@ function ctools_search_form_content_type_render($subtype, $conf, $panel_args, $c
       $path = $_GET['q'];
       $path = str_replace($keys, '', $path);
       break;
+
     case 'custom':
       $path = $conf['path'];
       break;
diff --git a/plugins/content_types/search/search_result.inc b/plugins/content_types/search/search_result.inc
index 32037bdf50049c294f9cac5f9ba7e68d572ec505..fb88a0fe4c118a660864ebbc624938dede07404c 100644
--- a/plugins/content_types/search/search_result.inc
+++ b/plugins/content_types/search/search_result.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('search')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -42,7 +46,7 @@ function ctools_search_result_content_type_render($subtype, $conf, $panel_args,
     $keys = $context->data;
   }
 
-  $conditions =  NULL;
+  $conditions = NULL;
   if (isset($info['conditions_callback']) && function_exists($info['conditions_callback'])) {
     // Build an optional array of more search conditions.
     $conditions = $info['conditions_callback']($keys);
@@ -59,9 +63,9 @@ function ctools_search_result_content_type_render($subtype, $conf, $panel_args,
   }
 
   // Build the content type block.
-  $block = new stdClass();
-  $block->module  = 'search';
-  $block->delta   = 'result';
+  $block         = new stdClass();
+  $block->module = 'search';
+  $block->delta  = 'result';
 
   $results = '';
 
@@ -160,7 +164,6 @@ function ctools_search_result_content_type_edit_form($form, &$form_state) {
     '#title' => t('Display text if no search keywords were submitted'),
   );
 
-
   $form['no_key_title'] = array(
     '#title' => t('Title'),
     '#type' => 'textfield',
diff --git a/plugins/content_types/term_context/term_description.inc b/plugins/content_types/term_context/term_description.inc
index 2b953ed01cd3ae89ca89bc9adf2bdc1beec95cf8..6367075b18a3f44911a8d9e2ccd35b51b4b238c1 100644
--- a/plugins/content_types/term_context/term_description.inc
+++ b/plugins/content_types/term_context/term_description.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('Term description'),
@@ -14,12 +16,12 @@ $plugin = array(
 );
 
 function ctools_term_description_content_type_render($subtype, $conf, $panel_args, $context) {
-  $term = isset($context->data) ? clone($context->data) : NULL;
+  $term = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'node_type';
 
-  $block->title = $term->name;
-  if ($term) {
+  if (!empty($term)) {
+    $block->title = $term->name;
     $block->content = check_markup($term->description, $term->format, '', TRUE);
     $block->delta = $term->tid;
 
@@ -33,6 +35,7 @@ function ctools_term_description_content_type_render($subtype, $conf, $panel_arg
     }
   }
   else {
+    $block->title = '';
     $block->content = t('Term description goes here.');
     $block->delta = 'unknown';
   }
@@ -45,6 +48,6 @@ function ctools_term_description_content_type_admin_title($subtype, $conf, $cont
 }
 
 function ctools_term_description_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/term_context/term_list.inc b/plugins/content_types/term_context/term_list.inc
index dc3124b1c6d8f3ca07a49a4463e098e64bea4467..a5330749e0a5208d24aae143f21db603572faa2c 100644
--- a/plugins/content_types/term_context/term_list.inc
+++ b/plugins/content_types/term_context/term_list.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('List of related terms'),
@@ -11,11 +13,17 @@ $plugin = array(
   'description' => t('Terms related to an existing term; may be child, siblings or top level.'),
   'required context' => new ctools_context_required(t('Term'), array('term', 'taxonomy_term')),
   'category' => t('Taxonomy term'),
-  'defaults' => array('title' => '', 'type' => 'child', 'list_type' => 'ul', 'path' => 'taxonomy/term'),
+  'defaults' => array(
+    'title' => '',
+    'type' => 'child',
+    'include_current_term' => FALSE,
+    'list_type' => 'ul',
+    'path' => 'taxonomy/term',
+  ),
 );
 
 function ctools_term_list_content_type_render($subtype, $conf, $panel_args, $context) {
-  $term = isset($context->data) ? clone($context->data) : NULL;
+  $term = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'term-list';
   $path = empty($conf['path']) ? 'taxonomy/term/%tid' : $conf['path'];
@@ -34,12 +42,15 @@ function ctools_term_list_content_type_render($subtype, $conf, $panel_args, $con
     $block->delta = $conf['type'];
     switch ($conf['type']) {
       case 'related':
-        // FIXME this no longer exists, must be done with Field API
+        // @todo this no longer exists, must be done with Field API.
         // $terms = taxonomy_get_related($term->tid);
         break;
 
       case 'child':
       default:
+        if (!empty($conf['include_current_term'])) {
+          $terms[] = $term;
+        }
         $terms = taxonomy_get_children($term->tid);
         break;
 
@@ -49,6 +60,9 @@ function ctools_term_list_content_type_render($subtype, $conf, $panel_args, $con
 
       case 'parent':
         $terms = taxonomy_get_parents($term->tid);
+        if (!empty($conf['include_current_term'])) {
+          $terms[] = $term;
+        }
         $block->title = count($terms) == 1 ? t('Parent term') : t('Parent terms');
         break;
 
@@ -66,7 +80,7 @@ function ctools_term_list_content_type_render($subtype, $conf, $panel_args, $con
 
       case 'synonyms':
         // FIXME this no longer exists, must be done with Field API
-//        $terms = taxonomy_get_synonyms($term->tid);
+        //        $terms = taxonomy_get_synonyms($term->tid);.
         break;
     }
 
@@ -116,6 +130,20 @@ function ctools_term_list_content_type_edit_form($form, &$form_state) {
     '#suffix' => '</div>',
   );
 
+  $form['include_current_term'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Include the current term in the list'),
+    '#default_value' => !empty($conf['include_current_term']),
+    '#prefix' => '<div class="clearfix no-float">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'invisible' => array(
+        ':input[name="type"], unique1' => array('!value' => 'child'),
+        ':input[name="type"], unique2' => array('!value' => 'parent'),
+      ),
+    ),
+  );
+
   $form['list_type'] = array(
     '#type' => 'select',
     '#title' => t('List type'),
@@ -143,4 +171,3 @@ function ctools_term_list_content_type_edit_form_submit($form, &$form_state) {
     $form_state['conf'][$key] = $form_state['values'][$key];
   }
 }
-
diff --git a/plugins/content_types/term_context/term_name.inc b/plugins/content_types/term_context/term_name.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ec30be4d90100834f60bee5dcc97f88345a491e6
--- /dev/null
+++ b/plugins/content_types/term_context/term_name.inc
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+
+$plugin = array(
+  'single' => TRUE,
+  'title' => t('Term name'),
+  'icon' => 'icon_term.png',
+  'description' => t('The name of this taxonomy term.'),
+  'required context' => new ctools_context_required(t('Term'), array('term', 'taxonomy_term')),
+  'category' => t('Taxonomy term'),
+  'defaults' => array(
+    'link' => TRUE,
+    'markup' => 'none',
+    'id' => '',
+    'class' => '',
+  ),
+);
+
+/**
+ * Render the custom content type.
+ */
+function ctools_term_name_content_type_render($subtype, $conf, $panel_args, $context) {
+  if (empty($context) || empty($context->data)) {
+    return;
+  }
+
+  // Get a shortcut to the term.
+  $term = $context->data;
+
+  // Load the vocabulary.
+  $vocab = taxonomy_vocabulary_load($term->vid);
+
+  // Generate the title.
+  $content = !empty($conf['link']) ? l($term->name, 'taxonomy/term/' . $term->tid) : check_plain($term->name);
+
+  // Build any surrounding markup if so configured.
+  if (isset($conf['markup']) && $conf['markup'] != 'none') {
+    $markup = '<' . $conf['markup'];
+    if (!empty($conf['id'])) {
+      $markup .= ' id="' . $conf['id'] . '"';
+    }
+    if (!empty($conf['class'])) {
+      $markup .= ' class="' . $conf['class'] . '"';
+    }
+    $markup .= '>' . $content . '</' . $conf['markup'] . '>' . "\n";
+    $content = $markup;
+  }
+
+  // Build the content type block.
+  $block          = new stdClass();
+  $block->module  = 'term_name';
+  $block->title   = t('Name');
+  $block->content = $content;
+  $block->delta   = $term->tid;
+
+  return $block;
+}
+
+/**
+ * Returns an edit form for custom type settings.
+ */
+function ctools_term_name_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+
+  $form['markup'] = array(
+    '#title' => t('Title tag'),
+    '#type' => 'select',
+    '#options' => array(
+      'none' => t('- No tag -'),
+      'h1' => t('h1'),
+      'h2' => t('h2'),
+      'h3' => t('h3'),
+      'h4' => t('h4'),
+      'h5' => t('h5'),
+      'h6' => t('h6'),
+      'div' => t('div'),
+    ),
+    '#default_value' => $conf['markup'],
+  );
+
+  $form['id'] = array(
+    '#title' => t('CSS id to use'),
+    '#type' => 'textfield',
+    '#default_value' => $conf['id'],
+  );
+
+  $form['class'] = array(
+    '#title' => t('CSS class to use'),
+    '#type' => 'textfield',
+    '#default_value' => $conf['class'],
+  );
+
+  $form['link'] = array(
+    '#title' => t('Link to term'),
+    '#type' => 'checkbox',
+    '#default_value' => $conf['link'],
+    '#description' => t('Check here to make the name link to the term page.'),
+  );
+  return $form;
+}
+
+/**
+ * Submit handler for the custom type settings form.
+ */
+function ctools_term_name_content_type_edit_form_submit($form, &$form_state) {
+  // Copy everything from our defaults.
+  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
+    $form_state['conf'][$key] = $form_state['values'][$key];
+  }
+}
+
+/**
+ * Returns the administrative title for a type.
+ */
+function ctools_term_name_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" name', array('@s' => $context->identifier));
+}
diff --git a/plugins/content_types/token/token.inc b/plugins/content_types/token/token.inc
index 7b6f7fcd51faa04a6db7122e84c142234ce49e90..32026d852e5e64f0c7a68e6053114630813baea6 100644
--- a/plugins/content_types/token/token.inc
+++ b/plugins/content_types/token/token.inc
@@ -62,8 +62,8 @@ function ctools_token_content_type_content_types() {
 }
 
 /**
-* Render the custom content type.
-*/
+ * Render the custom content type.
+ */
 function ctools_token_content_type_render($subtype, $conf, $panel_args, $context) {
   if (empty($context) || empty($context->data)) {
     return FALSE;
@@ -81,7 +81,7 @@ function ctools_token_content_type_render($subtype, $conf, $panel_args, $context
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'ctools';
   $block->title   = $info['tokens'][$entity_type][$name]['name'];
   $block->content = $values[$name];
@@ -91,8 +91,8 @@ function ctools_token_content_type_render($subtype, $conf, $panel_args, $context
 }
 
 /**
-* Returns an edit form for custom type settings.
-*/
+ * Returns an edit form for custom type settings.
+ */
 function ctools_token_content_type_edit_form($form, &$form_state) {
   $conf = $form_state['conf'];
 
@@ -113,10 +113,9 @@ function ctools_token_content_type_edit_form_submit($form, &$form_state) {
   $form_state['conf']['sanitize'] = $form_state['values']['sanitize'];
 }
 
-
 /**
-* Returns the administrative title for a type.
-*/
+ * Returns the administrative title for a type.
+ */
 function ctools_token_content_type_admin_title($subtype, $conf, $context) {
   return t('"@s" @name', array('@s' => $context->identifier, '@name' => $subtype));
 }
diff --git a/plugins/content_types/user_context/profile_fields.inc b/plugins/content_types/user_context/profile_fields.inc
index 55d5593db38c3ea12d0344b3d2e73bb15747e72f..019715fba82fc3f1f51eda829f7c206aa44212ba 100644
--- a/plugins/content_types/user_context/profile_fields.inc
+++ b/plugins/content_types/user_context/profile_fields.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('profile') && !(defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') && !is_null(profile_user_categories())) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -21,18 +25,18 @@ if (module_exists('profile') && !(defined('MAINTENANCE_MODE') && MAINTENANCE_MOD
  * 'Render' callback for the 'profile fields' content type.
  */
 function ctools_profile_fields_content_type_render($subtype, $conf, $panel_args, $context) {
-  $account = isset($context->data) ? clone($context->data) : NULL;
+  $account = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'profile fields';
 
   if ($account) {
-    // Get the category from the options
+    // Get the category from the options.
     $category = str_replace("_", " ", $conf['category']);
 
-    // Set the subject to the name of the category
+    // Set the subject to the name of the category.
     $block->subject = $category;
 
-    // Put all the fields in the category into an array
+    // Put all the fields in the category into an array.
     profile_view_profile($account);
 
     if (is_array($account->content[$category])) {
@@ -46,11 +50,11 @@ function ctools_profile_fields_content_type_render($subtype, $conf, $panel_args,
     }
 
     if (count($vars) == 0) {
-      // Output the given empty text
+      // Output the given empty text.
       $output = $conf['empty'];
     }
     else {
-      // Call the theme function with the field vars
+      // Call the theme function with the field vars.
       $output = theme('profile_fields_pane', $category, $vars);
     }
 
@@ -65,6 +69,7 @@ function ctools_profile_fields_content_type_render($subtype, $conf, $panel_args,
 
   return $block;
 }
+
 /**
  * Helper function : build the list of categories for the 'edit' form.
  */
diff --git a/plugins/content_types/user_context/profile_fields_pane.tpl.php b/plugins/content_types/user_context/profile_fields_pane.tpl.php
index 373681213aacea3506e5ca2ab2ebdf767d1e6b54..bac10ce9af12e7268612c9f8e9f52e742f8e6148 100644
--- a/plugins/content_types/user_context/profile_fields_pane.tpl.php
+++ b/plugins/content_types/user_context/profile_fields_pane.tpl.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Display profile fields.
diff --git a/plugins/content_types/user_context/user_links.inc b/plugins/content_types/user_context/user_links.inc
new file mode 100644
index 0000000000000000000000000000000000000000..85ecf8772ea5ef033790de49b27d191e6147f612
--- /dev/null
+++ b/plugins/content_types/user_context/user_links.inc
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+
+$plugin = array(
+  'single' => TRUE,
+  'title' => t('User links'),
+  'icon' => 'icon_user.png',
+  'description' => t('User links of the referenced user.'),
+  'required context' => new ctools_context_required(t('User'), 'user'),
+  'category' => t('User'),
+  'defaults' => array(
+    'override_title' => FALSE,
+    'override_title_text' => '',
+    'build_mode' => '',
+  ),
+);
+
+/**
+ * Output function for the user links.
+ */
+function ctools_user_links_content_type_render($subtype, $conf, $panel_args, $context) {
+  if (!empty($context) && empty($context->data)) {
+    return;
+  }
+
+  $account = clone $context->data;
+  $block = new stdClass();
+  $block->module = 'user';
+  $block->delta = $account->uid;
+
+  if (empty($account)) {
+    $block->delta   = 'placeholder';
+    $block->subject = t('User name.');
+    $block->content = t('User links go here.');
+  }
+  else {
+    $block->subject = $account->name;
+    user_build_content($account, $conf['build_mode']);
+    if (!empty($account->content['links'])) {
+      $block->content = $account->content['links'];
+    }
+    else {
+      $block->content = '';
+    }
+  }
+  return $block;
+}
+
+/**
+ * Returns an edit form for the custom type.
+ */
+function ctools_user_links_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+
+  $entity = entity_get_info('user');
+  $build_mode_options = array();
+  foreach ($entity['view modes'] as $mode => $option) {
+    $build_mode_options[$mode] = $option['label'];
+  }
+
+  $form['build_mode'] = array(
+    '#title' => t('Build mode'),
+    '#type' => 'select',
+    '#description' => t('Select a build mode for this user.'),
+    '#options' => $build_mode_options,
+    '#default_value' => $conf['build_mode'],
+  );
+
+  return $form;
+}
+
+function ctools_user_links_content_type_edit_form_submit($form, &$form_state) {
+  // Copy everything from our defaults.
+  foreach (array_keys($form_state['plugin']['defaults']) as $key) {
+    $form_state['conf'][$key] = $form_state['values'][$key];
+  }
+}
+
+function ctools_user_links_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" links', array('@s' => $context->identifier));
+}
diff --git a/plugins/content_types/user_context/user_picture.inc b/plugins/content_types/user_context/user_picture.inc
index 0934c20a5290f7c842718d2eb34dd6881de9237f..2d4d31bfe90bebf38ae147a837372a804a19e6bb 100644
--- a/plugins/content_types/user_context/user_picture.inc
+++ b/plugins/content_types/user_context/user_picture.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('User picture'),
@@ -22,7 +24,7 @@ function ctools_user_picture_content_type_render($subtype, $conf, $panel_args, $
 
   $account = clone $context->data;
 
-  // Check if user has permissions to access the user
+  // Check if user has permissions to access the user.
   if ($user->uid != $account->uid && (!user_access('access user profiles') && !user_access('administer users'))) {
     return;
   }
@@ -36,19 +38,18 @@ function ctools_user_picture_content_type_render($subtype, $conf, $panel_args, $
     '#account' => $account,
   );
 
-
   $block->content = $element;
   return $block;
 }
 
 /**
- * Display the administrative title for a panel pane in the drag & drop UI
+ * Display the administrative title for a panel pane in the drag & drop UI.
  */
 function ctools_user_picture_content_type_admin_title($subtype, $conf, $context) {
   return t('"@s" user picture', array('@s' => $context->identifier));
 }
 
 function ctools_user_picture_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/user_context/user_profile.inc b/plugins/content_types/user_context/user_profile.inc
index 6c41882ff136fe919f9a683d7d1df550d4ae8c29..3a28ca3910f59623fea86e49e5d492386a763d65 100644
--- a/plugins/content_types/user_context/user_profile.inc
+++ b/plugins/content_types/user_context/user_profile.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'single' => TRUE,
   'title' => t('User profile'),
@@ -20,7 +22,7 @@ $plugin = array(
  * Render the user profile content type.
  */
 function ctools_user_profile_content_type_render($subtype, $conf, $panel_args, $context) {
-  $account = isset($context->data) ? clone($context->data) : NULL;
+  $account = isset($context->data) ? clone $context->data : NULL;
   if (!$account) {
     return NULL;
   }
@@ -84,4 +86,3 @@ function ctools_user_profile_content_type_edit_form($form, &$form_state) {
 function ctools_user_profile_content_type_edit_form_submit($form, &$form_state) {
   $form_state['conf']['view_mode'] = $form_state['values']['view_mode'];
 }
-
diff --git a/plugins/content_types/user_context/user_signature.inc b/plugins/content_types/user_context/user_signature.inc
index ca7550b25b7be2c56e2d64e74ef79c48b6ab4b75..6a8e7f634a369e45fe182fca3e33a962308bea01 100644
--- a/plugins/content_types/user_context/user_signature.inc
+++ b/plugins/content_types/user_context/user_signature.inc
@@ -1,9 +1,11 @@
 <?php
 
 /**
+ * @file
  * Plugins are described by creating a $plugin array which will be used
  * by the system that includes this file.
  */
+
 $plugin = array(
   'title' => t('User signature'),
   'icon' => 'icon_user.png',
@@ -13,7 +15,7 @@ $plugin = array(
 );
 
 function ctools_user_signature_content_type_render($subtype, $conf, $panel_args, $context) {
-  $account = isset($context->data) ? clone($context->data) : NULL;
+  $account = isset($context->data) ? clone $context->data : NULL;
   $block = new stdClass();
   $block->module = 'user-signature';
 
@@ -31,13 +33,13 @@ function ctools_user_signature_content_type_render($subtype, $conf, $panel_args,
 }
 
 /**
- * Display the administrative title for a panel pane in the drag & drop UI
+ * Display the administrative title for a panel pane in the drag & drop UI.
  */
 function ctools_user_signature_content_type_admin_title($subtype, $conf, $context) {
   return t('"@s" user signature', array('@s' => $context->identifier));
 }
 
 function ctools_user_signature_content_type_edit_form($form, &$form_state) {
-  // provide a blank form so we have a place to have context setting.
+  // Provide a blank form so we have a place to have context setting.
   return $form;
 }
diff --git a/plugins/content_types/user_form/icon_user_form.png b/plugins/content_types/user_form/icon_user_form.png
new file mode 100644
index 0000000000000000000000000000000000000000..f0417cb6515aa7fb2856c90722b386ed99bfc501
Binary files /dev/null and b/plugins/content_types/user_form/icon_user_form.png differ
diff --git a/plugins/content_types/user_form/user_form_actions.inc b/plugins/content_types/user_form/user_form_actions.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e11587d81f7a0c60a7ae36f11071ce791eb901b3
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_actions.inc
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form actions / buttons'),
+  'description' => t('The user form actions / buttons.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the picture form field.
+ */
+function ctools_user_form_actions_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['actions'])) {
+      $block->content['actions'] = $context->form['actions'];
+      unset($context->form['actions']);
+    }
+    // Because we are adding the submit buttons outside the General form
+    // we can assume the necessary hidden components should be added as well.
+    if (!empty($context->form['form_build_id'])) {
+      $block->content['form_build_id'] = $context->form['form_build_id'];
+      unset($context->form['form_build_id']);
+    }
+    if (!empty($context->form['form_token'])) {
+      $block->content['form_token'] = $context->form['form_token'];
+      unset($context->form['form_token']);
+    }
+    if (!empty($context->form['form_id'])) {
+      $block->content['form_id'] = $context->form['form_id'];
+      unset($context->form['form_id']);
+    }
+  }
+  else {
+    $block->content = t('User actions / buttons form components.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the actions form field.
+ */
+function ctools_user_form_actions_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form actions / buttons field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the actions form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_actions_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_component.inc b/plugins/content_types/user_form/user_form_component.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b4963f99b765bf12687b5e5360d98291f1ffed9c
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_component.inc
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form: add a specific component'),
+  'description' => t('The user form component by selection.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the picture form field.
+ */
+function ctools_user_form_component_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form[$conf['field']])) {
+      $block->content[$conf['field']] = $context->form[$conf['field']];
+      unset($context->form[$conf['field']]);
+    }
+  }
+  else {
+    $block->content = t('User form edit components.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the a selectable form field.
+ */
+function ctools_user_form_component_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form @field field', array('@s' => $context->identifier, '@field' => $conf['field']));
+}
+
+/**
+ * Ctools plugin configuration edit form for the selectable form field.
+ *
+ * Provide the list of fields in the user profile edit form to select from the
+ * plugin configuration.
+ */
+function ctools_user_form_component_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+  $user_form = drupal_get_form('user_profile_form');
+
+  $field_keys = element_children($user_form);
+  $options = array_combine($field_keys, $field_keys);
+
+  $form['field'] = array(
+    '#type' => 'select',
+    '#title' => t('User form field'),
+    '#options' => $options,
+    '#description' => t('Select a form field from the current user form to display in this pane.'),
+    '#default_value' => !empty($conf['field']) ? $conf['field'] : '',
+  );
+  return $form;
+}
+
+/**
+ * Ctools plugin configuration edit form submit handler.
+ */
+function ctools_user_form_component_content_type_edit_form_submit($form, &$form_state) {
+  $form_state['conf']['field'] = $form_state['values']['field'];
+}
diff --git a/plugins/content_types/user_form/user_form_email.inc b/plugins/content_types/user_form/user_form_email.inc
new file mode 100644
index 0000000000000000000000000000000000000000..346555d0937dc3200fa5f60e4db4a47e6415ae43
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_email.inc
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form email field'),
+  'description' => t('The user email form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the email form field.
+ */
+function ctools_user_form_email_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    // The current password is required to change the email.
+    if (!empty($context->form['account']['current_pass'])) {
+      $block->content['current_pass'] = $context->form['account']['current_pass'];
+      unset($context->form['account']['current_pass']);
+    }
+    if (!empty($context->form['account']['mail'])) {
+      $block->content['mail'] = $context->form['account']['mail'];
+      unset($context->form['account']['mail']);
+    }
+  }
+  else {
+    $block->content = t('User email form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the email form field.
+ */
+function ctools_user_form_email_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form email field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the email form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_email_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_notify.inc b/plugins/content_types/user_form/user_form_notify.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bb74963c192b8e551d80e673326bda45cd023cce
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_notify.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form notify field'),
+  'description' => t('The user notify form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the notify form field.
+ */
+function ctools_user_form_notify_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['account']['notify'])) {
+      $block->content['notify'] = $context->form['account']['notify'];
+      unset($context->form['account']['notify']);
+    }
+  }
+  else {
+    $block->content = t('User notify form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the notify form field.
+ */
+function ctools_user_form_notify_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form notify field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the notify form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_notify_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_password.inc b/plugins/content_types/user_form/user_form_password.inc
new file mode 100644
index 0000000000000000000000000000000000000000..89bab949cbcb01a21fff272bd3f873765a6609b8
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_password.inc
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form password field'),
+  'description' => t('The user password form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the password form field.
+ */
+function ctools_user_form_password_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    // The current password is required to change the password.
+    if (!empty($context->form['account']['current_pass'])) {
+      $block->content['current_pass'] = $context->form['account']['current_pass'];
+      unset($context->form['account']['current_pass']);
+    }
+    if (!empty($context->form['account']['pass'])) {
+      $block->content['pass'] = $context->form['account']['pass'];
+      unset($context->form['account']['pass']);
+    }
+  }
+  else {
+    $block->content = t('User password form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the password form field.
+ */
+function ctools_user_form_password_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form password field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the password form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_password_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_picture.inc b/plugins/content_types/user_form/user_form_picture.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ac310bed7858041e198d65ba94e6de0e1df62b52
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_picture.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form picture field'),
+  'description' => t('The user picture form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the picture form field.
+ */
+function ctools_user_form_picture_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['picture'])) {
+      $block->content['picture'] = $context->form['picture'];
+      unset($context->form['picture']);
+    }
+  }
+  else {
+    $block->content = t('User picture form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the picture form field.
+ */
+function ctools_user_form_picture_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form picture field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the picture form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_picture_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_roles.inc b/plugins/content_types/user_form/user_form_roles.inc
new file mode 100644
index 0000000000000000000000000000000000000000..47a169f7fdb67114ed646dd4048718bebc495893
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_roles.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form roles field'),
+  'description' => t('The user roles form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the roles form field.
+ */
+function ctools_user_form_roles_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['account']['roles'])) {
+      $block->content['roles'] = $context->form['account']['roles'];
+      unset($context->form['account']['roles']);
+    }
+  }
+  else {
+    $block->content = t('User roles form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the roles form field.
+ */
+function ctools_user_form_roles_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form roles field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the roles form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_roles_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_signature_settings.inc b/plugins/content_types/user_form/user_form_signature_settings.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2a69ea09eaa45589144e7bb7f0701d062cfd3879
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_signature_settings.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form signature settings field'),
+  'description' => t('The user signature settings form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the signature settings form field.
+ */
+function ctools_user_form_signature_settings_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['signature_settings'])) {
+      $block->content['signature_settings'] = $context->form['signature_settings'];
+      unset($context->form['signature_settings']);
+    }
+  }
+  else {
+    $block->content = t('User signature settings form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the signature settings form field.
+ */
+function ctools_user_form_signature_settings_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form signature settings field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the signature settings form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_signature_settings_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_status.inc b/plugins/content_types/user_form/user_form_status.inc
new file mode 100644
index 0000000000000000000000000000000000000000..7c7f872474f196c46d21c3a626ac46605f427653
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_status.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form status field'),
+  'description' => t('The user status form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the status form field.
+ */
+function ctools_user_form_status_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['account']['status'])) {
+      $block->content['status'] = $context->form['account']['status'];
+      unset($context->form['account']['status']);
+    }
+  }
+  else {
+    $block->content = t('User status form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the status form field.
+ */
+function ctools_user_form_status_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form status field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the status form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_status_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_timezone.inc b/plugins/content_types/user_form/user_form_timezone.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1a0066488fb7fb187cad5c1ec93b0b2dcb8aea5e
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_timezone.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form timezone field'),
+  'description' => t('The user timezone form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the timezone form field.
+ */
+function ctools_user_form_timezone_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['timezone'])) {
+      $block->content['timezone'] = $context->form['timezone'];
+      unset($context->form['timezone']);
+    }
+  }
+  else {
+    $block->content = t('User timezone form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the timezone form field.
+ */
+function ctools_user_form_timezone_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form timezone field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the timezone form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_timezone_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/user_form/user_form_username.inc b/plugins/content_types/user_form/user_form_username.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d64953085083bb011f9dc3ddbac3180e8ec731ba
--- /dev/null
+++ b/plugins/content_types/user_form/user_form_username.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'single' => TRUE,
+  'icon' => 'icon_user_form.png',
+  'title' => t('User form username field'),
+  'description' => t('The user username form.'),
+  'required context' => new ctools_context_required(t('Form'), 'form'),
+  'category' => t('Form'),
+);
+
+/**
+ * Ctools plugin content type render for the username form field.
+ */
+function ctools_user_form_username_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+  $block->module = t('user-form');
+
+  $block->delta = 'title-options';
+
+  if (isset($context->form)) {
+    if (!empty($context->form['account']['name'])) {
+      $block->content['name'] = $context->form['account']['name'];
+      unset($context->form['account']['name']);
+    }
+  }
+  else {
+    $block->content = t('User username form.');
+  }
+  return $block;
+}
+
+/**
+ * Ctools plugin admin title function for the username form field.
+ */
+function ctools_user_form_username_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" user form username field', array('@s' => $context->identifier));
+}
+
+/**
+ * Ctools plugin configuration edit form for the username form field.
+ *
+ * Provide a blank form so we have a place to have context setting.
+ */
+function ctools_user_form_username_content_type_edit_form($form, &$form_state) {
+  return $form;
+}
diff --git a/plugins/content_types/vocabulary_context/vocabulary_terms.inc b/plugins/content_types/vocabulary_context/vocabulary_terms.inc
index 5f33a03816d21f2b8ac5b9d46574a43f114be8ec..6a7f8ef8ece54da56fb89c3df7f6465582124e26 100644
--- a/plugins/content_types/vocabulary_context/vocabulary_terms.inc
+++ b/plugins/content_types/vocabulary_context/vocabulary_terms.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 if (module_exists('taxonomy')) {
   /**
    * Plugins are described by creating a $plugin array which will be used
@@ -21,8 +25,8 @@ if (module_exists('taxonomy')) {
  * list of terms for the input vocabulary.
  */
 function ctools_vocabulary_terms_content_type_render($subtype, $conf, $panel_args, $context) {
-  $vocab = isset($context->data) ? clone($context->data) : NULL;
-  $max_depth = (!empty($conf['max_depth']) ? (int)$conf['max_depth'] : NULL);
+  $vocab = isset($context->data) ? clone $context->data : NULL;
+  $max_depth = (!empty($conf['max_depth']) ? (int) $conf['max_depth'] : NULL);
   if ($conf['tree'] == FALSE) {
     $terms = taxonomy_get_tree($vocab->vid, 0, $max_depth);
     $items = array();
@@ -35,9 +39,9 @@ function ctools_vocabulary_terms_content_type_render($subtype, $conf, $panel_arg
     $output = theme('item_list', array('items' => _ctools_content_vocabulary_terms($vocab->vid, $max_depth)));
   }
 
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'node_type';
-  $block->title = check_plain($vocab->name);
+  $block->title   = check_plain($vocab->name);
   $block->content = $output;
   $block->delta   = $vocab->vid;
 
@@ -97,4 +101,3 @@ function ctools_vocabulary_terms_content_type_edit_form_submit($form, &$form_sta
     $form_state['conf'][$key] = $form_state['values'][$key];
   }
 }
-
diff --git a/plugins/contexts/entity.inc b/plugins/contexts/entity.inc
index b214aa06b7aef12cab4432a1c7d9733561866900..d4f13cc7b5673556c55233faf41e90d72fd6a288 100644
--- a/plugins/contexts/entity.inc
+++ b/plugins/contexts/entity.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Plugin to provide a node context. A node context is a node wrapped in a
  * context object that can be utilized by anything that accepts contexts.
  */
@@ -23,6 +22,8 @@ $plugin = array(
     '#type' => 'textfield',
     '#description' => t('Enter the ID of an entity for this context.'),
   ),
+  // Tell ctools_context_get_context_from_context() how to interpret its $argument.
+  'placeholder name' => 'entity_id',
   'get child' => 'ctools_context_entity_get_child',
   'get children' => 'ctools_context_entity_get_children',
 );
@@ -54,7 +55,7 @@ function ctools_context_entity_get_children($plugin, $parent) {
  * It's important to remember that $conf is optional here, because contexts
  * are not always created from the UI.
  */
-function ctools_context_create_entity($empty, $data = NULL, $conf = FALSE, $plugin) {
+function ctools_context_create_entity($empty, $data = NULL, $conf = FALSE, $plugin = NULL) {
   $entity_type = $plugin['keyword'];
   $entity = entity_get_info($entity_type);
   $context = new ctools_context(array('entity:' . $entity_type, 'entity', $entity_type));
@@ -88,9 +89,9 @@ function ctools_context_create_entity($empty, $data = NULL, $conf = FALSE, $plug
   }
 
   if (!empty($data)) {
-    $context->data     = $data;
+    $context->data = $data;
     if (!empty($entity['entity keys']['label'])) {
-      $context->title    = $data->{$entity['entity keys']['label']};
+      $context->title = $data->{$entity['entity keys']['label']};
     }
     $context->argument = $id;
 
@@ -159,7 +160,7 @@ function ctools_context_entity_settings_form($form, &$form_state) {
  * Validate a node.
  */
 function ctools_context_entity_settings_form_validate($form, &$form_state) {
-  // Validate the autocomplete
+  // Validate the autocomplete.
   if (empty($form_state['values']['entity_id']) && empty($form_state['values']['entity'])) {
     form_error($form['entity'], t('You must select an entity.'));
     return;
@@ -169,7 +170,7 @@ function ctools_context_entity_settings_form_validate($form, &$form_state) {
     return;
   }
 
-  $id          = $form_state['values']['entity'];
+  $id           = $form_state['values']['entity'];
   $preg_matches = array();
   $match        = preg_match('/\[id: (\d+)\]/', $id, $preg_matches);
   if (!$match) {
diff --git a/plugins/contexts/language.inc b/plugins/contexts/language.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e66f02a16f69a22f5d23da95126c1b3744840065
--- /dev/null
+++ b/plugins/contexts/language.inc
@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * @file
+ * Ctools context type plugin to hold the current language context.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Language'),
+  'description' => t('Language object.'),
+  'context' => 'ctools_context_language_create',
+  'context name' => 'language',
+  'keyword' => 'language',
+
+  // Provides a list of items which are exposed as keywords.
+  'convert list' => 'ctools_language_context_convert_list',
+  // Convert keywords into data.
+  'convert' => 'ctools_language_context_convert',
+
+  'placeholder form' => array(
+    '#type' => 'textfield',
+    '#description' => t('Enter a valid langcode.'),
+    '#value' => $GLOBALS['language']->language,
+  ),
+
+  // Provide settings for the context.
+  'edit form' => 'ctools_context_language_settings_form',
+  'settings' => ctools_context_language_conf_defaults(),
+);
+
+/**
+ * Ensures a full populated settings array with sane defaults.
+ *
+ * @param mixed $conf
+ *   Array with the user defined settings, or a string identifying a language.
+ *
+ * @return array
+ *   Array with all available settings.
+ */
+function ctools_context_language_conf_defaults($conf = array()) {
+  if (!is_array($conf)) {
+    $conf = array(
+      'preset_langcode' => (string) $conf,
+    );
+  }
+
+  return $conf + array(
+    'enable_cache_argument' => TRUE,
+    'language_type' => 'language',
+    'preset_langcode' => $GLOBALS['language']->language,
+  );
+}
+
+/**
+ * Create a context, either from manual configuration or the current language.
+ */
+function ctools_context_language_create($empty, $data = NULL, $conf = FALSE) {
+  $context = new ctools_context('language');
+  $context->plugin = 'language';
+  if ($empty) {
+    return $context;
+  }
+  $context->title = t('Language');
+
+  $settings = ctools_context_language_conf_defaults($data);
+  if ($settings['language_type'] != 'preset') {
+    $language_object = $GLOBALS[$settings['language_type']];
+  }
+  else {
+    // Fetch the enabled language objects.
+    $languages = language_list('enabled');
+    $languages = $languages[1];
+
+    // Set the custom language, but fallback to the interface language.
+    $language_object = $GLOBALS['language'];
+    if (isset($languages[$settings['preset_langcode']])) {
+      $language_object = $languages[$settings['preset_langcode']];
+    }
+  }
+  // If enabled set the argument ot use in the cid.
+  if ($settings['enable_cache_argument']) {
+    $context->argument = $language_object->language;
+  }
+  $context->data = $language_object;
+  return $context;
+}
+
+/**
+ * Provide a list of sub-keywords.
+ *
+ * This is used to provide keywords from the context for use in a content type,
+ * pane, etc.
+ */
+function ctools_language_context_convert_list() {
+  $context = new stdClass();
+  $context->data = $GLOBALS['language'];
+  return array(
+    'language' => t('Langcode. E.g. !example', array('!example' => ctools_language_context_convert($context, 'language'))),
+    'name' => t('Name. E.g. !example', array('!example' => ctools_language_context_convert($context, 'name'))),
+    'native' => t('Native name of the language. E.g. !example', array('!example' => ctools_language_context_convert($context, 'native'))),
+    'direction' => t('Text direction 0=LRT, 1=RTL. E.g. !example', array('!example' => ctools_language_context_convert($context, 'direction'))),
+    'enabled' => t('Status. E.g. !example', array('!example' => ctools_language_context_convert($context, 'enabled'))),
+    'plurals' => t('Number of plural forms. E.g. !example', array('!example' => ctools_language_context_convert($context, 'plurals'))),
+    'formula' => t('Plural formula. E.g. !example', array('!example' => ctools_language_context_convert($context, 'formula'))),
+    'domain' => t('Domain prefix. E.g. !example', array('!example' => ctools_language_context_convert($context, 'domain'))),
+    'prefix' => t('Url prefix . E.g. !example', array('!example' => ctools_language_context_convert($context, 'prefix'))),
+    'weight' => t('The weight. E.g. !example', array('!example' => ctools_language_context_convert($context, 'weight'))),
+    'javascript' => t('Key of the javascript file with the translations. E.g. !example', array('!example' => ctools_language_context_convert($context, 'javascript'))),
+    'provider' => t('Negotiation method that defined the language. E.g. !example', array('!example' => ctools_language_context_convert($context, 'provider'))),
+  );
+}
+
+/**
+ * Convert a context property into a string to be used as a keyword.
+ */
+function ctools_language_context_convert($context, $type) {
+  if (isset($context->data->$type)) {
+    return $context->data->$type;
+  }
+}
+
+/**
+ * Settings form.
+ */
+function ctools_context_language_settings_form($form, &$form_state) {
+  $conf = ctools_context_language_conf_defaults($form_state['conf']);
+
+  $form['enable_cache_argument'] = array(
+    '#title' => t('Add language to cache id'),
+    '#description' => t('If enabled the langcode will be part of context aware caches.'),
+    '#type' => 'checkbox',
+    '#default_value' => $conf['enable_cache_argument'],
+  );
+
+  // Prepare language type options.
+  $language_type_options = drupal_map_assoc(language_types());
+  $language_type_options['preset'] = t('Custom');
+
+  $form['language_type'] = array(
+    '#title' => t('The language type to use'),
+    '#type' => 'radios',
+    '#required' => TRUE,
+    '#options' => $language_type_options,
+    '#default_value' => $conf['language_type'],
+  );
+
+  ctools_include('language');
+  $language_options = ctools_language_list();
+  $form['preset_langcode'] = array(
+    '#title' => t('Language'),
+    '#type' => 'select',
+    '#options' => $language_options,
+    '#default_value' => $conf['preset_langcode'],
+    '#states' => array(
+      'visible' => array(
+        ':input[name="language_type"]' => array('value' => 'preset'),
+      ),
+    ),
+  );
+
+  if (!empty($conf['preset_langcode']) && !isset($language_options[$conf['preset_langcode']])) {
+    drupal_set_message(t('The currently selected language %langcode is no longer available.', array('%langcode' => $conf['preset_langcode'])), 'error', FALSE);
+  }
+  return $form;
+}
diff --git a/plugins/contexts/node.inc b/plugins/contexts/node.inc
index 997cd1365ab43958c9acc96c1b5836bbe12dc5e9..156f7f83ef7fd5d5a9769c6578432a8c9a0234ec 100644
--- a/plugins/contexts/node.inc
+++ b/plugins/contexts/node.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Plugin to provide a node context. A node context is a node wrapped in a
  * context object that can be utilized by anything that accepts contexts.
  */
@@ -106,7 +105,7 @@ function ctools_context_node_settings_form($form, &$form_state) {
  * Validate a node.
  */
 function ctools_context_node_settings_form_validate($form, &$form_state) {
-  // Validate the autocomplete
+  // Validate the autocomplete.
   if (empty($form_state['values']['nid']) && empty($form_state['values']['node'])) {
     form_error($form['node'], t('You must select a node.'));
     return;
@@ -133,7 +132,7 @@ function ctools_context_node_settings_form_validate($form, &$form_state) {
     $node = db_query('SELECT nid, status FROM {node} WHERE LOWER(title) = LOWER(:title)', array(':title' => $nid))->fetchObject();
   }
 
-  // Do not allow unpublished nodes to be selected by unprivileged users
+  // Do not allow unpublished nodes to be selected by unprivileged users.
   if (!$node || (empty($node->status) && !(user_access('administer nodes')))) {
     form_error($form['node'], t('Invalid node selected.'));
   }
diff --git a/plugins/contexts/node_add_form.inc b/plugins/contexts/node_add_form.inc
index f10944c24dd2805a50de1a19e009b62eafb95e5b..98640e257573171418dc4786a1cc133bdd53b894 100644
--- a/plugins/contexts/node_add_form.inc
+++ b/plugins/contexts/node_add_form.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a node_add_form context
+ * Plugin to provide a node_add_form context.
  */
 
 /**
@@ -65,8 +64,8 @@ function ctools_context_create_node_add_form($empty, $data = NULL, $conf = FALSE
       $form_state = array(
         'want form' => TRUE,
         'build_info' => array(
-          'args' => array($node)
-        )
+          'args' => array($node),
+        ),
       );
 
       // Use module_load_include so that caches and stuff can know to load this.
@@ -81,10 +80,10 @@ function ctools_context_create_node_add_form($empty, $data = NULL, $conf = FALSE
 
       // These are specific pieces of data to this form.
       // All forms should place the form here.
-      $context->form       = $form;
-      $context->form_id    = $form_id;
-      $context->form_title = t('Submit @name', array('@name' => $types[$type]->name));
-      $context->node_type  = $type;
+      $context->form                 = $form;
+      $context->form_id              = $form_id;
+      $context->form_title           = t('Submit @name', array('@name' => $types[$type]->name));
+      $context->node_type            = $type;
       $context->restrictions['type'] = array($type);
       $context->restrictions['form'] = array('form');
 
diff --git a/plugins/contexts/node_edit_form.inc b/plugins/contexts/node_edit_form.inc
index 7565f5c8f66d037ab0a57e4b8a291266cc4cc90f..5401ef6f148a403a497abc3f719f5b080eba6e95 100644
--- a/plugins/contexts/node_edit_form.inc
+++ b/plugins/contexts/node_edit_form.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a node_edit_form context
+ * Plugin to provide a node_edit_form context.
  */
 
 /**
@@ -32,7 +31,7 @@ $plugin = array(
  */
 function ctools_context_create_node_edit_form($empty, $node = NULL, $conf = FALSE) {
   static $creating = FALSE;
-  $context = new ctools_context(array('form', 'node_edit', 'node_form',  'node_edit_form', 'node', 'entity:node'));
+  $context = new ctools_context(array('form', 'node_edit', 'node_form', 'node_edit_form', 'node', 'entity:node'));
   $context->plugin = 'node_edit_form';
 
   if ($empty || ($creating)) {
@@ -69,7 +68,7 @@ function ctools_context_create_node_edit_form($empty, $node = NULL, $conf = FALS
 
     $form = drupal_build_form($form_id, $form_state);
 
-    // Fill in the 'node' portion of the context
+    // Fill in the 'node' portion of the context.
     $context->data     = $node;
     $context->title    = isset($node->title) ? $node->title : '';
     $context->argument = isset($node->nid) ? $node->nid : $node->type;
@@ -126,7 +125,7 @@ function ctools_context_node_edit_form_settings_form($form, &$form_state) {
  * Validate a node.
  */
 function ctools_context_node_edit_form_settings_form_validate($form, &$form_state) {
-  // Validate the autocomplete
+  // Validate the autocomplete.
   if (empty($form_state['values']['nid']) && empty($form_state['values']['node'])) {
     form_error($form['node'], t('You must select a node.'));
     return;
@@ -153,7 +152,7 @@ function ctools_context_node_edit_form_settings_form_validate($form, &$form_stat
     $node = db_query('SELECT nid, status FROM {node} WHERE LOWER(title) = LOWER(:title)', array(':title' => $nid))->fetchObject();
   }
 
-  // Do not allow unpublished nodes to be selected by unprivileged users
+  // Do not allow unpublished nodes to be selected by unprivileged users.
   if (!$node || (empty($node->status) && !(user_access('administer nodes')))) {
     form_error($form['node'], t('Invalid node selected.'));
   }
diff --git a/plugins/contexts/query_string.inc b/plugins/contexts/query_string.inc
new file mode 100644
index 0000000000000000000000000000000000000000..23ade918b39859c38c85b42066a8a213c45a0f2a
--- /dev/null
+++ b/plugins/contexts/query_string.inc
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Context plugin that can extract arbitrary values from the query string.
+ */
+
+/**
+ * $plugin array which will be used by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Query string value'),
+  'description' => t('A context that extracts a value from the query string.'),
+  'context' => 'ctools_context_query_string_create_query_string',
+  'context name' => 'query_string',
+  'keyword' => 'query_string',
+  'edit form' => 'ctools_context_query_string_settings_form',
+  'convert list' => array(
+    'raw' => t('Raw string'),
+    'html_safe' => t('HTML-safe string'),
+  ),
+  'convert' => 'ctools_context_query_string_convert',
+);
+
+/**
+ * Create a context from manual configuration.
+ */
+function ctools_context_query_string_create_query_string($empty, $data = NULL, $conf = FALSE) {
+  $context = new ctools_context('query_string');
+  $context->plugin = 'query_string';
+
+  if ($empty) {
+    return $context;
+  }
+
+  if ($conf) {
+    if (!empty($_GET[$data['key']])) {
+      $context->data = $_GET[$data['key']];
+    }
+    else {
+      $context->data = $data['fallback_value'];
+    }
+  }
+  return $context;
+}
+
+/**
+ * Form builder; settings for the context.
+ */
+function ctools_context_query_string_settings_form($form, &$form_state) {
+  $form['key'] = array(
+    '#title' => t('Query string key'),
+    '#description' => t('Enter the key of the value that must be returned from the query string.'),
+    '#type' => 'textfield',
+    '#required' => TRUE,
+  );
+  if (isset($form_state['conf']['key'])) {
+    $form['key']['#default_value'] = $form_state['conf']['key'];
+  }
+  $form['fallback_value'] = array(
+    '#title' => t('Fallback value'),
+    '#description' => t('Enter a value that must be returned if the above specified key does not exist in the query string.'),
+    '#type' => 'textfield',
+  );
+  if (!empty($form_state['conf']['fallback_value'])) {
+    $form['fallback_value']['#default_value'] = $form_state['conf']['fallback_value'];
+  }
+  return $form;
+}
+
+/**
+ * Submit handler; settings form for the context.
+ */
+function ctools_context_query_string_settings_form_submit($form, &$form_state) {
+  $form_state['conf']['key'] = $form_state['values']['key'];
+  $form_state['conf']['fallback_value'] = $form_state['values']['fallback_value'];
+}
+
+/**
+ * Convert a context into a string.
+ */
+function ctools_context_query_string_convert($context, $type) {
+  switch ($type) {
+    case 'raw':
+      return $context->data;
+
+    case 'html_safe':
+      return check_plain($context->data);
+  }
+}
diff --git a/plugins/contexts/string.inc b/plugins/contexts/string.inc
index 9a715b8950c3fcd1c7ca298c07714c95997901bf..981b9f7c76f4f169b37e510b8b8f03a57f34b975 100644
--- a/plugins/contexts/string.inc
+++ b/plugins/contexts/string.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a string context
+ * Plugin to provide a string context.
  */
 
 /**
@@ -22,6 +21,7 @@ $plugin = array(
   'convert list' => array(
     'raw' => t('Raw string'),
     'html_safe' => t('HTML-safe string'),
+    'uppercase_words_html_safe' => t('Uppercase words HTML-safe string'),
   ),
   'convert' => 'ctools_context_string_convert',
   'placeholder form' => array(
@@ -37,7 +37,6 @@ $plugin = array(
 function ctools_context_create_string($empty, $data = NULL, $conf = FALSE) {
   // The input is expected to be an object as created by ctools_break_phrase
   // which contains a group of string.
-
   $context = new ctools_context('string');
   $context->plugin = 'string';
 
@@ -45,7 +44,7 @@ function ctools_context_create_string($empty, $data = NULL, $conf = FALSE) {
     return $context;
   }
 
-  if ($data !== FALSE ) {
+  if ($data !== FALSE) {
     // Support the array storage from the settings form but also handle direct input from arguments.
     $context->data = is_array($data) ? $data['string'] : $data;
     $context->title = ($conf) ? check_plain($data['identifier']) : check_plain($data);
@@ -60,8 +59,12 @@ function ctools_context_string_convert($context, $type) {
   switch ($type) {
     case 'raw':
       return $context->data;
+
     case 'html_safe':
       return check_plain($context->data);
+
+    case 'uppercase_words_html_safe':
+      return ucwords(str_replace('-', ' ', check_plain($context->data)));
   }
 }
 
diff --git a/plugins/contexts/term.inc b/plugins/contexts/term.inc
index 1d6d48e6fa5cb9330e4d93aaec22f7aa2d513048..56fe06c22462ef87b65fb8290cdd7b94b3e9d563 100644
--- a/plugins/contexts/term.inc
+++ b/plugins/contexts/term.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a term context
+ * Plugin to provide a term context.
  */
 
 /**
@@ -116,7 +115,7 @@ function ctools_context_term_settings_form($form, &$form_state) {
  * Validate a term.
  */
 function ctools_context_term_settings_form_validate($form, &$form_state) {
-  // Validate the autocomplete
+  // Validate the autocomplete.
   $vid = $form_state['values']['vid'];
   if (empty($form_state['values']['tid']) && empty($form_state['values']['taxonomy'][$vid])) {
     form_error($form['taxonomy'][$vid], t('You must select a term.'));
@@ -154,12 +153,16 @@ function ctools_context_term_convert($context, $type) {
   switch ($type) {
     case 'tid':
       return $context->data->tid;
+
     case 'name':
       return $context->data->name;
+
     case 'name_dashed':
       return drupal_strtolower(str_replace(' ', '-', $context->data->name));
+
     case 'vid':
       return $context->data->vid;
+
     case 'description':
       return $context->data->description;
   }
diff --git a/plugins/contexts/terms.inc b/plugins/contexts/terms.inc
index 6c3ab3611e867e8dc96bd802fe607fd04c23dd4a..1161ded60fc71e7ea3f6237d708139936bb8c9bd 100644
--- a/plugins/contexts/terms.inc
+++ b/plugins/contexts/terms.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a terms context
+ * Plugin to provide a terms context.
  */
 
 /**
@@ -37,7 +36,6 @@ $plugin = array(
 function ctools_context_create_terms($empty, $data = NULL, $conf = FALSE) {
   // The input is expected to be an object as created by ctools_break_phrase
   // which contains a group of terms.
-
   $context = new ctools_context(array('terms', 'entity:taxonomy_term'));
   $context->plugin = 'terms';
 
@@ -49,7 +47,7 @@ function ctools_context_create_terms($empty, $data = NULL, $conf = FALSE) {
     $context->operator = $data->operator;
     $context->tids     = $data->value;
     if (!isset($data->term)) {
-      // load the first term:
+      // Load the first term:
       reset($context->tids);
       $data->term = taxonomy_term_load(current($context->tids));
     }
@@ -67,12 +65,16 @@ function ctools_context_terms_convert($context, $type) {
   switch ($type) {
     case 'tid':
       return $context->data->tid;
+
     case 'tids':
       return $context->argument;
+
     case 'name':
       return $context->data->name;
+
     case 'name_dashed':
       return drupal_strtolower(str_replace(' ', '-', $context->data->name));
+
     case 'names':
     case 'names_dashed':
       // We only run this query if this item was requested:
@@ -92,6 +94,7 @@ function ctools_context_terms_convert($context, $type) {
         }
       }
       return $context->names;
+
     case 'vid':
       return $context->data->vid;
   }
diff --git a/plugins/contexts/token.inc b/plugins/contexts/token.inc
index 0445576916efdb3656e3e89cc0b581a9d610f59c..6286a697593d2f13310992b110880bd838bdbe93 100644
--- a/plugins/contexts/token.inc
+++ b/plugins/contexts/token.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- *  Provide a global context to allow for token support.
+ * Provide a global context to allow for token support.
  */
 
 $plugin = array(
@@ -17,6 +17,16 @@ $plugin = array(
 
 /**
  * Create a context from manual configuration.
+ *
+ * @param $empty
+ *   Unused.
+ * @param $data
+ *   Unused.
+ * @param $conf
+ *   Unused.
+ *
+ * @return ctools_context
+ *   A context of type token, with the plugin set appropriately.
  */
 function ctools_context_create_token($empty, $data = NULL, $conf = FALSE) {
   $context = new ctools_context('token');
@@ -27,9 +37,14 @@ function ctools_context_create_token($empty, $data = NULL, $conf = FALSE) {
 
 /**
  * Implementation of hook_ctools_context_convert_list().
+ *
+ * @return array|null
+ *   An array of token type information, keyed by 'type:id', or NULL if
+ *   none found.
  */
 function ctools_context_token_convert_list() {
   $tokens = token_info();
+  // Initialise $list here?
   foreach ($tokens['types'] as $type => $type_info) {
     if (empty($type_info['needs-data'])) {
       $real_type = isset($type_info['type']) ? $type_info['type'] : $type;
@@ -46,7 +61,17 @@ function ctools_context_token_convert_list() {
 }
 
 /**
- * Implementation of hook_ctools_context_converter_alter().
+ * Token conversion function: look up the token and return it's value.
+ *
+ * @param $context
+ *   Unused.
+ * @param string $token
+ *   The name of the token.
+ *
+ * @return array|null
+ *   The token value, or NULL if not found.
+ *
+ * @see ctools_context_convert_context()
  */
 function ctools_context_token_convert($context, $token) {
   $tokens = token_info();
@@ -59,4 +84,5 @@ function ctools_context_token_convert($context, $token) {
       return $values[$token];
     }
   }
+  return NULL;
 }
diff --git a/plugins/contexts/user.inc b/plugins/contexts/user.inc
index 638d146fba7a25dcb465b369697169c1e1df3128..9cd73085e47b29ec24868f2e01548238be7c91f1 100644
--- a/plugins/contexts/user.inc
+++ b/plugins/contexts/user.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a user context
+ * Plugin to provide a user context.
  */
 
 /**
@@ -42,8 +41,13 @@ function ctools_context_create_user($empty, $data = NULL, $conf = FALSE) {
   if ($conf) {
     if ($data['type'] == 'current') {
       global $user;
-      $data = user_load($user->uid);
-      $data->logged_in_user = TRUE;
+      if (user_is_logged_in()) {
+        $data = user_load($user->uid);
+        $data->logged_in_user = TRUE;
+      }
+      else {
+        $data = drupal_anonymous_user();
+      }
     }
     else {
       $data = user_load($data['uid']);
@@ -88,7 +92,7 @@ function ctools_context_user_settings_form($form, &$form_state) {
   if (!empty($conf['uid'])) {
     $info = user_load($conf['uid']);
     if ($info) {
-      $form['user']['#description'] = t('Currently set to !link', array('!link' => theme('username', $info)));
+      $form['user']['#description'] = t('Currently set to !link', array('!link' => theme('username', array('account' => $info))));
     }
   }
 
@@ -116,7 +120,7 @@ function ctools_context_user_settings_form_validate($form, &$form_state) {
     return;
   }
 
-  // Validate the autocomplete
+  // Validate the autocomplete.
   if (empty($form_state['values']['uid']) && empty($form_state['values']['user'])) {
     form_error($form['user'], t('You must select a user.'));
     return;
@@ -151,6 +155,7 @@ function ctools_context_user_settings_form_submit($form, &$form_state) {
  */
 function ctools_context_user_convert_list() {
   $tokens = token_info();
+  $list = array();
   foreach ($tokens['tokens']['user'] as $id => $info) {
     if (!isset($list[$id])) {
       $list[$id] = $info['name'];
diff --git a/plugins/contexts/user_edit_form.inc b/plugins/contexts/user_edit_form.inc
index da0cca0a552545b274f8c4c51c3d6df7fc8a594f..61f234a4114f201154937c6cbb3ebec7f43bf71a 100644
--- a/plugins/contexts/user_edit_form.inc
+++ b/plugins/contexts/user_edit_form.inc
@@ -1,8 +1,8 @@
 <?php
+
 /**
  * @file
- *
- * Plugin to provide a user_edit_form context
+ * Plugin to provide a user_edit_form context.
  */
 
 /**
@@ -34,15 +34,15 @@ function ctools_context_create_user_edit_form($empty, $user = NULL, $conf = FALS
   $category = !empty($conf['category']) ? $conf['category'] : FALSE;
   unset($conf['category']);
 
+  // If no category was specified, use the default 'account'.
+  if (!$category) {
+    $category = 'account';
+  }
   // Return previously created contexts, per category.
   static $created = array();
   if (!empty($created[$category])) {
     return $created[$category];
   }
-  // If no category was specified, use the default 'account'.
-  if (!$category) {
-    $category = 'account';
-  }
 
   $context = new ctools_context(array('form', 'user_edit', 'user_form', 'user_edit_form', 'user', 'entity:user'));
   // Store this context for later.
@@ -81,7 +81,7 @@ function ctools_context_create_user_edit_form($empty, $user = NULL, $conf = FALS
 
     $form = drupal_build_form($form_id, $form_state);
 
-    // Fill in the 'node' portion of the context
+    // Fill in the 'node' portion of the context.
     $context->data     = $user;
     $context->title    = isset($user->name) ? $user->name : '';
     $context->argument = $user->uid;
@@ -107,7 +107,7 @@ function ctools_context_user_edit_form_settings_form($form, &$form_state) {
   );
 
   if (!empty($conf['uid'])) {
-    $info = db_query('SELECT * FROM {user} WHERE uid = :uid', array(':uid' => $conf['uid']))->fetchObject();
+    $info = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => $conf['uid']))->fetchObject();
     if ($info) {
       $link = l(t("'%name' [user id %uid]", array('%name' => $info->name, '%uid' => $info->uid)), "user/$info->uid", array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE));
       $form['user']['#description'] = t('Currently set to !link', array('!link' => $link));
@@ -133,7 +133,7 @@ function ctools_context_user_edit_form_settings_form($form, &$form_state) {
  * Validate a node.
  */
 function ctools_context_user_edit_form_settings_form_validate($form, &$form_state) {
-  // Validate the autocomplete
+  // Validate the autocomplete.
   if (empty($form_state['values']['uid']) && empty($form_state['values']['user'])) {
     form_error($form['user'], t('You must select a user.'));
     return;
@@ -154,14 +154,15 @@ function ctools_context_user_edit_form_settings_form_validate($form, &$form_stat
     $uid = $preg_matches[1];
   }
   if (is_numeric($uid)) {
-    $user = db_query('SELECT uid FROM {user} WHEREuid = :uid', array(':uid' => $uid))->fetchObject();
+    $user = db_query('SELECT uid FROM {users} WHERE uid = :uid', array(':uid' => $uid))->fetchObject();
   }
   else {
-    $user = db_query('SELECT uid FROM {user} WHERE LOWER(name) = LOWER(:name)', array(':name' => $uid))->fetchObject();
+    $user = db_query('SELECT uid FROM {users} WHERE LOWER(name) = LOWER(:name)', array(':name' => $uid))->fetchObject();
   }
 
   form_set_value($form['uid'], $user->uid, $form_state);
 }
+
 function ctools_context_user_edit_form_settings_form_submit($form, &$form_state) {
   if ($form_state['values']['set_identifier']) {
     $user = user_load($form_state['values']['uid']);
diff --git a/plugins/contexts/vocabulary.inc b/plugins/contexts/vocabulary.inc
index 9c5d4cf79c3ea56025d44f64c90843a86eaad88a..e5b0b9c60a5cc11f9269ceac6af1bc3b705455ed 100644
--- a/plugins/contexts/vocabulary.inc
+++ b/plugins/contexts/vocabulary.inc
@@ -2,8 +2,7 @@
 
 /**
  * @file
- *
- * Plugin to provide a vocabulary context
+ * Plugin to provide a vocabulary context.
  */
 
 /**
diff --git a/plugins/export_ui/ctools_export_ui.class.php b/plugins/export_ui/ctools_export_ui.class.php
index 1048e199a3fa6cb961198f3f7961a6d637c5690e..f78795aadc46175b440125cbe82ae6d90c19d10d 100644
--- a/plugins/export_ui/ctools_export_ui.class.php
+++ b/plugins/export_ui/ctools_export_ui.class.php
@@ -13,7 +13,7 @@ class ctools_export_ui {
    * constructor because we are retaining PHP4 compatibility, which
    * would require all child classes to implement their own constructor.
    */
-  function init($plugin) {
+  public function init($plugin) {
     ctools_include('export');
 
     $this->plugin = $plugin;
@@ -22,7 +22,7 @@ class ctools_export_ui {
   /**
    * Get a page title for the current page from our plugin strings.
    */
-  function get_page_title($op, $item = NULL) {
+  public function get_page_title($op, $item = NULL) {
     if (empty($this->plugin['strings']['title'][$op])) {
       return;
     }
@@ -43,13 +43,13 @@ class ctools_export_ui {
    * This can be overridden for modules that want to be able to export
    * items currently being edited, for example.
    */
-  function load_item($item_name) {
+  public function load_item($item_name) {
     $item = ctools_export_crud_load($this->plugin['schema'], $item_name);
     return empty($item) ? FALSE : $item;
   }
 
   // ------------------------------------------------------------------------
-  // Menu item manipulation
+  // Menu item manipulation.
 
   /**
    * hook_menu() entry point.
@@ -57,7 +57,7 @@ class ctools_export_ui {
    * Child implementations that need to add or modify menu items should
    * probably call parent::hook_menu($items) and then modify as needed.
    */
-  function hook_menu(&$items) {
+  public function hook_menu(&$items) {
     // During upgrades, the schema can be empty as this is called prior to
     // actual update functions being run. Ensure that we can cope with this
     // situation.
@@ -99,7 +99,7 @@ class ctools_export_ui {
    * @return
    *   TRUE if the current user has access, FALSE if not.
    */
-  function access($op, $item) {
+  public function access($op, $item) {
     if (!user_access($this->plugin['access'])) {
       return FALSE;
     }
@@ -121,15 +121,20 @@ class ctools_export_ui {
 
     switch ($op) {
       case 'import':
-        return user_access('use PHP for settings');
+        return user_access('use ctools import');
+
       case 'revert':
         return ($item->export_type & EXPORT_IN_DATABASE) && ($item->export_type & EXPORT_IN_CODE);
+
       case 'delete':
         return ($item->export_type & EXPORT_IN_DATABASE) && !($item->export_type & EXPORT_IN_CODE);
+
       case 'disable':
         return empty($item->disabled);
+
       case 'enable':
         return !empty($item->disabled);
+
       default:
         return TRUE;
     }
@@ -144,7 +149,7 @@ class ctools_export_ui {
    * It is unlikely that a child object will need to override this method,
    * unless the listing mechanism is going to be highly specialized.
    */
-  function list_page($js, $input) {
+  public function list_page($js, $input) {
     $this->items = ctools_export_crud_load_all($this->plugin['schema'], $js);
 
     // Respond to a reset command by clearing session and doing a drupal goto
@@ -154,7 +159,7 @@ class ctools_export_ui {
       if (!$js) {
         drupal_goto($_GET['q']);
       }
-      // clear everything but form id, form build id and form token:
+      // Clear everything but form id, form build id and form token.
       $keys = array_keys($input);
       foreach ($keys as $id) {
         if (!in_array($id, array('form_id', 'form_build_id', 'form_token'))) {
@@ -224,7 +229,7 @@ class ctools_export_ui {
    * get the base form and then modify it as necessary to add search
    * gadgets for custom fields.
    */
-  function list_form(&$form, &$form_state) {
+  public function list_form(&$form, &$form_state) {
     // This forces the form to *always* treat as submitted which is
     // necessary to make it work.
     $form['#token'] = FALSE;
@@ -269,7 +274,7 @@ class ctools_export_ui {
       '#title' => t('Enabled'),
       '#options' => $all + array(
         '0' => t('Enabled'),
-        '1' => t('Disabled')
+        '1' => t('Disabled'),
       ),
       '#default_value' => 'all',
     );
@@ -305,7 +310,7 @@ class ctools_export_ui {
 
     $form['bottom row']['reset'] = array(
       '#type' => 'submit',
-      '#id' => 'ctools-export-ui-list-items-apply',
+      '#id' => 'ctools-export-ui-list-items-reset',
       '#value' => t('Reset'),
       '#attributes' => array('class' => array('use-ajax-submit')),
     );
@@ -324,7 +329,7 @@ class ctools_export_ui {
    * It is very rare that a filter form needs validation, but if it is
    * needed, override this.
    */
-  function list_form_validate(&$form, &$form_state) { }
+  public function list_form_validate(&$form, &$form_state) { }
 
   /**
    * Submit the filter/sort form.
@@ -336,7 +341,7 @@ class ctools_export_ui {
    * For the most part, you should not need to override this method, as the
    * fiddly bits call through to other functions.
    */
-  function list_form_submit(&$form, &$form_state) {
+  public function list_form_submit(&$form, &$form_state) {
     // Filter and re-sort the pages.
     $plugin = $this->plugin;
 
@@ -381,7 +386,7 @@ class ctools_export_ui {
    * @return
    *   TRUE if the item should be excluded.
    */
-  function list_filter($form_state, $item) {
+  public function list_filter($form_state, $item) {
     $schema = ctools_export_get_schema($this->plugin['schema']);
     if ($form_state['values']['storage'] != 'all' && $form_state['values']['storage'] != $item->{$schema['export']['export type string']}) {
       return TRUE;
@@ -411,7 +416,7 @@ class ctools_export_ui {
    * This widget will search against whatever fields are configured here. By
    * default it will attempt to search against the name, title and description fields.
    */
-  function list_search_fields() {
+  public function list_search_fields() {
     $fields = array(
       $this->plugin['export']['key'],
     );
@@ -432,7 +437,7 @@ class ctools_export_ui {
    * Override this if you wish to provide more or change how these work.
    * The actual handling of the sorting will happen in build_row().
    */
-  function list_sort_options() {
+  public function list_sort_options() {
     if (!empty($this->plugin['export']['admin_title'])) {
       $options = array(
         'disabled' => t('Enabled, title'),
@@ -458,14 +463,14 @@ class ctools_export_ui {
    *
    * Override this if you need custom CSS for your list.
    */
-  function list_css() {
+  public function list_css() {
     ctools_add_css('export-ui-list');
   }
 
   /**
    * Builds the operation links for a specific exportable item.
    */
-  function build_operations($item) {
+  public function build_operations($item) {
     $plugin = $this->plugin;
     $schema = ctools_export_get_schema($plugin['schema']);
     $operations = $plugin['allowed operations'];
@@ -515,7 +520,7 @@ class ctools_export_ui {
    * method, so this is building up a row suitable for theme('table').
    * This doesn't have to be true if you override both.
    */
-  function list_build_row($item, &$form_state, $operations) {
+  public function list_build_row($item, &$form_state, $operations) {
     // Set up sorting
     $name = $item->{$this->plugin['export']['key']};
     $schema = ctools_export_get_schema($this->plugin['schema']);
@@ -563,7 +568,7 @@ class ctools_export_ui {
    * If you've added columns via list_build_row() but are still using a
    * table, override this method to set up the table header.
    */
-  function list_table_header() {
+  public function list_table_header() {
     $header = array();
     if (!empty($this->plugin['export']['admin_title'])) {
       $header[] = array('data' => t('Title'), 'class' => array('ctools-export-ui-title'));
@@ -585,7 +590,7 @@ class ctools_export_ui {
    * Whatever you do if this method is overridden, the ID is important for AJAX
    * so be sure it exists.
    */
-  function list_render(&$form_state) {
+  public function list_render(&$form_state) {
     $table = array(
       'header' => $this->list_table_header(),
       'rows' => $this->rows,
@@ -600,14 +605,14 @@ class ctools_export_ui {
    *
    * This will appear after the filter/sort widgets.
    */
-  function list_header($form_state) { }
+  public function list_header($form_state) { }
 
   /**
    * Render a footer to go after thie list.
    *
    * This is a good place to add additional links.
    */
-  function list_footer($form_state) { }
+  public function list_footer($form_state) { }
 
   // ------------------------------------------------------------------------
   // These methods are the API for adding/editing exportable items
@@ -623,7 +628,7 @@ class ctools_export_ui {
    *   The item in use; this may be necessary as item IDs are often embedded in
    *   redirects.
    */
-  function redirect($op, $item = NULL) {
+  public function redirect($op, $item = NULL) {
     if (isset($this->plugin['redirect'][$op])) {
       $destination = (array) $this->plugin['redirect'][$op];
       if ($item) {
@@ -638,8 +643,9 @@ class ctools_export_ui {
     }
   }
 
-  function add_page($js, $input, $step = NULL) {
-    drupal_set_title($this->get_page_title('add'));
+  public function add_page($js, $input, $step = NULL) {
+    $args = func_get_args();
+    drupal_set_title($this->get_page_title('add'), PASS_THROUGH);
 
     // If a step not set, they are trying to create a new item. If a step
     // is set, they're in the process of creating an item.
@@ -661,7 +667,7 @@ class ctools_export_ui {
       'no_redirect' => TRUE,
       'step' => $step,
       // Store these in case additional args are needed.
-      'function args' => func_get_args(),
+      'function args' => $args,
     );
 
     $output = $this->edit_execute_form($form_state);
@@ -675,8 +681,9 @@ class ctools_export_ui {
   /**
    * Main entry point to edit an item.
    */
-  function edit_page($js, $input, $item, $step = NULL) {
-    drupal_set_title($this->get_page_title('edit', $item));
+  public function edit_page($js, $input, $item, $step = NULL) {
+    $args = func_get_args();
+    drupal_set_title($this->get_page_title('edit', $item), PASS_THROUGH);
 
     // Check to see if there is a cached item to get if we're using the wizard.
     if (!empty($this->plugin['use wizard'])) {
@@ -697,7 +704,7 @@ class ctools_export_ui {
       'no_redirect' => TRUE,
       'step' => $step,
       // Store these in case additional args are needed.
-      'function args' => func_get_args(),
+      'function args' => $args,
     );
 
     $output = $this->edit_execute_form($form_state);
@@ -711,8 +718,9 @@ class ctools_export_ui {
   /**
    * Main entry point to clone an item.
    */
-  function clone_page($js, $input, $original, $step = NULL) {
-    drupal_set_title($this->get_page_title('clone', $original));
+  public function clone_page($js, $input, $original, $step = NULL) {
+    $args = func_get_args();
+    drupal_set_title($this->get_page_title('clone', $original), PASS_THROUGH);
 
     // If a step not set, they are trying to create a new clone. If a step
     // is set, they're in the process of cloning an item.
@@ -724,7 +732,13 @@ class ctools_export_ui {
       // Export the handler, which is a fantastic way to clean database IDs out of it.
       $export = ctools_export_crud_export($this->plugin['schema'], $original);
       $item = ctools_export_crud_import($this->plugin['schema'], $export);
-      $item->{$this->plugin['export']['key']} = 'clone_of_' . $item->{$this->plugin['export']['key']};
+
+      if (!empty($input[$this->plugin['export']['key']])) {
+        $item->{$this->plugin['export']['key']} = $input[$this->plugin['export']['key']];
+      }
+      else {
+        $item->{$this->plugin['export']['key']} = 'clone_of_' . $item->{$this->plugin['export']['key']};
+      }
     }
 
     // Tabs and breadcrumb disappearing, this helps alleviate through cheating.
@@ -745,7 +759,7 @@ class ctools_export_ui {
       'no_redirect' => TRUE,
       'step' => $step,
       // Store these in case additional args are needed.
-      'function args' => func_get_args(),
+      'function args' => $args,
     );
 
     $output = $this->edit_execute_form($form_state);
@@ -762,7 +776,7 @@ class ctools_export_ui {
    * Add and Edit both funnel into this, but they have a few different
    * settings.
    */
-  function edit_execute_form(&$form_state) {
+  public function edit_execute_form(&$form_state) {
     if (!empty($this->plugin['use wizard'])) {
       return $this->edit_execute_form_wizard($form_state);
     }
@@ -776,7 +790,7 @@ class ctools_export_ui {
    *
    * By default, export UI will provide a single form for editing an object.
    */
-  function edit_execute_form_standard(&$form_state) {
+  public function edit_execute_form_standard(&$form_state) {
     $output = drupal_build_form('ctools_export_ui_edit_item_form', $form_state);
     if (!empty($form_state['executed']) && empty($form_state['rebuild'])) {
       $this->edit_save_form($form_state);
@@ -797,7 +811,7 @@ class ctools_export_ui {
    * @param array $form_state
    *   The already created form state.
    */
-  function get_wizard_info(&$form_state) {
+  public function get_wizard_info(&$form_state) {
     if (!isset($form_state['step'])) {
       $form_state['step'] = NULL;
     }
@@ -872,7 +886,7 @@ class ctools_export_ui {
    * Using 'add order' or 'edit order' can be used to ensure that add/edit order
    * is different.
    */
-  function edit_execute_form_wizard(&$form_state) {
+  public function edit_execute_form_wizard(&$form_state) {
     $form_info = $this->get_wizard_info($form_state);
 
     // If there aren't any forms set, fail.
@@ -895,7 +909,7 @@ class ctools_export_ui {
     if (!empty($form_state['complete'])) {
       $this->edit_save_form($form_state);
     }
-    else if ($output && !empty($form_state['item']->export_ui_item_is_cached)) {
+    elseif ($output && !empty($form_state['item']->export_ui_item_is_cached)) {
       // @todo this should be in the plugin strings
       drupal_set_message(t('You have unsaved changes. These changes will not be made permanent until you click <em>Save</em>.'), 'warning');
     }
@@ -913,7 +927,7 @@ class ctools_export_ui {
    *
    * The wizard callback delegates this back to the object.
    */
-  function edit_wizard_back(&$form_state) {
+  public function edit_wizard_back(&$form_state) {
     // This only exists so child implementations can use it.
   }
 
@@ -922,7 +936,7 @@ class ctools_export_ui {
    *
    * The wizard callback delegates this back to the object.
    */
-  function edit_wizard_next(&$form_state) {
+  public function edit_wizard_next(&$form_state) {
     $this->edit_cache_set($form_state['item'], $form_state['form type']);
   }
 
@@ -931,7 +945,7 @@ class ctools_export_ui {
    *
    * The wizard callback delegates this back to the object.
    */
-  function edit_wizard_cancel(&$form_state) {
+  public function edit_wizard_cancel(&$form_state) {
     $this->edit_cache_clear($form_state['item'], $form_state['form type']);
   }
 
@@ -940,7 +954,7 @@ class ctools_export_ui {
    *
    * The wizard callback delegates this back to the object.
    */
-  function edit_wizard_finish(&$form_state) {
+  public function edit_wizard_finish(&$form_state) {
     $form_state['complete'] = TRUE;
 
     // If we are importing, and overwrite was selected, delete the original so
@@ -955,7 +969,7 @@ class ctools_export_ui {
   /**
    * Retrieve the item currently being edited from the object cache.
    */
-  function edit_cache_get($item, $op = 'edit') {
+  public function edit_cache_get($item, $op = 'edit') {
     ctools_include('object-cache');
     if (is_string($item)) {
       $name = $item;
@@ -974,20 +988,20 @@ class ctools_export_ui {
   /**
    * Cache the item currently currently being edited.
    */
-  function edit_cache_set($item, $op = 'edit') {
+  public function edit_cache_set($item, $op = 'edit') {
     ctools_include('object-cache');
     $name = $this->edit_cache_get_key($item, $op);
     return $this->edit_cache_set_key($item, $name);
   }
 
-  function edit_cache_set_key($item, $name) {
+  public function edit_cache_set_key($item, $name) {
     return ctools_object_cache_set('ctui_' . $this->plugin['name'], $name, $item);
   }
 
   /**
    * Clear the object cache for the currently edited item.
    */
-  function edit_cache_clear($item, $op = 'edit') {
+  public function edit_cache_clear($item, $op = 'edit') {
     ctools_include('object-cache');
     $name = $this->edit_cache_get_key($item, $op);
     return ctools_object_cache_clear('ctui_' . $this->plugin['name'], $name);
@@ -996,7 +1010,7 @@ class ctools_export_ui {
   /**
    * Figure out what the cache key is for this object.
    */
-  function edit_cache_get_key($item, $op) {
+  public function edit_cache_get_key($item, $op) {
     $export_key = $this->plugin['export']['key'];
     return $op == 'edit' ? $item->{$this->plugin['export']['key']} : "::$op";
   }
@@ -1004,7 +1018,7 @@ class ctools_export_ui {
   /**
    * Called to save the final product from the edit form.
    */
-  function edit_save_form($form_state) {
+  public function edit_save_form($form_state) {
     $item = &$form_state['item'];
     $export_key = $this->plugin['export']['key'];
 
@@ -1023,7 +1037,7 @@ class ctools_export_ui {
   /**
    * Provide the actual editing form.
    */
-  function edit_form(&$form, &$form_state) {
+  public function edit_form(&$form, &$form_state) {
     $export_key = $this->plugin['export']['key'];
     $item = $form_state['item'];
     $schema = ctools_export_get_schema($this->plugin['schema']);
@@ -1096,7 +1110,7 @@ class ctools_export_ui {
   /**
    * Validate callback for the edit form.
    */
-  function edit_form_validate(&$form, &$form_state) {
+  public function edit_form_validate(&$form, &$form_state) {
     if (!empty($this->plugin['form']['validate'])) {
       // Pass $form by reference.
       $this->plugin['form']['validate']($form, $form_state);
@@ -1107,7 +1121,7 @@ class ctools_export_ui {
    * Perform a final validation check before allowing the form to be
    * finished.
    */
-  function edit_finish_validate(&$form, &$form_state) {
+  public function edit_finish_validate(&$form, &$form_state) {
     if ($form_state['op'] != 'edit') {
       // Validate the export key. Fake an element for form_error().
       $export_key = $this->plugin['export']['key'];
@@ -1129,7 +1143,7 @@ class ctools_export_ui {
    * If the keys all match up to the schema, this method will not need to be
    * overridden.
    */
-  function edit_form_submit(&$form, &$form_state) {
+  public function edit_form_submit(&$form, &$form_state) {
     if (!empty($this->plugin['form']['submit'])) {
       // Pass $form by reference.
       $this->plugin['form']['submit']($form, $form_state);
@@ -1151,14 +1165,14 @@ class ctools_export_ui {
   /**
    * Callback to enable a page.
    */
-  function enable_page($js, $input, $item) {
+  public function enable_page($js, $input, $item) {
     return $this->set_item_state(FALSE, $js, $input, $item);
   }
 
   /**
    * Callback to disable a page.
    */
-  function disable_page($js, $input, $item) {
+  public function disable_page($js, $input, $item) {
     return $this->set_item_state(TRUE, $js, $input, $item);
   }
 
@@ -1168,7 +1182,7 @@ class ctools_export_ui {
    * If javascript is in use, this will rebuild the list and send that back
    * as though the filter form had been executed.
    */
-  function set_item_state($state, $js, $input, $item) {
+  public function set_item_state($state, $js, $input, $item) {
     ctools_export_crud_set_status($this->plugin['schema'], $item, $state);
 
     if (!$js) {
@@ -1182,7 +1196,7 @@ class ctools_export_ui {
   /**
    * Page callback to delete an exportable item.
    */
-  function delete_page($js, $input, $item) {
+  public function delete_page($js, $input, $item) {
     $form_state = array(
       'plugin' => $this->plugin,
       'object' => &$this,
@@ -1205,7 +1219,7 @@ class ctools_export_ui {
   /**
    * Deletes exportable items from the database.
    */
-  function delete_form_submit(&$form_state) {
+  public function delete_form_submit(&$form_state) {
     $item = $form_state['item'];
 
     ctools_export_crud_delete($this->plugin['schema'], $item);
@@ -1217,16 +1231,17 @@ class ctools_export_ui {
   /**
    * Page callback to display export information for an exportable item.
    */
-  function export_page($js, $input, $item) {
-    drupal_set_title($this->get_page_title('export', $item));
+  public function export_page($js, $input, $item) {
+    drupal_set_title($this->get_page_title('export', $item), PASS_THROUGH);
     return drupal_get_form('ctools_export_form', ctools_export_crud_export($this->plugin['schema'], $item), t('Export'));
   }
 
   /**
    * Page callback to import information for an exportable item.
    */
-  function import_page($js, $input, $step = NULL) {
-    drupal_set_title($this->get_page_title('import'));
+  public function import_page($js, $input, $step = NULL) {
+    $args = func_get_args();
+    drupal_set_title($this->get_page_title('import'), PASS_THROUGH);
     // Import is basically a multi step wizard form, so let's go ahead and
     // use CTools' wizard.inc for it.
 
@@ -1250,7 +1265,7 @@ class ctools_export_ui {
       'no_redirect' => TRUE,
       'step' => $step,
       // Store these in case additional args are needed.
-      'function args' => func_get_args(),
+      'function args' => $args,
     );
 
     // import always uses the wizard.
@@ -1266,7 +1281,7 @@ class ctools_export_ui {
    * Import form. Provides simple helptext instructions and textarea for
    * pasting a export definition.
    */
-  function edit_form_import(&$form, &$form_state) {
+  public function edit_form_import(&$form, &$form_state) {
     $form['help'] = array(
       '#type' => 'item',
       '#value' => $this->plugin['strings']['help']['import'],
@@ -1292,7 +1307,7 @@ class ctools_export_ui {
    *
    * Evaluates code and make sure it creates an object before we continue.
    */
-  function edit_form_import_validate($form, &$form_state) {
+  public function edit_form_import_validate($form, &$form_state) {
     $item = ctools_export_crud_import($this->plugin['schema'], $form_state['values']['import']);
     if (is_string($item)) {
       form_error($form['import'], t('Unable to get an import from the code. Errors reported: @errors', array('@errors' => $item)));
@@ -1309,7 +1324,7 @@ class ctools_export_ui {
    *
    * Stores the item in the session.
    */
-  function edit_form_import_submit($form, &$form_state) {
+  public function edit_form_import_submit($form, &$form_state) {
     // The validate function already imported and stored the item. This
     // function exists simply to prevent it from going to the default
     // edit_form_submit() method.
@@ -1339,7 +1354,7 @@ function _ctools_export_ui_add_form_files($form, &$form_state) {
  *
  * This simply loads the object defined in the plugin and hands it off.
  */
-function ctools_export_ui_list_form($form, $form_state) {
+function ctools_export_ui_list_form($form, &$form_state) {
   $form_state['object']->list_form($form, $form_state);
   return $form;
 }
@@ -1441,7 +1456,7 @@ function ctools_export_ui_delete_confirm_form($form, &$form_state) {
 
   $export_key = $plugin['export']['key'];
   $question = str_replace('%title', check_plain($item->{$export_key}), $plugin['strings']['confirmation'][$form_state['op']]['question']);
-  $path = empty($_REQUEST['cancel_path']) ? ctools_export_ui_plugin_base_path($plugin) : $_REQUEST['cancel_path'];
+  $path = (!empty($_REQUEST['cancel_path']) && !url_is_external($_REQUEST['cancel_path'])) ? $_REQUEST['cancel_path'] : ctools_export_ui_plugin_base_path($plugin);
 
   $form = confirm_form($form,
     $question,
diff --git a/plugins/export_ui/ctools_export_ui.inc b/plugins/export_ui/ctools_export_ui.inc
index 4e0a84978ee1b219c8f5fbf7edfed3666f0269fd..3087ccae292fbeb2ba28979085779e81cc68eb56 100644
--- a/plugins/export_ui/ctools_export_ui.inc
+++ b/plugins/export_ui/ctools_export_ui.inc
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @file
  * The default plugin exists only to provide the base class. Other plugins
  * which do not provide a class will get this class instead. Any classes
  * provided should use this class as their parent:
@@ -15,6 +16,7 @@
  * Using the above notation will ensure that this plugin's is loaded before
  * the child plugin's class and avoid whitescreens.
  */
+
 $plugin = array(
   // As this is the base class plugin, it shouldn't declare any menu items.
   'has menu' => FALSE,
diff --git a/plugins/relationships/comment_parent.inc b/plugins/relationships/comment_parent.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ae29a08ceae58da8ca34f0f926433b35f4653b53
--- /dev/null
+++ b/plugins/relationships/comment_parent.inc
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file relationships/comment_parent.inc
+ * Plugin to provide a relationship handler for comment parent.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Parent comment'),
+  'keyword' => 'parent_comment',
+  'description' => t('Adds a parent comment from a comment context.'),
+  'required context' => new ctools_context_required(t('Comment'), 'entity:comment'),
+  'context' => 'ctools_comment_parent_context',
+);
+
+/**
+ * Return a new context based on an existing context.
+ */
+function ctools_comment_parent_context($context, $conf) {
+  if (empty($context->data)) {
+    return ctools_context_create_empty('entity:comment');
+  }
+
+  if (isset($context->data->pid) && ($context->data->pid !== 0)) {
+    $parent_comment = comment_load($context->data->pid);
+    return ctools_context_create('entity:comment', $parent_comment);
+  }
+}
diff --git a/plugins/relationships/entity_from_field.inc b/plugins/relationships/entity_from_field.inc
index d4880c6fb7423abf024f59010aee0c38ef88abdb..2589efd61bbedd70e7e6ef437f2f2c51f42f7c1f 100644
--- a/plugins/relationships/entity_from_field.inc
+++ b/plugins/relationships/entity_from_field.inc
@@ -140,7 +140,7 @@ function ctools_entity_from_field_get_children($parent_plugin, $parent) {
 
     $plugin_entities = array(
       'to' => array($to_entity => $to_entity_info),
-      'from' => array($from_entity => $from_entity_info)
+      'from' => array($from_entity => $from_entity_info),
     );
     drupal_alter('ctools_entity_context', $plugins[$key], $plugin_entities, $key);
   }
@@ -185,7 +185,7 @@ function ctools_entity_from_field_context($context, $conf) {
         $loaded_to_entity = array_shift($loaded_to_entity);
 
         // Pass current user account and entity type to access callback.
-        if (function_exists($to_entity_info['access callback']) && !call_user_func($to_entity_info['access callback'], 'view', $loaded_to_entity, $account, $to_entity)) {
+        if (isset($to_entity_info['access callback']) && function_exists($to_entity_info['access callback']) && !call_user_func($to_entity_info['access callback'], 'view', $loaded_to_entity, $account, $to_entity)) {
           return ctools_context_create_empty('entity:' . $to_entity, NULL);
         }
         else {
diff --git a/plugins/relationships/entity_from_query_string.inc b/plugins/relationships/entity_from_query_string.inc
new file mode 100644
index 0000000000000000000000000000000000000000..80c40fc3f7b7236b98446e87a0bbd60045532db9
--- /dev/null
+++ b/plugins/relationships/entity_from_query_string.inc
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Plugin to provide an relationship handler for entities from query string.
+ */
+
+/**
+ * Plugins are described by creating a $plugin array which will be used
+ * by the system that includes this file.
+ */
+$plugin = array(
+  'title' => t('Entity from query string'),
+  'keyword' => 'query_string_entity',
+  'description' => t('Entity from query string.'),
+  'required context' => new ctools_context_required(t('Query string'), 'query_string'),
+  'context' => 'ctools_entity_from_query_string_context',
+  'edit form' => 'ctools_entity_from_query_string_settings_form',
+);
+
+/**
+ * Return a new context based on an existing context.
+ */
+function ctools_entity_from_query_string_context($context, $conf) {
+  $entity_type = $conf['entity_type'];
+
+  // If unset it wants a generic, unfilled context, which is just NULL.
+  if (empty($context->data) || !isset($context->data) || !is_numeric($context->data)) {
+    return ctools_context_create_empty('entity:' . $entity_type, NULL);
+  }
+
+  if (!empty($context->data) && is_numeric($context->data)) {
+    // Load the entity from the query string value.
+    $entity_id = $context->data;
+    $entity = entity_load_single($entity_type, $entity_id);
+
+    // Send it to ctools.
+    return ctools_context_create('entity:' . $entity_type, $entity);
+  }
+}
+
+/**
+ * Settings form for the relationship.
+ */
+function ctools_entity_from_query_string_settings_form($form, &$form_state) {
+
+  // Get all avalible enity types.
+  foreach (entity_get_info() as $key => $value) {
+    $entity_types[$key] = $value['label'];
+  }
+
+  $form['entity_type'] = array(
+    '#title' => t('Entity type'),
+    '#description' => t('Choose entity type to load from query value'),
+    '#type' => 'select',
+    '#options' => $entity_types,
+  );
+  if (isset($form_state['conf']['entity_type'])) {
+    $form['entity_type']['#default_value'] = $form_state['conf']['entity_type'];
+  }
+
+  return $form;
+}
+
+/**
+ * Submit handler; settings form for the context.
+ */
+function ctools_entity_from_query_string_settings_form_submit($form, &$form_state) {
+  $form_state['conf']['entity_type'] = $form_state['values']['entity_type'];
+}
diff --git a/plugins/relationships/entity_from_schema.inc b/plugins/relationships/entity_from_schema.inc
index 809473eb65b93436cc79a9764ab41c06e8c496eb..edf6abe71751655b10a94f9aab83a1f2c41d0196 100644
--- a/plugins/relationships/entity_from_schema.inc
+++ b/plugins/relationships/entity_from_schema.inc
@@ -88,7 +88,7 @@ function ctools_entity_from_schema_get_children($parent_plugin, $parent) {
               $plugin_entities = array('to' => $from_entity_info, 'from' => $to_entity_info);
               $plugin_entities = array('to' => array($from_entity => $from_entity_info), 'from' => array($to_entity => $to_entity_info));
               drupal_alter('ctools_entity_context', $plugin, $plugin_entities, $plugin_id);
-               $plugins[$plugin_id] = $plugin;
+              $plugins[$plugin_id] = $plugin;
 
             }
           }
diff --git a/plugins/relationships/term_parent.inc b/plugins/relationships/term_parent.inc
index f084cca83e3685ef87bcb4cd8042ec3197b8ca49..c884e0aa98ef52c812ee5975eb1c6cf89a1436ce 100644
--- a/plugins/relationships/term_parent.inc
+++ b/plugins/relationships/term_parent.inc
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @file relationships/term_parent.inc
+ * @file
  * Plugin to provide an relationship handler for term parent.
  */
 
diff --git a/plugins/relationships/terms_from_node.inc b/plugins/relationships/terms_from_node.inc
index 07081f2ff2c2d4bee8efa34be646147313fc244c..ad306f05dba9251029ca896d2c91107abe9aa1fc 100644
--- a/plugins/relationships/terms_from_node.inc
+++ b/plugins/relationships/terms_from_node.inc
@@ -31,7 +31,7 @@ function ctools_terms_from_node_context($context, $conf) {
   // Collect all terms for the chosen vocabulary and concatenate them.
   $node = $context->data;
   $terms = array();
-  
+
   $fields = field_info_instances('node', $node->type);
   foreach ($fields as $name => $info) {
     $field_info = field_info_field($name);
@@ -43,8 +43,24 @@ function ctools_terms_from_node_context($context, $conf) {
         }
       }
     }
+    elseif ($field_info['type'] == 'entityreference' && $field_info['settings']['target_type'] == 'taxonomy_term') {
+      $items = field_get_items('node', $node, $name);
+      if (is_array($items)) {
+        $tids = array();
+        foreach ($items as $item) {
+          $tids[] = $item['target_id'];
+        }
+
+        $term_objects = taxonomy_term_load_multiple($tids);
+        foreach ($term_objects as $term) {
+          if (empty($conf['vocabulary']) || in_array($term->vocabulary_machine_name, $conf['vocabulary'])) {
+            $terms[] = $term->tid;
+          }
+        }
+      }
+    }
   }
-  
+
   if (!empty($terms)) {
     $all_terms = ctools_break_phrase(implode($conf['concatenator'], $terms));
     return ctools_context_create('terms', $all_terms);
diff --git a/plugins/relationships/user_category_edit_form_from_user.inc b/plugins/relationships/user_category_edit_form_from_user.inc
index 28dac72c52f107eb9da70d03a6564aa31efe18be..07eb3827e5497de9bf0ecb8150260d12a5762cb5 100644
--- a/plugins/relationships/user_category_edit_form_from_user.inc
+++ b/plugins/relationships/user_category_edit_form_from_user.inc
@@ -15,6 +15,8 @@ $plugin = array(
   'description' => t('Adds user category edit form from a user context.'),
   'required context' => new ctools_context_required(t('User'), 'user'),
   'context' => 'ctools_user_category_edit_form_from_user_context',
+  'edit form' => 'ctools_user_category_edit_form_from_user_settings_form',
+  'defaults' => array('category' => NULL),
 );
 
 /**
@@ -25,7 +27,35 @@ function ctools_user_category_edit_form_from_user_context($context, $conf) {
     return ctools_context_create_empty('user_edit_form', NULL);
   }
 
+  if (!empty($conf['category'])) {
+    return ctools_context_create('user_edit_form', $context->data, array('category' => $conf['category']));
+  }
+
   if (isset($context->data->user_category)) {
     return ctools_context_create('user_edit_form', $context->data, array('category' => $context->data->user_category));
   }
+
+  return ctools_context_create('user_edit_form', $context->data);
+}
+
+/**
+ * Settings form for the relationship.
+ */
+function ctools_user_category_edit_form_from_user_settings_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+
+  $categories = _user_categories();
+  $options = array();
+  foreach ($categories as $category) {
+    $options[$category['name']] = $category['title'];
+  }
+  $form['category'] = array(
+    '#type' => 'select',
+    '#title' => t('Category'),
+    '#options' => $options,
+    '#default_value' => isset($conf['category']) ? $conf['category'] : NULL,
+    '#empty_option' => 'Default',
+  );
+
+  return $form;
 }
diff --git a/stylizer/plugins/export_ui/stylizer.inc b/stylizer/plugins/export_ui/stylizer.inc
index a1fc1d8cab813903913b628eed37c27768a9bad6..8192efe139d7e186a8e92c8bd391826f9a8fc473 100644
--- a/stylizer/plugins/export_ui/stylizer.inc
+++ b/stylizer/plugins/export_ui/stylizer.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 $plugin = array(
   'schema' => 'stylizer',
   'access' => 'administer stylizer',
@@ -42,4 +46,3 @@ $plugin = array(
     ),
   ),
 );
-
diff --git a/stylizer/plugins/export_ui/stylizer_ui.class.php b/stylizer/plugins/export_ui/stylizer_ui.class.php
index 14d6293960219308b3e11369b4f097dea9f8bbe8..d4db36cc4a31e198311ece0b1b02d7bb4b4cb49d 100644
--- a/stylizer/plugins/export_ui/stylizer_ui.class.php
+++ b/stylizer/plugins/export_ui/stylizer_ui.class.php
@@ -5,16 +5,18 @@
  */
 class stylizer_ui extends ctools_export_ui {
 
-  function access($op, $item) {
+
+  public function access($op, $item) {
     $access = parent::access($op, $item);
     if ($op == 'add' && $access && empty($this->base_types)) {
-     // Make sure there are base styles defined.
-     $access = FALSE;
+      // Make sure there are base styles defined.
+      $access = FALSE;
     }
     return $access;
   }
 
-  function list_form(&$form, &$form_state) {
+
+  public function list_form(&$form, &$form_state) {
     ctools_include('stylizer');
     parent::list_form($form, $form_state);
 
@@ -60,7 +62,8 @@ class stylizer_ui extends ctools_export_ui {
     );
   }
 
-  function list_sort_options() {
+
+  public function list_sort_options() {
     return array(
       'disabled' => t('Enabled, title'),
       'title' => t('Title'),
@@ -71,7 +74,8 @@ class stylizer_ui extends ctools_export_ui {
     );
   }
 
-  function list_filter($form_state, $item) {
+
+  public function list_filter($form_state, $item) {
     if (empty($form_state['style_plugins'][$item->settings['style_base']])) {
       $this->style_plugin = array(
         'name' => 'broken',
@@ -102,30 +106,37 @@ class stylizer_ui extends ctools_export_ui {
     return parent::list_filter($form_state, $item);
   }
 
-  function list_search_fields() {
+
+  public function list_search_fields() {
     $fields = parent::list_search_fields();
     $fields[] = 'plugin_title';
     return $fields;
   }
 
-  function list_build_row($item, &$form_state, $operations) {
-    // Set up sorting
+
+  public function list_build_row($item, &$form_state, $operations) {
+    // Set up sorting.
     switch ($form_state['values']['order']) {
       case 'disabled':
         $this->sorts[$item->name] = empty($item->disabled) . $item->admin_title;
         break;
+
       case 'title':
         $this->sorts[$item->name] = $item->admin_title;
         break;
+
       case 'name':
         $this->sorts[$item->name] = $item->name;
         break;
+
       case 'type':
         $this->sorts[$item->name] = $this->style_plugin['type'] . $item->admin_title;
         break;
+
       case 'base':
         $this->sorts[$item->name] = $this->style_plugin['title'] . $item->admin_title;
         break;
+
       case 'storage':
         $this->sorts[$item->name] = $item->type . $item->admin_title;
         break;
@@ -154,7 +165,8 @@ class stylizer_ui extends ctools_export_ui {
     );
   }
 
-  function list_table_header() {
+
+  public function list_table_header() {
     return array(
       array('data' => t('Type'), 'class' => array('ctools-export-ui-type')),
       array('data' => t('Name'), 'class' => array('ctools-export-ui-name')),
@@ -165,14 +177,16 @@ class stylizer_ui extends ctools_export_ui {
     );
   }
 
-  function init($plugin) {
+
+  public function init($plugin) {
     ctools_include('stylizer');
     $this->base_types = ctools_get_style_base_types();
 
     parent::init($plugin);
   }
 
-  function get_wizard_info(&$form_state) {
+
+  public function get_wizard_info(&$form_state) {
     $form_info = parent::get_wizard_info($form_state);
     ctools_include('stylizer');
 
@@ -219,7 +233,7 @@ class stylizer_ui extends ctools_export_ui {
    * The stylizer wizard stores its stuff in slightly different places, so
    * we have to find it and move it to the right place.
    */
-  function store_stylizer_info(&$form_state) {
+  public function store_stylizer_info(&$form_state) {
     /*
     foreach (array('name', 'admin_title', 'admin_description') as $key) {
       if (!empty($form_state['values'][$key])) {
@@ -235,12 +249,14 @@ class stylizer_ui extends ctools_export_ui {
     $form_state['item']->settings['name'] = $form_state['item']->name;
   }
 
-  function edit_wizard_next(&$form_state) {
+
+  public function edit_wizard_next(&$form_state) {
     $this->store_stylizer_info($form_state);
     parent::edit_wizard_next($form_state);
   }
 
-  function edit_wizard_finish(&$form_state) {
+
+  public function edit_wizard_finish(&$form_state) {
     // These might be stored by the stylizer wizard, so we should clear them.
     if (isset($form_state['settings']['old_settings'])) {
       unset($form_state['settings']['old_settings']);
@@ -249,7 +265,8 @@ class stylizer_ui extends ctools_export_ui {
     parent::edit_wizard_finish($form_state);
   }
 
-  function edit_form_type(&$form, &$form_state) {
+
+  public function edit_form_type(&$form, &$form_state) {
     foreach ($this->base_types as $module => $info) {
       foreach ($info as $key => $base_type) {
         $types[$module . '-' . $key] = $base_type['title'];
@@ -266,7 +283,9 @@ class stylizer_ui extends ctools_export_ui {
     );
   }
 
-  function edit_form_type_submit(&$form, &$form_state) {
+
+  public function edit_form_type_submit(&$form, &$form_state) {
     list($form_state['item']->style_module, $form_state['item']->style_type) = explode('-', $form_state['values']['type']);
   }
+
 }
diff --git a/stylizer/stylizer.install b/stylizer/stylizer.install
index 5cefb0ddfb4d8c0ea461d61ee08e8ff7dd3a57fe..321ba8e1288a656c00be02f96397eb7c6d27062c 100644
--- a/stylizer/stylizer.install
+++ b/stylizer/stylizer.install
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Schema for stylizer.
  */
diff --git a/stylizer/stylizer.module b/stylizer/stylizer.module
index e7278975ddeea42760af54fab3607cf8258eceab..6035e26dbfb2c70342b26881c5caaa9bb96b06f3 100644
--- a/stylizer/stylizer.module
+++ b/stylizer/stylizer.module
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Stylizer module
+ * Stylizer module.
  *
  * This module allows styles to be created and managed on behalf of modules
  * that implement styles.
@@ -30,7 +30,7 @@ function stylizer_permission() {
  */
 function stylizer_ctools_plugin_directory($module, $plugin) {
   // Most of this module is implemented as an export ui plugin, and the
-  // rest is in ctools/includes/stylizer.inc
+  // rest is in ctools/includes/stylizer.inc.
   if ($module == 'ctools' && $plugin == 'export_ui') {
     return 'plugins/' . $plugin;
   }
@@ -59,7 +59,7 @@ function stylizer_panels_dashboard_blocks(&$vars) {
     'description' => t('Custom styles can be applied to Panel regions and Panel panes.'),
   );
 
-   // Load all mini panels and their displays.
+  // Load all mini panels and their displays.
   ctools_include('export');
   ctools_include('stylizer');
   $items = ctools_export_crud_load_all('stylizer');
@@ -122,14 +122,14 @@ function stylizer_theme() {
         'path' => $plugin['path'],
       );
 
-      // if no theme function exists, assume template.
+      // If no theme function exists, assume template.
       if (!function_exists("theme_$plugin[theme]")) {
         $theme[$plugin['theme']]['template'] = str_replace('_', '-', $plugin['theme']);
-        $theme[$plugin['theme']]['file'] = $plugin['file']; // for preprocess.
+        // For preprocess.
+        $theme[$plugin['theme']]['file'] = $plugin['file'];
       }
     }
   }
 
   return $theme;
 }
-
diff --git a/term_depth/plugins/access/term_depth.inc b/term_depth/plugins/access/term_depth.inc
index ab05b60942d02eac93b3c0d3b989bb52812fe144..eb302b6258d53b66eecd8b629f5173a588dd840b 100644
--- a/term_depth/plugins/access/term_depth.inc
+++ b/term_depth/plugins/access/term_depth.inc
@@ -15,7 +15,7 @@ $plugin = array(
   'callback' => 'term_depth_term_depth_ctools_access_check',
   'default' => array('vid' => array(), 'depth' => 0),
   'settings form' => 'term_depth_term_depth_ctools_access_settings',
-  'settings form validation' => 'term_depth_term_depth_ctools_access_settings_validate',
+  'settings form validate' => 'term_depth_term_depth_ctools_access_settings_validate',
   'settings form submit' => 'term_depth_term_depth_ctools_access_settings_submit',
   'summary' => 'term_depth_term_depth_ctools_access_summary',
   'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')),
@@ -25,28 +25,22 @@ $plugin = array(
  * Settings form for the 'term depth' access plugin.
  */
 function term_depth_term_depth_ctools_access_settings($form, &$form_state, $conf) {
-  // If no configuration was saved before, set some defaults.
-  if (empty($conf)) {
-    $conf = array(
-      'vid' => 0,
-    );
-  }
-  if (!isset($conf['vid'])) {
-    $conf['vid'] = 0;
-  }
-
+  $vocabularies = taxonomy_get_vocabularies();
+  $options = array();
   // Loop over each of the configured vocabularies.
-  foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) {
-    $options[$vid] = $vocabulary->name;
+  foreach ($vocabularies as $vid => $vocab) {
+    $options[$vocab->machine_name] = $vocab->name;
   }
 
-  $form['settings']['vid'] = array(
+  _term_depth_convert_config_vid_to_vocabulary_name($conf);
+
+  $form['settings']['vocabulary'] = array(
     '#title' => t('Vocabulary'),
     '#type' => 'select',
     '#options' => $options,
     '#description' => t('Select the vocabulary for this form. If there exists a parent term in that vocabulary, this access check will succeed.'),
-    '#id' => 'ctools-select-vid',
-    '#default_value' => $conf['vid'],
+    '#id' => 'ctools-select-vocabulary',
+    '#default_value' => !empty($conf['vocabulary']) ? $conf['vocabulary'] : array(),
     '#required' => TRUE,
   );
 
@@ -61,15 +55,24 @@ function term_depth_term_depth_ctools_access_settings($form, &$form_state, $conf
   return $form;
 }
 
+/**
+ * @param $conf
+ */
+function _term_depth_convert_config_vid_to_vocabulary_name(&$conf) {
+  // Fallback on legacy 'vid', when no vocabularies are available.
+  if (empty($conf['vocabulary']) && !empty($conf['vid'])) {
+    $vocabulary = _ctools_term_vocabulary_machine_name_convert(array($conf['vid']));
+    $conf['vocabulary'] = reset($vocabulary);
+    unset($conf['vid'], $vocabulary);
+  }
+}
+
 /**
  * Submit function for the access plugins settings.
- *
- * We cast all settings to numbers to ensure they can be safely handled.
  */
 function term_depth_term_depth_ctools_access_settings_submit($form, $form_state) {
-  foreach (array('depth', 'vid') as $key) {
-    $form_state['conf'][$key] = (integer) $form_state['values']['settings'][$key];
-  }
+  $form_state['conf']['depth'] = (integer) $form_state['values']['settings']['depth'];
+  $form_state['conf']['vocabulary'] = array_filter($form_state['conf']['vocabulary']);
 }
 
 /**
@@ -82,10 +85,17 @@ function term_depth_term_depth_ctools_access_check($conf, $context) {
     return FALSE;
   }
 
-  // Get the $vid.
-  if (!isset($conf['vid'])) {
+  _term_depth_convert_config_vid_to_vocabulary_name($conf);
+
+  // Get the $vocabulary.
+  if (!isset($conf['vocabulary'])) {
     return FALSE;
   }
+  $vocab = taxonomy_vocabulary_machine_name_load($conf['vocabulary']);
+  if ($vocab->vid != $context->data->vid) {
+    return FALSE;
+  }
+
   $depth = _term_depth($context->data->tid);
 
   return ($depth == $conf['depth']);
@@ -95,9 +105,9 @@ function term_depth_term_depth_ctools_access_check($conf, $context) {
  * Provide a summary description based upon the checked terms.
  */
 function term_depth_term_depth_ctools_access_summary($conf, $context) {
-  $vocab = taxonomy_vocabulary_load($conf['vid']);
-
-  return t('"@term" has parent in vocabulary "@vocab" at @depth', array(
+  _term_depth_convert_config_vid_to_vocabulary_name($conf);
+  $vocab = taxonomy_vocabulary_machine_name_load($conf['vocabulary']);
+  return t('"@term" is in vocabulary "@vocab" at depth @depth', array(
     '@term' => $context->identifier,
     '@vocab' => $vocab->name,
     '@depth' => $conf['depth'],
diff --git a/term_depth/term_depth.info b/term_depth/term_depth.info
index 465566fea71fefad1f310d0a28a0dbe68ec14c1a..81ae70c01cb33ef5e07b043a9500fdf9d7bfd0c6 100644
--- a/term_depth/term_depth.info
+++ b/term_depth/term_depth.info
@@ -2,4 +2,4 @@ name = Term Depth access
 description = Controls access to context based upon term depth
 core = 7.x
 dependencies[] = ctools
-package = Chaos tool suite
\ No newline at end of file
+package = Chaos tool suite
diff --git a/term_depth/term_depth.module b/term_depth/term_depth.module
index 10f9e3194dc933ebcd2f84b6d022109d82e8390e..f9f4ce7cbfe10326c19ba4f60c6706562ebcdf3b 100644
--- a/term_depth/term_depth.module
+++ b/term_depth/term_depth.module
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 function term_depth_ctools_plugin_directory($owner, $plugin) {
   if ($owner == 'ctools' && $plugin == 'access') {
     return 'plugins/' . $plugin;
diff --git a/tests/context.test b/tests/context.test
index bdf14e3f4e85974e61d325c716429c172f46205f..ca94a4fd849319b10d6154e2cba72bc6f58051ce 100644
--- a/tests/context.test
+++ b/tests/context.test
@@ -1,20 +1,206 @@
 <?php
 
+/**
+ * @file
+ * Test the keyword substitution functionality.
+ */
+
+class CtoolsContextIDTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Context IDs',
+      'description' => 'Verify that Context IDs work properly.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
+    ctools_include('context');
+  }
+
+  private function getTestContexts() {
+    $test_objects = array(
+      array(),
+      array(
+        'name' => 'foo_bar',
+      ),
+      array(
+        'id' => 25,
+      ),
+      array(
+        'id' => 5,
+        'name' => NULL,
+      ),
+      array(
+        'id' => 'a',
+        'name' => 'foo_bar',
+      ),
+      array(
+        'id' => 'z',
+        'name' => 'baz',
+      ),
+      array(
+        'id' => 15,
+        'name' => 'baz',
+      ),
+      array(
+        'id' => 'z',
+        'name' => 'foo',
+      ),
+      array(
+        'id' => 1,
+        'name' => 'foo',
+      ),
+      array(
+        'id' => 47,
+        'name' => 'bar',
+      ),
+      array(
+        'id' => 99,
+        'name' => 'bar',
+      ),
+    );
+    return $test_objects;
+  }
+
+  /**
+   * Test ctools_context_id where the context only has an id.
+   */
+  public function testContextId() {
+    $context = array();
+    $expected = 'context__1';
+    $actual = ctools_context_id($context);
+    $this->assertEqual($actual, $expected, 'Empty context has id ' . $expected);
+
+    $context = array('id' => 4);
+    $expected = 'context__4';
+    $actual = ctools_context_id($context);
+    $this->assertEqual($actual, $expected, 'Context 4 has id ' . $expected);
+
+    $context = array('id' => 'a');
+    $expected = 'context__a';
+    $actual = ctools_context_id($context);
+    $this->assertEqual($actual, $expected, 'Context "a" has id ' . $expected);
+  }
+
+  /**
+   * Test ctools_context_id where the context has an id and a name.
+   */
+  public function testContextIdName() {
+    $context = array('id' => '512', 'name' => 'foo');
+    $expected = 'context_foo_512';
+    $this->assertEqual(ctools_context_id($context), $expected, 'Context "512"/"foo" has id ' . $expected);
+
+    $context = array('id' => '512', 'name' => 'foo_bar');
+    $expected = 'context_foo_bar_512';
+    $this->assertEqual(ctools_context_id($context), $expected, 'Context "512"/"foo_bar" has id ' . $expected);
+  }
+
+  /**
+   * Test ctools_context_id where the context has an id & name, and a type is specified.
+   */
+  public function testContextIdNameType() {
+    $type = 'sort';
+    $context = array('id' => '512', 'name' => 'foo');
+    $expected = 'sort_foo_512';
+    $this->assertEqual(ctools_context_id($context, $type), $expected, 'Context "512" has id ' . $expected);
+
+    $type = NULL;
+    $context = array('id' => '512', 'name' => 'foo');
+    $expected = '_foo_512';
+    $this->assertEqual(ctools_context_id($context, $type), $expected, 'Context "512" has id ' . $expected);
+  }
+
+  /**
+   * Test ctools_context_next_id in various scenarios.
+   */
+  public function testNextContextId() {
+    $test_objects = $this->getTestContexts();
+
+    // If no object list or name is given?
+    $value = ctools_context_next_id(NULL, NULL);
+    $expected = 1;
+    $this->assertEqual($value, $expected, 'NULL objects have next id ' . $expected);
+
+    // If no object list is given?
+    $value = ctools_context_next_id(NULL, 'bar');
+    $expected = 1;
+    $this->assertEqual($value, $expected, 'NULL objects have next id ' . $expected);
+
+    // If no object list is given (another way)?
+    $value = ctools_context_next_id(array(), 'bar');
+    $expected = 1;
+    $this->assertEqual($value, $expected, 'Empty objects have next id ' . $expected);
+
+    // The name is empty... which is just another name.
+    $value = ctools_context_next_id($test_objects, '');
+    $expected = 1;
+    $this->assertEqual($value, $expected, 'Unnamed objects have next id ' . $expected . ' (got ' . $value . ')');
+
+    // The value of the id key is not a number.
+    $value = ctools_context_next_id($test_objects, 'foo_bar');
+    $expected = 1;
+    $this->assertEqual($value, $expected, 'Objects with non-integer ids are ignored ' . $expected);
+
+    // One object's id is not a number (ignore) but another is valid.
+    $value = ctools_context_next_id($test_objects, 'baz');
+    $expected = 16;
+    $this->assertEqual($value, $expected, 'Baz\'s objects have next id ' . $expected);
+
+    // An expected case: there is one match and the id is numeric.
+    $value = ctools_context_next_id($test_objects, 'foo');
+    $expected = 2;
+    $this->assertEqual($value, $expected, 'Foo\'s objects have next id ' . $expected);
+
+    // Another expected case: there are multiple numeric IDs.
+    $value = ctools_context_next_id($test_objects, 'bar');
+    $expected = 100;
+    $this->assertEqual($value, $expected, 'Bar\'s objects have next id ' . $expected);
+  }
+
+}
+
+
+/**
+ * Test the keyword substitution functionality.
+ */
 class CtoolsContextKeywordsSubstitutionTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
       'name' => 'Keywords substitution',
       'description' => 'Verify that keywords are properly replaced with data.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
     );
   }
 
-  public function setUp() {
-    parent::setUp('ctools');
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
 
     ctools_include('context');
   }
 
+  /**
+   * Test the keyword substitution.
+   */
   public function testKeywordsSubstitution() {
     // Create node context for substitution.
     $node = $this->drupalCreateNode();
@@ -23,40 +209,164 @@ class CtoolsContextKeywordsSubstitutionTestCase extends DrupalWebTestCase {
 
     // Run tests on some edge cases.
     $checks = array(
-      '%node:changed:raw:' => array(
+      array(
+        '%node:changed:raw:',
+        array('%title' => ''),
         "{$node->changed}:",
         t('Multi-level token has been replaced. Colon left untouched.'),
       ),
-      '%node:title' => array(
+      array(
+        '%node:title',
+        array('%title' => ''),
         "{$node->title}",
         t('Keyword and converter have been replaced.'),
       ),
-      '%%node:title' => array(
+      array(
+        '%%node:title',
+        array('%title' => ''),
         "%node:title",
         t('Keyword after escaped percent sign left untouched.'),
       ),
-      '%node:title%node:nid' => array(
+      array(
+        '%node:title%node:nid',
+        array('%title' => ''),
         "{$node->title}{$node->nid}",
         t('Multiple substitutions have been replaced.'),
       ),
-      '%node:title:' => array(
+      array(
+        '%node:title:',
+        array('%title' => ''),
         "{$node->title}:",
         t('Colon after keyword and converter left untouched.'),
       ),
-      '%node:title%%' => array(
+      array(
+        '%node:title%%',
+        array('%title' => ''),
         "{$node->title}%",
         t('Escaped percent sign after keyword and converter left untouched.'),
       ),
-      '%%%node:title' => array(
+      array(
+        '%%%node:title',
+        array('%title' => ''),
         "%{$node->title}",
         t('Keyword after escaped and unescaped percent sign has been replaced.'),
       ),
+      array(
+        '%%foo:bar',
+        array('%title' => ''),
+        "%foo:bar",
+        t('Non-existant context ignored.'),
+      ),
+      array(
+        'There was about 20%-30% difference in price.',
+        array('%title' => ''),
+        'There was about 20%-30% difference in price.',
+        t('Non-keyword percent sign left untouched.'),
+      ),
+      array(
+        'href="my%20file%2dname.pdf"',
+        array('%title' => ''),
+        'href="my%20file%2dname.pdf"',
+        t('HTTP URL escape left untouched.'),
+      ),
+      array(
+        'href="my%a0file%fdname.pdf"',
+        array('%title' => ''),
+        'href="my%a0file%fdname.pdf"',
+        t('HTTP URL escape (high-chars) left untouched.'),
+      ),
+      array(
+        '<a href="http://www.example.com/here%20is%20a%20pdf.pdf">Click here!</a>',
+        array('%title' => ''),
+        '<a href="http://www.example.com/here%20is%20a%20pdf.pdf">Click here!</a>',
+        t('HTTP URL escape percent sign left untouched in HTML.'),
+      ),
+      array(
+        'SELECT * FROM {table} WHERE field = "%s"',
+        array('%title' => ''),
+        'SELECT * FROM {table} WHERE field = "%s"',
+        t('SQL percent sign left untouched.'),
+      ),
+      array(
+        '%title',
+        array('%title' => 'foobar'),
+        'foobar',
+        t('String value in $keywords array is returned.'),
+      ),
+      array(
+        '%title',
+        array('%title' => ''),
+        '',
+        t('Empty string value in $keywords array returns empty string.'),
+      ),
+      array(
+        '%title',
+        array('%title' => NULL),
+        '',
+        t('NULL value in $keywords array returns empty string.'),
+      ),
+      array(
+        '%title',
+        array('%title' => FALSE),
+        '',
+        t('FALSE value in $keywords array returns empty string.'),
+      ),
+      array(
+        '%title',
+        array('%title' => 11),
+        '11',
+        t('Integer value in $keywords array returns string representation of the integer.'),
+      ),
+      array(
+        '%title',
+        array('%title' => 'substring %title'),
+        'substring %title',
+        t('Input value as substring in $keywords array left untouched.'),
+      ),
     );
-    foreach ($checks as $string => $expectations) {
-      list($expected_result, $message) = $expectations;
-      $actual_result = ctools_context_keyword_substitute($string, array(), $contexts);
+    foreach ($checks as $check) {
+      list($string, $keywords, $expected_result, $message) = $check;
+      $actual_result = ctools_context_keyword_substitute($string, $keywords, $contexts);
       $this->assertEqual($actual_result, $expected_result, $message);
     }
   }
 
 }
+
+/**
+ * Test the context classes.
+ */
+class CtoolsContextUnitTestCase extends DrupalUnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Context unit tests',
+      'description' => 'Verifies that context classes behave correctly',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    require_once __DIR__ . '/../includes/context.inc';
+  }
+
+  /**
+   * Tests that contexts have the correct required property value.
+   */
+  public function testOptionalRequiredContext() {
+    $required_context = new ctools_context_required('test1');
+    $this->assertTrue($required_context->required);
+
+    $optional_context = new ctools_context_optional('test2');
+    $this->assertFalse($optional_context->required);
+  }
+
+}
diff --git a/tests/css.test b/tests/css.test
index 4a5200caad76ae039d0c30a946531006a09ff53f..6c03730a57be6b67b9eaae1d5f2ccf899fa5783a 100644
--- a/tests/css.test
+++ b/tests/css.test
@@ -1,65 +1,98 @@
 <?php
-/**
- * @file
- * Tests for different parts of the ctools plugin system.
- */
 
 /**
  * Test menu links depending on user permissions.
  */
 class CtoolsCssTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
       'name' => 'CSS Tools tests',
-      'description' => '...',
-      'group' => 'Chaos Tools Suite',
+      'description' => 'Confirm the custom CSS handling works.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
     );
   }
 
-  function setUp() {
-    // Additionally enable contact module.
-    parent::setUp('ctools');
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
+    ctools_include('css');
   }
 
   /**
-   * Test that cached plugins are loaded correctly.
+   * Test that Stored CSS snippets can be retrieved, filtered or otherwise.
    */
-  function testCssStuff() {
+  public function testCssStoreFilterRetrieve() {
     $css = "#some-id .some-class {\n  color: black;\n  illegal-key: foo;\n}";
     $filtered_css = '#some-id .some-class{color:black;}';
 
-    ctools_include('css');
+    $this->assertNull(ctools_css_retrieve('missing-css-test'), 'Missing css snippet is not found');
+
     $filename1 = ctools_css_store('unfiltered-css-test', $css, FALSE);
     $filename2 = ctools_css_store('filtered-css-test', $css, TRUE);
 
+    $file_contents = file_get_contents($filename1);
+    $this->assertEqual($css, $file_contents, 'Unfiltered css file contents are correct');
+
     $this->assertEqual($filename1, ctools_css_retrieve('unfiltered-css-test'), 'Unfiltered css file successfully fetched');
     $file_contents = file_get_contents($filename1);
     $this->assertEqual($css, $file_contents, 'Unfiltered css file contents are correct');
-//    $match = $filename1 == ctools_css_retrieve('unfiltered-css-test') ? 'Match' : 'No match';
-//    $output .= '<pre>Unfiltered: ' . $filename1 . ' ' . $match . '</pre>';
-//    $output .= '<pre>' . file_get_contents($filename1) . '</pre>';
 
     $this->assertEqual($filename2, ctools_css_retrieve('filtered-css-test'), 'Filtered css file succcesfully fetched');
     $file_contents = file_get_contents($filename2);
     $this->assertEqual($filtered_css, $file_contents, 'Filtered css file contents are correct');
-    //    $match = $filename2 == ctools_css_retrieve('filtered-css-test') ? 'Match' : 'No match';
-//    $output .= '<pre>Filtered: ' . $filename2 . ' ' . $match . '</pre>';
-//    $output .= '<pre>' . file_get_contents($filename2) . '</pre>';
-//
-//    drupal_add_css($filename2, array('type' => 'file'));
-//    return array('#markup' => $output);
+  }
+
+  /**
+   * Test that Stored CSS snippets can be correctly overwritten.
+   */
+  public function testCssStoreOverwrite() {
+    $css1 = "#some-id .some-class {\n  color: black;\n  illegal-key: foo;\n}";
+
+    $css2 = "#other-id .other-class {\n  color: blue;\n  illegal-key: foo;\n}";
+    $filtered_css2 = '#other-id .other-class{color:blue;}';
+
+    ctools_css_store('unfiltered-css-test', $css1, FALSE);
+    ctools_css_store('filtered-css-test', $css1, TRUE);
 
+    // Now overwrite the first css with the second version.
+    $filename3 = ctools_css_store('unfiltered-css-test', $css2, FALSE);
+    $filename4 = ctools_css_store('filtered-css-test', $css2, TRUE);
 
-    // Test that in case that url can be used, the value surives when a colon is in it.
+    $file_contents3 = file_get_contents($filename3);
+    $file_contents4 = file_get_contents($filename4);
+
+    $this->assertEqual($css2, $file_contents3, 'Unfiltered CSS has overwritten earlier contents.');
+    $this->assertEqual($filtered_css2, $file_contents4, 'Filtered CSS has overwritten earlier contents.');
+  }
+
+  /**
+   * Test that in case that url is used, the colons survives filtering.
+   */
+  public function testCssFilterURLHandling() {
     $css = "#some-id {\n  background-image: url(http://example.com/example.gif);\n}";
     $css_data = ctools_css_disassemble($css);
     $empty_array = array();
     $disallowed_values_regex = '/(expression)/';
-    $filtered = ctools_css_assemble(ctools_css_filter_css_data($css_data, $empty_array, $empty_array, '', $disallowed_values_regex));
+
+    $intermediate = ctools_css_filter_css_data($css_data, $empty_array, $empty_array, '', $disallowed_values_regex);
+    $filtered = ctools_css_assemble($intermediate);
+
     $url = (strpos($filtered, 'http://example.com/example.gif') !== FALSE);
     $this->assertTrue($url, 'CSS with multiple colons can survive.');
+  }
 
-    // Test that in case the CSS has two properties defined are merged.
+  /**
+   * Test that when the CSS has two properties defined they are merged.
+   */
+  public function testCssFilterMergeProperties() {
     $css = "#some-id {\n  font-size: 12px;\n}\n#some-id {\n  color: blue;\n}";
     $filtered = ctools_css_filter($css);
     $font_size = (strpos($filtered, 'font-size:12px;') !== FALSE);
@@ -78,4 +111,5 @@ class CtoolsCssTestCase extends DrupalWebTestCase {
     $color = (strpos($filtered, 'color:red') !== FALSE);
     $this->assertTrue($font_size && $color, 'Multiple properties are retained.');
   }
+
 }
diff --git a/tests/css_cache.test b/tests/css_cache.test
new file mode 100644
index 0000000000000000000000000000000000000000..2aaa304d74403b1ddc486732348e3e572409745e
--- /dev/null
+++ b/tests/css_cache.test
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Tests the custom CSS cache handler.
+ */
+class CtoolsCSSObjectCache extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'CSS cache',
+      'description' => 'Tests the custom CSS cache handler.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Tests the custom CSS cache handler.
+   *
+   * @see https://drupal.org/node/1313368
+   */
+  public function testCssCache() {
+    // Create a CSS cache entry.
+    $filename = ctools_css_cache('body { color: red; }');
+
+    // Perform a cron run. The CSS cache entry should not be removed.
+    $this->cronRun();
+    $this->assertTrue(file_exists($filename), 'The CSS cache is not cleared after performing a cron run.');
+
+    // Manually clear the caches. The CSS cache entry should be removed.
+    drupal_flush_all_caches();
+    $this->assertFalse(file_exists($filename), 'The CSS cache is cleared after clearing all caches.');
+  }
+
+}
diff --git a/tests/ctools.plugins.test b/tests/ctools.plugins.test
index fe1829cfbc04998f857e9100c20b395850dfa340..ba086b96be94c6b2c61bc4c7d98b8a15f4cee243 100644
--- a/tests/ctools.plugins.test
+++ b/tests/ctools.plugins.test
@@ -1,26 +1,43 @@
 <?php
-/**
- * @file
- * Tests for different parts of the ctools plugin system.
- */
 
 /**
  * Test menu links depending on user permissions.
  */
 class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
       'name' => 'Get plugin info',
       'description' => 'Verify that plugin type definitions can properly set and overide values.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
     );
   }
 
-  function setUp() {
-    // Additionally enable contact module.
-    parent::setUp('ctools', 'ctools_plugin_test');
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    $modules[] = 'ctools_plugin_test';
+    parent::setUp($modules);
   }
 
+  /**
+   * Assert helper to check that a specific plugin function exists.
+   *
+   * @param $module
+   *   The module that owns the plugin.
+   * @param $type
+   *   The type of plugin.
+   * @param $id
+   *   The id of the specific plugin to load.
+   * @param $function
+   *   The identifier of the function. For example, 'settings form'.
+   */
   protected function assertPluginFunction($module, $type, $id, $function = 'function') {
     $func = ctools_plugin_load_function($module, $type, $id, $function);
     $this->assertTrue(function_exists($func), t('Plugin @plugin of plugin type @module:@type successfully retrieved @retrieved for @function.', array(
@@ -32,16 +49,40 @@ class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
     )));
   }
 
+  /**
+   * Assert helper to check that a specific plugin function does NOT exist.
+   *
+   * @param $module
+   *   The module that owns the plugin.
+   * @param $type
+   *   The type of plugin.
+   * @param $id
+   *   The id of the specific plugin to load.
+   * @param $function
+   *   The identifier of the function. For example, 'settings form'.
+   */
   protected function assertPluginMissingFunction($module, $type, $id, $function = 'function') {
     $func = ctools_plugin_load_function($module, $type, $id, $function);
     $this->assertEqual($func, NULL, t('Plugin @plugin of plugin type @module:@type for @function with missing function successfully failed.', array(
       '@plugin' => $id,
       '@module' => $module,
       '@type' => $type,
-      '@function' => $func,
+      '@function' => (string) $func,
     )));
   }
 
+  /**
+   * Assert helper to check that a plugin can be loaded using a named class.
+   *
+   * @param $module
+   *   The module that owns the plugin.
+   * @param $type
+   *   The type of plugin.
+   * @param $id
+   *   The id of the specific plugin to load.
+   * @param string $class
+   *   The name of the PHP class to load.
+   */
   protected function assertPluginClass($module, $type, $id, $class = 'handler') {
     $class_name = ctools_plugin_load_class($module, $type, $id, $class);
     $this->assertTrue(class_exists($class_name), t('Plugin @plugin of plugin type @module:@type successfully retrieved @retrieved for @class.', array(
@@ -53,6 +94,18 @@ class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
     )));
   }
 
+  /**
+   * Assert helper to check that a plugin DOES NOT contain the named class.
+   *
+   * @param $module
+   *   The module that owns the plugin.
+   * @param $type
+   *   The type of plugin.
+   * @param $id
+   *   The id of the specific plugin to load.
+   * @param string $class
+   *   The name of the PHP class to load.
+   */
   protected function assertPluginMissingClass($module, $type, $id, $class = 'handler') {
     $class_name = ctools_plugin_load_class($module, $type, $id, $class);
     $this->assertEqual($class_name, NULL, t('Plugin @plugin of plugin type @module:@type for @class with missing class successfully failed.', array(
@@ -66,7 +119,7 @@ class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
   /**
    * Test that plugins are loaded correctly.
    */
-  function testPluginLoading() {
+  public function testPluginLoading() {
     ctools_include('plugins');
     $module = 'ctools_plugin_test';
     $type = 'not_cached';
@@ -81,7 +134,7 @@ class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
     $this->assertPluginClass($module, $type, 'plugin_array', 'handler');
     $this->assertPluginClass($module, $type, 'plugin_array2', 'handler');
     $this->assertPluginMissingClass($module, $type, 'plugin_array_dne', 'handler');
-    // TODO Test big hook plugins.
+    // @todo Test big hook plugins.
 
     $type = 'cached';
 
@@ -95,6 +148,7 @@ class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
     $this->assertPluginClass($module, $type, 'plugin_array', 'handler');
     $this->assertPluginClass($module, $type, 'plugin_array2', 'handler');
     $this->assertPluginMissingClass($module, $type, 'plugin_array_dne', 'handler');
-    // TODO Test big hook plugins.
+    // @todo Test big hook plugins.
   }
+
 }
diff --git a/tests/ctools.test b/tests/ctools.test
new file mode 100644
index 0000000000000000000000000000000000000000..4d748c09e6423f8d73ec90d5caf6a3de9b9a51ef
--- /dev/null
+++ b/tests/ctools.test
@@ -0,0 +1,239 @@
+<?php
+
+/**
+ * @file Test classes for code in the CTools module file.
+ */
+
+/**
+ * Test menu links depending on user permissions.
+ */
+class CtoolsModuleTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Ctools module functions tests',
+      'description' => 'Check functions in the ctools.module not otherwise tested.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Test that the break phrase function behaves as expected.
+   */
+  public function testBreakPhrase() {
+    $tests = array(
+      NULL => array('value' => array()),
+      '' => array('value' => array()),
+      '1' => array('operator' => 'and', 'value' => array(1)),
+      '99' => array('operator' => 'and', 'value' => array(99)),
+      '+1' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      ' 1' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      '1 ' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      '-1' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      '-99' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      '1,2' => array('operator' => 'and', 'value' => array(1, 2)),
+      '1 2' => array('operator' => 'or', 'value' => array(1, 2)),
+      '1+2' => array('operator' => 'or', 'value' => array(1, 2)),
+      '1,2,3' => array('operator' => 'and', 'value' => array(1, 2, 3)),
+      '1 2 3' => array('operator' => 'or', 'value' => array(1, 2, 3)),
+      '1+2+3' => array('operator' => 'or', 'value' => array(1, 2, 3)),
+      '1 , 2 , 3' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      '1 + 2 + 3' => array('invalid_input' => TRUE, 'value' => array(-1)),
+      '1,2,3,4,5,6,7,8,9' => array(
+        'operator' => 'and',
+        'value' => array(1, 2, 3, 4, 5, 6, 7, 8, 9),
+      ),
+      '1 2,3,4 5 6 7 8 9' => array('invalid_input' => TRUE, 'value' => array(-1)),
+    );
+
+    foreach ($tests as $string => $expected) {
+      $result = ctools_break_phrase($string);
+      $expected = (object) $expected;
+      $this->assertEqual($result, $expected, 'Break Phrase test patterns: ' . $string);
+    }
+  }
+
+  /**
+   * Test that the (deprecated) getuserroles returns expected array.
+   */
+  public function testGetUserRoles() {
+    $result = ctools_get_roles();
+    $this->assertTrue(is_array($result), 'get_roles returns an array');
+
+    // A key-value array of integers.
+    foreach ($result as $k => $v) {
+      $this->assertTrue(is_numeric($k), 'Role key is numeric; ' . $k);
+      $this->assertTrue(is_string($v), 'Role id is string; ' . $v);
+    }
+  }
+
+  /**
+   * Test the ctools_attach_js function returns the expected paths.
+   */
+  public function testAttachJs() {
+    $taxonomy_path = drupal_get_path('module', 'taxonomy');
+    $ctools_path = drupal_get_path('module', 'ctools');
+
+    // Func should probably do a different thing but this is current behaviour.
+    $path = ctools_attach_js('');
+    $this->assertEqual($path, $ctools_path . '/js/.js', 'Attach an empty string');
+
+    $path = ctools_attach_js('foo');
+    $this->assertEqual($path, $ctools_path . '/js/foo.js', 'Attach simple string');
+
+    $path = ctools_attach_js('foo', 'ctools', '');
+    $this->assertEqual($path, $ctools_path . '//foo.js', 'Attach string with empty subdir');
+
+    $path = ctools_attach_js('foo', 'ctools', 'javascript');
+    $this->assertEqual($path, $ctools_path . '/javascript/foo.js', 'Attach string with alternate subdir');
+
+    $path = ctools_attach_js('foo', 'taxonomy', 'javascript');
+    $this->assertEqual($path, $taxonomy_path . '/javascript/foo.js', 'Attach string from different module');
+  }
+
+  /**
+   * Test the ctools_attach_css function returns the expected paths.
+   */
+  public function testAttachCss() {
+    $taxonomy_path = drupal_get_path('module', 'taxonomy');
+    $ctools_path = drupal_get_path('module', 'ctools');
+
+    // Func should probably do a different thing but this is current behaviour.
+    $path = ctools_attach_css('');
+    $this->assertEqual($path, $ctools_path . '/css/.css', 'Attach empty string');
+
+    $path = ctools_attach_css('foo');
+    $this->assertEqual($path, $ctools_path . '/css/foo.css', 'Attach simple string');
+
+    $path = ctools_attach_css('foo', 'ctools', '');
+    $this->assertEqual($path, $ctools_path . '//foo.css', 'Attach string with empty subdir');
+
+    $path = ctools_attach_css('foo', 'ctools', 'theme');
+    $this->assertEqual($path, $ctools_path . '/theme/foo.css', 'Attach string with alternate subdir');
+
+    $path = ctools_attach_css('foo', 'taxonomy', 'theme');
+    $this->assertEqual($path, $taxonomy_path . '/theme/foo.css', 'Attach string from different module');
+  }
+
+  /**
+   * Test the ctools version compare function.
+   */
+  public function testApiVersionCompare() {
+    // We're beyond version 1.
+    $ok = ctools_api_version('1.0');
+    $this->assertTrue($ok, 'Check API version 1.0 is ok');
+
+    // We're beyond version 1.0.1 too.
+    $ok = ctools_api_version('1.0.1');
+    $this->assertTrue($ok, 'Check API version 1.0.1 is ok');
+
+    // Not (yet) on api version 10.
+    $ok = ctools_api_version('10.0');
+    $this->assertFalse($ok, 'Check API version 10.0 is not ok');
+
+    // We are (currently) between version 1.1 and version 4.0.
+    $ok = ctools_api_version('1.1', '4.0');
+    $this->assertTrue($ok, 'Check API is between 1 and 4');
+  }
+
+  /**
+   * Test that the ctools_classs_add works.
+   */
+  public function testClassesAdd() {
+    ctools_class_reset();
+
+    ctools_class_add('testclass');
+
+    $classes = ctools_get_classes();
+    $this->assertEqual(is_array($classes), 1, 'Classes should be an array');
+    $this->assertEqual(count($classes), 1, 'Classes array has one element');
+    $this->assertEqual(count($classes['html']), 1, 'Classes array has element: html');
+    $this->assertTrue(isset($classes['html']['add']), 'Classes array has element: html/add');
+    $this->assertEqual($classes['html']['add'], array('testclass'), 'Classes array has expected value');
+
+    ctools_class_add('class2 class3');
+
+    $classes = ctools_get_classes();
+    $this->assertEqual(is_array($classes), 1, 'Classes should be an array');
+    $this->assertEqual(count($classes['html']), 1, 'Classes array has element: html');
+    // TODO: An undesirable result: array('testclass', 'class2', 'class3') is better.
+    $this->assertEqual($classes['html']['add'], array(
+      'testclass',
+      'class2 class3',
+    ), 'Classes array has expected value');
+  }
+
+  /**
+   * Test that the ctools_classs_remove works.
+   */
+  public function testClassesRemove() {
+    ctools_class_reset();
+
+    ctools_class_remove('testclass');
+
+    $classes = ctools_get_classes();
+    $this->assertEqual(is_array($classes), 1, 'Classes should be an array');
+    $this->assertEqual(count($classes), 1, 'Classes array has one element');
+    $this->assertEqual(count($classes['html']), 1, 'Classes array has element: html');
+    $this->assertTrue(isset($classes['html']['remove']), 'Classes array has element: html/remove');
+    $this->assertEqual($classes['html']['remove'], array('testclass'), 'Classes array has expected value');
+
+    ctools_class_remove('class2 class3');
+
+    $classes = ctools_get_classes();
+    $this->assertEqual(count($classes), 1, 'Classes array has one element');
+    $this->assertEqual(count($classes['html']), 1, 'Classes array has element: html');
+    // This is an undesirable result, is array('testclass', 'class2', 'class3') better.
+    $this->assertEqual($classes['html']['remove'], array(
+      'testclass',
+      'class2 class3',
+    ), 'Classes array has expected value');
+  }
+
+  /**
+   * Test that the ctools_classs_add and ctools_classs_remove interact well.
+   */
+  public function testClassesAddRemove() {
+    ctools_class_reset();
+
+    ctools_class_add('testclass');
+    ctools_class_remove('testclass');
+
+    $classes = ctools_get_classes();
+    $this->assertTrue(isset($classes['html']['add']), 'Classes array has an add set');
+    $this->assertEqual($classes['html']['add'], array('testclass'), 'testclass is in the add set');
+    $this->assertTrue(isset($classes['html']['remove']), 'Classes array has a remove set');
+    // TODO: Is it really good to let this happen?
+    $this->assertEqual($classes['html']['remove'], array('testclass'), 'testclass is in the remove set');
+  }
+
+  /**
+   * Test that the ctools_classs_add and ctools_classs_remove interact well .. 2.
+   */
+  public function testClassesAddRemove2() {
+    ctools_class_reset();
+
+    ctools_class_add('class2 class3');
+    ctools_class_remove('class3');
+
+    $classes = ctools_get_classes();
+    $this->assertTrue(isset($classes['html']['add']), 'Classes array has an add set');
+    $this->assertEqual($classes['html']['add'], array('class2 class3'), 'Added class2 class3 is in add set');
+    $this->assertTrue(isset($classes['html']['remove']), 'Classes array has a remove set');
+    // TODO: Is it really good to let this happen?
+    $this->assertEqual($classes['html']['remove'], array('class3'), 'class3 in remove set');
+  }
+
+}
diff --git a/tests/ctools_export_test/ctools_export.test b/tests/ctools_export_test/ctools_export.test
index 1accfd740cc260fe9bb141860f211a800fd905fd..ebeee49655fec8183d74488586f5c46e8ba93cf7 100644
--- a/tests/ctools_export_test/ctools_export.test
+++ b/tests/ctools_export_test/ctools_export.test
@@ -1,32 +1,34 @@
 <?php
 
 /**
- * @file
  * Tests for the CTools export system.
  */
-
-/**
- * Tests export CRUD.
- */
 class CtoolsExportCrudTestCase extends DrupalWebTestCase {
 
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
-      'name' => 'CTools export CRUD tests',
+      'name' => 'Export CRUD',
       'description' => 'Test the CRUD functionality for the ctools export system.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 
-  protected function setUp() {
-    parent::setUp('ctools_export_test');
-    $this->resetAll();
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    $modules[] = 'ctools_export_test';
+    parent::setUp($modules);
   }
 
   /**
    * Tests CRUD operation: Load.
    */
-  function testCrudExportLoad() {
+  public function testCrudExportLoad() {
     $loaded_export = ctools_export_crud_load('ctools_export_test', 'database_test');
 
     $expected_export = new stdClass();
@@ -47,7 +49,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
   /**
    * Tests CRUD operation: Load multiple.
    */
-  function testCrudExportLoadMultiple() {
+  public function testCrudExportLoadMultiple() {
     $exportable_names = array('database_test', 'overridden_test', 'default_test');
     $loaded_exports = ctools_export_crud_load_multiple('ctools_export_test', $exportable_names);
 
@@ -57,7 +59,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
   /**
    * Tests CRUD operation: Load all.
    */
-  function testCrudExportLoadAll() {
+  public function testCrudExportLoadAll() {
     $loaded_exports = ctools_export_crud_load_all('ctools_export_test');
 
     $this->assertEqual(count($loaded_exports), 3, 'All exportables have been loaded.');
@@ -66,10 +68,10 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
   /**
    * Tests CRUD operation: Save.
    */
-  function testCrudExportSave() {
+  public function testCrudExportSave() {
     $default_export = ctools_export_crud_load('ctools_export_test', 'default_test');
 
-    $this->assertTrue($default_export->in_code_only,'The loaded exportable is in code only.');
+    $this->assertTrue($default_export->in_code_only, 'The loaded exportable is in code only.');
 
     ctools_export_crud_save('ctools_export_test', $default_export);
 
@@ -84,7 +86,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
   /**
    * Tests CRUD operation: New.
    */
-  function testCrudExportNew() {
+  public function testCrudExportNew() {
     // Default exportable with defualt values.
     $new_export = ctools_export_crud_new('ctools_export_test');
 
@@ -113,7 +115,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
   /**
    * Tests CRUD operation: Revert.
    */
-  function testCrudExportRevert() {
+  public function testCrudExportRevert() {
     // Load exportable, will come from database.
     $original_export = ctools_export_crud_load('ctools_export_test', 'overridden_test');
 
@@ -135,14 +137,15 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
     // Check the exportable is now in_code_only.
     $this->assertTrue($default_export->in_code_only, 'The loaded exportable is in the database only.');
 
-    // Make sure the default object loaded matches the same overridden one in the database.
+    // Make sure the default object loaded matches the same overridden one in
+    // the database.
     $this->assertEqual($original_export->machine, $default_export->machine, 'The default exportable has been loaded and matches the overridden exportable.');
   }
 
   /**
    * Tests CRUD operation: Delete.
    */
-  function testCrudExportDelete() {
+  public function testCrudExportDelete() {
     // Create a stub entry save it and delete it from the database.
     $new_export = ctools_export_crud_new('ctools_export_test');
     ctools_export_crud_save('ctools_export_test', $new_export);
@@ -158,6 +161,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
 
     $machine = $database_export->machine;
     ctools_export_crud_delete('ctools_export_test', $database_export);
+
     // Clear the exportable caches as it's been loaded above.
     ctools_export_load_object_reset('ctools_export_test');
     $result = ctools_export_crud_load('ctools_export_test', $machine);
@@ -168,7 +172,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
   /**
    * Tests CRUD operation: Set status.
    */
-  function testCrudExportSetStatus() {
+  public function testCrudExportSetStatus() {
     // Database only object.
     $database_export = ctools_export_crud_load('ctools_export_test', 'database_test');
     ctools_export_crud_disable('ctools_export_test', $database_export);
diff --git a/tests/ctools_export_test/ctools_export_test.default_ctools_export_tests.inc b/tests/ctools_export_test/ctools_export_test.default_ctools_export_tests.inc
index 9f2dd6c6b268150c90f2d35dc085ca530c06c4f7..2f5ca584d17798e9a34c667ef169a61be2c2ce29 100644
--- a/tests/ctools_export_test/ctools_export_test.default_ctools_export_tests.inc
+++ b/tests/ctools_export_test/ctools_export_test.default_ctools_export_tests.inc
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Implements hook_default_export_tests().
  */
diff --git a/tests/ctools_export_test/ctools_export_test.install b/tests/ctools_export_test/ctools_export_test.install
index 2eb54ca398e223dc2ff3e04d36b120ddc2cfeb70..e6967ef5a69aa9afa58438215809d68dd23729d2 100644
--- a/tests/ctools_export_test/ctools_export_test.install
+++ b/tests/ctools_export_test/ctools_export_test.install
@@ -1,12 +1,16 @@
 <?php
 
 /**
- * Implements hook_schema();
+ * @file
+ */
+
+/**
+ * Implements hook_schema().
  */
 function ctools_export_test_schema() {
   $schema['ctools_export_test'] = array(
-   'description' => 'CTools export test data table',
-   'export' => array(
+    'description' => 'CTools export test data table',
+    'export' => array(
       'key' => 'machine',
       'identifier' => 'ctools_export_test',
       'default hook' => 'default_ctools_export_tests',
@@ -53,7 +57,7 @@ function ctools_export_test_schema() {
 }
 
 /**
- * Implments hook_install();
+ * Implements hook_install().
  */
 function ctools_export_test_install() {
   $ctools_export_tests = array();
diff --git a/tests/ctools_export_test/ctools_export_test.module b/tests/ctools_export_test/ctools_export_test.module
index 80f1adbb3761025d3e5ea7cdc44b92741880bf1e..9cd803cece3a279acd07226995fa674b5477c413 100644
--- a/tests/ctools_export_test/ctools_export_test.module
+++ b/tests/ctools_export_test/ctools_export_test.module
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @file
+ */
+
 /**
  * Implements hook_ctools_plugin_api().
  */
diff --git a/tests/ctools_plugin_test.info b/tests/ctools_plugin_test.info
index f50a7476019cf8ce56e1f49b5a3acf17c908651a..4b78c8d48a95972e07529a7e814f11a7388fab3d 100644
--- a/tests/ctools_plugin_test.info
+++ b/tests/ctools_plugin_test.info
@@ -3,10 +3,4 @@ description = Provides hooks for testing ctools plugins.
 package = Chaos tool suite
 core = 7.x
 dependencies[] = ctools
-files[] = ctools.plugins.test
-files[] = object_cache.test
-files[] = css.test
-files[] = context.test
-files[] = math_expression.test
-files[] = math_expression_stack.test
 hidden = TRUE
diff --git a/tests/ctools_plugin_test.module b/tests/ctools_plugin_test.module
index 567f6e73d39d3bd7a8e33c44cd2e48e6dd2deaaf..4e8770ed9777f17e8e3f7385804c7bcee6b82e57 100644
--- a/tests/ctools_plugin_test.module
+++ b/tests/ctools_plugin_test.module
@@ -1,10 +1,12 @@
 <?php
+
 /**
- * Define some plugin systems to test ctools plugin includes.
+ * @file
+ * Define some plugin systems to test CTools plugin includes.
  */
 
 /**
- * Implementation of hook_ctools_plugin_dierctory()
+ * Implementation of hook_ctools_plugin_directory().
  */
 function ctools_plugin_test_ctools_plugin_directory($module, $plugin) {
   if ($module == 'ctools_plugin_test') {
@@ -12,11 +14,14 @@ function ctools_plugin_test_ctools_plugin_directory($module, $plugin) {
   }
 }
 
+/**
+ * Implements hook_ctools_plugin_type().
+ */
 function ctools_plugin_test_ctools_plugin_type() {
   return array(
     'extra_defaults' => array(
       'defaults' => array(
-        'bool' => true,
+        'bool' => TRUE,
         'string' => 'string',
         'array' => array('some value'),
       ),
@@ -50,6 +55,11 @@ function ctools_plugin_test_ctools_plugin_type() {
   );
 }
 
+/**
+ * Plugin callback.
+ *
+ * @see ctools_plugin_test_ctools_plugin_type()
+ */
 function ctools_plugin_test_ctools_plugin_test_big_hook_cached() {
   return array(
     'test1' => array(
@@ -59,6 +69,11 @@ function ctools_plugin_test_ctools_plugin_test_big_hook_cached() {
   );
 }
 
+/**
+ * Plugin callback.
+ *
+ * @see ctools_plugin_test_ctools_plugin_type()
+ */
 function ctools_plugin_test_ctools_plugin_test_big_hook_not_cached() {
   return array(
     'test1' => array(
@@ -68,5 +83,18 @@ function ctools_plugin_test_ctools_plugin_test_big_hook_not_cached() {
   );
 }
 
-function ctools_plugin_test_hook_cached_test() {}
-function ctools_plugin_test_hook_not_cached_test() {}
+/**
+ * Callback for the big_hook_cached plugin.
+ *
+ * @see ctools_plugin_test_ctools_plugin_test_big_hook_cached
+ */
+function ctools_plugin_test_hook_cached_test() {
+}
+
+/**
+ * Callback for the big_hook_not_cached plugin.
+ *
+ * @see ctools_plugin_test_ctools_plugin_test_big_hook_not_cached()
+ */
+function ctools_plugin_test_hook_not_cached_test() {
+}
diff --git a/tests/math_expression.test b/tests/math_expression.test
index 730e079a5ca669bcd3bbede34269d498240150a3..023e46a4555b962c891d650de90a4e000e9abd02 100644
--- a/tests/math_expression.test
+++ b/tests/math_expression.test
@@ -1,129 +1,334 @@
 <?php
 
-/**
- * @file
- * Contains \CtoolsMathExpressionTestCase.
- */
-
 /**
  * Tests the MathExpression library of ctools.
  */
 class CtoolsMathExpressionTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
-      'name' => 'CTools math expression tests',
+      'name' => 'Math expressions',
       'description' => 'Test the math expression library of ctools.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
     );
   }
 
-  public function setUp() {
-    parent::setUp('ctools', 'ctools_plugin_test');
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    $modules[] = 'ctools_plugin_test';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Return the sign of the numeric arg $n as an integer -1, 0, 1.
+   *
+   * Note: Not defined when $n is Infinity or NaN (or NULL or ...)!
+   *
+   * @param int|float $n
+   *   The number to test.
+   *
+   * @return int
+   *   -1 if the $n is negative, 0 if $n is zero or 1 if $n is positive.
+   *
+   * @see gmp_sign()
+   */
+  protected static function sign($n) {
+    return ($n > 0) - ($n < 0);
   }
 
   /**
-   * Returns a random double between 0 and 1.
+   * Returns a random number between 0 and 1.
+   *
+   * @return float
+   *   A random number between 0 and 1 inclusive.
    */
   protected function rand01() {
-    return rand(0, PHP_INT_MAX) / PHP_INT_MAX;
+    return mt_rand(0, PHP_INT_MAX) / PHP_INT_MAX;
   }
 
   /**
    * A custom assertion with checks the values in a certain range.
+   *
+   * @param float $first
+   *   A value to check for equality.
+   * @param float $second
+   *   A value to check for equality.
+   * @param string $message
+   *   The message describing the correct behaviour, eg. "2/4 equals 1/2". The
+   *   default message is used if this value is empty.
+   * @param float $delta
+   *   The precision with which values must match. This accounts for rounding
+   *   errors and imprecise representation errors in the floating point format.
+   *   The value passed in should ideally be proportional to the values being
+   *   compared.
+   * @param string $group
+   *   Which group this assert belongs to.
+   *
+   * @return bool
+   *   TRUE if the assertion was correct (that is, $first == $second within the
+   *   given limits), FALSE otherwise.
    */
-  protected function assertFloat($first, $second, $delta = 0.0000001, $message = '', $group = 'Other') {
-    return $this->assert(abs($first - $second) <= $delta, $message ? $message : t('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
+  protected function assertFloat($first, $second, $message = '', $delta = 0.00000001, $group = 'Other') {
+    // Check for NaN and Inf because the abs() and sign() code won't like those.
+    $equal = FALSE
+      // Equal if both an infinity.
+      || (is_infinite($first) && is_infinite($second))
+
+      // Equal if both NaN.
+      || (is_nan($first) && is_nan($second))
+
+      // Equal if same absolute value (within limits) and same sign.
+      || ((abs($first - $second) <= $delta) && (self::sign($first) === self::sign($second)));
+
+    if (empty($message)) {
+      $default = t('Value !first is equal to value !second.',
+        array(
+          '!first' => var_export($first, TRUE),
+          '!second' => var_export($second, TRUE),
+        ));
+      $message = $default;
+    }
+
+    return $this->assert($equal, $message, $group);
   }
 
+  /**
+   * Test some arithmetic handling.
+   */
   public function testArithmetic() {
-    $math_expression = new ctools_math_expr();
-
-    // Test constant expressions.
-    $this->assertEqual($math_expression->e('2'), 2);
-    $random_number = rand(0, 10);
-    $this->assertEqual($random_number, $math_expression->e((string) $random_number));
-
-    // Test simple arithmetic.
-    $random_number_a = rand(5, 10);
-    $random_number_b = rand(5, 10);
-    $this->assertEqual($random_number_a + $random_number_b, $math_expression->e("$random_number_a + $random_number_b"));
-    $this->assertEqual($random_number_a - $random_number_b, $math_expression->e("$random_number_a - $random_number_b"));
-    $this->assertEqual($random_number_a * $random_number_b, $math_expression->e("$random_number_a * $random_number_b"));
-    $this->assertEqual($random_number_a / $random_number_b, $math_expression->e("$random_number_a / $random_number_b"));
-
-    // Test Associative property.
-    $random_number_c = rand(5, 10);
-    $this->assertEqual($math_expression->e("$random_number_a + ($random_number_b + $random_number_c)"), $math_expression->e("($random_number_a + $random_number_b) + $random_number_c"));
-    $this->assertEqual($math_expression->e("$random_number_a * ($random_number_b * $random_number_c)"), $math_expression->e("($random_number_a * $random_number_b) * $random_number_c"));
-
-    // Test Commutative property.
-    $this->assertEqual($math_expression->e("$random_number_a + $random_number_b"), $math_expression->e("$random_number_b + $random_number_a"));
-    $this->assertEqual($math_expression->e("$random_number_a * $random_number_b"), $math_expression->e("$random_number_b * $random_number_a"));
-
-    // Test Distributive property.
-    $this->assertEqual($math_expression->e("($random_number_a + $random_number_b) * $random_number_c"), $math_expression->e("($random_number_a * $random_number_c + $random_number_b * $random_number_c)"));
-
-    $this->assertEqual(pow($random_number_a, $random_number_b), $math_expression->e("$random_number_a ^ $random_number_b"));
+    $math_expr = new ctools_math_expr();
+
+    $this->assertEqual($math_expr->evaluate('2'), 2, 'Check Literal 2');
+
+    $this->assertEqual($math_expr->e('2+1'), $math_expr->evaluate('2+1'), 'Check that e() and evaluate() are equivalent.');
+
+    foreach (range(1, 4) as $n) {
+      // Test constant expressions.
+      $random_number = mt_rand(0, 20);
+      $this->assertEqual($random_number, $math_expr->evaluate((string) $random_number), "Literal $random_number");
+
+      // Test simple arithmetic.
+      $number_a = mt_rand(-55, 777);
+      $number_b = mt_rand(-555, 77);
+      $this->assertEqual(
+        $number_a + $number_b,
+        $math_expr->evaluate("$number_a + $number_b"),
+        "Addition: $number_a + $number_b");
+      $this->assertEqual(
+        $number_a - $number_b,
+        $math_expr->evaluate("$number_a - $number_b"),
+        "Subtraction: $number_a + $number_b");
+      $this->assertFloat(
+        ($number_a * $number_b),
+        $math_expr->evaluate("$number_a * $number_b"),
+        "Multiplication: $number_a * $number_b = " . ($number_a * $number_b));
+      $this->assertFloat(
+        ($number_a / $number_b),
+        $math_expr->evaluate("$number_a / $number_b"),
+        "Division: $number_a / $number_b = " . ($number_a / $number_b));
+
+      // Test Associative property.
+      $number_c = mt_rand(-99, 77);
+      $this->assertEqual(
+        $math_expr->evaluate("$number_a + ($number_b + $number_c)"),
+        $math_expr->evaluate("($number_a + $number_b) + $number_c"),
+        "Associative: $number_a + ($number_b + $number_c)");
+      $this->assertEqual(
+        $math_expr->evaluate("$number_a * ($number_b * $number_c)"),
+        $math_expr->evaluate("($number_a * $number_b) * $number_c"),
+        "Associative: $number_a * ($number_b * $number_c)");
+
+      // Test Commutative property.
+      $this->assertEqual(
+        $math_expr->evaluate("$number_a + $number_b"),
+        $math_expr->evaluate("$number_b + $number_a"),
+        "Commutative: $number_a + $number_b");
+      $this->assertEqual(
+        $math_expr->evaluate("$number_a * $number_b"),
+        $math_expr->evaluate("$number_b * $number_a"),
+        "Commutative: $number_a * $number_b");
+
+      // Test Distributive property.
+      $this->assertEqual(
+        $math_expr->evaluate("($number_a + $number_b) * $number_c"),
+        $math_expr->evaluate("($number_a * $number_c + $number_b * $number_c)"),
+        "Distributive: ($number_a + $number_b) * $number_c");
+
+      // @todo: Doesn't work with zero or negative powers when number is zero or negative, e.g. 0^0, 0^-2, -2^0, -2^-2.
+      $random_number = mt_rand(1, 15);
+      $random_power = mt_rand(-15, 15);
+
+      $this->assertFloat(
+        pow($random_number, $random_power),
+        $math_expr->evaluate("$random_number ^ $random_power"),
+        "$random_number ^ $random_power");
+
+      $this->assertFloat(
+        pow($random_number, $random_power),
+        $math_expr->evaluate("pow($random_number, $random_power)"),
+        "pow($random_number, $random_power)");
+    }
   }
 
+  /**
+   * Test various built-in transcendental and extended functions.
+   */
   public function testBuildInFunctions() {
-    $math_expression = new ctools_math_expr();
-
-    // @todo: maybe run this code multiple times to test different values.
-    $random_double = $this->rand01();
-    $random_int = rand(5, 10);
-    $this->assertFloat(sin($random_double), $math_expression->e("sin($random_double)"));
-    $this->assertFloat(cos($random_double), $math_expression->e("cos($random_double)"));
-    $this->assertFloat(tan($random_double), $math_expression->e("tan($random_double)"));
-    $this->assertFloat(exp($random_double), $math_expression->e("exp($random_double)"));
-    $this->assertFloat(sqrt($random_double), $math_expression->e("sqrt($random_double)"));
-    $this->assertFloat(log($random_double), $math_expression->e("ln($random_double)"));
-    $this->assertFloat(round($random_double), $math_expression->e("round($random_double)"));
-    $this->assertFloat(abs($random_double + $random_int), $math_expression->e('abs(' . ($random_double + $random_int) . ')'));
-    $this->assertEqual(round($random_double + $random_int), $math_expression->e('round(' . ($random_double + $random_int) . ')'));
-    $this->assertEqual(ceil($random_double + $random_int), $math_expression->e('ceil(' . ($random_double + $random_int) . ')'));
-    $this->assertEqual(floor($random_double + $random_int), $math_expression->e('floor(' . ($random_double + $random_int) . ')'));
-
-    // @fixme: you can't run time without an argument.
-    $this->assertFloat(time(), $math_expression->e('time(1)'));
+    $math_expr = new ctools_math_expr();
+
+    foreach (range(1, 4) as $n) {
+      $random_double = $this->rand01();
+      $random_int = mt_rand(-65535, 65535);
+      $this->assertFloat(sin($random_double), $math_expr->evaluate("sin($random_double)"), "sin($random_double)");
+      $this->assertFloat(cos($random_double), $math_expr->evaluate("cos($random_double)"), "cos($random_double)");
+      $this->assertFloat(tan($random_double), $math_expr->evaluate("tan($random_double)"), "tan($random_double)");
+      $this->assertFloat(exp($random_double), $math_expr->evaluate("exp($random_double)"), "exp($random_double)");
+      $this->assertFloat(sqrt($random_double), $math_expr->evaluate("sqrt($random_double)"), "sqrt($random_double)");
+      $this->assertFloat(log($random_double), $math_expr->evaluate("ln($random_double)"), "ln($random_double)");
+      $this->assertFloat(round($random_double), $math_expr->evaluate("round($random_double)"), "round($random_double)");
+
+      $random_real = $random_double + $random_int;
+      $this->assertFloat(abs($random_real), $math_expr->evaluate('abs(' . $random_real . ')'), "abs($random_real)");
+      $this->assertEqual(round($random_real), $math_expr->evaluate('round(' . $random_real . ')'), "round($random_real)");
+      $this->assertEqual(ceil($random_real), $math_expr->evaluate('ceil(' . $random_real . ')'), "ceil($random_real)");
+      $this->assertEqual(floor($random_real), $math_expr->evaluate('floor(' . $random_real . ')'), "floor($random_real)");
+    }
+
+    $this->assertFloat(time(), $math_expr->evaluate('time()'), "time()");
 
     $random_double_a = $this->rand01();
     $random_double_b = $this->rand01();
-    // @fixme: max/min don't work at the moment.
-//    $this->assertFloat(max($random_double_a, $random_double_b), $math_expression->e("max($random_double_a, $random_double_b)"));
-//    $this->assertFloat(min($random_double_a, $random_double_b), $math_expression->e("min($random_double_a, $random_double_b)"));
+    $this->assertFloat(
+      max($random_double_a, $random_double_b),
+      $math_expr->evaluate("max($random_double_a, $random_double_b)"),
+      "max($random_double_a, $random_double_b)");
+    $this->assertFloat(
+      min($random_double_a, $random_double_b),
+      $math_expr->evaluate("min($random_double_a, $random_double_b)"),
+      "min($random_double_a, $random_double_b)");
   }
 
+  /**
+   * Test variable handling.
+   */
   public function testVariables() {
-    $math_expression = new ctools_math_expr();
+    $math_expr = new ctools_math_expr();
 
-    $random_number_a = rand(5, 10);
-    $random_number_b = rand(5, 10);
+    // We should have a definition of pi:
+    $this->assertFloat(pi(), $math_expr->evaluate('pi'));
 
-    // Store the first random number and use it on calculations.
-    $math_expression->e("var = $random_number_a");
-    $this->assertEqual($random_number_a + $random_number_b, $math_expression->e("var + $random_number_b"));
-    $this->assertEqual($random_number_a * $random_number_b, $math_expression->e("var * $random_number_b"));
-    $this->assertEqual($random_number_a - $random_number_b, $math_expression->e("var - $random_number_b"));
-    $this->assertEqual($random_number_a / $random_number_b, $math_expression->e("var / $random_number_b"));
+    // And a definition of e:
+    $this->assertFloat(exp(1), $math_expr->evaluate('e'));
+
+    $number_a = 5;
+    $number_b = 10;
+
+    // Store the first number and use it on a calculation.
+    $math_expr->evaluate("var = $number_a");
+    $this->assertEqual($number_a + $number_b, $math_expr->evaluate("var + $number_b"));
+
+    // Change the value and check the new value is used.
+    $math_expr->evaluate("var = $number_b");
+    $this->assertEqual(
+      $number_b + $number_b,
+      $math_expr->evaluate("var + $number_b"),
+      "var + $number_b");
+
+    // Store another number and use it on a calculation.
+    $math_expr->evaluate("var = $number_a");
+    $math_expr->evaluate("newvar = $number_a");
+
+    $this->assertEqual(
+      $number_a + $number_a,
+      $math_expr->evaluate('var + newvar'),
+      'var + newvar');
+
+    $this->assertFloat(
+      $number_a / $number_b,
+      $math_expr->evaluate("var / $number_b"),
+      "var / $number_b");
   }
 
+  /**
+   * Test custom function handling.
+   */
   public function testCustomFunctions() {
-    $math_expression = new ctools_math_expr();
+    $math_expr = new ctools_math_expr();
 
-    $random_number_a = rand(5, 10);
-    $random_number_b = rand(5, 10);
+    $number_a = mt_rand(5, 10);
+    $number_b = mt_rand(5, 10);
 
     // Create a one-argument function.
-    $math_expression->e("f(x) = 2 * x");
-    $this->assertEqual($random_number_a * 2, $math_expression->e("f($random_number_a)"));
-    $this->assertEqual($random_number_b * 2, $math_expression->e("f($random_number_b)"));
+    $math_expr->evaluate("f(x) = 2 * x");
+    $this->assertEqual($number_a * 2, $math_expr->evaluate("f($number_a)"));
+    $this->assertEqual($number_b * 2, $math_expr->evaluate("f($number_b)"));
 
     // Create a two-argument function.
-    $math_expression->e("g(x, y) = 2 * x + y");
-    $this->assertEqual($random_number_a * 2 + $random_number_b, $math_expression->e("g($random_number_a, $random_number_b)"));
+    $math_expr->evaluate("g(x, y) = 2 * x + y");
+    $this->assertEqual(
+      $number_a * 2 + $number_b,
+      $math_expr->evaluate("g($number_a, $number_b)"),
+      "g($number_a, $number_b)");
 
     // Use a custom function in another function.
-    $this->assertEqual(($random_number_a * 2 + $random_number_b) * 2, $math_expression->e("f(g($random_number_a, $random_number_b))"));
+    $this->assertEqual(
+      ($number_a * 2 + $number_b) * 2,
+      $math_expr->evaluate("f(g($number_a, $number_b))"),
+      "f(g($number_a, $number_b))");
+  }
+
+  /**
+   * Test conditional handling.
+   */
+  public function testIf() {
+    $math_expr = new ctools_math_expr();
+
+    $number_a = mt_rand(1, 10);
+    $number_b = mt_rand(11, 20);
+
+    foreach (range(1, 4) as $n) {
+      // @todo: Doesn't work with negative numbers.
+      if ($n == 2 || $n == 4) {
+        //$number_a = -$number_a;
+      }
+
+      if ($n == 3 || $n == 4) {
+        //$number_b = -$number_b;
+      }
+
+      $this->assertEqual(
+        $number_a,
+        $math_expr->evaluate("if(1, $number_a, $number_b)"),
+        "if(1, $number_a, $number_b)");
+
+      $this->assertEqual(
+        $number_a,
+        $math_expr->evaluate("if(1, $number_a)",
+          "if(1, $number_a)"));
+
+      $this->assertEqual(
+        $number_b,
+        $math_expr->evaluate("if(0, $number_a, $number_b)"),
+        "if(0, $number_a, $number_b)");
+
+      // Also add an expression so ensure it's evaluated.
+      $this->assertEqual(
+        $number_b,
+        $math_expr->evaluate("if($number_a > $number_b, $number_a, $number_b)"),
+        "if($number_a > $number_b, $number_a, $number_b)");
+
+      $this->assertEqual(
+        $number_b,
+        $math_expr->evaluate("if($number_a < $number_b, $number_b, $number_a)"),
+        "if($number_a < $number_b, $number_b, $number_a)");
+    }
   }
+
 }
diff --git a/tests/math_expression_stack.test b/tests/math_expression_stack.test
index 8143a55b82c103fa0fd24a6d58225ee380efc77c..e1e587a2518293b9d45ca2c62a781efb809681be 100644
--- a/tests/math_expression_stack.test
+++ b/tests/math_expression_stack.test
@@ -1,26 +1,34 @@
 <?php
 
-/**
- * @file
- * Contains \CtoolsMathExpressionStackTestCase
- */
-
 /**
  * Tests the simple MathExpressionStack class.
  */
 class CtoolsMathExpressionStackTestCase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
-      'name' => 'CTools math expression stack tests',
+      'name' => 'Math expressions stack',
       'description' => 'Test the stack class of the math expression library.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
     );
   }
 
-  public function setUp() {
-    parent::setUp('ctools', 'ctools_plugin_test');
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    $modules[] = 'ctools_plugin_test';
+    parent::setUp($modules);
   }
 
+  /**
+   * Test the math expression stack system.
+   */
   public function testStack() {
     $stack = new ctools_math_expr_stack();
 
@@ -35,13 +43,15 @@ class CtoolsMathExpressionStackTestCase extends DrupalWebTestCase {
     $this->assertIdentical($value, $stack->pop());
     $this->assertNull($stack->pop());
 
-    // Add multiple elements and see whether they are returned in the right order.
+    // Add multiple elements and see whether they are returned in the right
+    // order.
     $values = array($this->randomName(), $this->randomName(), $this->randomName());
     foreach ($values as $value) {
       $stack->push($value);
     }
 
-    // Test the different elements at different positions with the last() method.
+    // Test the different elements at different positions with the last()
+    // method.
     $count = count($values);
     foreach ($values as $key => $value) {
       $this->assertEqual($value, $stack->last($count - $key));
@@ -58,6 +68,6 @@ class CtoolsMathExpressionStackTestCase extends DrupalWebTestCase {
       $this->assertEqual($stack->pop(), $value);
     }
     $this->assertNull($stack->pop());
-
   }
+
 }
diff --git a/tests/object_cache.test b/tests/object_cache.test
index 8791d7e706fe276a95e46dd0f302b9342e5e4783..87fa4153e8c5491c1eb42faa6946fdd235472f60 100644
--- a/tests/object_cache.test
+++ b/tests/object_cache.test
@@ -1,27 +1,34 @@
 <?php
-/**
- * @file
- * Tests for different parts of the ctools object caching system.
- */
 
 /**
  * Test object cache storage.
  */
 class CtoolsObjectCache extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
   public static function getInfo() {
     return array(
-      'name' => 'Ctools object cache storage',
+      'name' => 'Object cache storage (UI tests)',
       'description' => 'Verify that objects are written, readable and lockable.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
     );
   }
 
-  public function setUp() {
-    // Additionally enable ctools module.
-    parent::setUp('ctools');
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
   }
 
+
   public function testObjectStorage() {
+    ctools_include('cache');
+
     $account1 = $this->drupalCreateUser(array());
     $this->drupalLogin($account1);
 
@@ -36,11 +43,11 @@ class CtoolsObjectCache extends DrupalWebTestCase {
     // TODO Test object locking somehow.
     // Object locking/testing works on session_id but simpletest uses
     // $this->session_id so can't be tested ATM.
-
     ctools_object_cache_clear('testdata', 'one');
     $this->assertFalse(ctools_object_cache_get('testdata', 'one'), 'Object cache data successfully cleared');
 
     // TODO Test ctools_object_cache_clear_all somehow...
     // ctools_object_cache_clear_all requires session_id funtionality as well.
   }
+
 }
diff --git a/tests/object_cache_unit.test b/tests/object_cache_unit.test
new file mode 100644
index 0000000000000000000000000000000000000000..68b735031589576e1df0cc2aca5fca43b52ffd6b
--- /dev/null
+++ b/tests/object_cache_unit.test
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * Test ctools_cache_find_plugin and the structure of the default cache plugins.
+ */
+class CtoolsUnitObjectCachePlugins extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Object cache storage (unit tests)',
+      'description' => 'Verify that objects are written, readable and lockable.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Check that the supplied array looks like a ctools cache plugin.
+   *
+   * @param mixed $p
+   *   The value to check.
+   * @param string $msg
+   *   Prefix of the assertion message.
+   */
+  public function assertValidCachePlugin($p, $msg) {
+    $this->assertTrue(is_array($p), $msg . ': plugin is an array');
+
+    $this->assertEqual($p['plugin type'], 'cache', $msg . ': type is cache');
+
+    $this->assertTrue(array_key_exists('title', $p), $msg . ': title element exists');
+    $this->assertTrue(!empty($p['title']) && is_string($p['title']), $msg . ': title is a string');
+
+    $this->assertTrue(array_key_exists('cache get', $p), $msg . ': has a get function');
+    $this->assertTrue(!empty($p['cache get']) && is_callable($p['cache get']), $msg . ': get is executable');
+
+    $this->assertTrue(array_key_exists('cache set', $p), $msg . ': has a set function');
+    $this->assertTrue(!empty($p['cache set']) && is_callable($p['cache set']), $msg . ': set is executable');
+
+    // @todo Clear is required by the spec (cache.inc:40..48): but export_ui
+    // cache doesn't implement it. Enable the assertions when that problem is
+    // solved.
+    // $this->assertTrue(array_key_exists('cache clear', $p), $msg . ': has a clear function');
+    // $this->assertTrue(is_callable($p['cache clear']), $msg . ': clear is executable');
+    // @todo Break is optional acc'd to spec but does anything implement it?
+    $this->assertTrue(!array_key_exists('cache break', $p) || is_callable($p['cache break']), $msg . ': break is executable');
+
+    // @todo Finalize is optional so don't fail if not there??
+    $this->assertTrue(!array_key_exists('cache finalize', $p) || is_callable($p['cache finalize']), $msg . ': finalize is executable');
+  }
+
+  /**
+   * Check the return value of the ctools_cache_find_plugin function.
+   *
+   * @param mixed $p
+   *   The value to check.
+   * @param string $msg
+   *   Prefix of the assertion message.
+   */
+  public function assertPluginNotFound($p, $msg) {
+    $this->assertTrue(is_array($p), $msg . ': is an array');
+    $plugin = array_shift($p);
+    $this->assertNull($plugin, $msg . ': no plugin info');
+    $data = array_shift($p);
+    $this->assertTrue(empty($data) || is_string($data), $msg . ': data string-like');
+    $this->assertTrue(empty($p), $msg . ': just two elements');
+  }
+
+  /**
+   * Check the return value of the ctools_cache_find_plugin function.
+   *
+   * @param mixed $p
+   *   The value to check.
+   * @param string $msg
+   *   Prefix of the assertion message.
+   */
+  public function assertPluginFound($p, $msg) {
+    $this->assertTrue(is_array($p), $msg . ': is an array');
+    $plugin = array_shift($p);
+    $this->assertTrue(is_array($plugin), $msg . ': has plugin data');
+    $data = array_shift($p);
+    $this->assertTrue(empty($data) || is_string($data), $msg . ': data is string-like');
+    $this->assertTrue(empty($p), $msg . ': just two elements');
+  }
+
+  /**
+   * Test to see that we can find the standard simple plugin.
+   */
+  public function testFindSimpleCachePlugin() {
+    ctools_include('cache');
+
+    // The simple plugin.
+    $plugin = ctools_cache_find_plugin('simple');
+    $this->assertPluginFound($plugin, 'The Simple Cache plugin is present');
+    $this->assertValidCachePlugin($plugin[0], 'The Simple Cache plugin');
+
+    // The simple plugin, with ::.
+    $plugin = ctools_cache_find_plugin('simple::data');
+    $this->assertPluginFound($plugin, 'The Simple Cache plugin is present, with data');
+  }
+
+  /**
+   * Test to see that we can find the standard export_ui plugin.
+   */
+  public function testFindExportUICachePlugin() {
+    ctools_include('cache');
+
+    // The export plugin.
+    $plugin = ctools_cache_find_plugin('export_ui');
+    $this->assertPluginFound($plugin, 'The Export UI Cache plugin is present');
+    $this->assertValidCachePlugin($plugin[0], 'The Export Cache plugin');
+
+    // The export plugin, with ::.
+    $plugin = ctools_cache_find_plugin('export_ui::data');
+    $this->assertTrue(is_array($plugin), 'The Export UI Cache plugin is present, with data');
+  }
+
+  /**
+   * Test to see that we don't find plugins that aren't there.
+   */
+  public function testFindFoobarbazCachePlugin() {
+    ctools_include('cache');
+
+    // An imaginary foobarbaz plugin.
+    $plugin = ctools_cache_find_plugin('foobarbaz');
+    $this->assertPluginNotFound($plugin, 'The Foobarbaz Cache plugin is absent');
+    $plugin = ctools_cache_find_plugin('foobarbaz::data');
+    $this->assertPluginNotFound($plugin, 'The Foobarbaz Cache plugin is absent, with data');
+  }
+
+}
diff --git a/tests/page_tokens.test b/tests/page_tokens.test
new file mode 100644
index 0000000000000000000000000000000000000000..7d95d9ae9935d31809c029dd411404a9fe8b63b2
--- /dev/null
+++ b/tests/page_tokens.test
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * @file
+ * Tests for different parts of the ctools object caching system.
+ *
+ * Needs to be a WebTest because need access to database tables.
+ */
+
+class CtoolsPageTokens extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Page token processing',
+      'description' => 'Verify that page tokens can be set and read.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    parent::setUp($modules);
+
+    // Start each test anew.
+    ctools_reset_page_tokens();
+  }
+
+  /**
+   * Test that we can set page tokens.
+   */
+  public function testSetPageToken() {
+    ctools_set_page_token('id', 'variable', 'test');
+
+    $tokens = ctools_set_page_token();
+    $this->assertTrue(is_array($tokens) && count($tokens) === 1, 'Page tokens no longer empty.');
+    $this->assertEqual($tokens['id'], array('variable', 'test'), 'Page token has correct value.');
+  }
+
+  /**
+   * Test that we can set page tokens.
+   */
+  public function testSetVariableToken() {
+    $string = ctools_set_variable_token('title');
+    $tokens = ctools_set_page_token();
+
+    $this->assertTrue(is_array($tokens) && count($tokens) === 1, 'Page tokens no longer empty');
+    $this->assertEqual($tokens[$string], array('variable', 'title'), 'Page tokens no longer empty');
+  }
+
+  /**
+   * Test that we can set page tokens.
+   */
+  public function testReplaceVariableToken() {
+    $string = ctools_set_variable_token('title');
+    $this->assertEqual($string, '<!-- ctools-page-title -->', 'Expected form of token was found');
+
+    $elements = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('test')),
+      'title' => '<h2>Title</h2>',
+      'content' => array(
+        '#type' => 'markup',
+        '#markup' => t('This is my test markup'),
+        '#prefix' => $string,
+      ),
+      'link' => array(
+        '#type' => 'link',
+        '#title' => t('My link'),
+        '#href' => 'node/1',
+      ),
+    );
+    $markup = '<div class="test"><!-- ctools-page-title -->This is my test markup<a href="node/1">My link</a></div>';
+
+    $new_markup = ctools_page_token_processing($markup, $elements);
+
+    $this->assertTrue(is_string($new_markup) && strlen($new_markup) > 1, 'Should return string');
+
+    $this->assertTrue(strstr($new_markup, '<h2>'), 'Variable Token Markup should contain h2 element');
+    $this->assertFalse(strstr($new_markup, 'ctools-page-title'), 'Variable Token Markup should not contain comment element');
+  }
+
+  /**
+   * Test that we can set page tokens.
+   */
+  public function testReplaceCallbackToken() {
+    $string = ctools_set_callback_token('title', 'test_ctools_page_callback_token');
+    $this->assertEqual($string, '<!-- ctools-page-title -->', 'Expected form of token was found');
+
+    $elements = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('test')),
+      'content' => array(
+        '#type' => 'markup',
+        '#markup' => t('This is my test markup'),
+        '#prefix' => $string,
+      ),
+      'link' => array(
+        '#type' => 'link',
+        '#title' => t('My link'),
+        '#href' => 'node/1',
+      ),
+    );
+    $markup = '<div class="test"><!-- ctools-page-title -->This is my test markup<a href="node/1">My link</a></div>';
+
+    $new_markup = ctools_page_token_processing($markup, $elements);
+
+    $this->assertTrue(is_string($new_markup) && strlen($new_markup) > 1, 'Should return a non-empty string');
+
+    $this->assertTrue(strstr($new_markup, '<h2>'), 'Callback Token Markup should contain h2 element');
+    $this->assertFalse(strstr($new_markup, 'ctools-page-title'), 'Callback Token Markup should not contain comment element');
+  }
+
+}
+
+/**
+ *
+ * @param $elements
+ *
+ * @return string
+ */
+function test_ctools_page_callback_token($elements) {
+  // Check that 'elements' array looks good.
+  if (isset($elements['content'])) {
+    return '<h2>Title</h2>';
+  }
+  else {
+    return '<!--bad-->';
+  }
+}
diff --git a/tests/plugins/cached/ctoolsCachedPluginArray.class.php b/tests/plugins/cached/ctoolsCachedPluginArray.class.php
index 3037daa50cf19122fbe7e011160fc13cbef28cd7..c6753adc06133bfa13ff9550f5a465ceb2ed1713 100644
--- a/tests/plugins/cached/ctoolsCachedPluginArray.class.php
+++ b/tests/plugins/cached/ctoolsCachedPluginArray.class.php
@@ -1,7 +1,8 @@
 <?php
+
 /**
  * @file
- * A cached plugin object that tests inheritence including.
+ * A cached plugin object that tests inheritance including.
  */
 
 class ctoolsCachedPluginArray {}
diff --git a/tests/plugins/cached/ctoolsCachedPluginArray2.class.php b/tests/plugins/cached/ctoolsCachedPluginArray2.class.php
index 0f7d858405970c4374590cecadcaec9123a36bcb..37ddc110f477bdc68477fd75078d94b051da9614 100644
--- a/tests/plugins/cached/ctoolsCachedPluginArray2.class.php
+++ b/tests/plugins/cached/ctoolsCachedPluginArray2.class.php
@@ -1,7 +1,8 @@
 <?php
+
 /**
  * @file
- * A cached plugin object that tests inheritence including.
+ * A cached plugin object that tests inheritance including.
  */
 
 class ctoolsCachedPluginArray2 extends ctoolsCachedPluginArray {}
diff --git a/tests/plugins/cached/plugin_array.inc b/tests/plugins/cached/plugin_array.inc
index 40a4bf7360662a9d8fbfbfabfad67f692c48a567..90eb339169a6d6dc6552ca4968ed1c965f742421 100644
--- a/tests/plugins/cached/plugin_array.inc
+++ b/tests/plugins/cached/plugin_array.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Chaos Tools plugin include using a plugin array to declare a plugin.
@@ -17,4 +18,5 @@ $plugin = array(
 /**
  * Plugin array function plugin.
  */
-function ctools_plugin_test_plugin_array_cached_test() {}
+function ctools_plugin_test_plugin_array_cached_test() {
+}
diff --git a/tests/plugins/cached/plugin_array2.inc b/tests/plugins/cached/plugin_array2.inc
index e6676154d6cd14d2d48228df453eff7959513983..fa930b744403d4f03f12e046f4b9581fcd0d89bf 100644
--- a/tests/plugins/cached/plugin_array2.inc
+++ b/tests/plugins/cached/plugin_array2.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Chaos Tools plugin include using a plugin array to declare a plugin.
@@ -17,4 +18,5 @@ $plugin = array(
 /**
  * Plugin array function plugin.
  */
-function ctools_plugin_test_plugin_array2_cached_test() {}
+function ctools_plugin_test_plugin_array2_cached_test() {
+}
diff --git a/tests/plugins/cached/plugin_array_dne.inc b/tests/plugins/cached/plugin_array_dne.inc
index e3d3bfb90de04be18812639b1884a0fd381661a5..eccf19e84b15b04029f428398e4ea8e5a58eb6b9 100644
--- a/tests/plugins/cached/plugin_array_dne.inc
+++ b/tests/plugins/cached/plugin_array_dne.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Chaos Tools plugin include using a plugin array to declare a plugin.
diff --git a/tests/plugins/not_cached/ctoolsNotCachedPluginArray.class.php b/tests/plugins/not_cached/ctoolsNotCachedPluginArray.class.php
index a3043bc6bbb288c99a4607b78324d98c5eebeb1a..8dd9561e18cbcabaddf250189bbe424b7094b421 100644
--- a/tests/plugins/not_cached/ctoolsNotCachedPluginArray.class.php
+++ b/tests/plugins/not_cached/ctoolsNotCachedPluginArray.class.php
@@ -1,7 +1,8 @@
 <?php
+
 /**
  * @file
- * A cached plugin object that tests inheritence including.
+ * A cached plugin object that tests inheritance including.
  */
 
 class ctoolsNotCachedPluginArray extends ctoolsNotCachedPluginArray2 {}
diff --git a/tests/plugins/not_cached/ctoolsNotCachedPluginArray2.class.php b/tests/plugins/not_cached/ctoolsNotCachedPluginArray2.class.php
index d7687dd02e5a13ab29caabbbedac3fec3202e80d..07842b6183d528aead7b5251b58b4682f839b803 100644
--- a/tests/plugins/not_cached/ctoolsNotCachedPluginArray2.class.php
+++ b/tests/plugins/not_cached/ctoolsNotCachedPluginArray2.class.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * A cached plugin object that tests including.
diff --git a/tests/plugins/not_cached/plugin_array.inc b/tests/plugins/not_cached/plugin_array.inc
index 3f4539359622ba8754cadb8a0b23819c50f2f597..3a515dfbfb95d8fe6f5d6a2279d302e3a91f848b 100644
--- a/tests/plugins/not_cached/plugin_array.inc
+++ b/tests/plugins/not_cached/plugin_array.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Chaos Tools plugin include using a plugin array to declare a plugin.
@@ -17,4 +18,5 @@ $plugin = array(
 /**
  * Plugin array function plugin.
  */
-function ctools_plugin_test_plugin_array_not_cached_test() {}
+function ctools_plugin_test_plugin_array_not_cached_test() {
+}
diff --git a/tests/plugins/not_cached/plugin_array2.inc b/tests/plugins/not_cached/plugin_array2.inc
index 06b8175710206af88f0173dec96c1358f7bdf823..bbf64d29ce9cdc173a84108e44c8a98ed676c92a 100644
--- a/tests/plugins/not_cached/plugin_array2.inc
+++ b/tests/plugins/not_cached/plugin_array2.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Chaos Tools plugin include using a plugin array to declare a plugin.
@@ -17,4 +18,5 @@ $plugin = array(
 /**
  * Plugin array function plugin.
  */
-function ctools_plugin_test_plugin_array2_not_cached_test() {}
+function ctools_plugin_test_plugin_array2_not_cached_test() {
+}
diff --git a/tests/plugins/not_cached/plugin_array_dne.inc b/tests/plugins/not_cached/plugin_array_dne.inc
index 1f19d2a44592a7fa631840aebd36f3d42c396c21..85f932e4f66d405fd71f4585b6fbd7d5339531c8 100644
--- a/tests/plugins/not_cached/plugin_array_dne.inc
+++ b/tests/plugins/not_cached/plugin_array_dne.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Chaos Tools plugin include using a plugin array to declare a plugin.
diff --git a/views_content/plugins/content_types/views.inc b/views_content/plugins/content_types/views.inc
index 262d81defd85d2d7e4fe1fc7fb7050be1fe9dfac..0754d426146a6a9e6b85bbd33f92582c1fd435f9 100644
--- a/views_content/plugins/content_types/views.inc
+++ b/views_content/plugins/content_types/views.inc
@@ -63,18 +63,6 @@ function views_content_views_content_type_content_types($plugin) {
   return $types;
 }
 
-/**
- * Return a single content type.
- */
-function views_content_views_content_type_content_type($subtype, $plugin) {
-  $view = views_get_view($name);
-  if (empty($view)) {
-    return;
-  }
-
-  return _views_content_views_content_type($view);
-}
-
 /**
  * Create the content type info array to give back to ctools for a given display.
  */
@@ -136,7 +124,7 @@ function views_content_views_content_type_render($subtype, $conf, $panel_args, $
   if (isset($conf['context']) && is_array($conf['context'])) {
     foreach ($conf['context'] as $count => $context_info) {
       if (!strpos($context_info, '.')) {
-        // old skool: support pre-converter contexts as well.
+        // Old skool: support pre-converter contexts as well.
         $cid = $context_info;
         $converter = '';
       }
@@ -162,7 +150,7 @@ function views_content_views_content_type_render($subtype, $conf, $panel_args, $
 
   $block = new stdClass();
   $block->module = 'views';
-  $block->delta  = $view->name . '-' . $view->current_display;
+  $block->delta = $view->name . '-' . $view->current_display;
 
   if (!empty($conf['link_to_view'])) {
     $block->title_link = $view->get_url();
@@ -177,7 +165,7 @@ function views_content_views_content_type_render($subtype, $conf, $panel_args, $
   // pager type that Views uses.
   if ($conf['override_pager_settings']) {
     if (method_exists($view, 'init_pager')) {
-      // Views 3 version
+      // Views 3 version.
       $view->set_items_per_page($conf['nodes_per_page']);
       $view->set_offset($conf['offset']);
 
@@ -185,7 +173,7 @@ function views_content_views_content_type_render($subtype, $conf, $panel_args, $
       if ($conf['use_pager'] && ($pager['type'] == 'none' || $pager['type'] == 'some')) {
         $pager['type'] = 'full';
       }
-      elseif (!$conf['use_pager'] && $pager['type'] != 'none' && $pager['type'] != 'some') {
+      elseif (!$conf['use_pager']) {
         $pager['type'] = $view->get_items_per_page() ? 'some' : 'none';
       }
 
@@ -249,7 +237,7 @@ function views_content_views_select_display($form, &$form_state) {
     '#type' => 'select',
     '#title' => t('Display'),
     '#options' => $displays,
-    '#description' => t('Choose which display of this view you wish to use.')
+    '#description' => t('Choose which display of this view you wish to use.'),
   );
 
   return $form;
@@ -283,7 +271,6 @@ function views_content_views_content_type_edit_form($form, &$form_state) {
   // and check for that and forcibly set them to the right converter so that
   // it doesn't get changed to some whacky default. Oooor just let it get changed
   // to 'no context', I suppose.
-
   $required = array();
   if (isset($view->display_handler) && $arguments = $view->display_handler->get_handlers('argument')) {
     foreach ($arguments as $arg) {
@@ -446,7 +433,7 @@ function views_content_views_content_type_admin_info($subtype, $conf, $contexts)
       }
 
       if (!strpos($context_info, '.')) {
-        // old skool: support pre-converter contexts as well.
+        // Old skool: support pre-converter contexts as well.
         $cid = $context_info;
         $converter = '';
       }
@@ -458,8 +445,10 @@ function views_content_views_content_type_admin_info($subtype, $conf, $contexts)
         $converters = ctools_context_get_converters($cid . '.', $contexts[$cid]);
         $converter = !empty($converters[$context_info]) ? $converters[$context_info] : t('Default');
         $block->content .= '<li>' . t('Argument @arg using context @context converted into @converter', array(
-          '@arg' => $argument->ui_name(), '@context' => $contexts[$cid]->get_identifier(),
-          '@converter' => $converter)) . '</li>';
+          '@arg' => $argument->ui_name(),
+          '@context' => $contexts[$cid]->get_identifier(),
+          '@converter' => $converter,
+        )) . '</li>';
       }
       $argument = next($arguments);
     }
@@ -506,6 +495,7 @@ function views_content_views_content_type_admin_info($subtype, $conf, $contexts)
  *   versions it was the view name with a dash and the display ID.
  *   If this is the case, we can use it to correct the 'display' setting
  *   in the $conf.
+ *
  * @return
  *   The $view with the initialized display. If the $view could not be
  *   loaded, the name attempted will be loaded for use in errors.
@@ -546,7 +536,6 @@ function _views_content_views_update_conf(&$conf, $subtype) {
 
   $view->set_display($display);
   // $view->current_display will now reflect this value.
-
   // If set NOT to override, go ahead and refresh from the view.
   if (empty($conf['override_pager_settings'])) {
     if (method_exists($view, 'init_pager')) {
diff --git a/views_content/plugins/content_types/views_attachments.inc b/views_content/plugins/content_types/views_attachments.inc
index e938f539fdadf2524a2a5e6541e71bcedfe575ef..f399feaa708d311749e2caf7b40666d55fe3065d 100644
--- a/views_content/plugins/content_types/views_attachments.inc
+++ b/views_content/plugins/content_types/views_attachments.inc
@@ -25,7 +25,7 @@ function views_content_views_attachments_content_type_render($subtype, $conf, $p
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_attachments';
   $block->delta   = $context->argument;
   $block->title   = '';
@@ -41,7 +41,6 @@ function views_content_views_attachments_content_type_render($subtype, $conf, $p
   return $block;
 }
 
-
 function views_content_views_attachments_content_type_edit_form($form, &$form_state) {
   $conf = $form_state['conf'];
 
diff --git a/views_content/plugins/content_types/views_empty.inc b/views_content/plugins/content_types/views_empty.inc
index 4664d65d350f733636c34f4fc66d7b3d09a57a1d..01e95c329edaaf2e05619671db76b7edeb36ef90 100644
--- a/views_content/plugins/content_types/views_empty.inc
+++ b/views_content/plugins/content_types/views_empty.inc
@@ -22,7 +22,7 @@ function views_content_views_empty_content_type_render($subtype, $conf, $panel_a
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_empty';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/content_types/views_exposed.inc b/views_content/plugins/content_types/views_exposed.inc
index 93371e21f7cbc01e68d034f375a490e43e83eff0..f6d019fbc840083e7a9174b8e697aaab9b637beb 100644
--- a/views_content/plugins/content_types/views_exposed.inc
+++ b/views_content/plugins/content_types/views_exposed.inc
@@ -22,7 +22,7 @@ function views_content_views_exposed_content_type_render($subtype, $conf, $panel
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_exposed';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/content_types/views_feed.inc b/views_content/plugins/content_types/views_feed.inc
index f2fdb8af502a276f8ccd30a18b5e3391174f6644..774d593f648dbca17ee36fe84f15c14f046cb4c6 100644
--- a/views_content/plugins/content_types/views_feed.inc
+++ b/views_content/plugins/content_types/views_feed.inc
@@ -22,7 +22,7 @@ function views_content_views_feed_content_type_render($subtype, $conf, $panel_ar
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_feed';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/content_types/views_footer.inc b/views_content/plugins/content_types/views_footer.inc
index 81c87a3abbb0d956967f5fb2c9447feced028759..fc3d01b8e3089f284524d5fe067c926d08242e08 100644
--- a/views_content/plugins/content_types/views_footer.inc
+++ b/views_content/plugins/content_types/views_footer.inc
@@ -22,7 +22,7 @@ function views_content_views_footer_content_type_render($subtype, $conf, $panel_
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_footer';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/content_types/views_header.inc b/views_content/plugins/content_types/views_header.inc
index f144d29fa34616f6e734e20444ba39864d715508..b42806fda94d3f03cd8d5bf5489db04597f0fe90 100644
--- a/views_content/plugins/content_types/views_header.inc
+++ b/views_content/plugins/content_types/views_header.inc
@@ -22,7 +22,7 @@ function views_content_views_header_content_type_render($subtype, $conf, $panel_
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_header';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/content_types/views_pager.inc b/views_content/plugins/content_types/views_pager.inc
index faa65692b7543e120b4f1802f739922d20c4e9cb..f5b380e099c351e3b92a08b09cda871d60f084d8 100644
--- a/views_content/plugins/content_types/views_pager.inc
+++ b/views_content/plugins/content_types/views_pager.inc
@@ -22,7 +22,7 @@ function views_content_views_pager_content_type_render($subtype, $conf, $panel_a
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_pager';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/content_types/views_panes.inc b/views_content/plugins/content_types/views_panes.inc
index b77404e6f7725c0969682eff3ee7ce976215393e..afc98136b33b26141127bdf7c3a2117bf814f5aa 100644
--- a/views_content/plugins/content_types/views_panes.inc
+++ b/views_content/plugins/content_types/views_panes.inc
@@ -179,21 +179,21 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
         $args[] = (isset($conf['arguments'][$id])  && $conf['arguments'][$id] !== '') ? ctools_context_keyword_substitute($conf['arguments'][$id], array(), $contexts) : NULL;
         break;
 
-     case 'wildcard':
+      case 'wildcard':
         // Put in the wildcard.
-       $args[] = isset($arguments[$id]['wildcard']) ? $arguments[$id]['wildcard'] : '*';
-       break;
-
-     case 'none':
-     default:
-       // Put in NULL.
-       // views.module knows what to do with NULL (or missing) arguments
-       $args[] = NULL;
-       break;
+        $args[] = isset($arguments[$id]['wildcard']) ? $arguments[$id]['wildcard'] : '*';
+        break;
+
+      case 'none':
+      default:
+        // Put in NULL.
+        // views.module knows what to do with NULL (or missing) arguments.
+        $args[] = NULL;
+        break;
     }
   }
 
-  // remove any trailing NULL arguments as these are non-args:
+  // Remove any trailing NULL arguments as these are non-args:
   while (count($args) && end($args) === NULL) {
     array_pop($args);
   }
@@ -208,27 +208,32 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
   if ($allow['path_override'] && !empty($conf['path'])) {
     $view->override_path = $conf['path'];
   }
-  else if ($path = $view->display_handler->get_option('inherit_panels_path')) {
-    $view->override_path = $_GET['q'];
+  elseif ($path = $view->display_handler->get_option('inherit_panels_path')) {
+    if (drupal_is_front_page()) {
+      $view->override_path = '';
+    }
+    else {
+      $view->override_path = $_GET['q'];
+    }
   }
 
   $block = new stdClass();
   $block->module = 'views';
-  $block->delta  = $view->name . '-' . $display;
+  $block->delta = $view->name . '-' . $display;
 
   if (($allow['link_to_view'] && !empty($conf['link_to_view'])) ||
       (!$allow['link_to_view'] && $view->display_handler->get_option('link_to_view'))) {
     $block->title_link = $view->get_url();
   }
 
-  // more link
+  // More link.
   if ($allow['more_link']) {
     if (empty($conf['more_link'])) {
       $view->display_handler->set_option('use_more', FALSE);
     }
     else {
       $view->display_handler->set_option('use_more', TRUE);
-      // make sure the view runs the count query so we know whether or not the
+      // Make sure the view runs the count query so we know whether or not the
       // more link applies.
       $view->get_total_rows = TRUE;
     }
@@ -249,7 +254,7 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
     if ($conf['use_pager'] && ($pager['type'] == 'none' || $pager['type'] == 'some')) {
       $pager['type'] = 'full';
     }
-    elseif (!$conf['use_pager'] && $pager['type'] != 'none' && $pager['type'] != 'some') {
+    elseif (!$conf['use_pager']) {
       $pager['type'] = $view->get_items_per_page() || !empty($pager['options']['items_per_page']) ? 'some' : 'none';
     }
 
@@ -265,7 +270,7 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
   if ($allow['fields_override']) {
     if ($conf['fields_override']) {
       $fields = $view->get_items('field');
-      foreach ($fields as $field => $display) {
+      foreach ($fields as $field => $field_display) {
         $fields[$field]['exclude'] = empty($conf['fields_override'][$field]);
       }
       $view->display_handler->set_option('fields', $fields);
@@ -274,6 +279,11 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
   }
 
   if ($allow['exposed_form'] && !empty($conf['exposed'])) {
+    foreach ($conf['exposed'] as $filter_name => $filter_value) {
+      if (!is_array($filter_value)) {
+        $conf['exposed'][$filter_name] = ctools_context_keyword_substitute($filter_value, array(), $contexts);
+      }
+    }
     $view->set_exposed_input($conf['exposed']);
   }
 
@@ -284,6 +294,11 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
     return;
   }
 
+  // Add contextual links to the output.
+  $block = (array) $block;
+  views_add_block_contextual_links($block, $view, $display, 'panel_pane');
+  $block = (object) $block;
+
   $block->title = $view->get_title();
 
   if (empty($view->total_rows) || $view->total_rows <= $view->get_items_per_page()) {
@@ -311,9 +326,13 @@ function views_content_views_panes_content_type_render($subtype, $conf, $panel_a
 function views_content_views_panes_add_defaults(&$conf, $view) {
   $pager = $view->display_handler->get_option('pager');
 
+  if (empty($conf)) {
+    $conf = array();
+  }
+
   $conf += array(
     'link_to_view' => $view->display_handler->get_option('link_to_view'),
-    'more_link' => $view->display_handler->get_option('more_link'),
+    'more_link' => $view->display_handler->get_option('use_more'),
     'feed_icons' => FALSE,
     'use_pager' => $pager['type'] != 'none' && $pager['type'] != 'some',
     'pager_id' => isset($pager['options']['id']) ? $pager['options']['id'] : 0,
@@ -367,7 +386,7 @@ function views_content_views_panes_content_type_edit_form($form, &$form_state) {
       );
     }
   }
-  if ($allow['link_to_view'] ) {
+  if ($allow['link_to_view']) {
     $form['link_to_view'] = array(
       '#type' => 'checkbox',
       '#default_value' => isset($conf['link_to_view']) ? $conf['link_to_view'] : $view->display_handler->get_option('link_to_view'),
@@ -408,7 +427,7 @@ function views_content_views_panes_content_type_edit_form($form, &$form_state) {
       $form['fields_override'][$field] = array(
         '#type' => 'checkbox',
         '#title' => $title,
-        '#default_value' => isset($conf['fields_override'][$field]) ? $conf['fields_override'][$field] : TRUE,
+        '#default_value' => isset($conf['fields_override'][$field]) ? $conf['fields_override'][$field] : !$handler->options['exclude'],
       );
     }
   }
@@ -418,7 +437,7 @@ function views_content_views_panes_content_type_edit_form($form, &$form_state) {
     $form['use_pager'] = array(
       '#type' => 'checkbox',
       '#title' => t('Use pager'),
-        '#default_value' => $conf['use_pager'],
+      '#default_value' => $conf['use_pager'],
       '#id' => 'use-pager-checkbox',
       '#prefix' => '<div class="container-inline">',
     );
@@ -539,7 +558,7 @@ function views_content_views_panes_content_type_edit_form($form, &$form_state) {
     $form['exposed']['sort_order'] = $exposed_form['sort_order'];
   }
 
-  // Add the view object to the form to allow additional customization
+  // Add the view object to the form to allow additional customization.
   $form_state['view'] = $view;
 
   return $form;
@@ -551,7 +570,8 @@ function views_content_views_panes_content_type_edit_form($form, &$form_state) {
 function views_content_views_panes_content_type_edit_form_submit(&$form, &$form_state) {
   // Copy everything from our defaults.
   $keys = array('link_to_view', 'more_link', 'feed_icons', 'use_pager',
-    'pager_id', 'items_per_page', 'offset', 'path_override', 'path', 'arguments', 'fields_override', 'exposed');
+    'pager_id', 'items_per_page', 'offset', 'path_override', 'path', 'arguments', 'fields_override', 'exposed',
+  );
 
   foreach ($keys as $key) {
     if (isset($form_state['values'][$key])) {
@@ -560,7 +580,6 @@ function views_content_views_panes_content_type_edit_form_submit(&$form, &$form_
   }
 }
 
-
 /**
  * Returns the administrative title for a type.
  */
@@ -595,21 +614,21 @@ function views_content_views_panes_content_type_admin_info($subtype, $conf, $con
   $view->set_display($display_name);
   views_content_views_panes_add_defaults($conf, $view);
 
-  // Add arguments first
+  // Add arguments first.
   if (!empty($conf['arguments'])) {
     $keys = array_keys($conf['arguments']);
     $values = array_values($conf['arguments']);
     $argument_input = $view->display_handler->get_option('argument_input');
 
     foreach ($conf['arguments'] as $key => $value) {
-      if(!empty($value)){
+      if (!empty($value)) {
         $label = $argument_input[$key]['label'];
         $info[] = $label . ': ' . $value;
       }
     }
   }
 
-  $block = new stdClass;
+  $block = new stdClass();
   if ($info) {
     $block->title = array_shift($info);
 
diff --git a/views_content/plugins/content_types/views_row.inc b/views_content/plugins/content_types/views_row.inc
index 9672d020d5f1c8447596a20f0612e2bf63273308..6678f447d0b498ce1fb291127aa7bfeded2c29fa 100644
--- a/views_content/plugins/content_types/views_row.inc
+++ b/views_content/plugins/content_types/views_row.inc
@@ -35,7 +35,7 @@ function views_content_views_row_content_type_render($subtype, $conf, $panel_arg
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_row';
   $block->delta   = $context->argument;
   $block->title   = '';
@@ -91,7 +91,7 @@ function views_content_views_row_content_type_render($subtype, $conf, $panel_arg
         'view' => $view,
         'options' => $plugin->options,
         'rows' => $rows,
-        'title' => $title
+        'title' => $title,
       )
     );
   }
@@ -228,8 +228,9 @@ function views_content_views_row_content_type_admin_info($subtype, $conf, $conte
 
 function views_content_views_row_content_type_admin_title($subtype, $conf, $context) {
   $rows = array_filter($conf['rows']);
+  $row_count = count($rows);
   $rows = empty($rows) ? t('Show all') : implode(', ', $rows);
-  return format_plural(count($rows),
+  return format_plural($row_count,
     '"@context" row @rows',
     '"@context" rows @rows',
     array('@context' => $context->identifier, '@rows' => $rows)
diff --git a/views_content/plugins/content_types/views_view.inc b/views_content/plugins/content_types/views_view.inc
index dfb1175c3bf6ffef0dac91952b610e5ceeef9d50..54eec08550fdf6d0fee122e99f99718c87634025 100644
--- a/views_content/plugins/content_types/views_view.inc
+++ b/views_content/plugins/content_types/views_view.inc
@@ -22,7 +22,7 @@ function views_content_views_view_content_type_render($subtype, $conf, $panel_ar
   }
 
   // Build the content type block.
-  $block = new stdClass();
+  $block          = new stdClass();
   $block->module  = 'views_view';
   $block->delta   = $context->argument;
   $block->title   = '';
diff --git a/views_content/plugins/contexts/view.inc b/views_content/plugins/contexts/view.inc
index 1e926e457d3b10121ee9c03dca18a0261868957a..6380478aa7d8df09fb150832cab6055904655b24 100644
--- a/views_content/plugins/contexts/view.inc
+++ b/views_content/plugins/contexts/view.inc
@@ -2,7 +2,6 @@
 
 /**
  * @file
- *
  * Plugin to provide a node context. A node context is a node wrapped in a
  * context object that can be utilized by anything that accepts contexts.
  */
@@ -88,7 +87,7 @@ function views_content_context_view_create($empty, $data = NULL, $conf = FALSE,
         $data->set_display($display_id);
       }
     }
-    else if (!empty($plugin['view name'])) {
+    elseif (!empty($plugin['view name'])) {
       $data = views_get_view($plugin['view name']);
       $data->set_display($plugin['view display id']);
     }
@@ -101,7 +100,7 @@ function views_content_context_view_create($empty, $data = NULL, $conf = FALSE,
     // $output = views_content_context_get_output($context);
     // $view = $output['view'];
     // @endcode
-    $context->data     = array(
+    $context->data = array(
       'name' => $data->name,
       'display' => $data->current_display,
       'args' => $data->args,
@@ -158,8 +157,7 @@ function views_content_context_view_settings_form_validate($form, &$form_state)
  * Provide a list of ways that this context can be converted to a string.
  */
 function views_content_context_view_convert_list() {
-  $list = array(
-  );
+  $list = array();
 
   return $list;
 }
@@ -171,4 +169,3 @@ function views_content_context_view_convert($context, $type) {
   switch ($type) {
   }
 }
-
diff --git a/views_content/plugins/relationships/node_from_view.inc b/views_content/plugins/relationships/node_from_view.inc
index 0f3fa8e0a81a579b5abb8785583a97bcaa3d13db..f54cbc6b5f904b77aeb5deaefcef800fb241ede3 100644
--- a/views_content/plugins/relationships/node_from_view.inc
+++ b/views_content/plugins/relationships/node_from_view.inc
@@ -33,7 +33,7 @@ function views_content_node_from_view_context($context, $conf, $placeholder = FA
   views_content_context_get_output($context);
 
   $row = intval($conf['row']) - 1;
-  if (isset($view->result[$row])) {
+  if (isset($view->result[$row]) && isset($view->base_field) && isset($view->result[$row]->{$view->base_field})) {
     $nid = $view->result[$row]->{$view->base_field};
     if ($nid) {
       $node = node_load($nid);
diff --git a/views_content/plugins/relationships/term_from_view.inc b/views_content/plugins/relationships/term_from_view.inc
index bdd25b850255dab56cdfa5f51aa17350d5f2e48e..fc9e20d41c0d84e6b2b3e72d8fef5b067475579a 100644
--- a/views_content/plugins/relationships/term_from_view.inc
+++ b/views_content/plugins/relationships/term_from_view.inc
@@ -13,7 +13,7 @@ $plugin = array(
   'title' => t('Term from view'),
   'keyword' => 'term',
   'description' => t('Extract a term context from a view context of the base type term.'),
-  'required context' => new ctools_context_required(t('View'), 'view', array('base' => 'term_data')),
+  'required context' => new ctools_context_required(t('View'), 'view', array('base' => 'taxonomy_term_data')),
   'context' => 'views_content_term_from_view_context',
   'edit form' => 'views_content_term_from_view_settings_form',
   'edit form validate' => 'views_content_term_from_view_settings_form_validate',
@@ -26,7 +26,7 @@ $plugin = array(
 function views_content_term_from_view_context($context, $conf, $placeholder = FALSE) {
   // If unset it wants a generic, unfilled context, which is just NULL.
   if (empty($context->data) || $placeholder) {
-    return ctools_context_create_empty('term', NULL);
+    return ctools_context_create_empty('entity:taxonomy_term', NULL);
   }
   $view = views_content_context_get_view($context);
   // Ensure the view executes, but we don't need its output.
@@ -36,11 +36,11 @@ function views_content_term_from_view_context($context, $conf, $placeholder = FA
   if (isset($view->result[$row])) {
     $tid = $view->result[$row]->{$view->base_field};
     if ($tid) {
-      $term = taxonomy_get_term($tid);
-      return ctools_context_create('term', $term);
+      $term = taxonomy_term_load($tid);
+      return ctools_context_create('entity:taxonomy_term', $term);
     }
   }
-  return ctools_context_create_empty('term', NULL);
+  return ctools_context_create_empty('entity:taxonomy_term', NULL);
 }
 
 /**
diff --git a/views_content/plugins/relationships/view_from_argument.inc b/views_content/plugins/relationships/view_from_argument.inc
index cefc6dba005df309a1ee10e2002f9cd53dec02a2..cabd329b51655446c9667f571c564750779c2b06 100644
--- a/views_content/plugins/relationships/view_from_argument.inc
+++ b/views_content/plugins/relationships/view_from_argument.inc
@@ -73,7 +73,7 @@ function views_content_view_from_argument_context($contexts, $conf) {
     foreach ($data->display_handler->get_argument_input() as $id => $argument) {
       if ($argument['type'] == 'context') {
         $key = array_shift($context_keys);
-        if (isset($contexts [$key])) {
+        if (isset($contexts[$key])) {
           if (strpos($argument['context'], '.')) {
             list($context, $converter) = explode('.', $argument['context'], 2);
             $args[] = ctools_context_convert_context($contexts[$key], $converter, array('sanitize' => FALSE));
@@ -84,7 +84,7 @@ function views_content_view_from_argument_context($contexts, $conf) {
         }
       }
     }
-    // remove any trailing NULL arguments as these are non-args:
+    // Remove any trailing NULL arguments as these are non-args:
     while (count($args) && end($args) === NULL) {
       array_pop($args);
     }
diff --git a/views_content/plugins/views/views_content.views.inc b/views_content/plugins/views/views_content.views.inc
index 6724d3c5a28f0c3196435d4bc6c5d72818f5ab48..20b65a263282337b15c10fa42a9c575a5aa1f7e4 100644
--- a/views_content/plugins/views/views_content.views.inc
+++ b/views_content/plugins/views/views_content.views.inc
@@ -6,7 +6,7 @@
  */
 
 /**
- * Implements hook_views_plugins
+ * Implements hook_views_plugins().
  */
 function views_content_views_plugins() {
   return array(
@@ -25,6 +25,7 @@ function views_content_views_plugins() {
         'use more' => TRUE,
         'accept attachments' => TRUE,
         'help topic' => 'display-pane',
+        'contextual links locations' => array('panel_pane', 'view'),
       ),
       'ctools_context' => array(
         'title' => t('Context'),
diff --git a/views_content/plugins/views/views_content_plugin_display_ctools_context.inc b/views_content/plugins/views/views_content_plugin_display_ctools_context.inc
index 967f2fa8248d04ed7e40dc5e1136cff88c196355..87ee291ae6dbb5a4e70d421dc371c8d2f723b639 100644
--- a/views_content/plugins/views/views_content_plugin_display_ctools_context.inc
+++ b/views_content/plugins/views/views_content_plugin_display_ctools_context.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Contains the block display plugin.
@@ -14,19 +15,24 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
    * If this variable is true, this display counts as a context. We use this
    * variable so that we can easily build plugins against this display type.
    */
-  var $context_display = TRUE;
+  public $context_display = TRUE;
+
+
+  public function get_style_type() {
+    return 'context';
+  }
 
-  function get_style_type() { return 'context'; }
 
-  function defaultable_sections($section = NULL) {
-    if (in_array($section, array('style_options', 'style_plugin', 'row_options', 'row_plugin',))) {
+  public function defaultable_sections($section = NULL) {
+    if (in_array($section, array('style_options', 'style_plugin', 'row_options', 'row_plugin'))) {
       return FALSE;
     }
 
     return parent::defaultable_sections($section);
   }
 
-  function option_definition() {
+
+  public function option_definition() {
     $options = parent::option_definition();
 
     $options['admin_title'] = array('default' => '', 'translatable' => TRUE);
@@ -47,12 +53,13 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
   /**
    * The display block handler returns the structure necessary for a block.
    */
-  function execute() {
+  public function execute() {
     $this->executing = TRUE;
     return $this->view->render();
   }
 
-  function preview() {
+
+  public function preview() {
     $this->previewing = TRUE;
     return $this->view->render();
   }
@@ -60,7 +67,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
   /**
    * Render this display.
    */
-  function render() {
+  public function render() {
     if (!empty($this->previewing)) {
       return theme($this->theme_functions(), array('view' => $this->view));
     }
@@ -71,7 +78,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
       $hooks = theme_get_registry();
       $info = $hooks[$this->definition['theme']];
       if (!empty($info['file'])) {
-        @include_once('./' . $info['path'] . '/' . $info['file']);
+        @include_once './' . $info['path'] . '/' . $info['file'];
       }
       $this->variables = array('view' => &$this->view);
 
@@ -92,7 +99,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
    *
    * This output is returned as an array.
    */
-  function options_summary(&$categories, &$options) {
+  public function options_summary(&$categories, &$options) {
     // It is very important to call the parent function here:
     parent::options_summary($categories, $options);
 
@@ -135,7 +142,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
   /**
    * Provide the default form for setting options.
    */
-  function options_form(&$form, &$form_state) {
+  public function options_form(&$form, &$form_state) {
     // It is very important to call the parent function here:
     parent::options_form($form, $form_state);
     switch ($form_state['section']) {
@@ -143,6 +150,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
         // This just overwrites the existing row_plugin which is using the wrong options.
         $form['row_plugin']['#options'] = views_fetch_plugin_names('row', 'normal', array($this->view->base_table));
         break;
+
       case 'admin_title':
         $form['#title'] .= t('Administrative title');
 
@@ -152,6 +160,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
           '#description' => t('This is the title that will appear for this view context in the configure context dialog. If left blank, the view name will be used.'),
         );
         break;
+
       case 'inherit_panels_path':
         $form['#title'] .= t('Inherit path from panel display');
 
@@ -162,6 +171,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
           '#description' => t('If yes, all links generated by Views, such as more links, summary links, and exposed input links will go to the panels display path, not the view, if the display has a path.'),
         );
         break;
+
       case 'argument_input':
         $form['#title'] .= t('Choose the data source for view arguments');
         $argument_input = $this->get_argument_input();
@@ -216,7 +226,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  function options_submit(&$form, &$form_state) {
+  public function options_submit(&$form, &$form_state) {
     // It is very important to call the parent function here:
     parent::options_submit($form, $form_state);
     switch ($form_state['section']) {
@@ -234,7 +244,7 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
    * the arguments doesn't cause the argument input field to just
    * break.
    */
-  function get_argument_input() {
+  public function get_argument_input() {
     $arguments = $this->get_option('argument_input');
     $handlers = $this->get_handlers('argument');
 
@@ -260,7 +270,8 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
     return $output;
   }
 
-  function get_path() {
+
+  public function get_path() {
     if ($this->get_option('link_display') == 'custom_url' && $override_path = $this->get_option('link_url')) {
       return $override_path;
     }
@@ -269,4 +280,5 @@ class views_content_plugin_display_ctools_context extends views_plugin_display {
     }
     return parent::get_path();
   }
+
 }
diff --git a/views_content/plugins/views/views_content_plugin_display_panel_pane.inc b/views_content/plugins/views/views_content_plugin_display_panel_pane.inc
index e02f896a46b6d2cf1aa7117283cc007ceb5f91ef..af0704f30d8b6ef343877ff0e041a227bfcffb42 100644
--- a/views_content/plugins/views/views_content_plugin_display_panel_pane.inc
+++ b/views_content/plugins/views/views_content_plugin_display_panel_pane.inc
@@ -4,14 +4,18 @@
  * The plugin that handles a panel_pane.
  */
 class views_content_plugin_display_panel_pane extends views_plugin_display {
+
   /**
    * If this variable is true, this display counts as a panel pane. We use
    * this variable so that other modules can create alternate pane displays.
    */
-  var $panel_pane_display = TRUE;
-  var $has_pane_conf = NULL;
+  public $panel_pane_display = TRUE;
+  public $has_pane_conf = NULL;
 
-  function option_definition() {
+  /**
+   * {@inheritdoc}
+   */
+  public function option_definition() {
     $options = parent::option_definition();
 
     $options['pane_title'] = array('default' => '', 'translatable' => TRUE);
@@ -34,7 +38,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
         'title_override'  => array('default' => FALSE),
         'exposed_form'    => array('default' => FALSE),
         'fields_override' => array('default' => FALSE),
-       ),
+      ),
     );
 
     $options['argument_input'] = array('default' => array());
@@ -44,11 +48,13 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
     return $options;
   }
 
-  function has_pane_conf() {
+
+  public function has_pane_conf() {
     return isset($this->has_pane_conf);
   }
 
-  function set_pane_conf($conf = array()) {
+
+  public function set_pane_conf($conf = array()) {
     $this->set_option('pane_conf', $conf);
     $this->has_pane_conf = TRUE;
   }
@@ -58,7 +64,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
    *
    * This output is returned as an array.
    */
-  function options_summary(&$categories, &$options) {
+  public function options_summary(&$categories, &$options) {
     // It is very important to call the parent function here:
     parent::options_summary($categories, $options);
 
@@ -147,7 +153,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
   /**
    * Provide the default form for setting options.
    */
-  function options_form(&$form, &$form_state) {
+  public function options_form(&$form, &$form_state) {
     // It is very important to call the parent function here:
     parent::options_form($form, $form_state);
 
@@ -177,6 +183,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
           '#options' => $options,
         );
         break;
+
       case 'pane_title':
         $form['#title'] .= t('Administrative title');
 
@@ -318,7 +325,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
    * Perform any necessary changes to the form values prior to storage.
    * There is no need for this function to actually store the data.
    */
-  function options_submit(&$form, &$form_state) {
+  public function options_submit(&$form, &$form_state) {
     // It is very important to call the parent function here:
     parent::options_submit($form, $form_state);
     switch ($form_state['section']) {
@@ -340,7 +347,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
    * the arguments doesn't cause the argument input field to just
    * break.
    */
-  function get_argument_input() {
+  public function get_argument_input() {
     $arguments = $this->get_option('argument_input');
     $handlers = $this->get_handlers('argument');
 
@@ -368,7 +375,8 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
     return $output;
   }
 
-  function use_more() {
+
+  public function use_more() {
     $allow = $this->get_option('allow');
     if (!$allow['more_link'] || !$this->has_pane_conf()) {
       return parent::use_more();
@@ -377,21 +385,41 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
     return (bool) $conf['more_link'];
   }
 
-  function get_path() {
+  /**
+   * {@inheritdoc}
+   */
+  public function validate() {
+    // To bypass the validation of the path from Views we temporarily
+    // override the path if one doesn't exist because it will be generated
+    // by panels though we want the rest of the validations to run.
+    $path = $this->get_path();
+    if (!$path) {
+      $this->set_option('path', $_GET['q']);
+    }
+
+    return parent::validate();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get_path() {
     if (empty($this->view->override_path)) {
       return parent::get_path();
     }
     return $this->view->override_path;
   }
 
-  function get_url() {
+
+  public function get_url() {
     if ($this->get_option('inherit_panels_path')) {
       return $this->get_path();
     }
     return parent::get_url();
   }
 
-  function uses_exposed_form_in_block() {
+
+  public function uses_exposed_form_in_block() {
     // We'll always allow the exposed form in a block, regardless of path.
     return TRUE;
   }
@@ -405,7 +433,7 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
    * returns, exposed filters will not be used nor
    * displayed unless uses_exposed() returns TRUE.
    */
-  function displays_exposed() {
+  public function displays_exposed() {
     $conf = $this->get_option('allow');
     // If this is set, the exposed form is part of pane configuration, not
     // rendered normally.
@@ -413,4 +441,3 @@ class views_content_plugin_display_panel_pane extends views_plugin_display {
   }
 
 }
-
diff --git a/views_content/plugins/views/views_content_plugin_style_ctools_context.inc b/views_content/plugins/views/views_content_plugin_style_ctools_context.inc
index aafbebc1f23875885ce0c950fab6389807601356..ea5323c6d11ffc0b4b0c9c58d140ee4ee856819a 100644
--- a/views_content/plugins/views/views_content_plugin_style_ctools_context.inc
+++ b/views_content/plugins/views/views_content_plugin_style_ctools_context.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Contains the default style plugin.
@@ -11,12 +12,12 @@
  * @ingroup views_style_plugins
  */
 class views_content_plugin_style_ctools_context extends views_plugin_style {
-  var $rows = array();
+  public $rows = array();
 
   /**
    * Render the display in this style.
    */
-  function render() {
+  public function render() {
     if (!empty($this->view->display_handler->previewing)) {
       return parent::render();
     }
diff --git a/views_content/tests/modules/views_content_test.info b/views_content/tests/modules/views_content_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..fec543c3647777e85f37c44c26813f3dcd126c4a
--- /dev/null
+++ b/views_content/tests/modules/views_content_test.info
@@ -0,0 +1,6 @@
+name = Views content panes Test
+description = Test module for Views content panes.
+package = Views
+core = 7.x
+dependencies[] = views_content
+hidden = TRUE
\ No newline at end of file
diff --git a/views_content/tests/modules/views_content_test.module b/views_content/tests/modules/views_content_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..52998650a3d0ecc77237668ec4e1364fc71b6966
--- /dev/null
+++ b/views_content/tests/modules/views_content_test.module
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Helper module for Views content pane tests.
+ */
+
+/**
+ * Implements hook_views_api().
+ */
+function views_content_test_views_api() {
+  return array(
+    'api' => 3.0,
+  );
+}
diff --git a/views_content/tests/modules/views_content_test.views_default.inc b/views_content/tests/modules/views_content_test.views_default.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6dd08494c8afc92a47cde6beba0d9f4dd96accab
--- /dev/null
+++ b/views_content/tests/modules/views_content_test.views_default.inc
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Tests views.
+ */
+
+/**
+ * Implements hook_views_default_views().
+ */
+function views_content_test_views_default_views() {
+  $view = new view();
+  $view->name = 'views_content_more_link';
+  $view->description = '';
+  $view->tag = 'default';
+  $view->base_table = 'node';
+  $view->human_name = 'views_content_more_link';
+  $view->core = 7;
+  $view->api_version = '3.0';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Master */
+  $handler = $view->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'views_content_more_link';
+  $handler->display->display_options['use_more'] = TRUE;
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'none';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['style_plugin'] = 'table';
+  $handler->display->display_options['style_options']['columns'] = array(
+    'title' => 'title',
+  );
+  $handler->display->display_options['style_options']['class'] = '';
+  $handler->display->display_options['style_options']['default'] = '-1';
+  $handler->display->display_options['style_options']['info'] = array(
+    'title' => array(
+      'sortable' => 0,
+      'default_sort_order' => 'asc',
+      'align' => '',
+      'separator' => '',
+      'empty_column' => 0,
+    ),
+  );
+  /* Field: Content: Title */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['label'] = '';
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
+  /* Sort criterion: Content: Post date */
+  $handler->display->display_options['sorts']['created']['id'] = 'created';
+  $handler->display->display_options['sorts']['created']['table'] = 'node';
+  $handler->display->display_options['sorts']['created']['field'] = 'created';
+  $handler->display->display_options['sorts']['created']['order'] = 'DESC';
+  /* Filter criterion: Content: Published status */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'node';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = 1;
+  $handler->display->display_options['filters']['status']['group'] = 1;
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'views-content-more-link';
+
+  /* Display: Content pane */
+  $handler = $view->new_display('panel_pane', 'Content pane', 'panel_pane_1');
+  $handler->display->display_options['defaults']['pager'] = FALSE;
+  $handler->display->display_options['pager']['type'] = 'some';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '3';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+
+  $views[$view->name] = $view;
+
+  return $views;
+}
diff --git a/views_content/tests/src/views_content.test b/views_content/tests/src/views_content.test
new file mode 100644
index 0000000000000000000000000000000000000000..f8da9e2cae7fed17311a951e517cdbf556c11cf7
--- /dev/null
+++ b/views_content/tests/src/views_content.test
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains ViewsContentPanesTest.
+ */
+
+/**
+ * Avoid simpletest "Class ViewsSqlTest not found" error.
+ */
+if (!class_exists('ViewsSqlTest')) {
+  return;
+}
+
+/**
+ * Tests rendering views content pane displays.
+ */
+class ViewsContentPanesTest extends ViewsSqlTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Views content panes tests',
+      'description' => 'Tests rendering views content pane displays.',
+      'group' => 'ctools',
+      'dependencies' => array('ctools', 'views'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'ctools';
+    $modules[] = 'views_content';
+    $modules[] = 'views_content_test';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Tests rendering a content pane with a more link.
+   */
+  public function testViewMoreLink() {
+    // The view "views_content_more_link" has two displays: a content pane
+    // display and a page display. The content pane display displays 3 nodes,
+    // the page display displays all items.
+    // On the content pane display a "more" link is configured that should link
+    // to the page.
+    $view = views_get_view('views_content_more_link');
+
+    // Create four nodes that the view will display. The first three
+    // will get displayed on the content pane display and the remaining
+    // on the page display.
+    for ($i = 0; $i < 4; $i++) {
+      $this->drupalCreateNode();
+    }
+
+    // Render the content pane display and assert that a more link is shown.
+    $view->set_display('panel_pane_1');
+    $rendered_output = $view->preview();
+    $this->verbose($rendered_output);
+    $this->storeViewPreview($rendered_output);
+
+    $this->assertLink('more');
+    $this->assertLinkByHref('views-content-more-link');
+  }
+
+  /**
+   * Stores a view output in the elements.
+   *
+   * @param string $output
+   *   The Views HTML output.
+   */
+  protected function storeViewPreview($output) {
+    $html_dom = new DOMDocument();
+    @$html_dom->loadHTML($output);
+    if ($html_dom) {
+      // It's much easier to work with simplexml than DOM, luckily enough
+      // we can just simply import our DOM tree.
+      $this->elements = simplexml_import_dom($html_dom);
+    }
+  }
+
+}
diff --git a/views_content/views_content.admin.inc b/views_content/views_content.admin.inc
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/views_content/views_content.info b/views_content/views_content.info
index 3f6c8fc31725d34c40bb57fbb8042dc47c82908d..26aaf357d9c6e58c869de119d1f0c2ae3e811c7a 100644
--- a/views_content/views_content.info
+++ b/views_content/views_content.info
@@ -8,3 +8,4 @@ package = Chaos tool suite
 files[] = plugins/views/views_content_plugin_display_ctools_context.inc
 files[] = plugins/views/views_content_plugin_display_panel_pane.inc
 files[] = plugins/views/views_content_plugin_style_ctools_context.inc
+files[] = tests/src/views_content.test
diff --git a/views_content/views_content.module b/views_content/views_content.module
index e5074f5ff912bf9cd6ba83ee2803a9115554cac5..264408ac872f4521bfc83b65e2984629132564cb 100644
--- a/views_content/views_content.module
+++ b/views_content/views_content.module
@@ -1,8 +1,7 @@
 <?php
 
 /**
- * @file views_content.module
- *
+ * @file
  * Provides views as panels content, configurable by the administrator.
  * Each view provided as panel content must be configured in advance,
  * but once configured, building panels with views is a little bit simpler.
@@ -29,8 +28,9 @@ function views_content_menu() {
 }
 
 /**
- * Implementation of hook_ctools_plugin_dierctory() to let the system know
- * where our content_type plugins are.
+ * Implements hook_ctools_plugin_dierctory().
+ *
+ * To let the system know where our content_type plugins are.
  */
 function views_content_ctools_plugin_directory($owner, $plugin_type) {
   if ($owner == 'ctools') {
@@ -281,3 +281,17 @@ function _views_content_get_context_from_display($view, $id, $parent, $required
     'view display id' => $id,
   );
 }
+
+/**
+ * Implements hook_get_pane_links_alter().
+ */
+function views_content_get_pane_links_alter(&$links, $pane, $content_type) {
+  if ($pane->type === 'views_panes') {
+    list($view_name, $display_name) = explode('-', $pane->subtype);
+    $destination = array('destination' => current_path());
+    $links['top'][] = array(
+      'title' => t('Edit view'),
+      'href' => url('admin/structure/views/view/' . $view_name . '/edit/' . $display_name, array('query' => $destination, 'absolute' => TRUE)),
+    );
+  }
+}