diff --git a/civicrm.php b/civicrm.php
index 5b4cfb65196f46b1c1935ac1a17ae661627c605d..26a1e3bf3036f8102886b273aba55f280966bbd3 100644
--- a/civicrm.php
+++ b/civicrm.php
@@ -2,7 +2,7 @@
 /*
 Plugin Name: CiviCRM
 Description: CiviCRM - Growing and Sustaining Relationships
-Version: 5.15.2
+Version: 5.16.0
 Author: CiviCRM LLC
 Author URI: https://civicrm.org/
 Plugin URI: https://wiki.civicrm.org/confluence/display/CRMDOC/Installing+CiviCRM+for+WordPress
@@ -676,6 +676,9 @@ class CiviCRM_For_WordPress {
     // Print CiviCRM's header
     add_action('admin_head', array( $this, 'wp_head' ), 50);
 
+    // Listen for changes to the basepage setting
+    add_action( 'civicrm_postSave_civicrm_setting', array( $this, 'settings_change' ), 10 );
+
     // If settings file does not exist, show notice with link to installer
     if ( ! CIVICRM_INSTALLED ) {
       if ( isset( $_GET['page'] ) && $_GET['page'] == 'civicrm-install' ) {
@@ -693,6 +696,29 @@ class CiviCRM_For_WordPress {
   }
 
 
+  /**
+   * Force rewrite rules to be recreated.
+   *
+   * When CiviCRM settings are saved, the method is called post-save. It checks
+   * if it's the WordPress Base Page setting that has been saved and causes all
+   * rewrite rules to be flushed on the next page load.
+   *
+   * @since 5.14
+   *
+   * @param obj $dao The CiviCRM database access object.
+   */
+  public function settings_change( $dao ) {
+
+    // Delete the option if conditions are met
+    if ( $dao instanceOf CRM_Core_DAO_Setting ) {
+      if ( isset( $dao->name ) && $dao->name == 'wpBasePage' ) {
+        delete_option( 'civicrm_rules_flushed' );
+      }
+    }
+
+  }
+
+
   /**
    * Add our rewrite rules.
    *
diff --git a/civicrm/CRM/ACL/DAO/ACL.php b/civicrm/CRM/ACL/DAO/ACL.php
index 924a9eaf2aad3583fbdb796ee88c584e4f0290a9..d887be06bdffd509521fbe435890b17a64645338 100644
--- a/civicrm/CRM/ACL/DAO/ACL.php
+++ b/civicrm/CRM/ACL/DAO/ACL.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/ACL/ACL.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:810da5f19a7ead8c949065156674c087)
+ * (GenCodeChecksum:f415db79c66c2e8a95f88c886cec4266)
  */
 
 /**
diff --git a/civicrm/CRM/ACL/DAO/Cache.php b/civicrm/CRM/ACL/DAO/Cache.php
index 229f6f4c6e407f5aca70cb5648eb87ea45faeea5..52058d84a69f2c4867ee8e20fa5f8d12b188040d 100644
--- a/civicrm/CRM/ACL/DAO/Cache.php
+++ b/civicrm/CRM/ACL/DAO/Cache.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/ACL/Cache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f993d89f3a44999eed1b4c46b714b736)
+ * (GenCodeChecksum:9e80148349c86b214e0303642dfc47e7)
  */
 
 /**
diff --git a/civicrm/CRM/ACL/DAO/EntityRole.php b/civicrm/CRM/ACL/DAO/EntityRole.php
index ea001945755651fce5dd55b46f6648b3c2002064..4fe8594781b1a43e143a71fc8a82141e08429d2a 100644
--- a/civicrm/CRM/ACL/DAO/EntityRole.php
+++ b/civicrm/CRM/ACL/DAO/EntityRole.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/ACL/EntityRole.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:65952cc85e04acddbaef65cfcf7fc541)
+ * (GenCodeChecksum:cdb4379a1345c2f92f1f354aff42c446)
  */
 
 /**
diff --git a/civicrm/CRM/ACL/Form/WordPress/Permissions.php b/civicrm/CRM/ACL/Form/WordPress/Permissions.php
index bad293c934c17f1d0567697ce7abc3b935b3501e..65191fb9793aed95be6ef1190364b5fd59b5a109 100644
--- a/civicrm/CRM/ACL/Form/WordPress/Permissions.php
+++ b/civicrm/CRM/ACL/Form/WordPress/Permissions.php
@@ -54,7 +54,7 @@ class CRM_ACL_Form_WordPress_Permissions extends CRM_Core_Form {
     }
     foreach ($wp_roles->role_names as $role => $name) {
       // Don't show the permissions options for administrator, as they have all permissions
-      if ( is_multisite() OR $role !== 'administrator') {
+      if ($role !== 'administrator') {
         $roleObj = $wp_roles->get_role($role);
         if (!empty($roleObj->capabilities)) {
           foreach ($roleObj->capabilities as $ckey => $cname) {
diff --git a/civicrm/CRM/Activity/BAO/Activity.php b/civicrm/CRM/Activity/BAO/Activity.php
index fedf0b6d1bcce86d56fb56f11ae06d39f6a93fed..313fa5c1282749902ca579c43e32a15fd5fde457 100644
--- a/civicrm/CRM/Activity/BAO/Activity.php
+++ b/civicrm/CRM/Activity/BAO/Activity.php
@@ -329,7 +329,7 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
 
     // CRM-9137
     if (!empty($params['id'])) {
-      CRM_Utils_Hook::pre('edit', 'Activity', $activity->id, $params);
+      CRM_Utils_Hook::pre('edit', 'Activity', $params['id'], $params);
     }
     else {
       CRM_Utils_Hook::pre('create', 'Activity', NULL, $params);
diff --git a/civicrm/CRM/Activity/BAO/Query.php b/civicrm/CRM/Activity/BAO/Query.php
index 2c4a0440a7af07fd83dae95c64f6db930415cdef..db89d80422a5194151dca249cbff976325f0a474 100644
--- a/civicrm/CRM/Activity/BAO/Query.php
+++ b/civicrm/CRM/Activity/BAO/Query.php
@@ -175,7 +175,7 @@ class CRM_Activity_BAO_Query {
   public static function where(&$query) {
     foreach (array_keys($query->_params) as $id) {
       if (substr($query->_params[$id][0], 0, 9) == 'activity_') {
-        if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) {
+        if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) {
           $query->_useDistinct = TRUE;
         }
         $query->_params[$id][3];
diff --git a/civicrm/CRM/Activity/DAO/Activity.php b/civicrm/CRM/Activity/DAO/Activity.php
index 8f4053dfed6b2cbbffc4912e11034e97b2715b29..21468db91bc4392ee3e557a6cabe9be44e8e5312 100644
--- a/civicrm/CRM/Activity/DAO/Activity.php
+++ b/civicrm/CRM/Activity/DAO/Activity.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Activity/Activity.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:808e801e250ba56b83f69fe90d8b52c2)
+ * (GenCodeChecksum:b0a38b2fb168879a7b8097f17a313375)
  */
 
 /**
diff --git a/civicrm/CRM/Activity/DAO/ActivityContact.php b/civicrm/CRM/Activity/DAO/ActivityContact.php
index aac6059d38b0ac0ca9b91e9b4a1010331126a2cb..f82cd4c90f178c84f15782996b7f7040784355ab 100644
--- a/civicrm/CRM/Activity/DAO/ActivityContact.php
+++ b/civicrm/CRM/Activity/DAO/ActivityContact.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Activity/ActivityContact.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:bb5726fd8dc1e07e19a08982d502a9f1)
+ * (GenCodeChecksum:6500dec56f6917871572cd1296a52bc9)
  */
 
 /**
diff --git a/civicrm/CRM/Activity/Form/Activity.php b/civicrm/CRM/Activity/Form/Activity.php
index 38abfddd4c1107bd74bfdc70e5379e4947ebd452..c89b52f6c3a343136bc909ffbbe5a9784354aff6 100644
--- a/civicrm/CRM/Activity/Form/Activity.php
+++ b/civicrm/CRM/Activity/Form/Activity.php
@@ -136,9 +136,10 @@ class CRM_Activity_Form_Activity extends CRM_Contact_Form_Task {
    * @var bool
    *
    */
-
   protected $supportsActivitySeparation = TRUE;
 
+  public $submitOnce = TRUE;
+
   /**
    * Explicitly declare the entity api name.
    *
@@ -864,13 +865,17 @@ class CRM_Activity_Form_Activity extends CRM_Contact_Form_Task {
       $errors['activity_type_id'] = ts('Activity Type is a required field');
     }
 
-    if (CRM_Utils_Array::value('activity_type_id', $fields) == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email')
-      && CRM_Utils_Array::value('status_id', $fields) == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Scheduled')) {
-      $errors['status_id'] = ts('You cannot record scheduled email activity.');
-    }
-    elseif (CRM_Utils_Array::value('activity_type_id', $fields) == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'SMS')
-      && CRM_Utils_Array::value('status_id', $fields) == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Scheduled')) {
-      $errors['status_id'] = ts('You cannot record scheduled SMS activity.');
+    $activity_type_id = CRM_Utils_Array::value('activity_type_id', $fields);
+    $activity_status_id = CRM_Utils_Array::value('status_id', $fields);
+    $scheduled_status_id = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Scheduled');
+
+    if ($activity_type_id && $activity_status_id == $scheduled_status_id) {
+      if ($activity_type_id == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email')) {
+        $errors['status_id'] = ts('You cannot record scheduled email activity.');
+      }
+      elseif ($activity_type_id == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'SMS')) {
+        $errors['status_id'] = ts('You cannot record scheduled SMS activity');
+      }
     }
 
     if (!empty($fields['followup_activity_type_id']) && empty($fields['followup_date'])) {
@@ -991,6 +996,17 @@ class CRM_Activity_Form_Activity extends CRM_Contact_Form_Task {
       $activity = $this->processActivity($params);
     }
 
+    // Redirect to contact page or activity view in standalone mode
+    if ($this->_context == 'standalone') {
+      if (count($params['target_contact_id']) == 1) {
+        $url = CRM_Utils_System::url('civicrm/contact/view', ['cid' => CRM_Utils_Array::first($params['target_contact_id']), 'selectedChild' => 'activity']);
+      }
+      else {
+        $url = CRM_Utils_System::url('civicrm/activity', ['action' => 'view', 'reset' => 1, 'id' => $this->_activityId]);
+      }
+      CRM_Core_Session::singleton()->pushUserContext($url);
+    }
+
     $activityIds = empty($this->_activityIds) ? [$this->_activityId] : $this->_activityIds;
     foreach ($activityIds as $activityId) {
       // set params for repeat configuration in create mode
diff --git a/civicrm/CRM/Activity/Page/AJAX.php b/civicrm/CRM/Activity/Page/AJAX.php
index 1da789c2734afd668870371312bbad87f18d9a29..6c78fb59c5b1d879c5f267da09a7487c6d6b6905 100644
--- a/civicrm/CRM/Activity/Page/AJAX.php
+++ b/civicrm/CRM/Activity/Page/AJAX.php
@@ -161,7 +161,7 @@ class CRM_Activity_Page_AJAX {
 
     foreach ($caseRelationships as $key => $value) {
       // This role has been filled
-      unset($caseRoles[$value['relation_type']]);
+      unset($caseRoles[$value['relation_type'] . '_' . $value['relationship_direction']]);
       // mark original case relationships record to use on setting edit links below
       $caseRelationships[$key]['source'] = 'caseRel';
     }
@@ -209,7 +209,7 @@ class CRM_Activity_Page_AJAX {
     foreach ($caseRelationships as $key => &$row) {
       $typeLabel = $row['relation'];
       // Add "<br />(Case Manager)" to label
-      if (!empty($row['relation_type']) && $row['relation_type'] == $managerRoleId) {
+      if (!empty($row['relation_type']) && !empty($row['relationship_direction']) && $row['relation_type'] . '_' . $row['relationship_direction'] == $managerRoleId) {
         $row['relation'] .= '<br />' . '(' . ts('Case Manager') . ')';
       }
       // view user links
diff --git a/civicrm/CRM/Admin/Form/Preferences/Campaign.php b/civicrm/CRM/Admin/Form/Preferences/Campaign.php
deleted file mode 100644
index 3e372da4c94f5b2ca5e49b5ce62b1088f4bf0fef..0000000000000000000000000000000000000000
--- a/civicrm/CRM/Admin/Form/Preferences/Campaign.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2019
- */
-
-/**
- * This class displays campaign preferences.
- */
-class CRM_Admin_Form_Preferences_Campaign extends CRM_Admin_Form_Preferences {
-
-  protected $_settings = [
-    'tag_unconfirmed' => CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME,
-    'petition_contacts' => CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME,
-  ];
-
-}
diff --git a/civicrm/CRM/Admin/Form/Preferences/Contribute.php b/civicrm/CRM/Admin/Form/Preferences/Contribute.php
index 7421754c72290db0cd7c2ef5d756b13e8edfa163..2367796184c7ed85ddb12bba202aa077344e9ddf 100644
--- a/civicrm/CRM/Admin/Form/Preferences/Contribute.php
+++ b/civicrm/CRM/Admin/Form/Preferences/Contribute.php
@@ -117,14 +117,14 @@ class CRM_Admin_Form_Preferences_Contribute extends CRM_Admin_Form_Preferences {
         'weight' => 8,
         'option_values' => [
           'Do_not_show' => ts('Do not show breakdown, only show total -i.e ' .
-            $config->defaultCurrencySymbol . '120.00'),
+            CRM_Core_BAO_Country::defaultCurrencySymbol() . '120.00'),
           'Inclusive' => ts('Show [tax term] inclusive price - i.e. ' .
-            $config->defaultCurrencySymbol .
+            CRM_Core_BAO_Country::defaultCurrencySymbol() .
             '120.00 (includes [tax term] of ' .
-            $config->defaultCurrencySymbol . '20.00)'),
+            CRM_Core_BAO_Country::defaultCurrencySymbol() . '20.00)'),
           'Exclusive' => ts('Show [tax term] exclusive price - i.e. ' .
-            $config->defaultCurrencySymbol . '100.00 + ' .
-            $config->defaultCurrencySymbol . '20.00 [tax term]'),
+            CRM_Core_BAO_Country::defaultCurrencySymbol() . '100.00 + ' .
+            CRM_Core_BAO_Country::defaultCurrencySymbol() . '20.00 [tax term]'),
         ],
       ],
     ];
diff --git a/civicrm/CRM/Admin/Form/Preferences/Display.php b/civicrm/CRM/Admin/Form/Preferences/Display.php
index 9ba36825cdf95a5b513ca380b16a64049c03cd68..3e7b87a82509a14494b82a62fb1e31b19492cadc 100644
--- a/civicrm/CRM/Admin/Form/Preferences/Display.php
+++ b/civicrm/CRM/Admin/Form/Preferences/Display.php
@@ -53,6 +53,8 @@ class CRM_Admin_Form_Preferences_Display extends CRM_Admin_Form_Preferences {
     'sort_name_format' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'menubar_position' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'menubar_color' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
+    'theme_backend' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
+    'theme_frontend' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
   ];
 
   /**
diff --git a/civicrm/CRM/Admin/Form/Preferences/Multisite.php b/civicrm/CRM/Admin/Form/Preferences/Multisite.php
deleted file mode 100644
index e5616922686f93aa616d5e470fa2232689c17bdc..0000000000000000000000000000000000000000
--- a/civicrm/CRM/Admin/Form/Preferences/Multisite.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2019
- */
-
-/**
- * This class generates form components for multi site preferences.
- */
-class CRM_Admin_Form_Preferences_Multisite extends CRM_Admin_Form_Preferences {
-
-  protected $_settings = [
-    'is_enabled' => CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME,
-    'domain_group_id' => CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME,
-  ];
-
-}
diff --git a/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php b/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php
index d1a258738c8bc6e4d18f601fad56793de456445b..d4cf4ae094fd9fc2e3d20febafffc199ecbb82ab 100644
--- a/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php
+++ b/civicrm/CRM/Admin/Form/Setting/UpdateConfigBackend.php
@@ -42,22 +42,25 @@ class CRM_Admin_Form_Setting_UpdateConfigBackend extends CRM_Admin_Form_Setting
   public function buildQuickForm() {
     CRM_Utils_System::setTitle(ts('Settings - Cleanup Caches and Update Paths'));
 
-    $this->addElement(
-      'submit', $this->getButtonName('next', 'cleanup'), 'Cleanup Caches',
-      ['class' => 'crm-form-submit', 'id' => 'cleanup-cache']
-    );
-
-    $this->addElement(
-      'submit', $this->getButtonName('next', 'resetpaths'), 'Reset Paths',
-      ['class' => 'crm-form-submit', 'id' => 'resetpaths']
-    );
-
-    //parent::buildQuickForm();
+    $this->addButtons([
+      [
+        'type' => 'next',
+        'name' => ts('Cleanup Caches'),
+        'subName' => 'cleanup',
+        'icon' => 'fa-undo',
+
+      ],
+      [
+        'type' => 'next',
+        'name' => ts('Reset Paths'),
+        'subName' => 'resetpaths',
+        'icon' => 'fa-terminal',
+      ],
+    ]);
   }
 
   public function postProcess() {
-    if (!empty($_POST['_qf_UpdateConfigBackend_next_cleanup'])) {
-
+    if (isset($_REQUEST['_qf_UpdateConfigBackend_next_cleanup'])) {
       $config = CRM_Core_Config::singleton();
 
       // cleanup templates_c directory
@@ -74,14 +77,13 @@ class CRM_Admin_Form_Setting_UpdateConfigBackend extends CRM_Admin_Form_Setting
 
       CRM_Core_Session::setStatus(ts('Cache has been cleared and menu has been rebuilt successfully.'), ts("Success"), "success");
     }
-
-    if (!empty($_POST['_qf_UpdateConfigBackend_next_resetpaths'])) {
+    elseif (isset($_REQUEST['_qf_UpdateConfigBackend_next_resetpaths'])) {
       $msg = CRM_Core_BAO_ConfigSetting::doSiteMove();
 
       CRM_Core_Session::setStatus($msg, ts("Success"), "success");
     }
 
-    return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/setting/updateConfigBackend', 'reset=1'));
+    CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/setting/updateConfigBackend', 'reset=1'));
   }
 
 }
diff --git a/civicrm/CRM/Admin/Page/CKEditorConfig.php b/civicrm/CRM/Admin/Page/CKEditorConfig.php
index 22f65399139ca4f2cb2d9499727097c6a6c8176a..02328983d7cfee0004a34a5194b591b2da197995 100644
--- a/civicrm/CRM/Admin/Page/CKEditorConfig.php
+++ b/civicrm/CRM/Admin/Page/CKEditorConfig.php
@@ -163,7 +163,7 @@ class CRM_Admin_Page_CKEditorConfig extends CRM_Core_Page {
     foreach (glob($pluginDir . '/*', GLOB_ONLYDIR) as $dir) {
       $dir = rtrim(str_replace('\\', '/', $dir), '/');
       $name = substr($dir, strrpos($dir, '/') + 1);
-      $dir = CRM_Utils_file::addTrailingSlash($dir, '/');
+      $dir = CRM_Utils_File::addTrailingSlash($dir, '/');
       if (is_file($dir . 'plugin.js')) {
         $plugins[$name] = [
           'id' => $name,
diff --git a/civicrm/CRM/Batch/BAO/Batch.php b/civicrm/CRM/Batch/BAO/Batch.php
index fb2b2a326194d20ab2e40f98ddc18535d189a1a9..771c0cc412138cf9f5d28344e4e5d0a684893066 100644
--- a/civicrm/CRM/Batch/BAO/Batch.php
+++ b/civicrm/CRM/Batch/BAO/Batch.php
@@ -709,15 +709,14 @@ LEFT JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id
       'contribution_receipt_date_is_not_null',
       'contribution_pcp_made_through_id',
       'contribution_pcp_display_in_roll',
-      'contribution_date_relative',
       'contribution_amount_low',
       'contribution_amount_high',
       'contribution_in_honor_of',
       'contact_tags',
       'group',
-      'contribution_date_relative',
-      'contribution_date_high',
-      'contribution_date_low',
+      'receive_date_relative',
+      'receive_date_high',
+      'receive_date_low',
       'contribution_check_number',
       'contribution_status_id',
       'financial_trxn_card_type_id',
@@ -740,11 +739,11 @@ LEFT JOIN civicrm_contribution_soft ON civicrm_contribution_soft.contribution_id
         if ($field == 'group') {
           $from .= " LEFT JOIN civicrm_group_contact `civicrm_group_contact-{$params[$field]}` ON contact_a.id = `civicrm_group_contact-{$params[$field]}`.contact_id ";
         }
-        if ($field == 'contribution_date_relative') {
+        if ($field == 'receive_date_relative') {
           $relativeDate = explode('.', $params[$field]);
           $date = CRM_Utils_Date::relativeToAbsolute($relativeDate[0], $relativeDate[1]);
-          $values['contribution_date_low'] = $date['from'];
-          $values['contribution_date_high'] = $date['to'];
+          $values['receive_date_low'] = $date['from'];
+          $values['receive_date_high'] = $date['to'];
         }
       }
     }
diff --git a/civicrm/CRM/Batch/DAO/Batch.php b/civicrm/CRM/Batch/DAO/Batch.php
index 26340d54ad15b2cb5df9088e82ee3dff2b383dab..3ccd9c869eb3722bd433b2e5825dd8931e0f7428 100644
--- a/civicrm/CRM/Batch/DAO/Batch.php
+++ b/civicrm/CRM/Batch/DAO/Batch.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Batch/Batch.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3e98e0127d48dfc44b2e6db904cd556f)
+ * (GenCodeChecksum:bb7740fd38ae1c433a5e643de9d1b041)
  */
 
 /**
diff --git a/civicrm/CRM/Batch/DAO/EntityBatch.php b/civicrm/CRM/Batch/DAO/EntityBatch.php
index 5e0cb9ecb089cc13ae1eeee771235d1a88b7463e..d07e6e1aab47b7e9414120b92158021bb4b727f3 100644
--- a/civicrm/CRM/Batch/DAO/EntityBatch.php
+++ b/civicrm/CRM/Batch/DAO/EntityBatch.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Batch/EntityBatch.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:12e2c6e8e3c0890f0531819aebcfc543)
+ * (GenCodeChecksum:2d08c3008d6c7a05698fdbe02ad48921)
  */
 
 /**
diff --git a/civicrm/CRM/Batch/Form/Entry.php b/civicrm/CRM/Batch/Form/Entry.php
index b787b344a5f5307c8f10abbcd64d9e4355b7b712..46555a290ba38e637670c6d3483c0c4fb7abaee2 100644
--- a/civicrm/CRM/Batch/Form/Entry.php
+++ b/civicrm/CRM/Batch/Form/Entry.php
@@ -122,6 +122,7 @@ class CRM_Batch_Form_Entry extends CRM_Core_Form {
       ->addSetting(['setting' => ['monetaryThousandSeparator' => CRM_Core_Config::singleton()->monetaryThousandSeparator]])
       ->addSetting(['setting' => ['monetaryDecimalPoint' => CRM_Core_Config::singleton()->monetaryDecimalPoint]]);
 
+    $this->assign('defaultCurrencySymbol', CRM_Core_BAO_Country::defaultCurrencySymbol());
   }
 
   /**
diff --git a/civicrm/CRM/Campaign/DAO/Campaign.php b/civicrm/CRM/Campaign/DAO/Campaign.php
index a3c496b315dbdeefb10a9fe70f7ae928cba0bf11..f8f815a130129fcfbd9ec7e7aaf5531453005e07 100644
--- a/civicrm/CRM/Campaign/DAO/Campaign.php
+++ b/civicrm/CRM/Campaign/DAO/Campaign.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Campaign/Campaign.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5f32f92aafb04b54f15a47d07a2fe105)
+ * (GenCodeChecksum:2e624d3c874f1720634bf3954f77f460)
  */
 
 /**
diff --git a/civicrm/CRM/Campaign/DAO/CampaignGroup.php b/civicrm/CRM/Campaign/DAO/CampaignGroup.php
index 07f34d5fde2953b4bf852b362bdbba4ac5b708a7..6f94488d13d1b60a5a3ff5524246fd75796d9ced 100644
--- a/civicrm/CRM/Campaign/DAO/CampaignGroup.php
+++ b/civicrm/CRM/Campaign/DAO/CampaignGroup.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Campaign/CampaignGroup.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c399857d6182b7d1dcc2f037518ba8c3)
+ * (GenCodeChecksum:c67604933af69d768aa2f989e082bc11)
  */
 
 /**
diff --git a/civicrm/CRM/Campaign/DAO/Survey.php b/civicrm/CRM/Campaign/DAO/Survey.php
index d013622630e25ed789c72cd006e0314939ab2396..3bc1a8e71ed95d14528874bdfbbb7ce1d7b49ae2 100644
--- a/civicrm/CRM/Campaign/DAO/Survey.php
+++ b/civicrm/CRM/Campaign/DAO/Survey.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Campaign/Survey.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ad39991f1177492db1fd47cbaacf676a)
+ * (GenCodeChecksum:23a4ac88478af204885d170f42c5990b)
  */
 
 /**
diff --git a/civicrm/CRM/Campaign/Form/Campaign.php b/civicrm/CRM/Campaign/Form/Campaign.php
index 06a3c6130bdac33d42fda5bb028d3d352452ea11..813d34005586eaef82181d552c1bdd3dac01e8c2 100644
--- a/civicrm/CRM/Campaign/Form/Campaign.php
+++ b/civicrm/CRM/Campaign/Form/Campaign.php
@@ -81,7 +81,7 @@ class CRM_Campaign_Form_Campaign extends CRM_Core_Form {
     $this->assign('context', $this->_context);
 
     $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this);
-    $this->_campaignId = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+    $this->_campaignId = CRM_Utils_Request::retrieve('id', 'Positive');
 
     $title = NULL;
     if ($this->_action & CRM_Core_Action::UPDATE) {
@@ -186,6 +186,7 @@ class CRM_Campaign_Form_Campaign extends CRM_Core_Form {
     //lets assign custom data type and subtype.
     $this->assign('customDataType', 'Campaign');
     $this->assign('entityID', $this->_campaignId);
+    $this->assign('id', $this->_campaignId);
     $this->assign('customDataSubType', CRM_Utils_Array::value('campaign_type_id', $this->_values));
 
     $attributes = CRM_Core_DAO::getAttribute('CRM_Campaign_DAO_Campaign');
@@ -288,10 +289,9 @@ class CRM_Campaign_Form_Campaign extends CRM_Core_Form {
    */
   public function postProcess() {
     // store the submitted values in an array
-    $params = $this->controller->exportValues($this->_name);
-    $session = CRM_Core_Session::singleton();
 
-    $groups = [];
+    $session = CRM_Core_Session::singleton();
+    $params = $this->controller->exportValues($this->_name);
     if (isset($this->_campaignId)) {
       if ($this->_action & CRM_Core_Action::DELETE) {
         CRM_Campaign_BAO_Campaign::del($this->_campaignId);
@@ -309,7 +309,25 @@ class CRM_Campaign_Form_Campaign extends CRM_Core_Form {
     $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
     $params['last_modified_id'] = $session->get('userID');
     $params['last_modified_date'] = date('YmdHis');
+    $result = self::submit($params, $this);
+    if (!$result['is_error']) {
+      CRM_Core_Session::setStatus(ts('Campaign %1 has been saved.', [1 => $result['values'][$result['id']]['title']]), ts('Saved'), 'success');
+      $session->pushUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign'));
+      $this->ajaxResponse['id'] = $result['id'];
+      $this->ajaxResponse['label'] = $result['values'][$result['id']]['title'];
+    }
+    $buttonName = $this->controller->getButtonName();
+    if ($buttonName == $this->getButtonName('upload', 'new')) {
+      CRM_Core_Session::setStatus(ts(' You can add another Campaign.'), '', 'info');
+      $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign/add', 'reset=1&action=add'));
+    }
+    else {
+      $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign'));
+    }
+  }
 
+  public static function submit($params = [], $form) {
+    $groups = [];
     if (is_array($params['includeGroups'])) {
       foreach ($params['includeGroups'] as $key => $id) {
         if ($id) {
@@ -322,7 +340,7 @@ class CRM_Campaign_Form_Campaign extends CRM_Core_Form {
     // delete previous includes/excludes, if campaign already existed
     $groupTableName = CRM_Contact_BAO_Group::getTableName();
     $dao = new CRM_Campaign_DAO_CampaignGroup();
-    $dao->campaign_id = $this->_campaignId;
+    $dao->campaign_id = $form->_campaignId;
     $dao->entity_table = $groupTableName;
     $dao->find();
     while ($dao->fetch()) {
@@ -334,27 +352,13 @@ class CRM_Campaign_Form_Campaign extends CRM_Core_Form {
       CRM_Utils_Array::value('campaign_type_id', $params)
     );
     $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
-      $this->_campaignId,
+      $form->_campaignId,
       'Campaign'
     );
-
-    $result = CRM_Campaign_BAO_Campaign::create($params);
-
-    if ($result) {
-      CRM_Core_Session::setStatus(ts('Campaign %1 has been saved.', [1 => $result->title]), ts('Saved'), 'success');
-      $session->pushUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign'));
-      $this->ajaxResponse['id'] = $result->id;
-      $this->ajaxResponse['label'] = $result->title;
-    }
-
-    $buttonName = $this->controller->getButtonName();
-    if ($buttonName == $this->getButtonName('upload', 'new')) {
-      CRM_Core_Session::setStatus(ts(' You can add another Campaign.'), '', 'info');
-      $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign/add', 'reset=1&action=add'));
-    }
-    else {
-      $session->replaceUserContext(CRM_Utils_System::url('civicrm/campaign', 'reset=1&subPage=campaign'));
-    }
+    // dev/core#1067 Clean Money before passing onto BAO to do the create.
+    $params['goal_revenue'] = CRM_Utils_Rule::cleanMoney($params['goal_revenue']);
+    $result = civicrm_api3('Campaign', 'create', $params);
+    return $result;
   }
 
 }
diff --git a/civicrm/CRM/Campaign/Form/Petition/Signature.php b/civicrm/CRM/Campaign/Form/Petition/Signature.php
index f39166cebff2988a5d9ce421804995683585736c..29e398ef185053e0b2029774e21aa8087cae62ea 100644
--- a/civicrm/CRM/Campaign/Form/Petition/Signature.php
+++ b/civicrm/CRM/Campaign/Form/Petition/Signature.php
@@ -605,9 +605,7 @@ class CRM_Campaign_Form_Petition_Signature extends CRM_Core_Form {
         }
 
         if ($addCaptcha && !$viewOnly) {
-          $captcha = CRM_Utils_ReCAPTCHA::singleton();
-          $captcha->add($this);
-          $this->assign("isCaptcha", TRUE);
+          CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
         }
       }
     }
diff --git a/civicrm/CRM/Campaign/Selector/Search.php b/civicrm/CRM/Campaign/Selector/Search.php
index 7c22820e9bd363d2d2b0c498b01336f121edc171..13420533145995e337757e7d38e633e906c4c372 100644
--- a/civicrm/CRM/Campaign/Selector/Search.php
+++ b/civicrm/CRM/Campaign/Selector/Search.php
@@ -296,7 +296,7 @@ FROM {$sql['from']}
 
       if (Civi::service('prevnext') instanceof CRM_Core_PrevNextCache_Sql) {
         // SQL-backed prevnext cache uses an extra record for pruning the cache.
-        CRM_Core_BAO_Cache::setItem($cacheKey, 'CiviCRM Search PrevNextCache', $cacheKey);
+        Civi::cache('prevNextCache')->set($cacheKey, $cacheKey);
       }
     }
   }
diff --git a/civicrm/CRM/Campaign/xml/Menu/Campaign.xml b/civicrm/CRM/Campaign/xml/Menu/Campaign.xml
index a5c673f24eb848ec580e55473ac51400032657b8..555eb1f2843bffb3a57e9c664303e15726e178bb 100644
--- a/civicrm/CRM/Campaign/xml/Menu/Campaign.xml
+++ b/civicrm/CRM/Campaign/xml/Menu/Campaign.xml
@@ -72,7 +72,7 @@
   <item>
      <path>civicrm/admin/setting/preferences/campaign</path>
      <title>CiviCampaign Component Settings</title>
-     <page_callback>CRM_Admin_Form_Preferences_Campaign</page_callback>
+     <page_callback>CRM_Admin_Form_Generic</page_callback>
      <desc>Configure global CiviCampaign behaviors.</desc>
      <adminGroup>CiviCampaign</adminGroup>
      <weight>10</weight>
diff --git a/civicrm/CRM/Case/BAO/Case.php b/civicrm/CRM/Case/BAO/Case.php
index 4fcbe01cae28af268eb7b5d5cc5df684f53efb55..1b1340a9ef17c30887344fdd688c2977471c8621 100644
--- a/civicrm/CRM/Case/BAO/Case.php
+++ b/civicrm/CRM/Case/BAO/Case.php
@@ -434,7 +434,7 @@ WHERE cc.contact_id = %1 AND civicrm_case_type.name = '{$caseType}'";
       'civicrm_case.status_id as case_status_id',
       't_act.status_id as status_id',
       'civicrm_case.start_date as case_start_date',
-      'case_relation_type.label_b_a as case_role',
+      "GROUP_CONCAT(DISTINCT IF(case_relationship.contact_id_b = $userID, case_relation_type.label_a_b, case_relation_type.label_b_a) SEPARATOR ', ') as case_role",
       't_act.activity_date_time as activity_date_time',
       't_act.id as activity_id',
     );
@@ -475,8 +475,8 @@ HERESQL;
           ON civicrm_phone.contact_id = civicrm_contact.id
             AND civicrm_phone.is_primary = 1
         LEFT JOIN civicrm_relationship case_relationship
-          ON case_relationship.contact_id_a = civicrm_case_contact.contact_id
-            AND case_relationship.contact_id_b = {$userID}
+          ON ((case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID})
+          OR (case_relationship.contact_id_b = civicrm_case_contact.contact_id AND case_relationship.contact_id_a = {$userID}))
             AND case_relationship.is_active
             AND case_relationship.case_id = civicrm_case.id
         LEFT JOIN civicrm_relationship_type case_relation_type
@@ -535,10 +535,11 @@ HERESQL;
     $whereClauses = array('civicrm_case.is_deleted = 0 AND civicrm_contact.is_deleted <> 1');
 
     if (!$allCases) {
-      $whereClauses[] .= " case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
+      $whereClauses[] = "(case_relationship.contact_id_b = {$userID} OR case_relationship.contact_id_a = {$userID})";
+      $whereClauses[] = 'case_relationship.is_active';
     }
     if (empty($params['status_id']) && ($type == 'upcoming' || $type == 'any')) {
-      $whereClauses[] = " civicrm_case.status_id != " . CRM_Core_PseudoConstant::getKey('CRM_Case_BAO_Case', 'case_status_id', 'Closed');
+      $whereClauses[] = "civicrm_case.status_id != " . CRM_Core_PseudoConstant::getKey('CRM_Case_BAO_Case', 'case_status_id', 'Closed');
     }
 
     foreach (array('case_type_id', 'status_id') as $column) {
@@ -703,26 +704,28 @@ HERESQL;
 
     // build rows with actual data
     $rows = array();
-    $myGroupByClause = $mySelectClause = $myCaseFromClause = $myCaseWhereClause = '';
+    $myGroupByClause = $mySelectClause = $myCaseFromClause = $myCaseWhereClauseA = $myCaseWhereClauseB = '';
 
     if ($allCases) {
       $userID = 'null';
       $all = 1;
       $case_owner = 1;
-      $myGroupByClause = ' GROUP BY civicrm_case.id';
+      $myGroupByClauseB = ' GROUP BY civicrm_case.id';
     }
     else {
       $all = 0;
       $case_owner = 2;
-      $myCaseWhereClause = " AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
-      $myGroupByClause = " GROUP BY CONCAT(case_relationship.case_id,'-',case_relationship.contact_id_b)";
+      $myCaseWhereClauseA = " AND case_relationship.contact_id_a = {$userID} AND case_relationship.is_active ";
+      $myGroupByClauseA = " GROUP BY CONCAT(civicrm_case.id,'-',case_relationship.contact_id_a)";
+      $myCaseWhereClauseB = " AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active ";
+      $myGroupByClauseB = " GROUP BY CONCAT(civicrm_case.id,'-',case_relationship.contact_id_b)";
     }
-    $myGroupByClause .= ", case_status.label, status_id, case_type_id";
-
+    $myGroupByClauseB .= ", case_status.label, status_id, case_type_id, civicrm_case.id";
+    $myGroupByClauseA = $myGroupByClauseB;
     // FIXME: This query could be a lot more efficient if it used COUNT() instead of returning all rows and then counting them with php
     $query = "
-SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
- case_type_id, case_relationship.contact_id_b
+SELECT civicrm_case.id, case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
+ case_type_id, case_relationship.contact_id_b as case_contact
  FROM civicrm_case
  INNER JOIN civicrm_case_contact cc on cc.case_id = civicrm_case.id
  LEFT JOIN civicrm_case_type ON civicrm_case.case_type_id = civicrm_case_type.id
@@ -732,7 +735,20 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
  LEFT JOIN civicrm_relationship case_relationship ON ( case_relationship.case_id  = civicrm_case.id
  AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active )
  WHERE is_deleted = 0 AND cc.contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted <> 1)
-{$myCaseWhereClause} {$myGroupByClause}";
+{$myCaseWhereClauseB} {$myGroupByClauseB}
+UNION
+SELECT civicrm_case.id, case_status.label AS case_status, status_id, civicrm_case_type.title AS case_type,
+ case_type_id, case_relationship.contact_id_a as case_contact
+ FROM civicrm_case
+ INNER JOIN civicrm_case_contact cc on cc.case_id = civicrm_case.id
+ LEFT JOIN civicrm_case_type ON civicrm_case.case_type_id = civicrm_case_type.id
+ LEFT JOIN civicrm_option_group option_group_case_status ON ( option_group_case_status.name = 'case_status' )
+ LEFT JOIN civicrm_option_value case_status ON ( civicrm_case.status_id = case_status.value
+ AND option_group_case_status.id = case_status.option_group_id )
+ LEFT JOIN civicrm_relationship case_relationship ON ( case_relationship.case_id  = civicrm_case.id
+ AND case_relationship.contact_id_a = {$userID})
+ WHERE is_deleted = 0 AND cc.contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted <> 1)
+{$myCaseWhereClauseA} {$myGroupByClauseA}";
 
     $res = CRM_Core_DAO::executeQuery($query);
     while ($res->fetch()) {
@@ -1077,7 +1093,7 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
         $caseActivity['no_attachments'] = count($attachmentIDs);
       }
 
-      $caseActivities[$caseActivityId]['links'] = self::addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao);
+      $caseActivities[$caseActivityId]['links'] = CRM_Case_Selector_Search::addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao);
     }
 
     $caseActivitiesDT = array();
@@ -1088,80 +1104,6 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
     return $caseActivitiesDT;
   }
 
-  /**
-   * FIXME: This is a transitional function to facilitate a refactor of this to use CRM_Core_Action and actionLinks
-   * Add the set of "actionLinks" to the case activity
-   *
-   * @param int $caseID
-   * @param int $contactID
-   * @param int $userID
-   * @param string $context
-   * @param \CRM_Core_DAO $dao
-   *
-   * @return string
-   *   HTML formatted Link
-   */
-  private static function addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao) {
-    // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup.
-    $caseActivityId = $dao->id;
-    $allowView = self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID);
-    $allowEdit = self::checkPermission($caseActivityId, 'edit', $dao->activity_type_id, $userID);
-    $allowDelete = self::checkPermission($caseActivityId, 'delete', $dao->activity_type_id, $userID);
-    $emailActivityTypeIDs = [
-      'Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email'),
-      'Inbound Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email'),
-    ];
-    $url = CRM_Utils_System::url("civicrm/case/activity",
-      "reset=1&cid={$contactID}&caseid={$caseID}", FALSE, NULL, FALSE
-    );
-    $contextUrl = '';
-    if ($context == 'fulltext') {
-      $contextUrl = "&context={$context}";
-    }
-    $editUrl = "{$url}&action=update{$contextUrl}";
-    $deleteUrl = "{$url}&action=delete{$contextUrl}";
-    $restoreUrl = "{$url}&action=renew{$contextUrl}";
-    $viewTitle = ts('View activity');
-    $caseDeleted = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'is_deleted');
-
-    $url = "";
-    $css = 'class="action-item crm-hover-button"';
-    if ($allowView) {
-      $viewUrl = CRM_Utils_System::url('civicrm/case/activity/view', array('cid' => $contactID, 'aid' => $caseActivityId));
-      $url = '<a ' . str_replace('action-item', 'action-item medium-pop-up', $css) . 'href="' . $viewUrl . '" title="' . $viewTitle . '">' . ts('View') . '</a>';
-    }
-    $additionalUrl = "&id={$caseActivityId}";
-    if (!$dao->deleted) {
-      //hide edit link of activity type email.CRM-4530.
-      if (!in_array($dao->type, $emailActivityTypeIDs)) {
-        //hide Edit link if activity type is NOT editable (special case activities).CRM-5871
-        if ($allowEdit) {
-          $url .= '<a ' . $css . ' href="' . $editUrl . $additionalUrl . '">' . ts('Edit') . '</a> ';
-        }
-      }
-      if ($allowDelete) {
-        $url .= ' <a ' . str_replace('action-item', 'action-item small-popup', $css) . ' href="' . $deleteUrl . $additionalUrl . '">' . ts('Delete') . '</a>';
-      }
-    }
-    elseif (!$caseDeleted) {
-      $url = ' <a ' . $css . ' href="' . $restoreUrl . $additionalUrl . '">' . ts('Restore') . '</a>';
-    }
-
-    //check for operations.
-    if (self::checkPermission($caseActivityId, 'Move To Case', $dao->activity_type_id)) {
-      $url .= ' <a ' . $css . ' href="#" onClick="Javascript:fileOnCase( \'move\',' . $caseActivityId . ', ' . $caseID . ', this ); return false;">' . ts('Move To Case') . '</a> ';
-    }
-    if (self::checkPermission($caseActivityId, 'Copy To Case', $dao->activity_type_id)) {
-      $url .= ' <a ' . $css . ' href="#" onClick="Javascript:fileOnCase( \'copy\',' . $caseActivityId . ',' . $caseID . ', this ); return false;">' . ts('Copy To Case') . '</a> ';
-    }
-    // if there are file attachments we will return how many and, if only one, add a link to it
-    if (!empty($dao->attachment_ids)) {
-      $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId));
-    }
-
-    return $url;
-  }
-
   /**
    * Helper function to generate a formatted contact link/name for display in the Case activities tab
    *
@@ -1204,29 +1146,53 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
       $caseInfo = civicrm_api3('Case', 'getsingle', array(
         'id' => $caseID,
         // Most efficient way of retrieving definition is to also include case type id and name so the api doesn't have to look it up separately
-        'return' => array('case_type_id', 'case_type_id.name', 'case_type_id.definition'),
+        'return' => array('case_type_id', 'case_type_id.name', 'case_type_id.definition', 'contact_id'),
       ));
       if (!empty($caseInfo['case_type_id.definition']['caseRoles'])) {
         $caseRoles = CRM_Utils_Array::rekey($caseInfo['case_type_id.definition']['caseRoles'], 'name');
       }
     }
-    $values = array();
-    $query = '
-      SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_b_a as role, crt.name_b_a, ce.email, cp.phone
-      FROM civicrm_relationship cr
-      LEFT JOIN civicrm_relationship_type crt
-        ON crt.id = cr.relationship_type_id
-      LEFT JOIN civicrm_contact cc
-        ON cc.id = cr.contact_id_b
-      LEFT JOIN civicrm_email ce
-        ON ce.contact_id = cc.id
-        AND ce.is_primary= 1
-      LEFT JOIN civicrm_phone cp
-        ON cp.contact_id = cc.id
-        AND cp.is_primary= 1
-      WHERE cr.case_id =  %1 AND cr.is_active AND cc.is_deleted <> 1';
 
-    $params = array(1 => array($caseID, 'Integer'));
+    $values = array();
+    $query = <<<HERESQL
+    SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_b_a as role, crt.name_b_a as role_name, ce.email, cp.phone
+    FROM civicrm_relationship cr
+    JOIN civicrm_relationship_type crt
+     ON crt.id = cr.relationship_type_id
+    JOIN civicrm_contact cc
+     ON cc.id = cr.contact_id_a
+     AND cc.is_deleted <> 1
+    LEFT JOIN civicrm_email ce
+     ON ce.contact_id = cc.id
+     AND ce.is_primary= 1
+    LEFT JOIN civicrm_phone cp
+     ON cp.contact_id = cc.id
+     AND cp.is_primary= 1
+    WHERE cr.case_id =  %1
+     AND cr.is_active
+     AND cc.id NOT IN (%2)
+    UNION
+    SELECT cc.display_name as name, cc.sort_name as sort_name, cc.id, cr.relationship_type_id, crt.label_a_b as role, crt.name_a_b as role_name, ce.email, cp.phone
+    FROM civicrm_relationship cr
+    JOIN civicrm_relationship_type crt
+     ON crt.id = cr.relationship_type_id
+    JOIN civicrm_contact cc
+     ON cc.id = cr.contact_id_b
+     AND cc.is_deleted <> 1
+    LEFT JOIN civicrm_email ce
+     ON ce.contact_id = cc.id
+     AND ce.is_primary= 1
+    LEFT JOIN civicrm_phone cp
+     ON cp.contact_id = cc.id
+     AND cp.is_primary= 1
+    WHERE cr.case_id =  %1
+     AND cr.is_active
+     AND cc.id NOT IN (%2)
+HERESQL;
+    $params = array(
+      1 => array($caseID, 'Integer'),
+      2 => array(implode(',', $caseInfo['client_id']), 'String'),
+    );
     $dao = CRM_Core_DAO::executeQuery($query, $params);
 
     while ($dao->fetch()) {
@@ -1244,7 +1210,7 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
           'phone' => $dao->phone,
         );
         // Add more info about the role (creator, manager)
-        $role = CRM_Utils_Array::value($dao->name_b_a, $caseRoles);
+        $role = CRM_Utils_Array::value($dao->role_name, $caseRoles);
         if ($role) {
           unset($role['name']);
           $details += $role;
@@ -1848,16 +1814,27 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
     $managerRoleId = $xmlProcessor->getCaseManagerRoleId($caseType);
 
     if (!empty($managerRoleId)) {
-      $managerRoleQuery = "
-SELECT civicrm_contact.id as casemanager_id,
-       civicrm_contact.sort_name as casemanager
- FROM civicrm_contact
- LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
- LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
- WHERE civicrm_case.id = %2 AND is_active = 1";
+      if (substr($managerRoleId, -4) == '_a_b') {
+        $managerRoleQuery = "
+          SELECT civicrm_contact.id as casemanager_id,
+                 civicrm_contact.sort_name as casemanager
+           FROM civicrm_contact
+           LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_b = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
+           LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
+           WHERE civicrm_case.id = %2 AND is_active = 1";
+      }
+      if (substr($managerRoleId, -4) == '_b_a') {
+        $managerRoleQuery = "
+          SELECT civicrm_contact.id as casemanager_id,
+                 civicrm_contact.sort_name as casemanager
+           FROM civicrm_contact
+           LEFT JOIN civicrm_relationship ON (civicrm_relationship.contact_id_a = civicrm_contact.id AND civicrm_relationship.relationship_type_id = %1) AND civicrm_relationship.is_active
+           LEFT JOIN civicrm_case ON civicrm_case.id = civicrm_relationship.case_id
+           WHERE civicrm_case.id = %2 AND is_active = 1";
+      }
 
       $managerRoleParams = array(
-        1 => array($managerRoleId, 'Integer'),
+        1 => array(substr($managerRoleId, 0, -4), 'Integer'),
         2 => array($caseId, 'Integer'),
       );
 
@@ -3214,4 +3191,58 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
     return $filters;
   }
 
+  /**
+   * Fetch Case Role direction from Case Type
+   */
+  public static function getCaseRoleDirection($caseId, $roleTypeId = NULL) {
+    try {
+      $case = civicrm_api3('Case', 'getsingle', array('id' => $caseId));
+    }
+    catch (CiviCRM_API3_Exception $e) {
+      // Lack of permissions will throw an exception
+      return 0;
+    }
+    if (!empty($case['case_type_id'])) {
+      try {
+        $caseType = civicrm_api3('CaseType', 'getsingle', array('id' => $case['case_type_id'], 'return' => array('definition')));
+      }
+      catch (CiviCRM_API3_Exception $e) {
+        // Lack of permissions will throw an exception
+        return 'no case type found';
+      }
+      if (!empty($caseType['definition']['caseRoles'])) {
+        $caseRoles = array();
+        foreach ($caseType['definition']['caseRoles'] as $key => $roleDetails) {
+          // Check if its an a_b label
+          try {
+            $relType = civicrm_api3('RelationshipType', 'getsingle', array('label_a_b' => $roleDetails['name']));
+          }
+          catch (CiviCRM_API3_Exception $e) {
+          }
+          if (!empty($relType['id'])) {
+            $roleDetails['id'] = $relType['id'];
+            $roleDetails['direction'] = 'b_a';
+          }
+          // Check if its a b_a label
+          try {
+            $relTypeBa = civicrm_api3('RelationshipType', 'getsingle', array('label_b_a' => $roleDetails['name']));
+          }
+          catch (CiviCRM_API3_Exception $e) {
+          }
+          if (!empty($relTypeBa['id'])) {
+            if (!empty($roleDetails['direction'])) {
+              $roleDetails['direction'] = 'bidrectional';
+            }
+            else {
+              $roleDetails['id'] = $relTypeBa['id'];
+              $roleDetails['direction'] = 'a_b';
+            }
+          }
+          $caseRoles[$roleDetails['id']] = $roleDetails;
+        }
+      }
+      return $caseRoles;
+    }
+  }
+
 }
diff --git a/civicrm/CRM/Case/BAO/Query.php b/civicrm/CRM/Case/BAO/Query.php
index e5bf54125eb7996e80fc93e4a275a0d49ce71a55..321118bf96e74613625e82dd299eff8ff4338cfe 100644
--- a/civicrm/CRM/Case/BAO/Query.php
+++ b/civicrm/CRM/Case/BAO/Query.php
@@ -110,7 +110,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
     }
 
     if (!empty($query->_returnProperties['case_role'])) {
-      $query->_select['case_role'] = "case_relation_type.label_b_a as case_role";
+      $query->_select['case_role'] = "IF(case_relationship.contact_id_b = contact_a.id, case_relation_type.label_b_a, case_relation_type.label_a_b) as case_role";
       $query->_element['case_role'] = 1;
       $query->_tables['case_relationship'] = $query->_whereTables['case_relationship'] = 1;
       $query->_tables['case_relation_type'] = $query->_whereTables['case_relation_type'] = 1;
@@ -296,7 +296,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
           if ($value == 2) {
             $session = CRM_Core_Session::singleton();
             $userID = $session->get('userID');
-            $query->_where[$grouping][] = ' ( ' . CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_b", $op, $userID, 'Int') . ' AND ' . CRM_Contact_BAO_Query::buildClause("case_relationship.is_active", '<>', 0, 'Int') . ' ) ';
+            $query->_where[$grouping][] = ' (( ' . CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_b", $op, $userID, 'Int') . ' AND ' . CRM_Contact_BAO_Query::buildClause("case_relationship.is_active", '<>', 0, 'Int') . ' ) OR ( ' . CRM_Contact_BAO_Query::buildClause("case_relationship.contact_id_a", $op, $userID, 'Int') . ' AND ' . CRM_Contact_BAO_Query::buildClause("case_relationship.is_active", '<>', 0, 'Int') . ' ))';
             $query->_qill[$grouping][] = ts('Case %1 My Cases', [1 => $op]);
             $query->_tables['case_relationship'] = $query->_whereTables['case_relationship'] = 1;
           }
@@ -434,7 +434,6 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       // adding where clause for case_role
 
       case 'case_role':
-        $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_relation_type.name_b_a", $op, $value, 'String');
         $query->_qill[$grouping][] = ts("Role in Case  %1 '%2'", [1 => $op, 2 => $value]);
         $query->_tables['case_relation_type'] = $query->_whereTables['case_relationship_type'] = 1;
         $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
@@ -549,7 +548,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       case 'case_relationship':
         $session = CRM_Core_Session::singleton();
         $userID = $session->get('userID');
-        $from .= " $side JOIN civicrm_relationship case_relationship ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.case_id = civicrm_case.id )";
+        $from .= " $side JOIN civicrm_relationship case_relationship ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.case_id = civicrm_case.id OR case_relationship.contact_id_b = civicrm_case_contact.contact_id AND case_relationship.contact_id_a = {$userID} AND case_relationship.case_id = civicrm_case.id )";
         break;
 
       case 'case_relation_type':
diff --git a/civicrm/CRM/Case/DAO/Case.php b/civicrm/CRM/Case/DAO/Case.php
index 717b2b1bf1b91b8158757f9d76a44fbbfef050ec..32f599953d1e6bb343b534f6a3f1661e60238b20 100644
--- a/civicrm/CRM/Case/DAO/Case.php
+++ b/civicrm/CRM/Case/DAO/Case.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Case/Case.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f7d3f0df9ce94aec00f5eb0e20cedd1e)
+ * (GenCodeChecksum:ef55a2e5b12047af86439542927b6800)
  */
 
 /**
diff --git a/civicrm/CRM/Case/DAO/CaseActivity.php b/civicrm/CRM/Case/DAO/CaseActivity.php
index 40b275fbf882c50366f2500ac8e75eeb8b92f240..d19ca14a36ca171adfdb05481b81833c765bb0a5 100644
--- a/civicrm/CRM/Case/DAO/CaseActivity.php
+++ b/civicrm/CRM/Case/DAO/CaseActivity.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Case/CaseActivity.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:cb7a73ba739c93a482d18ef28ed0c589)
+ * (GenCodeChecksum:5697d114b740fb610d38577657c1dbfd)
  */
 
 /**
diff --git a/civicrm/CRM/Case/DAO/CaseContact.php b/civicrm/CRM/Case/DAO/CaseContact.php
index 42a830d70315acc6d67c21c7d8aed67495a23d88..f1f5a9866b603a45692c7fac841fd25556392f58 100644
--- a/civicrm/CRM/Case/DAO/CaseContact.php
+++ b/civicrm/CRM/Case/DAO/CaseContact.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Case/CaseContact.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:84dae97091e4a1612c67274f5cb10531)
+ * (GenCodeChecksum:c74aa90d8f31629354041ed18de9a468)
  */
 
 /**
diff --git a/civicrm/CRM/Case/DAO/CaseType.php b/civicrm/CRM/Case/DAO/CaseType.php
index 533f0e03a3356bc91c6b7c72fa2b2e85d7bf84c7..84a3300b3ac8cf7cfbb6c915dd2fcfe8f0f0a8df 100644
--- a/civicrm/CRM/Case/DAO/CaseType.php
+++ b/civicrm/CRM/Case/DAO/CaseType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Case/CaseType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:317907ffe519c3f3eab8af9d8e9e1f7f)
+ * (GenCodeChecksum:27419fd4de448a468cd726a85b097d19)
  */
 
 /**
diff --git a/civicrm/CRM/Case/Form/Activity/OpenCase.php b/civicrm/CRM/Case/Form/Activity/OpenCase.php
index ed571d76f3ad37edddc1965634af4174d056967b..c233fd321a612b878386627e252d6cbb1c3a4306 100644
--- a/civicrm/CRM/Case/Form/Activity/OpenCase.php
+++ b/civicrm/CRM/Case/Form/Activity/OpenCase.php
@@ -198,7 +198,6 @@ class CRM_Case_Form_Activity_OpenCase {
         'type' => 'upload',
         'name' => ts('Save'),
         'isDefault' => TRUE,
-        'submitOnce' => TRUE,
       ],
       [
         'type' => 'upload',
diff --git a/civicrm/CRM/Case/Form/AddToCaseAsRole.php b/civicrm/CRM/Case/Form/AddToCaseAsRole.php
index 20be94a95ad2be7f831c7d0a0d3bf5be7b2ef1a7..f2809047e3c97398e3caf18df8f555d3f7319307 100644
--- a/civicrm/CRM/Case/Form/AddToCaseAsRole.php
+++ b/civicrm/CRM/Case/Form/AddToCaseAsRole.php
@@ -68,15 +68,23 @@ class CRM_Case_Form_AddToCaseAsRole extends CRM_Contact_Form_Task {
     $contacts = $this->_contactIds;
 
     $clients = CRM_Case_BAO_Case::getCaseClients($caseId);
+    $caseRole = CRM_Case_BAO_Case::getCaseRoleDirection($caseId, $roleTypeId);
 
     $params = [
-      'contact_id_a' => $clients[0],
-      'contact_id_b' => $contacts,
       'case_id' => $caseId,
       'relationship_type_id' => $roleTypeId,
     ];
 
-    CRM_Contact_BAO_Relationship::createMultiple($params, 'a');
+    if ($caseRole[$roleTypeId]['direction'] == 'b_a') {
+      $params['contact_id_b'] = $clients[0];
+      $params['contact_id_a'] = $contacts;
+      CRM_Contact_BAO_Relationship::createMultiple($params, 'b');
+    }
+    elseif ($caseRole[$roleTypeId]['direction'] == 'a_b'  || $caseRole[$roleTypeId]['direction'] = 'bidirectional') {
+      $params['contact_id_a'] = $clients[0];
+      $params['contact_id_b'] = $contacts;
+      CRM_Contact_BAO_Relationship::createMultiple($params, 'a');
+    }
 
     $url = CRM_Utils_System::url(
       'civicrm/contact/view/case',
diff --git a/civicrm/CRM/Case/Form/Case.php b/civicrm/CRM/Case/Form/Case.php
index 685ce79553d009aafacc0f47d4d65dbba375572b..80b83d578cde94b797b18c44e522199136672790 100644
--- a/civicrm/CRM/Case/Form/Case.php
+++ b/civicrm/CRM/Case/Form/Case.php
@@ -91,6 +91,8 @@ class CRM_Case_Form_Case extends CRM_Core_Form {
    */
   public $_caseTypeId = NULL;
 
+  public $submitOnce = TRUE;
+
   /**
    * Explicitly declare the entity api name.
    */
diff --git a/civicrm/CRM/Case/Form/CaseView.php b/civicrm/CRM/Case/Form/CaseView.php
index fdf587ca58dfd4284866c8c8cf5778708a487ea4..2f9eb82a0e8c5da1e3b3706d123817968dc5b489 100644
--- a/civicrm/CRM/Case/Form/CaseView.php
+++ b/civicrm/CRM/Case/Form/CaseView.php
@@ -289,7 +289,7 @@ class CRM_Case_Form_CaseView extends CRM_Core_Form {
 
     foreach ($caseRelationships as $key => & $value) {
       if (!empty($managerRoleId)) {
-        if ($managerRoleId == $value['relation_type']) {
+        if (substr($managerRoleId, 0, -4) == $value['relation_type'] && substr($managerRoleId, -3) == $value['relationship_direction']) {
           $value['relation'] = $managerLabel;
         }
       }
diff --git a/civicrm/CRM/Case/Info.php b/civicrm/CRM/Case/Info.php
index 413385c55ddfa9d9a1cae443827c35fcc2c25dc1..ce5421fd1b0d754869efd47c00da6e5f7e1844ac 100644
--- a/civicrm/CRM/Case/Info.php
+++ b/civicrm/CRM/Case/Info.php
@@ -144,8 +144,14 @@ class CRM_Case_Info extends CRM_Core_Component_Info {
     }
     elseif ($dao instanceof CRM_Contact_DAO_RelationshipType) {
       /** @var $dao CRM_Contact_DAO_RelationshipType */
-      $count = CRM_Case_XMLRepository::singleton()
-        ->getRelationshipReferenceCount($dao->{CRM_Case_XMLProcessor::REL_TYPE_CNAME});
+
+      // Need to look both directions, but no need to translate case role
+      // direction from XML perspective to client-based perspective
+      $xmlRepo = CRM_Case_XMLRepository::singleton();
+      $count = $xmlRepo->getRelationshipReferenceCount($dao->label_a_b);
+      if ($dao->label_a_b != $dao->label_b_a) {
+        $count += $xmlRepo->getRelationshipReferenceCount($dao->label_b_a);
+      }
       if ($count > 0) {
         $result[] = [
           'name' => 'casetypexml:relationships',
diff --git a/civicrm/CRM/Case/ManagedEntities.php b/civicrm/CRM/Case/ManagedEntities.php
index 461b51f5dafc78929b7c99b7452bf9337fd8dcbd..15bc97354f7e0448489900456c68aac7f9966ac9 100644
--- a/civicrm/CRM/Case/ManagedEntities.php
+++ b/civicrm/CRM/Case/ManagedEntities.php
@@ -112,12 +112,23 @@ class CRM_Case_ManagedEntities {
 
     if (!isset(Civi::$statics[__CLASS__]['reltypes'])) {
       $relationshipInfo = CRM_Core_PseudoConstant::relationshipType('label', TRUE, NULL);
-      Civi::$statics[__CLASS__]['reltypes'] = CRM_Utils_Array::collect(CRM_Case_XMLProcessor::REL_TYPE_CNAME, $relationshipInfo);
+      foreach ($relationshipInfo as $id => $relTypeDetails) {
+        Civi::$statics[__CLASS__]['reltypes']["{$id}_a_b"] = $relTypeDetails['label_a_b'];
+        if ($relTypeDetails['label_a_b'] != $relTypeDetails['label_b_a']) {
+          Civi::$statics[__CLASS__]['reltypes']["{$id}_b_a"] = $relTypeDetails['label_b_a'];
+        }
+      }
     }
     $validRelTypes = Civi::$statics[__CLASS__]['reltypes'];
 
     $relTypes = $xmlRepo->getAllDeclaredRelationshipTypes();
     foreach ($relTypes as $relType) {
+      // Making assumption that client is the A side of the relationship.
+      // Relationship label coming from XML, meaning from perspective of
+      // non-client.
+
+      // These assumptions only apply if a case type is introduced without the
+      // relationship types already existing.
       $managed = [
         'module' => 'civicrm',
         'name' => "civicase:rel:$relType",
@@ -131,8 +142,8 @@ class CRM_Case_ManagedEntities {
           'label_a_b' => "$relType is",
           'label_b_a' => $relType,
           'description' => $relType,
-          'contact_type_a' => 'Individual',
-          'contact_type_b' => 'Individual',
+          'contact_type_a' => NULL,
+          'contact_type_b' => NULL,
           'contact_sub_type_a' => NULL,
           'contact_sub_type_b' => NULL,
         ],
diff --git a/civicrm/CRM/Case/Selector/Search.php b/civicrm/CRM/Case/Selector/Search.php
index 5a4ab88c8e03b6ed742912e6969a6d8c254a68d2..c1a4e68536612c70b4aa663ba5caab77cc42f855 100644
--- a/civicrm/CRM/Case/Selector/Search.php
+++ b/civicrm/CRM/Case/Selector/Search.php
@@ -479,4 +479,77 @@ class CRM_Case_Selector_Search extends CRM_Core_Selector_Base {
     return ts('Case Search');
   }
 
+  /**
+   * Add the set of "actionLinks" to the case activity
+   *
+   * @param int $caseID
+   * @param int $contactID
+   * @param int $userID
+   * @param string $context
+   * @param \CRM_Core_DAO $dao
+   *
+   * @return string
+   *   HTML formatted Link
+   */
+  public static function addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao) {
+    // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup.
+    $caseActivityId = $dao->id;
+    $allowView = CRM_Case_BAO_Case::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID);
+    $allowEdit = CRM_Case_BAO_Case::checkPermission($caseActivityId, 'edit', $dao->activity_type_id, $userID);
+    $allowDelete = CRM_Case_BAO_Case::checkPermission($caseActivityId, 'delete', $dao->activity_type_id, $userID);
+    $emailActivityTypeIDs = [
+      'Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email'),
+      'Inbound Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email'),
+    ];
+    $url = CRM_Utils_System::url("civicrm/case/activity",
+      "reset=1&cid={$contactID}&caseid={$caseID}", FALSE, NULL, FALSE
+    );
+    $contextUrl = '';
+    if ($context == 'fulltext') {
+      $contextUrl = "&context={$context}";
+    }
+    $editUrl = "{$url}&action=update{$contextUrl}";
+    $deleteUrl = "{$url}&action=delete{$contextUrl}";
+    $restoreUrl = "{$url}&action=renew{$contextUrl}";
+    $viewTitle = ts('View activity');
+    $caseDeleted = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'is_deleted');
+
+    $url = "";
+    $css = 'class="action-item crm-hover-button"';
+    if ($allowView) {
+      $viewUrl = CRM_Utils_System::url('civicrm/case/activity/view', array('cid' => $contactID, 'aid' => $caseActivityId));
+      $url = '<a ' . str_replace('action-item', 'action-item medium-pop-up', $css) . 'href="' . $viewUrl . '" title="' . $viewTitle . '">' . ts('View') . '</a>';
+    }
+    $additionalUrl = "&id={$caseActivityId}";
+    if (!$dao->deleted) {
+      //hide edit link of activity type email.CRM-4530.
+      if (!in_array($dao->type, $emailActivityTypeIDs)) {
+        //hide Edit link if activity type is NOT editable (special case activities).CRM-5871
+        if ($allowEdit) {
+          $url .= '<a ' . $css . ' href="' . $editUrl . $additionalUrl . '">' . ts('Edit') . '</a> ';
+        }
+      }
+      if ($allowDelete) {
+        $url .= ' <a ' . str_replace('action-item', 'action-item small-popup', $css) . ' href="' . $deleteUrl . $additionalUrl . '">' . ts('Delete') . '</a>';
+      }
+    }
+    elseif (!$caseDeleted) {
+      $url = ' <a ' . $css . ' href="' . $restoreUrl . $additionalUrl . '">' . ts('Restore') . '</a>';
+    }
+
+    //check for operations.
+    if (CRM_Case_BAO_Case::checkPermission($caseActivityId, 'Move To Case', $dao->activity_type_id)) {
+      $url .= ' <a ' . $css . ' href="#" onClick="Javascript:fileOnCase( \'move\',' . $caseActivityId . ', ' . $caseID . ', this ); return false;">' . ts('Move To Case') . '</a> ';
+    }
+    if (CRM_Case_BAO_Case::checkPermission($caseActivityId, 'Copy To Case', $dao->activity_type_id)) {
+      $url .= ' <a ' . $css . ' href="#" onClick="Javascript:fileOnCase( \'copy\',' . $caseActivityId . ',' . $caseID . ', this ); return false;">' . ts('Copy To Case') . '</a> ';
+    }
+    // if there are file attachments we will return how many and, if only one, add a link to it
+    if (!empty($dao->attachment_ids)) {
+      $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId));
+    }
+
+    return $url;
+  }
+
 }
diff --git a/civicrm/CRM/Case/XMLProcessor.php b/civicrm/CRM/Case/XMLProcessor.php
index 863ea68ff5b58ca152ab9a3120fdc3f129fcafa6..245e9ace1c268058e45222cd0903df05d3c2083b 100644
--- a/civicrm/CRM/Case/XMLProcessor.php
+++ b/civicrm/CRM/Case/XMLProcessor.php
@@ -42,26 +42,6 @@ class CRM_Case_XMLProcessor {
    */
   public static $activityTypes = NULL;
 
-  /**
-   * FIXME: This does *NOT* belong in a static property, but we're too late in
-   * the 4.5-cycle to do the necessary cleanup.
-   *
-   * Format is array(int $id => string $relTypeCname).
-   *
-   * @var array|null
-   */
-  public static $relationshipTypes = NULL;
-
-  /**
-   * Relationship-types have four name fields (name_a_b, name_b_a, label_a_b,
-   * label_b_a), but CiviCase XML refers to reltypes by a single name.
-   * REL_TYPE_CNAME identifies the canonical name field as used by CiviCase XML.
-   *
-   * This appears to be "label_b_a", but IMHO "name_b_a" would be more
-   * sensible.
-   */
-  const REL_TYPE_CNAME = 'label_b_a';
-
   /**
    * @param $caseType
    *
@@ -111,19 +91,33 @@ class CRM_Case_XMLProcessor {
   }
 
   /**
+   * Get all relationship type labels
+   *
+   * TODO: These should probably be names, but under legacy behavior this has
+   * been labels.
+   *
+   * @param bool $fromXML
+   *   Is this to be used for lookup of values from XML?
+   *   Relationships are recorded in XML from the perspective of the non-client
+   *   while relationships in the UI and everywhere else are from the
+   *   perspective of the client.  Since the XML can't be expected to be
+   *   switched, the direction needs to be translated.
    * @return array
    */
-  public function &allRelationshipTypes() {
-    if (self::$relationshipTypes === NULL) {
+  public function &allRelationshipTypes($fromXML = FALSE) {
+    if (!isset(Civi::$statics[__CLASS__]['reltypes'][$fromXML])) {
       $relationshipInfo = CRM_Core_PseudoConstant::relationshipType('label', TRUE);
 
-      self::$relationshipTypes = [];
+      Civi::$statics[__CLASS__]['reltypes'][$fromXML] = [];
       foreach ($relationshipInfo as $id => $info) {
-        self::$relationshipTypes[$id] = $info[CRM_Case_XMLProcessor::REL_TYPE_CNAME];
+        Civi::$statics[__CLASS__]['reltypes'][$fromXML][$id . '_b_a'] = ($fromXML) ? $info['label_a_b'] : $info['label_b_a'];
+        if ($info['label_b_a'] !== $info['label_a_b']) {
+          Civi::$statics[__CLASS__]['reltypes'][$fromXML][$id . '_a_b'] = ($fromXML) ? $info['label_b_a'] : $info['label_a_b'];
+        }
       }
     }
 
-    return self::$relationshipTypes;
+    return Civi::$statics[__CLASS__]['reltypes'][$fromXML];
   }
 
   /**
@@ -131,7 +125,7 @@ class CRM_Case_XMLProcessor {
    */
   public static function flushStaticCaches() {
     self::$activityTypes = NULL;
-    self::$relationshipTypes = NULL;
+    unset(Civi::$statics[__CLASS__]['reltypes']);
   }
 
 }
diff --git a/civicrm/CRM/Case/XMLProcessor/Process.php b/civicrm/CRM/Case/XMLProcessor/Process.php
index b83e11cce6637e89012059f1be4e1ab238cb538e..4cfb5c8d7e1abcf6142a5e97ab2acc580d1663c3 100644
--- a/civicrm/CRM/Case/XMLProcessor/Process.php
+++ b/civicrm/CRM/Case/XMLProcessor/Process.php
@@ -181,7 +181,11 @@ class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
    * @return array|mixed
    */
   public function &caseRoles($caseRolesXML, $isCaseManager = FALSE) {
-    $relationshipTypes = &$this->allRelationshipTypes();
+    // Look up relationship types according to the XML convention (described
+    // from perspective of non-client) but return the labels according to the UI
+    // convention (described from perspective of client)
+    $relationshipTypes = &$this->allRelationshipTypes(TRUE);
+    $relationshipTypesToReturn = &$this->allRelationshipTypes(FALSE);
 
     $result = [];
     foreach ($caseRolesXML as $caseRoleXML) {
@@ -195,7 +199,7 @@ class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
         }
 
         if (!$isCaseManager) {
-          $result[$relationshipTypeID] = $relationshipTypeName;
+          $result[$relationshipTypeID] = $relationshipTypesToReturn[$relationshipTypeID];
         }
         elseif ($relationshipTypeXML->manager == 1) {
           return $relationshipTypeID;
@@ -213,11 +217,13 @@ class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
    * @throws Exception
    */
   public function createRelationships($relationshipTypeName, &$params) {
-    $relationshipTypes = &$this->allRelationshipTypes();
-    // get the relationship id
-    $relationshipTypeID = array_search($relationshipTypeName, $relationshipTypes);
+    // The relationshipTypeName is coming from XML, so the argument should be
+    // `TRUE`
+    $relationshipTypes = &$this->allRelationshipTypes(TRUE);
+    // get the relationship
+    $relationshipType = array_search($relationshipTypeName, $relationshipTypes);
 
-    if ($relationshipTypeID === FALSE) {
+    if ($relationshipType === FALSE) {
       $docLink = CRM_Utils_System::docURL2("user/case-management/set-up");
       CRM_Core_Error::fatal(ts('Relationship type %1, found in case configuration file, is not present in the database %2',
         [1 => $relationshipTypeName, 2 => $docLink]
@@ -232,15 +238,22 @@ class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
 
     foreach ($client as $key => $clientId) {
       $relationshipParams = [
-        'relationship_type_id' => $relationshipTypeID,
-        'contact_id_a' => $clientId,
-        'contact_id_b' => $params['creatorID'],
+        'relationship_type_id' => substr($relationshipType, 0, -4),
         'is_active' => 1,
         'case_id' => $params['caseID'],
         'start_date' => date("Ymd"),
         'end_date' => CRM_Utils_Array::value('relationship_end_date', $params),
       ];
 
+      if (substr($relationshipType, -4) == '_b_a') {
+        $relationshipParams['contact_id_b'] = $clientId;
+        $relationshipParams['contact_id_a'] = $params['creatorID'];
+      }
+      if (substr($relationshipType, -4) == '_a_b') {
+        $relationshipParams['contact_id_a'] = $clientId;
+        $relationshipParams['contact_id_b'] = $params['creatorID'];
+      }
+
       if (!$this->createRelationship($relationshipParams)) {
         CRM_Core_Error::fatal();
         return FALSE;
@@ -343,6 +356,8 @@ class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
   }
 
   /**
+   * Relationships are straight from XML, described from perspective of non-client
+   *
    * @param SimpleXMLElement $caseTypeXML
    *
    * @return array<string> symbolic relationship-type names
diff --git a/civicrm/CRM/Case/XMLProcessor/Report.php b/civicrm/CRM/Case/XMLProcessor/Report.php
index 98534dc95ec8fe2e6aababc572f8c1334ab6def5..2915874f79e57ed5d0668c8569f25d17fb3b060e 100644
--- a/civicrm/CRM/Case/XMLProcessor/Report.php
+++ b/civicrm/CRM/Case/XMLProcessor/Report.php
@@ -824,8 +824,8 @@ LIMIT  1
     $xmlProcessor = new CRM_Case_XMLProcessor_Process();
     $caseRoles = $xmlProcessor->get($caseType, 'CaseRoles');
     foreach ($caseRelationships as $key => & $value) {
-      if (!empty($caseRoles[$value['relation_type']])) {
-        unset($caseRoles[$value['relation_type']]);
+      if (!empty($caseRoles[$value['relation_type'] . '_' . $value['relationship_direction']])) {
+        unset($caseRoles[$value['relation_type'] . '_' . $value['relationship_direction']]);
       }
       if ($isRedact) {
         if (!array_key_exists($value['name'], $report->_redactionStringRules)) {
diff --git a/civicrm/CRM/Case/XMLRepository.php b/civicrm/CRM/Case/XMLRepository.php
index 54011e77e3b91aa0da88799ea7d85d06520febf7..243c74c5cc7325a38b74cb97806c61b9acc960d0 100644
--- a/civicrm/CRM/Case/XMLRepository.php
+++ b/civicrm/CRM/Case/XMLRepository.php
@@ -258,6 +258,8 @@ class CRM_Case_XMLRepository {
   }
 
   /**
+   * Relationships are straight from XML, described from perspective of non-client
+   *
    * @return array<string> symbolic-names of relationship-types
    */
   public function getAllDeclaredRelationshipTypes() {
diff --git a/civicrm/CRM/Contact/BAO/Contact.php b/civicrm/CRM/Contact/BAO/Contact.php
index cf540790ed10087b353470fce00e9e8ed74fb8a8..a6f660669d429b6883f3cb9ea504d116a1ce8e0e 100644
--- a/civicrm/CRM/Contact/BAO/Contact.php
+++ b/civicrm/CRM/Contact/BAO/Contact.php
@@ -128,7 +128,7 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
       if (empty($params['contact_sub_type'])) {
         $params['contact_sub_type'] = 'null';
       }
-      else {
+      elseif ($params['contact_sub_type'] !== 'null') {
         if (!CRM_Contact_BAO_ContactType::isExtendsContactType($params['contact_sub_type'],
           $params['contact_type'], TRUE
         )
@@ -140,11 +140,6 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
         $params['contact_sub_type'] = CRM_Utils_Array::implodePadded($params['contact_sub_type']);
       }
     }
-    else {
-      // Reset the value.
-      // CRM-101XX.
-      $params['contact_sub_type'] = 'null';
-    }
 
     if (isset($params['preferred_communication_method']) && is_array($params['preferred_communication_method'])) {
       CRM_Utils_Array::formatArrayKeys($params['preferred_communication_method']);
@@ -272,18 +267,25 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
       return $contact;
     }
 
-    if (!empty($params['contact_id']) && empty($params['contact_type'])) {
+    $isEdit = !empty($params['contact_id']);
+
+    if ($isEdit && empty($params['contact_type'])) {
       $params['contact_type'] = self::getContactType($params['contact_id']);
     }
 
-    $isEdit = TRUE;
+    if (!empty($params['check_permissions']) && isset($params['api_key'])
+      && !CRM_Core_Permission::check([['edit api keys', 'administer CiviCRM']])
+      && !($isEdit && CRM_Core_Permission::check('edit own api keys') && $params['contact_id'] == CRM_Core_Session::getLoggedInContactID())
+    ) {
+      throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify api key');
+    }
+
     if ($invokeHooks) {
       if (!empty($params['contact_id'])) {
         CRM_Utils_Hook::pre('edit', $params['contact_type'], $params['contact_id'], $params);
       }
       else {
         CRM_Utils_Hook::pre('create', $params['contact_type'], NULL, $params);
-        $isEdit = FALSE;
       }
     }
 
@@ -374,7 +376,7 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
             'subject' => CRM_Utils_Array::value('subject', $note),
             'contact_id' => $contactId,
           );
-          CRM_Core_BAO_Note::add($noteParams, CRM_Core_DAO::$_nullArray);
+          CRM_Core_BAO_Note::add($noteParams);
         }
       }
       else {
@@ -391,7 +393,7 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
           'subject' => CRM_Utils_Array::value('subject', $params),
           'contact_id' => $contactId,
         );
-        CRM_Core_BAO_Note::add($noteParams, CRM_Core_DAO::$_nullArray);
+        CRM_Core_BAO_Note::add($noteParams);
       }
     }
 
@@ -442,9 +444,36 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
       self::processGreetings($contact);
     }
 
+    if (!empty($params['check_permissions'])) {
+      $contacts = [&$contact];
+      self::unsetProtectedFields($contacts);
+    }
+
     return $contact;
   }
 
+  /**
+   * Format the output of the create contact function
+   * @param CRM_Contact_DAO_Contact[]|array[] $contacts
+   */
+  public static function unsetProtectedFields(&$contacts) {
+    if (!CRM_Core_Permission::check([['edit api keys', 'administer CiviCRM']])) {
+      $currentUser = CRM_Core_Session::getLoggedInContactID();
+      $editOwn = $currentUser && CRM_Core_Permission::check('edit own api keys');
+      foreach ($contacts as &$contact) {
+        $cid = is_object($contact) ? $contact->id : CRM_Utils_Array::value('id', $contact);
+        if (!($editOwn && $cid == $currentUser)) {
+          if (is_object($contact)) {
+            unset($contact->api_key);
+          }
+          else {
+            unset($contact['api_key']);
+          }
+        }
+      }
+    }
+  }
+
   /**
    * Ensure greeting parameters are set.
    *
@@ -549,13 +578,15 @@ WHERE     civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer');
    * Add billing fields to the params if appropriate.
    *
    * If we have ANY name fields then we want to ignore all the billing name fields. However, if we
-   * don't then we should set the name fields to the filling fields AND add the preserveDBName
+   * don't then we should set the name fields to the billing fields AND add the preserveDBName
    * parameter (which will tell the BAO only to set those fields if none already exist.
    *
    * We specifically don't want to set first name from billing and last name form an on-page field. Mixing &
    * matching is best done by hipsters.
    *
    * @param array $params
+   *
+   * @fixme How does this relate to almost the same thing being done in CRM_Core_Form::formatParamsForPaymentProcessor()
    */
   public static function addBillingNameFieldsIfOtherwiseNotSet(&$params) {
     $nameFields = array('first_name', 'middle_name', 'last_name', 'nick_name', 'prefix_id', 'suffix_id');
@@ -1318,6 +1349,7 @@ WHERE     civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer');
     $cacheKeyString .= $showAll ? '_1' : '_0';
     $cacheKeyString .= $isProfile ? '_1' : '_0';
     $cacheKeyString .= $checkPermission ? '_1' : '_0';
+    $cacheKeyString .= '_' . CRM_Core_Config::domainID() . '_';
 
     $fields = CRM_Utils_Array::value($cacheKeyString, self::$_importableFields);
 
@@ -1962,7 +1994,7 @@ ORDER BY civicrm_email.is_primary DESC";
    */
   public static function createProfileContact(
     &$params,
-    &$fields,
+    &$fields = [],
     $contactID = NULL,
     $addToGroupID = NULL,
     $ufGroupId = NULL,
diff --git a/civicrm/CRM/Contact/BAO/Contact/Utils.php b/civicrm/CRM/Contact/BAO/Contact/Utils.php
index a839ce5626e2ce1a689762ee748e9146a6cd97c7..8850d9acc50227b806e5711cbe3223976740535c 100644
--- a/civicrm/CRM/Contact/BAO/Contact/Utils.php
+++ b/civicrm/CRM/Contact/BAO/Contact/Utils.php
@@ -132,9 +132,7 @@ SELECT count( DISTINCT contact_type )
 FROM   civicrm_contact
 WHERE  id IN ( $idString )
 ";
-    $count = CRM_Core_DAO::singleValueQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    $count = CRM_Core_DAO::singleValueQuery($query);
     return $count > 1 ? TRUE : FALSE;
   }
 
diff --git a/civicrm/CRM/Contact/BAO/GroupNestingCache.php b/civicrm/CRM/Contact/BAO/GroupNestingCache.php
index e48d988b902362c3d178077dfe85cf7d2dd8b50b..49efecdcef23934ba86814fbe7adcba158c52b07 100644
--- a/civicrm/CRM/Contact/BAO/GroupNestingCache.php
+++ b/civicrm/CRM/Contact/BAO/GroupNestingCache.php
@@ -100,7 +100,7 @@ WHERE  id = $id
     }
 
     // this tree stuff is quite useful, so lets store it in the cache
-    CRM_Core_BAO_Cache::setItem($tree, 'contact groups', 'nestable tree hierarchy');
+    Civi::cache('groups')->set('nestable tree hierarchy', $tree);
   }
 
   /**
@@ -153,11 +153,11 @@ WHERE  id = $id
    * @return array
    */
   public static function getPotentialCandidates($id, &$groups) {
-    $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
+    $tree = Civi::cache('groups')->get('nestable tree hierarchy');
 
     if ($tree === NULL) {
       self::update();
-      $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
+      $tree = Civi::cache('groups')->get('nestable tree hierarchy');
     }
 
     $potential = $groups;
@@ -219,11 +219,11 @@ WHERE  id = $id
    * @return string
    */
   public static function json() {
-    $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
+    $tree = Civi::cache('groups')->get('nestable tree hierarchy');
 
     if ($tree === NULL) {
       self::update();
-      $tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
+      $tree = Civi::cache('groups')->get('nestable tree hierarchy');
     }
 
     // get all the groups
diff --git a/civicrm/CRM/Contact/BAO/Query.php b/civicrm/CRM/Contact/BAO/Query.php
index 11aa9f4996f3900dcd791ced6372f72952c57333..ab5e7f69d06f46bc270cd6638e7be3033216fabf 100644
--- a/civicrm/CRM/Contact/BAO/Query.php
+++ b/civicrm/CRM/Contact/BAO/Query.php
@@ -607,7 +607,7 @@ class CRM_Contact_BAO_Query {
       if (empty($value[0])) {
         continue;
       }
-      $cfID = CRM_Core_BAO_CustomField::getKeyID($value[0]);
+      $cfID = CRM_Core_BAO_CustomField::getKeyID(str_replace('_relative', '', $value[0]));
       if ($cfID) {
         if (!array_key_exists($cfID, $this->_cfIDs)) {
           $this->_cfIDs[$cfID] = [];
@@ -1554,7 +1554,7 @@ class CRM_Contact_BAO_Query {
 
     self::filterCountryFromValuesIfStateExists($formValues);
     // We shouldn't have to whitelist fields to not hack but here we are, for now.
-    $nonLegacyDateFields = ['participant_register_date_relative'];
+    $nonLegacyDateFields = ['participant_register_date_relative', 'receive_date_relative'];
     // Handle relative dates first
     foreach (array_keys($formValues) as $id) {
       if (
@@ -1638,8 +1638,7 @@ class CRM_Contact_BAO_Query {
       }
       elseif (substr($id, 0, 7) == 'custom_'
         &&  (
-          substr($id, -9, 9) == '_relative'
-          || substr($id, -5, 5) == '_from'
+          substr($id, -5, 5) == '_from'
           || substr($id, -3, 3) == '_to'
         )
       ) {
@@ -2140,6 +2139,12 @@ class CRM_Contact_BAO_Query {
       $field = CRM_Utils_Array::value($locType[0], $this->_fields);
 
       if (!$field) {
+        // Strip any trailing _high & _low that might be appended.
+        $realFieldName = str_replace(['_high', '_low'], '', $name);
+        if (isset($this->_fields[$realFieldName])) {
+          $field = $this->_fields[str_replace(['_high', '_low'], '', $realFieldName)];
+          $this->dateQueryBuilder($values, $field['table_name'], $realFieldName, $realFieldName, $field['title']);
+        }
         return;
       }
     }
@@ -2656,7 +2661,7 @@ class CRM_Contact_BAO_Query {
         continue;
       }
 
-      $from .= self::getEntitySpecificJoins($name, $mode, $side, $primaryLocation);
+      $from .= ' ' . trim(self::getEntitySpecificJoins($name, $mode, $side, $primaryLocation)) . ' ';
     }
     return $from;
   }
@@ -5227,6 +5232,7 @@ civicrm_relationship.start_date > {$today}
     $appendTimeStamp = TRUE,
     $dateFormat = 'YmdHis'
   ) {
+    // @todo - remove dateFormat - pretty sure it's never passed in...
     list($name, $op, $value, $grouping, $wildcard) = $values;
 
     if ($name == "{$fieldName}_low" ||
@@ -6925,7 +6931,9 @@ AND   displayRelType.is_active = 1
     $tableName = $fieldSpec['table_name'];
     $filters = CRM_Core_OptionGroup::values('relative_date_filters');
     $grouping = CRM_Utils_Array::value(3, $values);
-    $this->_tables[$tableName] = $this->_whereTables[$tableName] = 1;
+    // If the table value is already set for a custom field it will be more nuanced than just '1'.
+    $this->_tables[$tableName] = $this->_tables[$tableName] ?? 1;
+    $this->_whereTables[$tableName] = $this->_whereTables[$tableName] ?? 1;
 
     $dates = CRM_Utils_Date::getFromTo($value, NULL, NULL);
     if (empty($dates[0])) {
diff --git a/civicrm/CRM/Contact/BAO/Relationship.php b/civicrm/CRM/Contact/BAO/Relationship.php
index 4898e7f204dbb045d68c315d0a16b1781198a5c9..1f10c643020d11d00d344a0aad50a2ff086df846 100644
--- a/civicrm/CRM/Contact/BAO/Relationship.php
+++ b/civicrm/CRM/Contact/BAO/Relationship.php
@@ -1751,7 +1751,7 @@ SELECT count(*)
     AND is_current_member = 1";
             $result = CRM_Core_DAO::singleValueQuery($query);
             if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) {
-              CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray);
+              CRM_Member_BAO_Membership::create($membershipValues);
             }
           }
         }
diff --git a/civicrm/CRM/Contact/BAO/SavedSearch.php b/civicrm/CRM/Contact/BAO/SavedSearch.php
index 46886c6413600608b35aedfeb390ba49900deb89..b3561a72fed2ab933d3e6386e5958bab7adcd1c9 100644
--- a/civicrm/CRM/Contact/BAO/SavedSearch.php
+++ b/civicrm/CRM/Contact/BAO/SavedSearch.php
@@ -434,10 +434,12 @@ LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_
    * @param array $formValues
    */
   public static function saveRelativeDates(&$queryParams, $formValues) {
+    // This is required only until all fields are converted to datepicker fields as the new format is truer to the
+    // form format and simply saves (e.g) custom_3_relative => "this.year"
     $relativeDates = ['relative_dates' => []];
     $specialDateFields = ['event_relative', 'case_from_relative', 'case_to_relative', 'participant_relative'];
     foreach ($formValues as $id => $value) {
-      if ((preg_match('/(_date|custom_[0-9]+)_relative$/', $id) || in_array($id, $specialDateFields)) && !empty($value)) {
+      if ((preg_match('/_date$/', $id) || in_array($id, $specialDateFields)) && !empty($value)) {
         $entityName = strstr($id, '_date', TRUE);
         if (empty($entityName)) {
           $entityName = strstr($id, '_relative', TRUE);
diff --git a/civicrm/CRM/Contact/DAO/ACLContactCache.php b/civicrm/CRM/Contact/DAO/ACLContactCache.php
index 1134bf2a1c995e8f8b22a638d50bb848ff7e0713..b62b6e482e4e9e5f4562ca4d2a760126c484bfc0 100644
--- a/civicrm/CRM/Contact/DAO/ACLContactCache.php
+++ b/civicrm/CRM/Contact/DAO/ACLContactCache.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/ACLContactCache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:8bc987e1284d464f9b475686d9dc32a2)
+ * (GenCodeChecksum:de29bdc03ca3c85509bde973de137240)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/Contact.php b/civicrm/CRM/Contact/DAO/Contact.php
index 139e0e71c02a1a8218e3c0766fc07dc54f9368a5..3b662f4815894e9f819a748a7848fd244cab1e91 100644
--- a/civicrm/CRM/Contact/DAO/Contact.php
+++ b/civicrm/CRM/Contact/DAO/Contact.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/Contact.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e2181ea97a3e309b7e74b636757b6aac)
+ * (GenCodeChecksum:881cb541dcc67f4520c7cf44d65d047d)
  */
 
 /**
@@ -805,7 +805,12 @@ class CRM_Contact_DAO_Contact extends CRM_Core_DAO {
           'maxlength' => 32,
           'size' => CRM_Utils_Type::MEDIUM,
           'where' => 'civicrm_contact.api_key',
-          'protected' => 'true',
+          'permission' => [
+            [
+              'administer CiviCRM',
+              'edit api keys',
+            ],
+          ],
           'table_name' => 'civicrm_contact',
           'entity' => 'Contact',
           'bao' => 'CRM_Contact_BAO_Contact',
diff --git a/civicrm/CRM/Contact/DAO/ContactType.php b/civicrm/CRM/Contact/DAO/ContactType.php
index a999b9d40292d1ef6aca1d69d848b9eb2a4eca88..78e7b6680c21b5e9446bd9bd4329cccd987a07ee 100644
--- a/civicrm/CRM/Contact/DAO/ContactType.php
+++ b/civicrm/CRM/Contact/DAO/ContactType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/ContactType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:adba53a6a4d64ba498d7e36b03c0f968)
+ * (GenCodeChecksum:4b0fb96273ba6a1e4e767dfa25453688)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/DashboardContact.php b/civicrm/CRM/Contact/DAO/DashboardContact.php
index edb5b3e3528b701c819442acaeb666c904793fbf..1684bbefb6e824ea13053327ad5164af7c41a75e 100644
--- a/civicrm/CRM/Contact/DAO/DashboardContact.php
+++ b/civicrm/CRM/Contact/DAO/DashboardContact.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/DashboardContact.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2adb5645722410e9059da0a345a0a30b)
+ * (GenCodeChecksum:a1e9fb0cd3adf30a24d357fc8d1635b4)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/Group.php b/civicrm/CRM/Contact/DAO/Group.php
index 3e2eddaf1f04e8cc1bccceb4bb3c14b9f27dcace..20d066e94f6595ed5d0c8f67a808cb6c4814d744 100644
--- a/civicrm/CRM/Contact/DAO/Group.php
+++ b/civicrm/CRM/Contact/DAO/Group.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/Group.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:28c32e7038a2b7aa7ca2c45117660974)
+ * (GenCodeChecksum:1d60242104df0a4f536e0f317ad70eef)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/GroupContact.php b/civicrm/CRM/Contact/DAO/GroupContact.php
index ba7352ccf1923c971427e5ebc9fc49489adb51d6..5e651f25c66b356790a67fc395c0d0519c6006a3 100644
--- a/civicrm/CRM/Contact/DAO/GroupContact.php
+++ b/civicrm/CRM/Contact/DAO/GroupContact.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/GroupContact.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:abb2a96c7fd72f93619b605fbb11b4b5)
+ * (GenCodeChecksum:68d2a6dddcaeb556fb8f688e8c035f65)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/GroupContactCache.php b/civicrm/CRM/Contact/DAO/GroupContactCache.php
index c6697590c45e9783378879e9cb1a0fdb8bace286..5157e2cf534780cd914ae6ba073813e11d430c88 100644
--- a/civicrm/CRM/Contact/DAO/GroupContactCache.php
+++ b/civicrm/CRM/Contact/DAO/GroupContactCache.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/GroupContactCache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:217f20fad2d47f50e3a9c43b62df2c17)
+ * (GenCodeChecksum:76b51ba6400cb7eabe4278e34a733df6)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/GroupNesting.php b/civicrm/CRM/Contact/DAO/GroupNesting.php
index bbc3cf99366886d09199cf35c88efecac4d9c9c3..ff40b3bd70b6a2a6d0aaf18f60d50ad4133bc011 100644
--- a/civicrm/CRM/Contact/DAO/GroupNesting.php
+++ b/civicrm/CRM/Contact/DAO/GroupNesting.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/GroupNesting.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2559ff6c3da8f02b147577a6d4e26004)
+ * (GenCodeChecksum:3f80175bbbca60e85ffc680bc191a74e)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/GroupOrganization.php b/civicrm/CRM/Contact/DAO/GroupOrganization.php
index d35db86708f7015ab4fbe25571213e389badd05f..2b81492759177a2329284837855c25402f8e3ad6 100644
--- a/civicrm/CRM/Contact/DAO/GroupOrganization.php
+++ b/civicrm/CRM/Contact/DAO/GroupOrganization.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/GroupOrganization.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:00717d9edb0719d380b5fd7c3e91bc74)
+ * (GenCodeChecksum:fb8f634bd98fa9467d94c41c11b4b83d)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/Relationship.php b/civicrm/CRM/Contact/DAO/Relationship.php
index 0eb497e53b380317d41b6944959a7a7b10028a86..1f3778e22b82cbdc89004ed4f874c81bc105b11e 100644
--- a/civicrm/CRM/Contact/DAO/Relationship.php
+++ b/civicrm/CRM/Contact/DAO/Relationship.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/Relationship.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ebfcea88ae4bd09a0821a942ecdfa4db)
+ * (GenCodeChecksum:79b9fa57db6e675d1d366f69afca215d)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/RelationshipType.php b/civicrm/CRM/Contact/DAO/RelationshipType.php
index edb59a6b76d131d23bbd0608b2f16d9d982619d2..c5a9278a672ce6774ce0c73486b55df15b28987b 100644
--- a/civicrm/CRM/Contact/DAO/RelationshipType.php
+++ b/civicrm/CRM/Contact/DAO/RelationshipType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/RelationshipType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:78a8cea89e73b1a409f7908ad08cf99e)
+ * (GenCodeChecksum:4f2d363d1dc33b8b4dcbf82b72da2c79)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/SavedSearch.php b/civicrm/CRM/Contact/DAO/SavedSearch.php
index 32eab9829360f3801769d5a691bec173e92e4c34..e9cf758ade8aefe3e41b9a0138e39a0aa74251bb 100644
--- a/civicrm/CRM/Contact/DAO/SavedSearch.php
+++ b/civicrm/CRM/Contact/DAO/SavedSearch.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/SavedSearch.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:556322817dc9b7b9dab015e1f0179fb7)
+ * (GenCodeChecksum:0b26e371ea12eb1b8a948c28ba923d32)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/DAO/SubscriptionHistory.php b/civicrm/CRM/Contact/DAO/SubscriptionHistory.php
index dd16bbcd649849b656c0769b7ec1bf8666220062..bf79a94348e21a6d31ac73045be6465ac27966df 100644
--- a/civicrm/CRM/Contact/DAO/SubscriptionHistory.php
+++ b/civicrm/CRM/Contact/DAO/SubscriptionHistory.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/SubscriptionHistory.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:af7ac35767e88f1dd090f54ab44c3b35)
+ * (GenCodeChecksum:8d39eedce498de37290f0702f7a84773)
  */
 
 /**
diff --git a/civicrm/CRM/Contact/Form/Search/Criteria.php b/civicrm/CRM/Contact/Form/Search/Criteria.php
index 1a533342a05e6ac8ab4e603d122229b93dbda4a9..0532894df383ff8e39050db269bee1a27348e594 100644
--- a/civicrm/CRM/Contact/Form/Search/Criteria.php
+++ b/civicrm/CRM/Contact/Form/Search/Criteria.php
@@ -275,7 +275,13 @@ class CRM_Contact_Form_Search_Criteria {
    * @param CRM_Core_Form $form
    */
   protected static function setBasicSearchFields($form) {
-    $form->assign('basicSearchFields', self::getBasicSearchFields());
+    $searchFields = [];
+    foreach (self::getSearchFieldMetadata() as $fieldName => $field) {
+      if ($field['template_grouping'] === 'basic') {
+        $searchFields[$fieldName] = $field;
+      }
+    }
+    $form->assign('basicSearchFields', array_merge(self::getBasicSearchFields(), $searchFields));
   }
 
   /**
@@ -285,7 +291,8 @@ class CRM_Contact_Form_Search_Criteria {
   public static function getBasicSearchFields() {
     $userFramework = CRM_Core_Config::singleton()->userFramework;
     return [
-      'sort_name' => ['name' => 'sort_name'],
+      // For now an empty array is still left in place for ordering.
+      'sort_name' => [],
       'email' => ['name' => 'email'],
       'contact_type' => ['name' => 'contact_type'],
       'group' => [
diff --git a/civicrm/CRM/Contact/Form/Search/Custom/ActivitySearch.php b/civicrm/CRM/Contact/Form/Search/Custom/ActivitySearch.php
index afda78618c2c1b44213df67ddbfc2b8c17df9a4f..30d95f1847610477d06691ef3a7883547d867e9e 100644
--- a/civicrm/CRM/Contact/Form/Search/Custom/ActivitySearch.php
+++ b/civicrm/CRM/Contact/Form/Search/Custom/ActivitySearch.php
@@ -368,9 +368,7 @@ ORDER BY contact_a.sort_name';
   public function count() {
     $sql = $this->all();
 
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     return $dao->N;
   }
 
diff --git a/civicrm/CRM/Contact/Form/Search/Custom/Base.php b/civicrm/CRM/Contact/Form/Search/Custom/Base.php
index b4edd5986d433669514cea7ece71802b0c00cf32..9baf5429b3ed21345c52a8c399806582c6fce281 100644
--- a/civicrm/CRM/Contact/Form/Search/Custom/Base.php
+++ b/civicrm/CRM/Contact/Form/Search/Custom/Base.php
@@ -95,7 +95,7 @@ class CRM_Contact_Form_Search_Custom_Base {
       return $sql;
     }
 
-    return CRM_Core_DAO::composeQuery($sql, CRM_Core_DAO::$_nullArray);
+    return CRM_Core_DAO::composeQuery($sql);
   }
 
   /**
diff --git a/civicrm/CRM/Contact/Form/Search/Custom/ContributionAggregate.php b/civicrm/CRM/Contact/Form/Search/Custom/ContributionAggregate.php
index f776f8448e2d1afb555abcf8aff8e7f8a668e897..5437e0d2a0253d706cd3008f4032274b06b4996d 100644
--- a/civicrm/CRM/Contact/Form/Search/Custom/ContributionAggregate.php
+++ b/civicrm/CRM/Contact/Form/Search/Custom/ContributionAggregate.php
@@ -63,6 +63,8 @@ class CRM_Contact_Form_Search_Custom_ContributionAggregate extends CRM_Contact_F
    * @param CRM_Core_Form $form
    */
   public function buildForm(&$form) {
+    $form->addSearchFieldMetadata(['Contribution' => self::getSearchFieldMetadata()]);
+    $form->addFormFieldsFromMetadata();
 
     /**
      * You can define a custom title for the search form
@@ -83,7 +85,6 @@ class CRM_Contact_Form_Search_Custom_ContributionAggregate extends CRM_Contact_F
       ts('...and $')
     );
     $form->addRule('max_amount', ts('Please enter a valid amount (numbers and decimal point only).'), 'money');
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_date', 1, '_low', '_high', ts('From:'), FALSE, FALSE);
 
     $form->addSelect('financial_type_id',
       ['entity' => 'contribution', 'multiple' => 'multiple', 'context' => 'search']
@@ -187,6 +188,20 @@ civicrm_contact AS contact_a {$this->_aclFrom}
     return $from;
   }
 
+  /**
+   * Get the metadata for fields to be included on the contact search form.
+   */
+  public static function getSearchFieldMetadata() {
+    $fields = [
+      'receive_date' => ['title' => ''],
+    ];
+    $metadata = civicrm_api3('Contribution', 'getfields', [])['values'];
+    foreach ($fields as $fieldName => $field) {
+      $fields[$fieldName] = array_merge(CRM_Utils_Array::value($fieldName, $metadata, []), $field);
+    }
+    return $fields;
+  }
+
   /**
    * WHERE clause is an array built from any required JOINS plus conditional filters based on search criteria field values.
    *
@@ -201,9 +216,9 @@ civicrm_contact AS contact_a {$this->_aclFrom}
     ];
 
     foreach ([
-      'contribution_date_relative',
-      'contribution_date_low',
-      'contribution_date_high',
+      'receive_date_relative',
+      'receive_date_low',
+      'receive_date_high',
     ] as $dateFieldName) {
       $dateParams[$dateFieldName] = CRM_Utils_Array::value(
         $dateFieldName,
@@ -214,10 +229,16 @@ civicrm_contact AS contact_a {$this->_aclFrom}
     foreach (CRM_Contact_BAO_Query::convertFormValues($dateParams) as $values) {
       list($name, $op, $value) = $values;
       if (strstr($name, '_low')) {
-        $clauses[] = "contrib.receive_date >= " . CRM_Utils_Date::processDate($value);
+        if (strlen($value) == 10) {
+          $value .= ' 00:00:00';
+        }
+        $clauses[] = "contrib.receive_date >= '{$value}'";
       }
       else {
-        $clauses[] = "contrib.receive_date <= " . CRM_Utils_Date::processDate($value);
+        if (strlen($value) == 10) {
+          $value .= ' 23:59:59';
+        }
+        $clauses[] = "contrib.receive_date <= '{$value}'";
       }
     }
 
@@ -280,9 +301,7 @@ civicrm_contact AS contact_a {$this->_aclFrom}
   public function count() {
     $sql = $this->all();
 
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     return $dao->N;
   }
 
diff --git a/civicrm/CRM/Contact/Form/Search/Custom/DateAdded.php b/civicrm/CRM/Contact/Form/Search/Custom/DateAdded.php
index f3be4f2e2d97d599c906c81907c5475201fc2183..12b3a03e54ff1f6e04802d0760fdd9b0e49d2ac0 100644
--- a/civicrm/CRM/Contact/Form/Search/Custom/DateAdded.php
+++ b/civicrm/CRM/Contact/Form/Search/Custom/DateAdded.php
@@ -211,7 +211,7 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
               date_added >= '$startDate 00:00:00'
               $endDateFix";
 
-    CRM_Core_DAO::executeQuery($dateRange, CRM_Core_DAO::$_nullArray);
+    CRM_Core_DAO::executeQuery($dateRange);
 
     // Only include groups in the search query of one or more Include OR Exclude groups has been selected.
     // CRM-6356
@@ -256,7 +256,7 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
                      civicrm_group_contact.status = 'Added' AND
                      civicrm_group_contact.group_id IN( {$xGroups})";
 
-        CRM_Core_DAO::executeQuery($excludeGroup, CRM_Core_DAO::$_nullArray);
+        CRM_Core_DAO::executeQuery($excludeGroup);
 
         //search for smart group contacts
         foreach ($this->_excludeGroups as $keys => $values) {
@@ -271,7 +271,7 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
 
             $smartGroupQuery = " INSERT IGNORE INTO {$this->_xgTable}(contact_id) $smartSql";
 
-            CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray);
+            CRM_Core_DAO::executeQuery($smartGroupQuery);
           }
         }
       }
@@ -303,7 +303,7 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
         $includeGroup .= " AND  {$this->_xgTable}.contact_id IS null";
       }
 
-      CRM_Core_DAO::executeQuery($includeGroup, CRM_Core_DAO::$_nullArray);
+      CRM_Core_DAO::executeQuery($includeGroup);
 
       //search for smart group contacts
       foreach ($this->_includeGroups as $keys => $values) {
@@ -330,13 +330,13 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
                         {$this->_igTable}(contact_id)
                         $smartSql";
 
-          CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray);
+          CRM_Core_DAO::executeQuery($smartGroupQuery);
           $insertGroupNameQuery = "UPDATE IGNORE {$this->_igTable}
                         SET group_names = (SELECT title FROM civicrm_group
                             WHERE civicrm_group.id = $values)
                         WHERE {$this->_igTable}.contact_id IS NOT NULL
                             AND {$this->_igTable}.group_names IS NULL";
-          CRM_Core_DAO::executeQuery($insertGroupNameQuery, CRM_Core_DAO::$_nullArray);
+          CRM_Core_DAO::executeQuery($insertGroupNameQuery);
         }
       }
     }
@@ -395,9 +395,7 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
   public function count() {
     $sql = $this->all();
 
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     return $dao->N;
   }
 
@@ -405,12 +403,12 @@ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_C
     //drop the temp. tables if they exist
     if ($this->_igTable && !empty($this->_includeGroups)) {
       $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_igTable}";
-      CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
+      CRM_Core_DAO::executeQuery($sql);
     }
 
     if ($this->_xgTable && !empty($this->_excludeGroups)) {
       $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_xgTable}";
-      CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray);
+      CRM_Core_DAO::executeQuery($sql);
     }
   }
 
diff --git a/civicrm/CRM/Contact/Form/Search/Custom/EventAggregate.php b/civicrm/CRM/Contact/Form/Search/Custom/EventAggregate.php
index 441688dab657400d737306576b1ddd79203afc31..e3b36fc95dc76ac3a4e69f5bd37ad9eb72dcf0e3 100644
--- a/civicrm/CRM/Contact/Form/Search/Custom/EventAggregate.php
+++ b/civicrm/CRM/Contact/Form/Search/Custom/EventAggregate.php
@@ -306,9 +306,7 @@ class CRM_Contact_Form_Search_Custom_EventAggregate extends CRM_Contact_Form_Sea
         WHERE   $where
         ";
 
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     $totals = [];
     while ($dao->fetch()) {
       $totals['payment_amount'] = $dao->payment_amount;
@@ -329,9 +327,7 @@ class CRM_Contact_Form_Search_Custom_EventAggregate extends CRM_Contact_Form_Sea
   public function count() {
     $sql = $this->all();
 
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     return $dao->N;
   }
 
diff --git a/civicrm/CRM/Contact/Form/Search/Custom/TagContributions.php b/civicrm/CRM/Contact/Form/Search/Custom/TagContributions.php
index df0e60488fe1774121e44e2a0a83c844f30a1491..d6bd1b17d8ec73456dfa141d52b01e49d5673ea1 100644
--- a/civicrm/CRM/Contact/Form/Search/Custom/TagContributions.php
+++ b/civicrm/CRM/Contact/Form/Search/Custom/TagContributions.php
@@ -229,9 +229,7 @@ WHERE  $where
   public function count() {
     $sql = $this->all();
 
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     return $dao->N;
   }
 
diff --git a/civicrm/CRM/Contact/Form/Task/AddToGroup.php b/civicrm/CRM/Contact/Form/Task/AddToGroup.php
index 2958f6e98eff204d0520096d588fb2dc244aa9ab..a25f920de3ab1fc62a37face7b43ec316fac0539 100644
--- a/civicrm/CRM/Contact/Form/Task/AddToGroup.php
+++ b/civicrm/CRM/Contact/Form/Task/AddToGroup.php
@@ -162,7 +162,7 @@ class CRM_Contact_Form_Task_AddToGroup extends CRM_Contact_Form_Task {
    * Add local and global form rules.
    */
   public function addRules() {
-    $this->addFormRule(['CRM_Contact_Form_task_AddToGroup', 'formRule']);
+    $this->addFormRule(['CRM_Contact_Form_Task_AddToGroup', 'formRule']);
   }
 
   /**
diff --git a/civicrm/CRM/Contact/Page/CustomSearch.php b/civicrm/CRM/Contact/Page/CustomSearch.php
index 15b313f23182753fd6a40afb4f82e2b07fafb021..0ee1969f915b7b7fc3cbafafa72ad330d085f2d6 100644
--- a/civicrm/CRM/Contact/Page/CustomSearch.php
+++ b/civicrm/CRM/Contact/Page/CustomSearch.php
@@ -56,9 +56,7 @@ AND    g.name = 'custom_search'
 AND    v.is_active = 1
 ORDER By  v.weight
 ";
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
 
     $rows = [];
     while ($dao->fetch()) {
diff --git a/civicrm/CRM/Contact/Page/Inline/Website.php b/civicrm/CRM/Contact/Page/Inline/Website.php
index 929ec1e5091c6e49c2bf312ed5b2e800dd7f15bd..5e9ce5ea2c0e782252d0ce8e215a0f199cc7b7c8 100644
--- a/civicrm/CRM/Contact/Page/Inline/Website.php
+++ b/civicrm/CRM/Contact/Page/Inline/Website.php
@@ -48,7 +48,7 @@ class CRM_Contact_Page_Inline_Website extends CRM_Core_Page {
     $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
 
     $params = ['contact_id' => $contactId];
-    $websites = CRM_Core_BAO_Website::getValues($params, CRM_Core_DAO::$_nullArray);
+    $websites = CRM_Core_BAO_Website::getValues($params);
     if (!empty($websites)) {
       foreach ($websites as $key => & $value) {
         $value['website_type'] = $websiteTypes[$value['website_type_id']];
diff --git a/civicrm/CRM/Contact/Selector.php b/civicrm/CRM/Contact/Selector.php
index a560a9adf32b174801cbc0aa9feec73d92bc9b1a..ab894330c7df3e104c24607b9730030f54243b70 100644
--- a/civicrm/CRM/Contact/Selector.php
+++ b/civicrm/CRM/Contact/Selector.php
@@ -1063,7 +1063,7 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
 
     if (Civi::service('prevnext') instanceof CRM_Core_PrevNextCache_Sql) {
       // SQL-backed prevnext cache uses an extra record for pruning the cache.
-      CRM_Core_BAO_Cache::setItem($cacheKey, 'CiviCRM Search PrevNextCache', $cacheKey);
+      Civi::cache('prevNextCache')->set($cacheKey, $cacheKey);
     }
   }
 
diff --git a/civicrm/CRM/Contribute/BAO/Contribution.php b/civicrm/CRM/Contribute/BAO/Contribution.php
index 5ca5894dcafbad2e8c6aa1cfe53d7a40ab45b8ba..82a3e3d6828f0ef0a151c47c7951450fb9361fb6 100644
--- a/civicrm/CRM/Contribute/BAO/Contribution.php
+++ b/civicrm/CRM/Contribute/BAO/Contribution.php
@@ -301,6 +301,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
         FALSE, FALSE, FALSE, 'AND is_default = 1')
       ),
       'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
+      'receive_date' => date('Y-m-d H:i:s'),
     ];
   }
 
@@ -317,7 +318,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
    * @return CRM_Contribute_BAO_Contribution|null
    *   The found object or null
    */
-  public static function getValues($params, &$values, &$ids) {
+  public static function getValues($params, &$values = [], &$ids = []) {
     if (empty($params)) {
       return NULL;
     }
@@ -397,8 +398,8 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
             'id' => $contributionID,
             'return' => ['total_amount', 'net_amount', 'fee_amount'],
           ]);
-          $totalAmount = isset($params['total_amount']) ? $params['total_amount'] : CRM_Utils_Array::value('total_amount', $contribution);
-          $feeAmount = isset($params['fee_amount']) ? $params['fee_amount'] : CRM_Utils_Array::value('fee_amount', $contribution);
+          $totalAmount = (isset($params['total_amount']) ? (float) $params['total_amount'] : (float) CRM_Utils_Array::value('total_amount', $contribution));
+          $feeAmount = (isset($params['fee_amount']) ? (float) $params['fee_amount'] : (float) CRM_Utils_Array::value('fee_amount', $contribution));
           $params['net_amount'] = $totalAmount - $feeAmount;
         }
       }
@@ -495,6 +496,9 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
    * @return CRM_Contribute_BAO_Contribution
    */
   public static function create(&$params, $ids = []) {
+    $contributionID = CRM_Utils_Array::value('contribution', $ids, CRM_Utils_Array::value('id', $params));
+    $action = $contributionID ? 'edit' : 'create';
+
     $dateFields = [
       'receive_date',
       'cancel_date',
@@ -523,7 +527,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     if (!empty($params['custom']) &&
       is_array($params['custom'])
     ) {
-      CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_contribution', $contribution->id);
+      CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_contribution', $contribution->id, $action);
     }
 
     $session = CRM_Core_Session::singleton();
@@ -705,7 +709,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
    *
    * @return CRM_Contribute_BAO_Contribution
    */
-  public static function retrieve(&$params, &$defaults, &$ids) {
+  public static function retrieve(&$params, &$defaults = [], &$ids = []) {
     $contribution = CRM_Contribute_BAO_Contribution::getValues($params, $defaults, $ids);
     return $contribution;
   }
@@ -941,7 +945,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
    *
    * @return int
    */
-  protected static function getToFinancialAccount($contribution, $params) {
+  public static function getToFinancialAccount($contribution, $params) {
     $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
     CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
     $pendingStatus = [
@@ -2943,13 +2947,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
           if (!isset($this->_relatedObjects['contributionPage'])) {
             $this->loadRelatedEntitiesByID(['contributionPage' => $this->contribution_page_id]);
           }
-          // CRM-8254 - override default currency if applicable
-          $config = CRM_Core_Config::singleton();
-          $config->defaultCurrency = CRM_Utils_Array::value(
-            'currency',
-            $values,
-            $config->defaultCurrency
-          );
+          CRM_Contribute_BAO_Contribution_Utils::overrideDefaultCurrency($values);
         }
       }
       // no contribution page -probably back office
@@ -4501,8 +4499,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     $primaryContributionID = isset($contribution->id) ? $contribution->id : $objects['first_contribution']->id;
     // The previous details are used when calculating line items so keep it before any code that 'does something'
     if (!empty($contribution->id)) {
-      $input['prevContribution'] = CRM_Contribute_BAO_Contribution::getValues(['id' => $contribution->id],
-        CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray);
+      $input['prevContribution'] = CRM_Contribute_BAO_Contribution::getValues(['id' => $contribution->id]);
     }
     $inputContributionWhiteList = [
       'fee_amount',
@@ -4741,7 +4738,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     // Use input value if supplied.
     if (!empty($input['receipt_from_email'])) {
       return [
-        CRM_Utils_array::value('receipt_from_name', $input, ''),
+        CRM_Utils_Array::value('receipt_from_name', $input, ''),
         $input['receipt_from_email'],
       ];
     }
@@ -4847,7 +4844,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
    * @return CRM_Financial_DAO_FinancialTrxn
    */
   public static function recordPartialPayment($contribution, $params) {
-
+    CRM_Core_Error::deprecatedFunctionWarning('use payment create api');
     $balanceTrxnParams['to_financial_account_id'] = self::getToFinancialAccount($contribution, $params);
     $balanceTrxnParams['from_financial_account_id'] = CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship($contribution['financial_type_id'], 'Accounts Receivable Account is');
     $balanceTrxnParams['total_amount'] = $params['total_amount'];
@@ -5246,7 +5243,7 @@ LEFT JOIN  civicrm_contribution on (civicrm_contribution.contact_id = civicrm_co
    * @return \CRM_Contribute_BAO_Contribution|null
    */
   private static function getOriginalContribution($contributionID) {
-    return self::getValues(['id' => $contributionID], CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray);
+    return self::getValues(['id' => $contributionID]);
   }
 
   /**
diff --git a/civicrm/CRM/Contribute/BAO/Contribution/Utils.php b/civicrm/CRM/Contribute/BAO/Contribution/Utils.php
index 08c84098c3840bb5c0a96036404da5f71a2078f4..ce18d470f36e1ccdeaa35ac56fae7fdb431f9502 100644
--- a/civicrm/CRM/Contribute/BAO/Contribution/Utils.php
+++ b/civicrm/CRM/Contribute/BAO/Contribution/Utils.php
@@ -640,4 +640,16 @@ LIMIT 1
     return $statuses;
   }
 
+  /**
+   * CRM-8254 / CRM-6907 - override default currency if applicable
+   * these lines exist to support a non-default currency on the form but are probably
+   * obsolete & meddling wth the defaultCurrency is not the right approach....
+   *
+   * @param array $params
+   */
+  public static function overrideDefaultCurrency($params) {
+    $config = CRM_Core_Config::singleton();
+    $config->defaultCurrency = CRM_Utils_Array::value('currency', $params, $config->defaultCurrency);
+  }
+
 }
diff --git a/civicrm/CRM/Contribute/BAO/ContributionPage.php b/civicrm/CRM/Contribute/BAO/ContributionPage.php
index fa6c55592e32e76087eafd1c25caa7497d46dea4..164ab946ab2e28a47329c09b60e6d9823e082f16 100644
--- a/civicrm/CRM/Contribute/BAO/ContributionPage.php
+++ b/civicrm/CRM/Contribute/BAO/ContributionPage.php
@@ -734,7 +734,7 @@ FROM civicrm_premiums
 WHERE entity_table = 'civicrm_contribution_page'
       AND entity_id ={$id}";
 
-    $premiumDao = CRM_Core_DAO::executeQuery($premiumQuery, CRM_Core_DAO::$_nullArray);
+    $premiumDao = CRM_Core_DAO::executeQuery($premiumQuery);
     while ($premiumDao->fetch()) {
       if ($premiumDao->id) {
         CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_PremiumsProduct', [
diff --git a/civicrm/CRM/Contribute/BAO/ContributionRecur.php b/civicrm/CRM/Contribute/BAO/ContributionRecur.php
index 5f45d1868f42ea8d12ba68fb4423ed383cc7dabd..b87dba3494ad57b4beddeb1a085552eb19c1b2f4 100644
--- a/civicrm/CRM/Contribute/BAO/ContributionRecur.php
+++ b/civicrm/CRM/Contribute/BAO/ContributionRecur.php
@@ -754,12 +754,6 @@ INNER JOIN civicrm_contribution       con ON ( con.id = mp.contribution_id )
       2 => ts('Recurring contributions with at least one payment'),
     ];
     $form->addRadio('contribution_recur_payment_made', NULL, $recurringPaymentOptions, ['allowClear' => TRUE]);
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_recur_start_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_recur_end_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_recur_modified_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_recur_next_sched_contribution_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_recur_failure_retry_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_recur_cancel_date', 1, '_low', '_high', ts('From'), FALSE, FALSE, 'birth');
 
     // Add field for contribution status
     $form->addSelect('contribution_recur_contribution_status_id',
diff --git a/civicrm/CRM/Contribute/BAO/ContributionSoft.php b/civicrm/CRM/Contribute/BAO/ContributionSoft.php
index 8b7e1ec8c9d66e5ee49a3923a448fd13274d477e..1ddfbedc566d9806359f732003c9328ad002e9c1 100644
--- a/civicrm/CRM/Contribute/BAO/ContributionSoft.php
+++ b/civicrm/CRM/Contribute/BAO/ContributionSoft.php
@@ -168,8 +168,9 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio
         $honorId = CRM_Utils_Array::value(0, $ids);
       }
 
+      $null = [];
       $honorId = CRM_Contact_BAO_Contact::createProfileContact(
-        $params['honor'], CRM_Core_DAO::$_nullArray,
+        $params['honor'], $null,
         $honorId, NULL,
         $form->_values['honoree_profile_id']
       );
diff --git a/civicrm/CRM/Contribute/BAO/Query.php b/civicrm/CRM/Contribute/BAO/Query.php
index e2ad53b2602e1e9824ca9251e7387474d921dca4..1e88c66618714c03369d36a10abb147d14084401 100644
--- a/civicrm/CRM/Contribute/BAO/Query.php
+++ b/civicrm/CRM/Contribute/BAO/Query.php
@@ -115,7 +115,7 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
         continue;
       }
       if (substr($query->_params[$id][0], 0, 13) == 'contribution_' || substr($query->_params[$id][0], 0, 10) == 'financial_'  || substr($query->_params[$id][0], 0, 8) == 'payment_') {
-        if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) {
+        if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) {
           $query->_useDistinct = TRUE;
         }
         // CRM-12065
@@ -186,6 +186,7 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
       case 'contribution_date_low_time':
       case 'contribution_date_high':
       case 'contribution_date_high_time':
+        CRM_Core_Error::deprecatedFunctionWarning('search by receive_date');
         // process to / from date
         $query->dateQueryBuilder($values,
           'civicrm_contribution', 'contribution_date', 'receive_date', ts('Contribution Date')
@@ -835,7 +836,7 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
         // site
         'thankyou_date' => 1,
         // performance
-        'cancel_date' => 1,
+        'contribution_cancel_date' => 1,
         // and
         'total_amount' => 1,
         // torture
@@ -927,6 +928,8 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
       'contribution_source',
       'cancel_reason',
       'invoice_number',
+      'receive_date',
+      'contribution_cancel_date',
     ];
     $metadata = civicrm_api3('Contribution', 'getfields', [])['values'];
     return array_intersect_key($metadata, array_flip($fields));
@@ -944,11 +947,6 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
 
     $form->addSearchFieldMetadata(['Contribution' => self::getSearchFieldMetadata()]);
     $form->addFormFieldsFromMetadata();
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_date', 1, '_low', '_high', ts('From:'), FALSE);
-    // CRM-17602
-    // This hidden element added for displaying Date Range error correctly. Definitely a dirty hack, but... it works.
-    $form->addElement('hidden', 'contribution_date_range_error');
-    $form->addFormRule(['CRM_Contribute_BAO_Query', 'formRule'], $form);
 
     $form->add('text', 'contribution_amount_low', ts('From'), ['size' => 8, 'maxlength' => 8]);
     $form->addRule('contribution_amount_low', ts('Please enter a valid money value (e.g. %1).', [1 => CRM_Utils_Money::format('9.99', ' ')]), 'money');
@@ -956,9 +954,6 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
     $form->add('text', 'contribution_amount_high', ts('To'), ['size' => 8, 'maxlength' => 8]);
     $form->addRule('contribution_amount_high', ts('Please enter a valid money value (e.g. %1).', [1 => CRM_Utils_Money::format('99.99', ' ')]), 'money');
 
-    CRM_Core_Form_Date::buildDateRange($form, 'contribution_cancel_date', 1, '_low', '_high', ts('From:'), FALSE);
-    $form->addElement('hidden', 'contribution_cancel_date_range_error');
-
     // Adding select option for curreny type -- CRM-4711
     $form->add('select', 'contribution_currency_type',
       ts('Currency Type'),
@@ -1127,28 +1122,6 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
     return TRUE;
   }
 
-  /**
-   * Custom form rules.
-   *
-   * @param array $fields
-   * @param array $files
-   * @param CRM_Core_Form $form
-   *
-   * @return bool|array
-   */
-  public static function formRule($fields, $files, $form) {
-    $errors = [];
-
-    if (!empty($fields['contribution_date_high']) && !empty($fields['contribution_date_low'])) {
-      CRM_Utils_Rule::validDateRange($fields, 'contribution_date', $errors, ts('Date Received'));
-    }
-    if (!empty($fields['contribution_cancel_date_high']) && !empty($fields['contribution_cancel_date_low'])) {
-      CRM_Utils_Rule::validDateRange($fields, 'contribution_cancel_date', $errors, ts('Cancel Date'));
-    }
-
-    return empty($errors) ? TRUE : $errors;
-  }
-
   /**
    * Add the soft credit fields to the select fields.
    *
diff --git a/civicrm/CRM/Contribute/BAO/Widget.php b/civicrm/CRM/Contribute/BAO/Widget.php
index e4bff0b4ffec2548eb01f5e4f8ef87666d900e8b..396fae527388269a767623529ffad3fbb07fefdc 100644
--- a/civicrm/CRM/Contribute/BAO/Widget.php
+++ b/civicrm/CRM/Contribute/BAO/Widget.php
@@ -49,7 +49,7 @@ class CRM_Contribute_BAO_Widget extends CRM_Contribute_DAO_Widget {
     $config = CRM_Core_Config::singleton();
 
     $data = [];
-    $data['currencySymbol'] = $config->defaultCurrencySymbol;
+    $data['currencySymbol'] = CRM_Core_BAO_Country::defaultCurrencySymbol();
 
     if (empty($contributionPageID) ||
       CRM_Utils_Type::validate($contributionPageID, 'Integer') == NULL
diff --git a/civicrm/CRM/Contribute/DAO/Contribution.php b/civicrm/CRM/Contribute/DAO/Contribution.php
index b628edef8cc62bb2e23c8986612da24f01f01951..2284edf5472516b8725bb6795efafc2c74e31a21 100644
--- a/civicrm/CRM/Contribute/DAO/Contribution.php
+++ b/civicrm/CRM/Contribute/DAO/Contribution.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/Contribution.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7a81b495b5661ae881321938d4ee38c9)
+ * (GenCodeChecksum:a38f41244c16c766116e56b8df3d4c5e)
  */
 
 /**
@@ -552,10 +552,10 @@ class CRM_Contribute_DAO_Contribution extends CRM_Core_DAO {
             'nameColumn' => 'name',
           ],
         ],
-        'cancel_date' => [
+        'contribution_cancel_date' => [
           'name' => 'cancel_date',
           'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
-          'title' => ts('Cancel Date'),
+          'title' => ts('Cancelled / Refunded Date'),
           'description' => ts('when was gift cancelled'),
           'import' => TRUE,
           'where' => 'civicrm_contribution.cancel_date',
diff --git a/civicrm/CRM/Contribute/DAO/ContributionPage.php b/civicrm/CRM/Contribute/DAO/ContributionPage.php
index e7d37109d37084c79482581a9981215832501733..3f731e4f95b022c7979e1edee98af3efc7e444af 100644
--- a/civicrm/CRM/Contribute/DAO/ContributionPage.php
+++ b/civicrm/CRM/Contribute/DAO/ContributionPage.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/ContributionPage.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c6e11bf69550f2253d2a287e8ebeae3d)
+ * (GenCodeChecksum:476aca3020ef286e4ba5208fa231eb58)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/ContributionProduct.php b/civicrm/CRM/Contribute/DAO/ContributionProduct.php
index 5913150b44b50933f08a82d9d1d4c0703339f9c5..b23eca995a5f519d05b143cd5cd77c4177bce22a 100644
--- a/civicrm/CRM/Contribute/DAO/ContributionProduct.php
+++ b/civicrm/CRM/Contribute/DAO/ContributionProduct.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/ContributionProduct.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:565e6473df8dd62f25ba951b18860b5c)
+ * (GenCodeChecksum:ecc5bc5ad7a739764dbf41e27897d03b)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/ContributionRecur.php b/civicrm/CRM/Contribute/DAO/ContributionRecur.php
index dfc0899bc53b18550edef8b23421651f7d7497fe..ca9594294c0cd5cb167f835c39530c30adb88f61 100644
--- a/civicrm/CRM/Contribute/DAO/ContributionRecur.php
+++ b/civicrm/CRM/Contribute/DAO/ContributionRecur.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/ContributionRecur.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:1efdc763e4b5337f0dc4f9f13bd2d719)
+ * (GenCodeChecksum:1c5a083e992b74571e2a7852de0cdee0)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/ContributionSoft.php b/civicrm/CRM/Contribute/DAO/ContributionSoft.php
index 129b3a32ada6b44e37414eeb9bf37f5de3981de9..ec9594b5d81e5c97e1334218ebfea0dc21613126 100644
--- a/civicrm/CRM/Contribute/DAO/ContributionSoft.php
+++ b/civicrm/CRM/Contribute/DAO/ContributionSoft.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/ContributionSoft.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:12f49d75296e9500e850dd63741372ea)
+ * (GenCodeChecksum:99263c64e6bfa08bf725daf83d6aedcf)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/Premium.php b/civicrm/CRM/Contribute/DAO/Premium.php
index 48a7bfcd2d29bb9036a6ef99a9ac785a7ee415f5..282a55e2b0c5decda73015271706a5677bd71ea5 100644
--- a/civicrm/CRM/Contribute/DAO/Premium.php
+++ b/civicrm/CRM/Contribute/DAO/Premium.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/Premium.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5193d923732bb6b983b32e86e9441d72)
+ * (GenCodeChecksum:10cc32dfc45ec3853caebce2d5b78018)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/PremiumsProduct.php b/civicrm/CRM/Contribute/DAO/PremiumsProduct.php
index cdc9f3e15430426b107bff49a974ab04496bbb69..ed9ae181665231f81f2bc7db252060b44a72677d 100644
--- a/civicrm/CRM/Contribute/DAO/PremiumsProduct.php
+++ b/civicrm/CRM/Contribute/DAO/PremiumsProduct.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/PremiumsProduct.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:400970a4b33e5fc5af3784b5dbf9f90c)
+ * (GenCodeChecksum:1e7a968a1d7448211b025026d2c716d3)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/Product.php b/civicrm/CRM/Contribute/DAO/Product.php
index ad147b0646de9c74880da19fc9d781618493aa1f..a85ae650c35b3d1250e6f1252ff17403ca956542 100644
--- a/civicrm/CRM/Contribute/DAO/Product.php
+++ b/civicrm/CRM/Contribute/DAO/Product.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/Product.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:27002591d220b4bc2498b367bef17367)
+ * (GenCodeChecksum:bbb44dd82a92de8b8fc92d095c0651f6)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/DAO/Widget.php b/civicrm/CRM/Contribute/DAO/Widget.php
index aa2cbc3fab303b95e4f4f5d58b11931cac354189..a90456f89131ae0bb2a8b45ed860ece51bc6e3b7 100644
--- a/civicrm/CRM/Contribute/DAO/Widget.php
+++ b/civicrm/CRM/Contribute/DAO/Widget.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/Widget.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c958a95fa7e2ff07a891780d343cd308)
+ * (GenCodeChecksum:11c8bb223fe748c9d19d1a103dd404a2)
  */
 
 /**
diff --git a/civicrm/CRM/Contribute/Form/AbstractEditPayment.php b/civicrm/CRM/Contribute/Form/AbstractEditPayment.php
index 196a0c348baae2090d1b8333bed4c92ad51787a9..8da1c12557af9b6937ffc18bcd72f923bfeee69a 100644
--- a/civicrm/CRM/Contribute/Form/AbstractEditPayment.php
+++ b/civicrm/CRM/Contribute/Form/AbstractEditPayment.php
@@ -338,9 +338,7 @@ SELECT *
 FROM   civicrm_contribution_product
 WHERE  contribution_id = {$id}
 ";
-    $dao = CRM_Core_DAO::executeQuery($sql,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($sql);
     if ($dao->fetch()) {
       $this->_premiumID = $dao->id;
       $this->_productDAO = $dao;
diff --git a/civicrm/CRM/Contribute/Form/Contribution.php b/civicrm/CRM/Contribute/Form/Contribution.php
index 0121cd1dbb9db75124df4539b2fec61df6cda8df..79a4db615d218cb5b76314712ecac8ebd9ed9073 100644
--- a/civicrm/CRM/Contribute/Form/Contribution.php
+++ b/civicrm/CRM/Contribute/Form/Contribution.php
@@ -250,7 +250,7 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
     $this->assign('action', $this->_action);
 
     // Get the contribution id if update
-    $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+    $this->_id = CRM_Utils_Request::retrieve('id', 'Positive');
     if (!empty($this->_id)) {
       $this->assignPaymentInfoBlock();
       $this->assign('contribID', $this->_id);
@@ -466,6 +466,10 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
    * Build the form object.
    */
   public function buildQuickForm() {
+    if ($this->_id) {
+      $this->add('hidden', 'id', $this->_id);
+    }
+
     if ($this->_action & CRM_Core_Action::DELETE) {
       $this->addButtons([
         [
diff --git a/civicrm/CRM/Contribute/Form/Contribution/Confirm.php b/civicrm/CRM/Contribute/Form/Contribution/Confirm.php
index 9add6a4ec12fc172b89cf6f7ee609fabdc9aa145..ffd9a524cee08a4aed0d9cc2b18d4657ee507b34 100644
--- a/civicrm/CRM/Contribute/Form/Contribution/Confirm.php
+++ b/civicrm/CRM/Contribute/Form/Contribution/Confirm.php
@@ -52,6 +52,8 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
    */
   public $_contributionID;
 
+  public $submitOnce = TRUE;
+
   /**
    * @param $form
    * @param $params
@@ -615,7 +617,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         'name' => $contribButton,
         'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
         'isDefault' => TRUE,
-        'js' => ['onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"],
       ],
       [
         'type' => 'back',
diff --git a/civicrm/CRM/Contribute/Form/Contribution/Main.php b/civicrm/CRM/Contribute/Form/Contribution/Main.php
index 601c8e08fd2ebbbca2caba0e5171d0bf5feee9a4..7738e66017ad81901524758fa6fc81e9ea4df205 100644
--- a/civicrm/CRM/Contribute/Form/Contribution/Main.php
+++ b/civicrm/CRM/Contribute/Form/Contribution/Main.php
@@ -525,7 +525,7 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
       ];
       // Add submit-once behavior when confirm page disabled
       if (empty($this->_values['is_confirm_enabled'])) {
-        $submitButton['js'] = ['onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"];
+        $this->submitOnce = TRUE;
       }
       //change button name for updating contribution
       if (!empty($this->_ccid)) {
diff --git a/civicrm/CRM/Contribute/Form/ContributionBase.php b/civicrm/CRM/Contribute/Form/ContributionBase.php
index 18fcdc93be35905f83303c9fa8bcfb41641d7069..1cd24557cf7ea49a23076258ad7a2cb165c15206 100644
--- a/civicrm/CRM/Contribute/Form/ContributionBase.php
+++ b/civicrm/CRM/Contribute/Form/ContributionBase.php
@@ -479,14 +479,7 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
     // This can, for example, by used by payment processors using client side encryption
     $this->assign('currency', $this->getCurrency());
 
-    //CRM-6907
-    // these lines exist to support a non-default currenty on the form but are probably
-    // obsolete & meddling wth the defaultCurrency is not the right approach....
-    $config = CRM_Core_Config::singleton();
-    $config->defaultCurrency = CRM_Utils_Array::value('currency',
-      $this->_values,
-      $config->defaultCurrency
-    );
+    CRM_Contribute_BAO_Contribution_Utils::overrideDefaultCurrency($this->_values);
 
     //lets allow user to override campaign.
     $campID = CRM_Utils_Request::retrieve('campID', 'Positive', $this);
@@ -749,11 +742,7 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
    * Enable ReCAPTCHA on Contribution form
    */
   protected function enableCaptchaOnForm() {
-    $captcha = CRM_Utils_ReCAPTCHA::singleton();
-    if ($captcha->hasSettingsAvailable()) {
-      $captcha->add($this);
-      $this->assign('isCaptcha', TRUE);
-    }
+    CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
   }
 
   public function assignPaymentFields() {
@@ -813,8 +802,7 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
    */
   protected function displayCaptchaWarning() {
     if (CRM_Core_Permission::check("administer CiviCRM")) {
-      $captcha = CRM_Utils_ReCAPTCHA::singleton();
-      if (!$captcha->hasSettingsAvailable()) {
+      if (!CRM_Utils_ReCAPTCHA::hasSettingsAvailable()) {
         $this->assign('displayCaptchaWarning', TRUE);
       }
     }
@@ -824,8 +812,7 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
    * Check if ReCAPTCHA has to be added on Contribution form forcefully.
    */
   protected function hasToAddForcefully() {
-    $captcha = CRM_Utils_ReCAPTCHA::singleton();
-    return $captcha->hasToAddForcefully();
+    return CRM_Utils_ReCAPTCHA::hasToAddForcefully();
   }
 
   /**
diff --git a/civicrm/CRM/Contribute/Form/Search.php b/civicrm/CRM/Contribute/Form/Search.php
index 847f64688b488d415a0e0f1fc8f9d6c44fe69189..d021b8157ba5956150c790749f29277d225335f8 100644
--- a/civicrm/CRM/Contribute/Form/Search.php
+++ b/civicrm/CRM/Contribute/Form/Search.php
@@ -72,6 +72,9 @@ class CRM_Contribute_Form_Search extends CRM_Core_Form_Search {
 
   /**
    * Processing needed for buildForm and later.
+   *
+   * @throws \CiviCRM_API3_Exception
+   * @throws \CRM_Core_Exception
    */
   public function preProcess() {
     $this->set('searchFormName', 'Search');
@@ -103,6 +106,9 @@ class CRM_Contribute_Form_Search extends CRM_Core_Form_Search {
     }
 
     if ($this->_force) {
+      // Search field metadata is normally added in buildForm but we are bypassing that in this flow
+      // (I've always found the flow kinda confusing & perhaps that is the problem but this mitigates)
+      $this->addSearchFieldMetadata(['Contribution' => CRM_Contribute_BAO_Query::getSearchFieldMetadata()]);
       $this->postProcess();
       $this->set('force', 0);
     }
@@ -149,10 +155,27 @@ class CRM_Contribute_Form_Search extends CRM_Core_Form_Search {
    * Set defaults.
    *
    * @return array
+   * @throws \Exception
    */
   public function setDefaultValues() {
-    if (empty($this->_defaults['contribution_status'])) {
-      $this->_defaults['contribution_status'][1] = 1;
+    $lowReceiveDate = CRM_Utils_Request::retrieve('start', 'Timestamp');
+    if (!empty($lowReceiveDate)) {
+      $this->_formValues['receive_date_low'] = date('Y-m-d H:i:s', strtotime($lowReceiveDate));
+      CRM_Core_Error::deprecatedFunctionWarning('pass receive_date_low not start');
+    }
+    $highReceiveDate = CRM_Utils_Request::retrieve('end', 'Timestamp');
+    if (!empty($highReceiveDate)) {
+      $this->_formValues['receive_date_high'] = date('Y-m-d H:i:s', strtotime($highReceiveDate));
+      CRM_Core_Error::deprecatedFunctionWarning('pass receive_date_high not end');
+    }
+    $this->_defaults = parent::setDefaultValues();
+    if (empty($this->_defaults['contribution_status_id']) && !$this->_force) {
+      // In force mode only parameters from the url will be used. When visible/ explicit this is a useful default.
+      $this->_defaults['contribution_status_id'][1] = CRM_Core_PseudoConstant::getKey(
+        'CRM_Contribute_BAO_Contribution',
+        'contribution_status_id',
+        'Completed'
+      );
     }
     return $this->_defaults;
   }
@@ -390,6 +413,8 @@ class CRM_Contribute_Form_Search extends CRM_Core_Form_Search {
     if (!$this->_force) {
       return;
     }
+    // Start by loading url defaults.
+    $this->_formValues = $this->setDefaultValues();
 
     $status = CRM_Utils_Request::retrieve('status', 'String');
     if ($status) {
@@ -423,25 +448,6 @@ class CRM_Contribute_Form_Search extends CRM_Core_Form_Search {
       }
     }
 
-    $lowDate = CRM_Utils_Request::retrieve('start', 'Timestamp');
-    if ($lowDate) {
-      $lowDate = CRM_Utils_Type::escape($lowDate, 'Timestamp');
-      $date = CRM_Utils_Date::setDateDefaults($lowDate);
-      $this->_formValues['contribution_date_low'] = $this->_defaults['contribution_date_low'] = $date[0];
-    }
-
-    $highDate = CRM_Utils_Request::retrieve('end', 'Timestamp');
-    if ($highDate) {
-      $highDate = CRM_Utils_Type::escape($highDate, 'Timestamp');
-      $date = CRM_Utils_Date::setDateDefaults($highDate);
-      $this->_formValues['contribution_date_high'] = $this->_defaults['contribution_date_high'] = $date[0];
-    }
-
-    if ($highDate || $lowDate) {
-      //set the Choose Date Range value
-      $this->_formValues['contribution_date_relative'] = 0;
-    }
-
     $this->_limit = CRM_Utils_Request::retrieve('limit', 'Positive',
       $this
     );
diff --git a/civicrm/CRM/Contribute/Form/Task/SearchTaskHookSample.php b/civicrm/CRM/Contribute/Form/Task/SearchTaskHookSample.php
index 6c84b5315d193be9ba4d804f3951d14da3490d91..81a3f827df1fe848946569b5ea5446cc766fe828 100644
--- a/civicrm/CRM/Contribute/Form/Task/SearchTaskHookSample.php
+++ b/civicrm/CRM/Contribute/Form/Task/SearchTaskHookSample.php
@@ -55,9 +55,7 @@ class CRM_Contribute_Form_Task_SearchTaskHookSample extends CRM_Contribute_Form_
 INNER JOIN civicrm_contact ct ON ( co.contact_id = ct.id )
      WHERE co.id IN ( $contribIDs )";
 
-    $dao = CRM_Core_DAO::executeQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($query);
 
     while ($dao->fetch()) {
       $rows[] = [
diff --git a/civicrm/CRM/Contribute/Form/Task/Status.php b/civicrm/CRM/Contribute/Form/Task/Status.php
index bc291dc167b35b69b858d193e7b3f584c14628f9..388362b05cef6830c5f2698776aaa52ecc882fe8 100644
--- a/civicrm/CRM/Contribute/Form/Task/Status.php
+++ b/civicrm/CRM/Contribute/Form/Task/Status.php
@@ -70,9 +70,7 @@ SELECT count(*)
 FROM   civicrm_contribution
 WHERE  contribution_status_id != 2
 AND    {$this->_componentClause}";
-    $count = CRM_Core_DAO::singleValueQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    $count = CRM_Core_DAO::singleValueQuery($query);
     if ($count != 0) {
       CRM_Core_Error::statusBounce(ts('Please select only online contributions with Pending status.'));
     }
@@ -110,9 +108,7 @@ FROM   civicrm_contact c,
        civicrm_contribution co
 WHERE  co.contact_id = c.id
 AND    co.id IN ( $contribIDs )";
-    $dao = CRM_Core_DAO::executeQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($query);
 
     // build a row for each contribution id
     $this->_rows = [];
@@ -323,9 +319,7 @@ LEFT JOIN civicrm_participant         p  ON pp.participant_id  = p.id
 WHERE     c.id IN ( $contributionIDs )";
 
     $rows = [];
-    $dao = CRM_Core_DAO::executeQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    $dao = CRM_Core_DAO::executeQuery($query);
 
     while ($dao->fetch()) {
       $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute';
diff --git a/civicrm/CRM/Contribute/Import/Parser/Contribution.php b/civicrm/CRM/Contribute/Import/Parser/Contribution.php
index 9aacd34faefab680ca6abdb081d34650cc4051c4..35b776de85af6e1d9bff2ff9c5e4f5b9f839620f 100644
--- a/civicrm/CRM/Contribute/Import/Parser/Contribution.php
+++ b/civicrm/CRM/Contribute/Import/Parser/Contribution.php
@@ -56,11 +56,11 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Contribute_Import_Pa
    * Class constructor.
    *
    * @param $mapperKeys
-   * @param null $mapperSoftCredit
+   * @param array $mapperSoftCredit
    * @param null $mapperPhoneType
-   * @param null $mapperSoftCreditType
+   * @param array $mapperSoftCreditType
    */
-  public function __construct(&$mapperKeys, $mapperSoftCredit = NULL, $mapperPhoneType = NULL, $mapperSoftCreditType = NULL) {
+  public function __construct(&$mapperKeys, $mapperSoftCredit = [], $mapperPhoneType = NULL, $mapperSoftCreditType = []) {
     parent::__construct();
     $this->_mapperKeys = &$mapperKeys;
     $this->_mapperSoftCredit = &$mapperSoftCredit;
@@ -220,7 +220,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Contribute_Import_Pa
     if (isset($params['total_amount']) && $params['total_amount'] == 0) {
       $params['total_amount'] = '0.00';
     }
-    $this->formatInput($params);
+    $this->formatInput($params, $formatted);
 
     static $indieFields = NULL;
     if ($indieFields == NULL) {
@@ -593,8 +593,9 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Contribute_Import_Pa
    * CRM_Contribute_Import_Parser_ContributionTest.
    *
    * @param array $params
+   * @param array $formatted
    */
-  public function formatInput(&$params) {
+  public function formatInput(&$params, &$formatted = []) {
     $dateType = CRM_Core_Session::singleton()->get('dateTypes');
     $customDataType = !empty($params['contact_type']) ? $params['contact_type'] : 'Contribution';
     $customFields = CRM_Core_BAO_CustomField::getFields($customDataType);
@@ -619,7 +620,7 @@ class CRM_Contribute_Import_Parser_Contribution extends CRM_Contribute_Import_Pa
         }
         if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) {
           if ($customFields[$customFieldID]['data_type'] == 'Date') {
-            CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $params, $dateType, $key);
+            CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key);
             unset($params[$key]);
           }
           elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') {
diff --git a/civicrm/CRM/Contribute/Page/ContributionPage.php b/civicrm/CRM/Contribute/Page/ContributionPage.php
index 0f9f8df41a68c4bda3cbea3ad3be835572a9b77c..826c4f06788f31c0668be08f3683a783df5f959c 100644
--- a/civicrm/CRM/Contribute/Page/ContributionPage.php
+++ b/civicrm/CRM/Contribute/Page/ContributionPage.php
@@ -247,21 +247,21 @@ class CRM_Contribute_Page_ContributionPage extends CRM_Core_Page {
           'name' => ts('Current Month-To-Date'),
           'title' => ts('Current Month-To-Date'),
           'url' => $urlString,
-          'qs' => "{$urlParams}&start={$monthDate}&end={$now}",
+          'qs' => "{$urlParams}&receive_date_low={$monthDate}&receive_date_high={$now}",
           'uniqueName' => 'current_month_to_date',
         ),
         CRM_Core_Action::REVERT => array(
           'name' => ts('Fiscal Year-To-Date'),
           'title' => ts('Fiscal Year-To-Date'),
           'url' => $urlString,
-          'qs' => "{$urlParams}&start={$yearDate}&end={$yearNow}",
+          'qs' => "{$urlParams}&receive_date_low={$yearDate}&receive_date_high={$yearNow}",
           'uniqueName' => 'fiscal_year_to_date',
         ),
         CRM_Core_Action::BROWSE => array(
           'name' => ts('Cumulative'),
           'title' => ts('Cumulative'),
           'url' => $urlString,
-          'qs' => "{$urlParams}&start=&end=$now",
+          'qs' => "{$urlParams}&receive_date_low=&receive_date_high=$now",
           'uniqueName' => 'cumulative',
         ),
       );
diff --git a/civicrm/CRM/Contribute/Tokens.php b/civicrm/CRM/Contribute/Tokens.php
index 25d247c51f5902a7e66a192a3550f2688f3b4ccd..6c97c765dfa8b41aea77247f91c608a5c3b02bf2 100644
--- a/civicrm/CRM/Contribute/Tokens.php
+++ b/civicrm/CRM/Contribute/Tokens.php
@@ -50,7 +50,7 @@ class CRM_Contribute_Tokens extends \Civi\Token\AbstractTokenSubscriber {
       'trxn_id',
       'invoice_id',
       'currency',
-      'cancel_date',
+      'contribution_cancel_date',
       'receipt_date',
       'thankyou_date',
       'tax_amount',
@@ -69,6 +69,7 @@ class CRM_Contribute_Tokens extends \Civi\Token\AbstractTokenSubscriber {
       'source' => 'contribution_source',
       'status' => 'contribution_status_id',
       'type' => 'financial_type_id',
+      'cancel_date' => 'contribution_cancel_date',
     ];
   }
 
diff --git a/civicrm/CRM/Core/BAO/ActionSchedule.php b/civicrm/CRM/Core/BAO/ActionSchedule.php
index a85f4df8526141fe32d29926b7b37a9a26975e7f..abc90a1cfb313222848d392c32c88a5292adce07 100644
--- a/civicrm/CRM/Core/BAO/ActionSchedule.php
+++ b/civicrm/CRM/Core/BAO/ActionSchedule.php
@@ -332,7 +332,6 @@ FROM civicrm_action_schedule cas
         CRM_Core_BAO_ActionLog::create($logParams);
       }
 
-      $dao->free();
     }
   }
 
diff --git a/civicrm/CRM/Core/BAO/Address.php b/civicrm/CRM/Core/BAO/Address.php
index cbe0066deca007b27622f88ec14cfc62b5394c10..71ebf132db34c44a174ddefc3c13721604488b0c 100644
--- a/civicrm/CRM/Core/BAO/Address.php
+++ b/civicrm/CRM/Core/BAO/Address.php
@@ -162,15 +162,20 @@ class CRM_Core_BAO_Address extends CRM_Core_DAO_Address {
     $address->save();
 
     if ($address->id) {
-      $customFields = CRM_Core_BAO_CustomField::getFields('Address', FALSE, TRUE, NULL, NULL, FALSE, FALSE, $checkPermissions);
-
-      if (!empty($customFields)) {
-        $addressCustom = CRM_Core_BAO_CustomField::postProcess($params,
-          $address->id,
-          'Address',
-          FALSE,
-          $checkPermissions
-        );
+      if (isset($params['custom'])) {
+        $addressCustom = $params['custom'];
+      }
+      else {
+        $customFields = CRM_Core_BAO_CustomField::getFields('Address', FALSE, TRUE, NULL, NULL, FALSE, FALSE, $checkPermissions);
+
+        if (!empty($customFields)) {
+          $addressCustom = CRM_Core_BAO_CustomField::postProcess($params,
+            $address->id,
+            'Address',
+            FALSE,
+            $checkPermissions
+          );
+        }
       }
       if (!empty($addressCustom)) {
         CRM_Core_BAO_CustomValueTable::store($addressCustom, 'civicrm_address', $address->id);
diff --git a/civicrm/CRM/Core/BAO/Cache.php b/civicrm/CRM/Core/BAO/Cache.php
index fe41bd06cc350843cea3b0685f3f89981c32d18a..ef2bc60eee6ac8003dcba1ed3ea3a9b3bb70070a 100644
--- a/civicrm/CRM/Core/BAO/Cache.php
+++ b/civicrm/CRM/Core/BAO/Cache.php
@@ -242,14 +242,22 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
     }
 
     if ($clearAll) {
-      // also reset ACL Cache
-      CRM_ACL_BAO_Cache::resetCache();
-
-      // also reset memory cache if any
-      CRM_Utils_System::flushCache();
+      self::resetCaches();
     }
   }
 
+  /**
+   * Cleanup ACL and System Level caches
+   */
+  public static function resetCaches() {
+    // also reset ACL Cache
+    // @todo why is this called when CRM_Utils_System::flushCache() does it as well.
+    CRM_ACL_BAO_Cache::resetCache();
+
+    // also reset memory cache if any
+    CRM_Utils_System::flushCache();
+  }
+
   /**
    * The next two functions are internal functions used to store and retrieve session from
    * the database cache. This keeps the session to a limited size and allows us to
diff --git a/civicrm/CRM/Core/BAO/Cache/Psr16.php b/civicrm/CRM/Core/BAO/Cache/Psr16.php
index 03463d473ee56df7615266d6c2ee0faae1e7de56..ecf107831a48a6e94ab4ae8b4db24b13958db75a 100644
--- a/civicrm/CRM/Core/BAO/Cache/Psr16.php
+++ b/civicrm/CRM/Core/BAO/Cache/Psr16.php
@@ -180,12 +180,10 @@ class CRM_Core_BAO_Cache_Psr16 {
    * @return array
    */
   public static function getLegacyGroups() {
-    return [
+    $groups = [
       // Core
-      'CiviCRM Search PrevNextCache',
       'contact fields',
       'navigation',
-      'contact groups',
       'custom data',
 
       // Universe
@@ -199,12 +197,32 @@ class CRM_Core_BAO_Cache_Psr16 {
       // civihr/uk.co.compucorp.civicrm.hrcore
       'HRCore_Info',
 
-      // nz.co.fuzion.entitysetting
-      'CiviCRM setting Spec',
-
-      // org.civicrm.multisite
-      'descendant groups for an org',
     ];
+    // Handle Legacy Multisite caching group.
+    $extensions = CRM_Extension_System::singleton()->getManager();
+    $multisiteExtensionStatus = $extensions->getStatus('org.civicrm.multisite');
+    if ($multisiteExtensionStatus == $extensions::STATUS_INSTALLED) {
+      $extension_version = civicrm_api3('Extension', 'get', ['key' => 'org.civicrm.multisite'])['values'][0]['version'];
+      if (version_compare($extension_version, '2.7', '<')) {
+        Civi::log()->warning(
+          'CRM_Core_BAO_Cache_PSR is deprecated for multisite extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
+          ['civi.tag' => 'deprecated']
+        );
+        $groups[] = 'descendant groups for an org';
+      }
+    }
+    $entitySettingExtensionStatus = $extensions->getStatus('nz.co.fuzion.entitysetting');
+    if ($multisiteExtensionStatus == $extensions::STATUS_INSTALLED) {
+      $extension_version = civicrm_api3('Extension', 'get', ['key' => 'nz.co.fuzion.entitysetting'])['values'][0]['version'];
+      if (version_compare($extension_version, '1.3', '<')) {
+        Civi::log()->warning(
+          'CRM_Core_BAO_Cache_PSR is deprecated for entity setting extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
+          ['civi.tag' => 'deprecated']
+        );
+        $groups[] = 'CiviCRM setting Spec';
+      }
+    }
+    return $groups;
   }
 
 }
diff --git a/civicrm/CRM/Core/BAO/Country.php b/civicrm/CRM/Core/BAO/Country.php
index df195660c0082b711505e8afc5cb543a25e66729..f6059a6debcef80390753e816ba2de557e3c0d9d 100644
--- a/civicrm/CRM/Core/BAO/Country.php
+++ b/civicrm/CRM/Core/BAO/Country.php
@@ -160,8 +160,7 @@ class CRM_Core_BAO_Country extends CRM_Core_DAO_Country {
    * @return string
    */
   public static function getDefaultCurrencySymbol($k = NULL) {
-    $config = CRM_Core_Config::singleton();
-    return $config->defaultCurrencySymbol(Civi::settings()->get('defaultCurrency'));
+    return CRM_Core_BAO_Country::defaultCurrencySymbol(\Civi::settings()->get('defaultCurrency'));
   }
 
 }
diff --git a/civicrm/CRM/Core/BAO/CustomField.php b/civicrm/CRM/Core/BAO/CustomField.php
index c0fb792829067804c2ddadabe8ba9dd9231d75eb..d41a71e1a0f7560f9d03e1ef464fa17f3ff771ab 100644
--- a/civicrm/CRM/Core/BAO/CustomField.php
+++ b/civicrm/CRM/Core/BAO/CustomField.php
@@ -151,162 +151,14 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
    *
    * @return CRM_Core_DAO_CustomField
    */
-  public static function create(&$params) {
-    $origParams = array_merge(array(), $params);
-
-    $op = empty($params['id']) ? 'create' : 'edit';
-
-    CRM_Utils_Hook::pre($op, 'CustomField', CRM_Utils_Array::value('id', $params), $params);
-
-    if ($op == 'create') {
-      if (!isset($params['column_name'])) {
-        // if add mode & column_name not present, calculate it.
-        $params['column_name'] = strtolower(CRM_Utils_String::munge($params['label'], '_', 32));
-      }
-      if (!isset($params['name'])) {
-        $params['name'] = CRM_Utils_String::munge($params['label'], '_', 64);
-      }
-    }
-    else {
-      $params['column_name'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField',
-        $params['id'],
-        'column_name'
-      );
-    }
-    $columnName = $params['column_name'];
-
-    $indexExist = FALSE;
-    //as during create if field is_searchable we had created index.
-    if (!empty($params['id'])) {
-      $indexExist = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $params['id'], 'is_searchable');
-    }
-
-    switch (CRM_Utils_Array::value('html_type', $params)) {
-      case 'Select Date':
-        if (empty($params['date_format'])) {
-          $config = CRM_Core_Config::singleton();
-          $params['date_format'] = $config->dateInputFormat;
-        }
-        break;
-
-      case 'CheckBox':
-      case 'Multi-Select':
-        if (isset($params['default_checkbox_option'])) {
-          $tempArray = array_keys($params['default_checkbox_option']);
-          $defaultArray = array();
-          foreach ($tempArray as $k => $v) {
-            if ($params['option_value'][$v]) {
-              $defaultArray[] = $params['option_value'][$v];
-            }
-          }
-
-          if (!empty($defaultArray)) {
-            // also add the separator before and after the value per new convention (CRM-1604)
-            $params['default_value'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $defaultArray) . CRM_Core_DAO::VALUE_SEPARATOR;
-          }
-        }
-        else {
-          if (!empty($params['default_option']) && isset($params['option_value'][$params['default_option']])
-          ) {
-            $params['default_value'] = $params['option_value'][$params['default_option']];
-          }
-        }
-        break;
-    }
-
+  public static function create($params) {
     $transaction = new CRM_Core_Transaction();
-
-    $htmlType = CRM_Utils_Array::value('html_type', $params);
-    $dataType = CRM_Utils_Array::value('data_type', $params);
-    $allowedOptionTypes = array('String', 'Int', 'Float', 'Money');
-
-    // create any option group & values if required
-    if ($htmlType != 'Text' && in_array($dataType, $allowedOptionTypes)
-    ) {
-      //CRM-16659: if option_value then create an option group for this custom field.
-      if ($params['option_type'] == 1 && (empty($params['option_group_id']) || !empty($params['option_value']))) {
-        // first create an option group for this custom group
-        $optionGroup = new CRM_Core_DAO_OptionGroup();
-        $optionGroup->name = "{$columnName}_" . date('YmdHis');
-        $optionGroup->title = $params['label'];
-        $optionGroup->is_active = 1;
-        // Don't set reserved as it's not a built-in option group and may be useful for other custom fields.
-        $optionGroup->is_reserved = 0;
-        $optionGroup->data_type = $dataType;
-        $optionGroup->save();
-        $params['option_group_id'] = $optionGroup->id;
-        if (!empty($params['option_value']) && is_array($params['option_value'])) {
-          foreach ($params['option_value'] as $k => $v) {
-            if (strlen(trim($v))) {
-              $optionValue = new CRM_Core_DAO_OptionValue();
-              $optionValue->option_group_id = $optionGroup->id;
-              $optionValue->label = $params['option_label'][$k];
-              $optionValue->name = CRM_Utils_String::titleToVar($params['option_label'][$k]);
-              switch ($dataType) {
-                case 'Money':
-                  $optionValue->value = CRM_Utils_Rule::cleanMoney($v);
-                  break;
-
-                case 'Int':
-                  $optionValue->value = intval($v);
-                  break;
-
-                case 'Float':
-                  $optionValue->value = floatval($v);
-                  break;
-
-                default:
-                  $optionValue->value = trim($v);
-              }
-
-              $optionValue->weight = $params['option_weight'][$k];
-              $optionValue->is_active = CRM_Utils_Array::value($k, $params['option_status'], FALSE);
-              $optionValue->save();
-            }
-          }
-        }
-      }
-    }
-
-    // check for orphan option groups
-    if (!empty($params['option_group_id'])) {
-      if (!empty($params['id'])) {
-        self::fixOptionGroups($params['id'], $params['option_group_id']);
-      }
-
-      // if we do not have a default value
-      // retrieve it from one of the other custom fields which use this option group
-      if (empty($params['default_value'])) {
-        //don't insert only value separator as default value, CRM-4579
-        $defaultValue = self::getOptionGroupDefault($params['option_group_id'],
-          $htmlType
-        );
-
-        if (!CRM_Utils_System::isNull(explode(CRM_Core_DAO::VALUE_SEPARATOR,
-          $defaultValue
-        ))
-        ) {
-          $params['default_value'] = $defaultValue;
-        }
-      }
-    }
-
-    // since we need to save option group id :)
-    if (!isset($params['attributes']) && strtolower($htmlType) == 'textarea') {
-      $params['attributes'] = 'rows=4, cols=60';
-    }
+    $op = empty($params['id']) ? 'create' : 'edit';
+    $origParams = array_merge([], $params);
+    $params = self::prepareCreate($params, $op);
 
     $customField = new CRM_Core_DAO_CustomField();
     $customField->copyValues($params);
-    if ($op == 'create') {
-      $customField->is_required = CRM_Utils_Array::value('is_required', $params, FALSE);
-      $customField->is_searchable = CRM_Utils_Array::value('is_searchable', $params, FALSE);
-      $customField->in_selector = CRM_Utils_Array::value('in_selector', $params, FALSE);
-      $customField->is_search_range = CRM_Utils_Array::value('is_search_range', $params, FALSE);
-      //CRM-15792 - Custom field gets disabled if is_active not set
-      $customField->is_active = CRM_Utils_Array::value('is_active', $params, TRUE);
-      $customField->is_view = CRM_Utils_Array::value('is_view', $params, FALSE);
-    }
     $customField->save();
 
     // make sure all values are present in the object for further processing
@@ -315,20 +167,23 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
     $triggerRebuild = CRM_Utils_Array::value('triggerRebuild', $params, TRUE);
     //create/drop the index when we toggle the is_searchable flag
     if ($op == 'edit') {
+      $indexExist = FALSE;
+      //as during create if field is_searchable we had created index.
+      if (!empty($params['id'])) {
+        $indexExist = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $params['id'], 'is_searchable');
+      }
       self::createField($customField, 'modify', $indexExist, $triggerRebuild);
     }
     else {
       if (!isset($origParams['column_name'])) {
-        $columnName .= "_{$customField->id}";
-        $params['column_name'] = $columnName;
+        $params['column_name'] .= "_{$customField->id}";
       }
-      $customField->column_name = $columnName;
+      $customField->column_name = $params['column_name'];
       $customField->save();
       // make sure all values are present in the object
       $customField->find(TRUE);
 
-      $indexExist = FALSE;
-      self::createField($customField, 'add', $indexExist, $triggerRebuild);
+      self::createField($customField, 'add', FALSE, $triggerRebuild);
     }
 
     // complete transaction
@@ -503,6 +358,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
     $cacheKey .= $onlyParent ? '_1_' : '_0_';
     $cacheKey .= $onlySubType ? '_1_' : '_0_';
     $cacheKey .= $checkPermission ? '_1_' : '_0_';
+    $cacheKey .= '_' . CRM_Core_Config::domainID() . '_';
 
     $cgTable = CRM_Core_DAO_CustomGroup::getTableName();
 
@@ -1309,7 +1165,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
             // In other contexts show a paperclip icon
             if (CRM_Utils_Rule::integer($value)) {
               $icons = CRM_Core_BAO_File::paperIconAttachment('*', $value);
-              $display = $icons[$value];
+              $display = $icons[$value] . civicrm_api3('File', 'getvalue', ['return' => "description", 'id' => $value]);
             }
             else {
               //CRM-18396, if filename is passed instead
@@ -1944,9 +1800,7 @@ SELECT count(*)
 FROM   $tableName
 WHERE  $columnName is not null
 ";
-    $count = CRM_Core_DAO::singleValueQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    $count = CRM_Core_DAO::singleValueQuery($query);
     if ($count > 0) {
       $query = "
 SELECT extends
@@ -2015,6 +1869,166 @@ WHERE  id IN ( %1, %2 )
     CRM_Utils_System::flushCache();
   }
 
+  /**
+   * Create an option value for a custom field option group ID.
+   *
+   * @param array $params
+   * @param string $value
+   * @param \CRM_Core_DAO_OptionGroup $optionGroup
+   * @param string $optionName
+   * @param string $dataType
+   */
+  protected static function createOptionValue(&$params, $value, CRM_Core_DAO_OptionGroup $optionGroup, $optionName, $dataType) {
+    if (strlen(trim($value))) {
+      $optionValue = new CRM_Core_DAO_OptionValue();
+      $optionValue->option_group_id = $optionGroup->id;
+      $optionValue->label = $params['option_label'][$optionName];
+      $optionValue->name = CRM_Utils_String::titleToVar($params['option_label'][$optionName]);
+      switch ($dataType) {
+        case 'Money':
+          $optionValue->value = CRM_Utils_Rule::cleanMoney($value);
+          break;
+
+        case 'Int':
+          $optionValue->value = intval($value);
+          break;
+
+        case 'Float':
+          $optionValue->value = floatval($value);
+          break;
+
+        default:
+          $optionValue->value = trim($value);
+      }
+
+      $optionValue->weight = $params['option_weight'][$optionName];
+      $optionValue->is_active = CRM_Utils_Array::value($optionName, $params['option_status'], FALSE);
+      $optionValue->save();
+    }
+  }
+
+  /**
+   * Prepare for the create operation.
+   *
+   * Munge params, create the option values if needed.
+   *
+   * This could be called by a single create or a batchCreate.
+   *
+   * @param array $params
+   * @param string $op
+   *
+   * @return array
+   */
+  protected static function prepareCreate($params, $op) {
+
+    CRM_Utils_Hook::pre($op, 'CustomField', CRM_Utils_Array::value('id', $params), $params);
+    if ($op === 'create') {
+      CRM_Core_DAO::setCreateDefaults($params, self::getDefaults());
+      if (!isset($params['column_name'])) {
+        // if add mode & column_name not present, calculate it.
+        $params['column_name'] = strtolower(CRM_Utils_String::munge($params['label'], '_', 32));
+      }
+      if (!isset($params['name'])) {
+        $params['name'] = CRM_Utils_String::munge($params['label'], '_', 64);
+      }
+    }
+    else {
+      $params['column_name'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField',
+        $params['id'],
+        'column_name'
+      );
+    }
+
+    switch (CRM_Utils_Array::value('html_type', $params)) {
+      case 'Select Date':
+        if (empty($params['date_format'])) {
+          $config = CRM_Core_Config::singleton();
+          $params['date_format'] = $config->dateInputFormat;
+        }
+        break;
+
+      case 'CheckBox':
+      case 'Multi-Select':
+        if (isset($params['default_checkbox_option'])) {
+          $tempArray = array_keys($params['default_checkbox_option']);
+          $defaultArray = [];
+          foreach ($tempArray as $k => $v) {
+            if ($params['option_value'][$v]) {
+              $defaultArray[] = $params['option_value'][$v];
+            }
+          }
+
+          if (!empty($defaultArray)) {
+            // also add the separator before and after the value per new convention (CRM-1604)
+            $params['default_value'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $defaultArray) . CRM_Core_DAO::VALUE_SEPARATOR;
+          }
+        }
+        else {
+          if (!empty($params['default_option']) && isset($params['option_value'][$params['default_option']])
+          ) {
+            $params['default_value'] = $params['option_value'][$params['default_option']];
+          }
+        }
+        break;
+    }
+
+    $htmlType = CRM_Utils_Array::value('html_type', $params);
+    $dataType = CRM_Utils_Array::value('data_type', $params);
+    $allowedOptionTypes = ['String', 'Int', 'Float', 'Money'];
+
+    // create any option group & values if required
+    if ($htmlType != 'Text' && in_array($dataType, $allowedOptionTypes)
+    ) {
+      //CRM-16659: if option_value then create an option group for this custom field.
+      if ($params['option_type'] == 1 && (empty($params['option_group_id']) || !empty($params['option_value']))) {
+        // first create an option group for this custom group
+        $optionGroup = new CRM_Core_DAO_OptionGroup();
+        $optionGroup->name = "{$params['column_name']}_" . date('YmdHis');
+        $optionGroup->title = $params['label'];
+        $optionGroup->is_active = 1;
+        // Don't set reserved as it's not a built-in option group and may be useful for other custom fields.
+        $optionGroup->is_reserved = 0;
+        $optionGroup->data_type = $dataType;
+        $optionGroup->save();
+        $params['option_group_id'] = $optionGroup->id;
+        if (!empty($params['option_value']) && is_array($params['option_value'])) {
+          foreach ($params['option_value'] as $k => $v) {
+            self::createOptionValue($params, $v, $optionGroup, $k, $dataType);
+          }
+        }
+      }
+    }
+
+    // check for orphan option groups
+    if (!empty($params['option_group_id'])) {
+      if (!empty($params['id'])) {
+        self::fixOptionGroups($params['id'], $params['option_group_id']);
+      }
+
+      // if we do not have a default value
+      // retrieve it from one of the other custom fields which use this option group
+      if (empty($params['default_value'])) {
+        //don't insert only value separator as default value, CRM-4579
+        $defaultValue = self::getOptionGroupDefault($params['option_group_id'],
+          $htmlType
+        );
+
+        if (!CRM_Utils_System::isNull(explode(CRM_Core_DAO::VALUE_SEPARATOR,
+          $defaultValue
+        ))
+        ) {
+          $params['default_value'] = $defaultValue;
+        }
+      }
+    }
+
+    // since we need to save option group id :)
+    if (!isset($params['attributes']) && strtolower($htmlType) == 'textarea') {
+      $params['attributes'] = 'rows=4, cols=60';
+    }
+    return $params;
+  }
+
   /**
    * Move custom data from one contact to another.
    *
@@ -2159,6 +2173,24 @@ INNER JOIN  civicrm_custom_field f ON ( g.id = f.option_group_id )
     return $customOptionGroup[$cacheKey];
   }
 
+  /**
+   * Get defaults for new entity.
+   *
+   * @return array
+   */
+  public static function getDefaults() {
+    return [
+      'is_required' => FALSE,
+      'is_searchable' => FALSE,
+      'in_selector' => FALSE,
+      'is_search_range' => FALSE,
+      //CRM-15792 - Custom field gets disabled if is_active not set
+      // this would ideally be a mysql default.
+      'is_active' => TRUE,
+      'is_view' => FALSE,
+    ];
+  }
+
   /**
    * Fix orphan groups.
    *
diff --git a/civicrm/CRM/Core/BAO/CustomQuery.php b/civicrm/CRM/Core/BAO/CustomQuery.php
index eb1b645c744a5bf5015b58bee0029bb1ed915ba9..a3e2cf2736773a5d336c807136530713a2284470 100644
--- a/civicrm/CRM/Core/BAO/CustomQuery.php
+++ b/civicrm/CRM/Core/BAO/CustomQuery.php
@@ -227,8 +227,7 @@ SELECT f.id, f.label, f.data_type,
         return;
       }
 
-      $this->_tables[$name] = "\nLEFT JOIN $name ON $name.entity_id = $joinTable.id";
-      $this->_whereTables[$name] = $this->_tables[$name];
+      $this->joinCustomTableForField($field);
 
       if ($joinTable) {
         $joinClause = 1;
@@ -292,6 +291,8 @@ SELECT f.id, f.label, f.data_type,
 
         $qillOp = CRM_Utils_Array::value($op, CRM_Core_SelectValues::getSearchBuilderOperators(), $op);
 
+        // Ensure the table is joined in (eg if in where but not select).
+        $this->joinCustomTableForField($field);
         switch ($field['data_type']) {
           case 'String':
           case 'StateProvince':
@@ -414,9 +415,12 @@ SELECT f.id, f.label, f.data_type,
             break;
 
           case 'Date':
-            $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Date');
-            list($qillOp, $qillVal) = CRM_Contact_BAO_Query::buildQillForFieldValue(NULL, $field['label'], $value, $op, [], CRM_Utils_Type::T_DATE);
-            $this->_qill[$grouping][] = "{$field['label']} $qillOp '$qillVal'";
+            if (substr($name, -9, 9) !== '_relative') {
+              // Relative dates are handled in the buildRelativeDateQuery function.
+              $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Date');
+              list($qillOp, $qillVal) = CRM_Contact_BAO_Query::buildQillForFieldValue(NULL, $field['label'], $value, $op, [], CRM_Utils_Type::T_DATE);
+              $this->_qill[$grouping][] = "{$field['label']} $qillOp '$qillVal'";
+            }
             break;
 
           case 'File':
@@ -471,4 +475,16 @@ SELECT f.id, f.label, f.data_type,
     ];
   }
 
+  /**
+   * Join the custom table for the field in (if not already in the query).
+   *
+   * @param array $field
+   */
+  protected function joinCustomTableForField($field) {
+    $name = $field['table_name'];
+    $join = "\nLEFT JOIN $name ON $name.entity_id = {$field['search_table']}.id";
+    $this->_tables[$name] = $this->_tables[$name] ?? $join;
+    $this->_whereTables[$name] = $this->_whereTables[$name] ?? $join;
+  }
+
 }
diff --git a/civicrm/CRM/Core/BAO/CustomValueTable.php b/civicrm/CRM/Core/BAO/CustomValueTable.php
index 759e83a71954d764bceecafa0e8195dd8a95b45d..c25baac556bdd74b4f3d8bb96ddb97002a9c44be 100644
--- a/civicrm/CRM/Core/BAO/CustomValueTable.php
+++ b/civicrm/CRM/Core/BAO/CustomValueTable.php
@@ -36,10 +36,15 @@ class CRM_Core_BAO_CustomValueTable {
 
   /**
    * @param array $customParams
+   * @param string $parentOperation Operation being taken on the parent entity.
+   *   If we know the parent entity is doing an insert we can skip the
+   *   ON DUPLICATE UPDATE - which improves performance and reduces deadlocks.
+   *   - edit
+   *   - create
    *
    * @throws Exception
    */
-  public static function create(&$customParams) {
+  public static function create($customParams, $parentOperation = NULL) {
     if (empty($customParams) ||
       !is_array($customParams)
     ) {
@@ -256,7 +261,7 @@ class CRM_Core_BAO_CustomValueTable {
             $fieldValues = implode(',', array_values($set));
             $query = "$sqlOP ( $fieldNames ) VALUES ( $fieldValues )";
             // for multiple values we dont do on duplicate key update
-            if (!$isMultiple) {
+            if (!$isMultiple && $parentOperation !== 'create') {
               $query .= " ON DUPLICATE KEY UPDATE $setClause";
             }
           }
@@ -337,8 +342,13 @@ class CRM_Core_BAO_CustomValueTable {
    * @param array $params
    * @param $entityTable
    * @param int $entityID
+   * @param string $parentOperation Operation being taken on the parent entity.
+   *   If we know the parent entity is doing an insert we can skip the
+   *   ON DUPLICATE UPDATE - which improves performance and reduces deadlocks.
+   *   - edit
+   *   - create
    */
-  public static function store(&$params, $entityTable, $entityID) {
+  public static function store($params, $entityTable, $entityID, $parentOperation = NULL) {
     $cvParams = [];
     foreach ($params as $fieldID => $param) {
       foreach ($param as $index => $customValue) {
@@ -375,7 +385,7 @@ class CRM_Core_BAO_CustomValueTable {
       }
     }
     if (!empty($cvParams)) {
-      self::create($cvParams);
+      self::create($cvParams, $parentOperation);
     }
   }
 
diff --git a/civicrm/CRM/Core/BAO/File.php b/civicrm/CRM/Core/BAO/File.php
index c2c06bd279fbc166fe15af0537e3f7c2afe6d840..a0a28476edc2777c95dcf5b4accb80d980df820f 100644
--- a/civicrm/CRM/Core/BAO/File.php
+++ b/civicrm/CRM/Core/BAO/File.php
@@ -366,7 +366,6 @@ class CRM_Core_BAO_File extends CRM_Core_DAO_File {
       }
     }
 
-    $dao->free();
     return $results;
   }
 
diff --git a/civicrm/CRM/Core/BAO/FinancialTrxn.php b/civicrm/CRM/Core/BAO/FinancialTrxn.php
index 742ad4aeb256d9ec7c8b7846f6a5f50a8d509f45..b02538e4294d08ae3b409854e590bac877feb6d2 100644
--- a/civicrm/CRM/Core/BAO/FinancialTrxn.php
+++ b/civicrm/CRM/Core/BAO/FinancialTrxn.php
@@ -119,7 +119,7 @@ class CRM_Core_BAO_FinancialTrxn extends CRM_Financial_DAO_FinancialTrxn {
    *
    * @return \CRM_Financial_DAO_FinancialTrxn
    */
-  public static function retrieve(&$params, &$defaults) {
+  public static function retrieve(&$params, &$defaults = []) {
     $financialItem = new CRM_Financial_DAO_FinancialTrxn();
     $financialItem->copyValues($params);
     if ($financialItem->find(TRUE)) {
diff --git a/civicrm/CRM/Core/BAO/Mapping.php b/civicrm/CRM/Core/BAO/Mapping.php
index 55e1ef9ae2e2d16a326fdc978a5c6024a791c288..606c3d282c88622bfca7258ac368a62cc8be9745 100644
--- a/civicrm/CRM/Core/BAO/Mapping.php
+++ b/civicrm/CRM/Core/BAO/Mapping.php
@@ -661,7 +661,6 @@ class CRM_Core_BAO_Mapping extends CRM_Core_DAO_Mapping {
                   $relatedFields = array_merge($relatedFields, (array) $relationshipCustomFields);
                 }
               }
-              $relationshipType->free();
               asort($relatedFields);
               $sel5[$k][$field] = $relatedFields;
             }
diff --git a/civicrm/CRM/Core/BAO/MessageTemplate.php b/civicrm/CRM/Core/BAO/MessageTemplate.php
index 6687dd0ee4c16da9be2278b3a3549b9bb1d78282..4b81879706d30b8f65adb8c8e3bf30afd1379a55 100644
--- a/civicrm/CRM/Core/BAO/MessageTemplate.php
+++ b/civicrm/CRM/Core/BAO/MessageTemplate.php
@@ -310,8 +310,6 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate {
       $result = CRM_Utils_Mail::send($mailParams);
     }
 
-    $messageTemplates->free();
-
     return $result;
   }
 
@@ -442,7 +440,6 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate {
       'valueName' => $params['valueName'],
       'messageTemplateID' => $params['messageTemplateID'],
     ];
-    $dao->free();
 
     CRM_Utils_Hook::alterMailContent($mailContent);
 
@@ -459,7 +456,6 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate {
       $mailContent['subject'] = $testDao->subject . $mailContent['subject'];
       $mailContent['text'] = $testDao->text . $mailContent['text'];
       $mailContent['html'] = preg_replace('/<body(.*)$/im', "<body\\1\n{$testDao->html}", $mailContent['html']);
-      $testDao->free();
     }
 
     // replace tokens in the three elements (in subject as if it was the text body)
diff --git a/civicrm/CRM/Core/BAO/Navigation.php b/civicrm/CRM/Core/BAO/Navigation.php
index 90cc56fb1cf30484917fbb2823b932ad61a419ec..bac09cd73cc19a0a3dc3f9cb2f91a692ae96f078 100644
--- a/civicrm/CRM/Core/BAO/Navigation.php
+++ b/civicrm/CRM/Core/BAO/Navigation.php
@@ -159,7 +159,7 @@ class CRM_Core_BAO_Navigation extends CRM_Core_DAO_Navigation {
    *   returns associated array
    */
   public static function getNavigationList() {
-    $cacheKeyString = "navigationList";
+    $cacheKeyString = "navigationList_" . CRM_Core_Config::domainID();
     $whereClause = '';
 
     $config = CRM_Core_Config::singleton();
diff --git a/civicrm/CRM/Core/BAO/PrevNextCache.php b/civicrm/CRM/Core/BAO/PrevNextCache.php
index bfb410d993349f93d2de73228a81d33197a756cb..416709e59a4fe73774ebe335a9588a293cc00dd7 100644
--- a/civicrm/CRM/Core/BAO/PrevNextCache.php
+++ b/civicrm/CRM/Core/BAO/PrevNextCache.php
@@ -170,10 +170,12 @@ WHERE  cachekey     = %3 AND
    * @param int $id2
    * @param string $cacheKey
    * @param array $conflicts
+   * @param string $mode
    *
    * @return bool
+   * @throws CRM_Core_Exception
    */
-  public static function markConflict($id1, $id2, $cacheKey, $conflicts) {
+  public static function markConflict($id1, $id2, $cacheKey, $conflicts, $mode) {
     if (empty($cacheKey) || empty($conflicts)) {
       return FALSE;
     }
@@ -191,11 +193,32 @@ WHERE  cachekey     = %3 AND
     ];
     $pncFind = CRM_Core_DAO::executeQuery($sql, $params);
 
+    $conflictTexts = [];
+
+    foreach ($conflicts as $entity => $entityConflicts) {
+      if ($entity === 'contact') {
+        foreach ($entityConflicts as $conflict) {
+          $conflictTexts[] = "{$conflict['title']}: '{$conflict[$id1]}' vs. '{$conflict[$id2]}'";
+        }
+      }
+      else {
+        foreach ($entityConflicts as $locationConflict) {
+          if (!is_array($locationConflict)) {
+            continue;
+          }
+          $displayField = CRM_Dedupe_Merger::getLocationBlockInfo()[$entity]['displayField'];
+          $conflictTexts[] = "{$locationConflict['title']}: '{$locationConflict[$displayField][$id1]}' vs. '{$locationConflict[$displayField][$id2]}'";
+        }
+      }
+    }
+    $conflictString = implode(', ', $conflictTexts);
+
     while ($pncFind->fetch()) {
       $data = $pncFind->data;
       if (!empty($data)) {
-        $data = unserialize($data);
-        $data['conflicts'] = implode(",", array_values($conflicts));
+        $data = CRM_Core_DAO::unSerializeField($data, CRM_Core_DAO::SERIALIZE_PHP);
+        $data['conflicts'] = $conflictString;
+        $data[$mode]['conflicts'] = $conflicts;
 
         $pncUp = new CRM_Core_DAO_PrevNextCache();
         $pncUp->id = $pncFind->id;
@@ -424,7 +447,7 @@ WHERE      c.group_name = %1
 AND        c.created_date < date_sub( NOW( ), INTERVAL %2 day )
 ";
     $params = [
-      1 => ['CiviCRM Search PrevNextCache', 'String'],
+      1 => [CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache'), 'String'],
       2 => [$cacheTimeIntervalDays, 'Integer'],
     ];
     CRM_Core_DAO::executeQuery($sql, $params);
diff --git a/civicrm/CRM/Core/BAO/SchemaHandler.php b/civicrm/CRM/Core/BAO/SchemaHandler.php
index 5fe0666b15c8df4cd24932afa07d68b5126de008..2dbe66fdff91659a2b7d822ad285e8c399d44499 100644
--- a/civicrm/CRM/Core/BAO/SchemaHandler.php
+++ b/civicrm/CRM/Core/BAO/SchemaHandler.php
@@ -64,20 +64,19 @@ class CRM_Core_BAO_SchemaHandler {
    *   TRUE if successfully created, FALSE otherwise
    *
    */
-  public static function createTable(&$params) {
+  public static function createTable($params) {
     $sql = self::buildTableSQL($params);
     // do not i18n-rewrite
     CRM_Core_DAO::executeQuery($sql, [], TRUE, NULL, FALSE, FALSE);
 
-    $config = CRM_Core_Config::singleton();
-    if ($config->logging) {
+    if (CRM_Core_Config::singleton()->logging) {
       // logging support
       $logging = new CRM_Logging_Schema();
       $logging->fixSchemaDifferencesFor($params['name'], NULL, FALSE);
     }
 
     // always do a trigger rebuild for this table
-    CRM_Core_DAO::triggerRebuild($params['name']);
+    Civi::service('sql_triggers')->rebuild($params['name'], TRUE);
 
     return TRUE;
   }
@@ -87,7 +86,7 @@ class CRM_Core_BAO_SchemaHandler {
    *
    * @return string
    */
-  public static function buildTableSQL(&$params) {
+  public static function buildTableSQL($params) {
     $sql = "CREATE TABLE {$params['name']} (";
     if (isset($params['fields']) &&
       is_array($params['fields'])
@@ -124,7 +123,7 @@ class CRM_Core_BAO_SchemaHandler {
    *
    * @return string
    */
-  public static function buildFieldSQL(&$params, $separator, $prefix) {
+  public static function buildFieldSQL($params, $separator, $prefix) {
     $sql = '';
     $sql .= $separator;
     $sql .= str_repeat(' ', 8);
@@ -159,7 +158,7 @@ class CRM_Core_BAO_SchemaHandler {
    *
    * @return NULL|string
    */
-  public static function buildPrimaryKeySQL(&$params, $separator, $prefix) {
+  public static function buildPrimaryKeySQL($params, $separator, $prefix) {
     $sql = NULL;
     if (!empty($params['primary'])) {
       $sql .= $separator;
@@ -178,7 +177,7 @@ class CRM_Core_BAO_SchemaHandler {
    *
    * @return NULL|string
    */
-  public static function buildSearchIndexSQL(&$params, $separator, $prefix, $indexExist = FALSE) {
+  public static function buildSearchIndexSQL($params, $separator, $prefix, $indexExist = FALSE) {
     $sql = NULL;
 
     // dont index blob
@@ -271,7 +270,7 @@ ALTER TABLE {$tableName}
    *
    * @return NULL|string
    */
-  public static function buildForeignKeySQL(&$params, $separator, $prefix, $tableName) {
+  public static function buildForeignKeySQL($params, $separator, $prefix, $tableName) {
     $sql = NULL;
     if (!empty($params['fk_table_name']) && !empty($params['fk_field_name'])) {
       $sql .= $separator;
@@ -295,42 +294,12 @@ ALTER TABLE {$tableName}
    *
    * @return bool
    */
-  public static function alterFieldSQL(&$params, $indexExist = FALSE, $triggerRebuild = TRUE) {
-    $sql = str_repeat(' ', 8);
-    $sql .= "ALTER TABLE {$params['table_name']}";
+  public static function alterFieldSQL($params, $indexExist = FALSE, $triggerRebuild = TRUE) {
 
     // lets suppress the required flag, since that can cause sql issue
     $params['required'] = FALSE;
 
-    switch ($params['operation']) {
-      case 'add':
-        $separator = "\n";
-        $prefix = "ADD ";
-        $sql .= self::buildFieldSQL($params, $separator, "ADD COLUMN ");
-        $separator = ",\n";
-        $sql .= self::buildPrimaryKeySQL($params, $separator, "ADD PRIMARY KEY ");
-        $sql .= self::buildSearchIndexSQL($params, $separator, "ADD INDEX ");
-        $sql .= self::buildForeignKeySQL($params, $separator, "ADD ", $params['table_name']);
-        break;
-
-      case 'modify':
-        $separator = "\n";
-        $prefix = "MODIFY ";
-        $sql .= self::buildFieldSQL($params, $separator, $prefix);
-        $separator = ",\n";
-        $sql .= self::buildSearchIndexSQL($params, $separator, "ADD INDEX ", $indexExist);
-        break;
-
-      case 'delete':
-        $sql .= " DROP COLUMN `{$params['name']}`";
-        if (!empty($params['primary'])) {
-          $sql .= ", DROP PRIMARY KEY";
-        }
-        if (!empty($params['fk_table_name'])) {
-          $sql .= ", DROP FOREIGN KEY FK_{$params['fkName']}";
-        }
-        break;
-    }
+    $sql = self::buildFieldChangeSql($params, $indexExist);
 
     // CRM-7007: do not i18n-rewrite this query
     CRM_Core_DAO::executeQuery($sql, [], TRUE, NULL, FALSE, FALSE);
@@ -342,12 +311,12 @@ ALTER TABLE {$tableName}
       // Are there any modifies we DON'T was to call this function for (& shouldn't it be clever enough to cope?)
       if ($params['operation'] == 'add' || $params['operation'] == 'modify') {
         $logging = new CRM_Logging_Schema();
-        $logging->fixSchemaDifferencesFor($params['table_name'], [trim($prefix) => [$params['name']]], FALSE);
+        $logging->fixSchemaDifferencesFor($params['table_name'], [trim(strtoupper($params['operation'])) => [$params['name']]], FALSE);
       }
     }
 
     if ($triggerRebuild) {
-      CRM_Core_DAO::triggerRebuild($params['table_name']);
+      Civi::service('sql_triggers')->rebuild($params['table_name'], TRUE);
     }
 
     return TRUE;
@@ -779,4 +748,45 @@ MODIFY      {$columnName} varchar( $length )
     }
   }
 
+  /**
+   * Build the sql to alter the field.
+   *
+   * @param array $params
+   * @param bool $indexExist
+   *
+   * @return string
+   */
+  public static function buildFieldChangeSql($params, $indexExist) {
+    $sql = str_repeat(' ', 8);
+    $sql .= "ALTER TABLE {$params['table_name']}";
+    switch ($params['operation']) {
+      case 'add':
+        $separator = "\n";
+        $sql .= self::buildFieldSQL($params, $separator, "ADD COLUMN ");
+        $separator = ",\n";
+        $sql .= self::buildPrimaryKeySQL($params, $separator, "ADD PRIMARY KEY ");
+        $sql .= self::buildSearchIndexSQL($params, $separator, "ADD INDEX ");
+        $sql .= self::buildForeignKeySQL($params, $separator, "ADD ", $params['table_name']);
+        break;
+
+      case 'modify':
+        $separator = "\n";
+        $sql .= self::buildFieldSQL($params, $separator, "MODIFY ");
+        $separator = ",\n";
+        $sql .= self::buildSearchIndexSQL($params, $separator, "ADD INDEX ", $indexExist);
+        break;
+
+      case 'delete':
+        $sql .= " DROP COLUMN `{$params['name']}`";
+        if (!empty($params['primary'])) {
+          $sql .= ", DROP PRIMARY KEY";
+        }
+        if (!empty($params['fk_table_name'])) {
+          $sql .= ", DROP FOREIGN KEY FK_{$params['fkName']}";
+        }
+        break;
+    }
+    return $sql;
+  }
+
 }
diff --git a/civicrm/CRM/Core/BAO/UFGroup.php b/civicrm/CRM/Core/BAO/UFGroup.php
index 3adba27015c53d0b4b0268721538da21f6fbc0ef..98b606568869adb6bdbe537bf5c2eecb5fb7096d 100644
--- a/civicrm/CRM/Core/BAO/UFGroup.php
+++ b/civicrm/CRM/Core/BAO/UFGroup.php
@@ -357,7 +357,6 @@ class CRM_Core_BAO_UFGroup extends CRM_Core_DAO_UFGroup {
           $fields[$name] = $formattedField;
         }
       }
-      $field->free();
     }
 
     if (empty($fields) && !$validGroup) {
diff --git a/civicrm/CRM/Core/BAO/UFMatch.php b/civicrm/CRM/Core/BAO/UFMatch.php
index 18ce81f8aa223c64c193fde5417bcece30585e5d..83713e6cf5e06545e7e794594977740af1e70fec 100644
--- a/civicrm/CRM/Core/BAO/UFMatch.php
+++ b/civicrm/CRM/Core/BAO/UFMatch.php
@@ -296,7 +296,7 @@ AND    domain_id = %2
           }
         }
 
-        $contactId = CRM_Contact_BAO_Contact::createProfileContact($params, CRM_Core_DAO::$_nullArray);
+        $contactId = CRM_Contact_BAO_Contact::createProfileContact($params);
         $ufmatch->contact_id = $contactId;
         $ufmatch->uf_name = $uniqId;
       }
@@ -323,7 +323,6 @@ AND    domain_id    = %4
 
       if (!$conflict) {
         $ufmatch = CRM_Core_BAO_UFMatch::create((array) $ufmatch);
-        $ufmatch->free();
         $newContact = TRUE;
         $transaction->commit();
       }
@@ -431,25 +430,23 @@ AND    domain_id    = %4
       $contactDetails = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactId);
 
       if (trim($contactDetails[1])) {
+        //update if record is found but different
         $emailID = $contactDetails[3];
-        //update if record is found
-        $query = "UPDATE  civicrm_email
-                     SET email = %1
-                     WHERE id =  %2";
-        $p = [
-          1 => [$emailAddress, 'String'],
-          2 => [$emailID, 'Integer'],
-        ];
-        $dao = CRM_Core_DAO::executeQuery($query, $p);
+        if (trim($contactDetails[1]) != $emailAddress) {
+          civicrm_api3('Email', 'create', [
+            'id' => $emailID,
+            'email' => $emailAddress,
+          ]);
+        }
       }
       else {
         //else insert a new email record
-        $email = new CRM_Core_DAO_Email();
-        $email->contact_id = $contactId;
-        $email->is_primary = 1;
-        $email->email = $emailAddress;
-        $email->save();
-        $emailID = $email->id;
+        $result = civicrm_api3('Email', 'create', [
+          'contact_id' => $contactId,
+          'email' => $emailAddress,
+          'is_primary' => 1,
+        ]);
+        $emailID = $result->id;
       }
 
       CRM_Core_BAO_Log::register($contactId,
diff --git a/civicrm/CRM/Core/BAO/Website.php b/civicrm/CRM/Core/BAO/Website.php
index f947253594eb4cb2e7930c9154748268a5392469..f7fba2c6a257b2e708565e065e644e0cdd093fbf 100644
--- a/civicrm/CRM/Core/BAO/Website.php
+++ b/civicrm/CRM/Core/BAO/Website.php
@@ -141,7 +141,6 @@ class CRM_Core_BAO_Website extends CRM_Core_DAO_Website {
       return FALSE;
     }
     CRM_Utils_Hook::post('delete', 'Website', $id, $obj);
-    $obj->free();
     return TRUE;
   }
 
@@ -154,7 +153,7 @@ class CRM_Core_BAO_Website extends CRM_Core_DAO_Website {
    *
    * @return bool
    */
-  public static function &getValues(&$params, &$values) {
+  public static function &getValues(&$params = [], &$values = []) {
     $websites = [];
     $website = new CRM_Core_DAO_Website();
     $website->contact_id = $params['contact_id'];
diff --git a/civicrm/CRM/Core/CodeGen/BaseTask.php b/civicrm/CRM/Core/CodeGen/BaseTask.php
index c58a32ac15aa06b6fd140bcfd522402b37549c6a..caf7ff6611ee5b2437bd570ad30da8597bc44c33 100644
--- a/civicrm/CRM/Core/CodeGen/BaseTask.php
+++ b/civicrm/CRM/Core/CodeGen/BaseTask.php
@@ -75,6 +75,7 @@ abstract class CRM_Core_CodeGen_BaseTask implements CRM_Core_CodeGen_ITask {
   protected function isApproxPhpMatch($actual, $expected) {
     foreach (['actual', 'expected'] as $var) {
       $$var = CRM_Core_CodeGen_Util_ArraySyntaxConverter::convert($$var);
+      $$var = preg_replace("#  '\\d+' => #", "  ", $$var);
       $$var = preg_replace(';\(GenCodeChecksum:([a-zA-Z0-9]+)\);', '', $$var);
       $$var = strtolower(preg_replace(';[ \r\n\t];', '', $$var));
     }
diff --git a/civicrm/CRM/Core/CodeGen/I18n.php b/civicrm/CRM/Core/CodeGen/I18n.php
index ea648adaaaf76b417c67418e5bd34ebfe8001787..3d3ecc1bcf410fd3f81a75d94c205508c0d3662f 100644
--- a/civicrm/CRM/Core/CodeGen/I18n.php
+++ b/civicrm/CRM/Core/CodeGen/I18n.php
@@ -36,8 +36,11 @@ class CRM_Core_CodeGen_I18n extends CRM_Core_CodeGen_BaseTask {
         continue;
       }
       foreach ($table['fields'] as $field) {
+        $required = $field['required'] ? ' NOT NULL' : '';
+        $default = $field['default'] ? ' DEFAULT ' . $field['default'] : '';
+        $comment = $field['comment'] ? " COMMENT '" . $field['comment'] . "'" : '';
         if ($field['localizable']) {
-          $columns[$table['name']][$field['name']] = $field['sqlType'];
+          $columns[$table['name']][$field['name']] = $field['sqlType'] . $required . $default . $comment;
           $widgets[$table['name']][$field['name']] = $field['widget'];
         }
       }
diff --git a/civicrm/CRM/Core/CodeGen/Specification.php b/civicrm/CRM/Core/CodeGen/Specification.php
index 9593c45148819d4a2ffafb2955800f9e428e97cc..8e518894d2ba8c550264ca15197983a323fbcae0 100644
--- a/civicrm/CRM/Core/CodeGen/Specification.php
+++ b/civicrm/CRM/Core/CodeGen/Specification.php
@@ -370,7 +370,13 @@ class CRM_Core_CodeGen_Specification {
     $field['uniqueName'] = $this->value('uniqueName', $fieldXML);
     $field['serialize'] = $this->value('serialize', $fieldXML);
     $field['html'] = $this->value('html', $fieldXML);
-    $field['protected'] = $this->value('protected', $fieldXML);
+    if (isset($fieldXML->permission)) {
+      $field['permission'] = trim($this->value('permission', $fieldXML));
+      $field['permission'] = $field['permission'] ? array_filter(array_map('trim', explode(',', $field['permission']))) : [];
+      if (isset($fieldXML->permission->or)) {
+        $field['permission'][] = array_filter(array_map('trim', explode(',', $fieldXML->permission->or)));
+      }
+    }
     if (!empty($field['html'])) {
       $validOptions = [
         'type',
diff --git a/civicrm/CRM/Core/CodeGen/Util/Template.php b/civicrm/CRM/Core/CodeGen/Util/Template.php
index ed2eac1cae61d5f975a5875dae798a935f1ec4b5..5183997b45078f6858c77b96a716d3add26ffe36 100644
--- a/civicrm/CRM/Core/CodeGen/Util/Template.php
+++ b/civicrm/CRM/Core/CodeGen/Util/Template.php
@@ -77,13 +77,15 @@ class CRM_Core_CodeGen_Util_Template {
         "\n  }\n}\n" => "\n  }\n\n}\n",
         '=> true,' => '=> TRUE,',
         '=> false,' => '=> FALSE,',
-        'static ::' => 'static::'
+        'static ::' => 'static::',
       ];
       $contents = str_replace(array_keys($replacements), array_values($replacements), $contents);
       $contents = preg_replace('#(\s*)\\/\\*\\*#', "\n\$1/**", $contents);
 
       // Convert old array syntax to new square brackets
       $contents = CRM_Core_CodeGen_Util_ArraySyntaxConverter::convert($contents);
+      // Remove numeric array keys (assuming its non-associative)
+      $contents = preg_replace("#  '\\d+' => #", "  ", $contents);
     }
     // Ensure file ends with a newline
     if (substr($contents, -1) !== "\n") {
diff --git a/civicrm/CRM/Core/Config.php b/civicrm/CRM/Core/Config.php
index b9c632feb6d213eebb5052e0675c609507d4d42c..4e3679fb6d4d305d38afedff0d4e7261fda28ada 100644
--- a/civicrm/CRM/Core/Config.php
+++ b/civicrm/CRM/Core/Config.php
@@ -496,6 +496,7 @@ class CRM_Core_Config extends CRM_Core_Config_MagicMerge {
    * @return string
    */
   public function defaultCurrencySymbol($defaultCurrency = NULL) {
+    CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultCurrencySymbol');
     return CRM_Core_BAO_Country::defaultCurrencySymbol($defaultCurrency);
   }
 
diff --git a/civicrm/CRM/Core/DAO.php b/civicrm/CRM/Core/DAO.php
index e2adbc6f7e97f3477452e90e244ca2d676968acc..5eb4713b8fe6cb21cf520acaa6b636478e1ec983 100644
--- a/civicrm/CRM/Core/DAO.php
+++ b/civicrm/CRM/Core/DAO.php
@@ -1599,11 +1599,14 @@ FROM   civicrm_domain
    * @param string $blockCopyOfDependencies
    *   Fields that you want to block from.
    *   getting copied
+   * @param bool $blockCopyofCustomValues
+   *   Case when you don't want to copy the custom values set in a
+   *   template as it will override/ignore the submitted custom values
    *
    * @return CRM_Core_DAO|bool
    *   the newly created copy of the object. False if none created.
    */
-  public static function copyGeneric($daoName, $criteria, $newData = NULL, $fieldsFix = NULL, $blockCopyOfDependencies = NULL) {
+  public static function copyGeneric($daoName, $criteria, $newData = NULL, $fieldsFix = NULL, $blockCopyOfDependencies = NULL, $blockCopyofCustomValues = FALSE) {
     $object = new $daoName();
     $newObject = FALSE;
     if (!$newData) {
@@ -1671,7 +1674,9 @@ FROM   civicrm_domain
         }
       }
       $newObject->save();
-      $newObject->copyCustomFields($object->id, $newObject->id);
+      if (!$blockCopyofCustomValues) {
+        $newObject->copyCustomFields($object->id, $newObject->id);
+      }
       CRM_Utils_Hook::post('create', CRM_Core_DAO_AllCoreTables::getBriefName(str_replace('_BAO_', '_DAO_', $daoName)), $newObject->id, $newObject);
     }
 
@@ -2872,8 +2877,9 @@ SELECT contact_id
    *
    * @param string|null $value
    * @param $serializationType
+   *
    * @return array|null
-   * @throws \Exception
+   * @throws CRM_Core_Exception
    */
   public static function unSerializeField($value, $serializationType) {
     if ($value === NULL) {
@@ -2893,13 +2899,13 @@ SELECT contact_id
         return strlen($value) ? json_decode($value, TRUE) : [];
 
       case self::SERIALIZE_PHP:
-        return strlen($value) ? unserialize($value) : [];
+        return strlen($value) ? unserialize($value, ['allowed_classes' => FALSE]) : [];
 
       case self::SERIALIZE_COMMA:
         return explode(',', trim(str_replace(', ', '', $value)));
 
       default:
-        throw new Exception('Unknown serialization method for field.');
+        throw new CRM_Core_Exception('Unknown serialization method for field.');
     }
   }
 
diff --git a/civicrm/CRM/Core/DAO/ActionLog.php b/civicrm/CRM/Core/DAO/ActionLog.php
index 86a10b240d7d38d35b32f071b55953ae58ee72ff..6737bd08b9d65a0b53c25a9b69f9842b6796f606 100644
--- a/civicrm/CRM/Core/DAO/ActionLog.php
+++ b/civicrm/CRM/Core/DAO/ActionLog.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/ActionLog.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2ccacada384ba37fcf929647dfa3d845)
+ * (GenCodeChecksum:8222f77d3172efea46b87c6924caca5a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/ActionMapping.php b/civicrm/CRM/Core/DAO/ActionMapping.php
index 841bc7d0e24bf738176f6f082434b5f169eebcef..bfc83ced0219d597cc965ed8aa317739df3af35f 100644
--- a/civicrm/CRM/Core/DAO/ActionMapping.php
+++ b/civicrm/CRM/Core/DAO/ActionMapping.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/ActionMapping.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c7d2ed31b30490f0a1794fb81b700ac6)
+ * (GenCodeChecksum:97df1735e5aca0e6f5d44639d54ae2e9)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/ActionSchedule.php b/civicrm/CRM/Core/DAO/ActionSchedule.php
index d6d17288faae82e6a4b079edafe6e1728267aade..dba72de1150adc7f8c55a0a6674d34546758e1eb 100644
--- a/civicrm/CRM/Core/DAO/ActionSchedule.php
+++ b/civicrm/CRM/Core/DAO/ActionSchedule.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/ActionSchedule.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:cb2618343c279fbf0baabe1f1ebd9973)
+ * (GenCodeChecksum:102f7e04ce302d5c27944002ddc9a7e4)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Address.php b/civicrm/CRM/Core/DAO/Address.php
index 50841dbee55325491e74f2daba06a743aaf50263..8317a6a3abd484cfe7a2fc59dfabca6833e27795 100644
--- a/civicrm/CRM/Core/DAO/Address.php
+++ b/civicrm/CRM/Core/DAO/Address.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Address.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:4999e79688aae8d0958e46cbd320ae3a)
+ * (GenCodeChecksum:0bdffc6881044732530669419c70abf8)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/AddressFormat.php b/civicrm/CRM/Core/DAO/AddressFormat.php
index 4aebbfb3c9e78c9d6cfdf12108134b25dcefe5aa..de8520b8ce68abc67b1eb98b96f66f157cf701e3 100644
--- a/civicrm/CRM/Core/DAO/AddressFormat.php
+++ b/civicrm/CRM/Core/DAO/AddressFormat.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/AddressFormat.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:144542b9aa31391600f73d885f819091)
+ * (GenCodeChecksum:7fc341ff6e09eedcfdd201337a1f525a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Cache.php b/civicrm/CRM/Core/DAO/Cache.php
index b9c0d73da33dac1b7975cf00d44515ad84ec271a..5c68f255fa9a098781d49b924b351184aabfcdeb 100644
--- a/civicrm/CRM/Core/DAO/Cache.php
+++ b/civicrm/CRM/Core/DAO/Cache.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Cache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2ed8c033a46531123b2a0bb158487c30)
+ * (GenCodeChecksum:45ad2336491944c63577ccf7c92cb3a1)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Component.php b/civicrm/CRM/Core/DAO/Component.php
index 77def7da10836da0e55ccf4bd63dc783c9149d01..d6b17a7f79f9bbc2c8dd5511e55a144e35364e1c 100644
--- a/civicrm/CRM/Core/DAO/Component.php
+++ b/civicrm/CRM/Core/DAO/Component.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Component.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3259789de86a7fb333ce0b11d35fe6aa)
+ * (GenCodeChecksum:ee0bd8a1777473537b84b92163d7271b)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Country.php b/civicrm/CRM/Core/DAO/Country.php
index 5087ed41384ba39150b4200078997003a990540f..adf66bb8d842bc108a827bc26b06eb3745c519a2 100644
--- a/civicrm/CRM/Core/DAO/Country.php
+++ b/civicrm/CRM/Core/DAO/Country.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Country.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:367384a5604d933a66247bddb06e96bb)
+ * (GenCodeChecksum:7479471ae701d767241aea412fae5024)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/County.php b/civicrm/CRM/Core/DAO/County.php
index 853be19f1b431548a7e205a73ea50b9d2525f50a..69853165767dbf641edf1f0c8a5dfe990845a703 100644
--- a/civicrm/CRM/Core/DAO/County.php
+++ b/civicrm/CRM/Core/DAO/County.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/County.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3ce3045eed44f727cbca947945315329)
+ * (GenCodeChecksum:3a4393198768dfdf5115b4cac511d225)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/CustomField.php b/civicrm/CRM/Core/DAO/CustomField.php
index 573ac27fa01bcceb9792c5fa5d4a13329e4fc2eb..972923f326c970205e88c3f110019315076dc6c5 100644
--- a/civicrm/CRM/Core/DAO/CustomField.php
+++ b/civicrm/CRM/Core/DAO/CustomField.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/CustomField.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:58323f46f5ac021f96591e075b37cca6)
+ * (GenCodeChecksum:2b60ad1539ff2829d131e5b25c1c0c56)
  */
 
 /**
@@ -197,14 +197,14 @@ class CRM_Core_DAO_CustomField extends CRM_Core_DAO {
   public $time_format;
 
   /**
-   *  Number of columns in Note Field
+   * Number of columns in Note Field
    *
    * @var int
    */
   public $note_columns;
 
   /**
-   *  Number of rows in Note Field
+   * Number of rows in Note Field
    *
    * @var int
    */
@@ -570,6 +570,9 @@ class CRM_Core_DAO_CustomField extends CRM_Core_DAO {
           'entity' => 'CustomField',
           'bao' => 'CRM_Core_BAO_CustomField',
           'localizable' => 0,
+          'pseudoconstant' => [
+            'callback' => 'CRM_Core_SelectValues::getDatePluginInputFormats',
+          ],
         ],
         'time_format' => [
           'name' => 'time_format',
@@ -581,6 +584,9 @@ class CRM_Core_DAO_CustomField extends CRM_Core_DAO {
           'entity' => 'CustomField',
           'bao' => 'CRM_Core_BAO_CustomField',
           'localizable' => 0,
+          'pseudoconstant' => [
+            'callback' => 'CRM_Core_SelectValues::getTimeFormats',
+          ],
         ],
         'note_columns' => [
           'name' => 'note_columns',
diff --git a/civicrm/CRM/Core/DAO/CustomGroup.php b/civicrm/CRM/Core/DAO/CustomGroup.php
index 363c13e419c59855e7c463d45ceae76a55b08ca4..0c57ff05fb0ded28c9cad843158b2ad14c1043d1 100644
--- a/civicrm/CRM/Core/DAO/CustomGroup.php
+++ b/civicrm/CRM/Core/DAO/CustomGroup.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/CustomGroup.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:288ec5d75e51339f23a2057dc1a383d2)
+ * (GenCodeChecksum:e4103701823c6d2ba240e404fbefbea8)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Dashboard.php b/civicrm/CRM/Core/DAO/Dashboard.php
index ea13f322039f5bd1acbd9d0291dbb4481901d67e..c0239c42704dcd71bf948eee5cbee7db49fc6aa6 100644
--- a/civicrm/CRM/Core/DAO/Dashboard.php
+++ b/civicrm/CRM/Core/DAO/Dashboard.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Dashboard.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:d1fc3dec2d559acdfedb070a6a5bd107)
+ * (GenCodeChecksum:5b7465862bef69918ea63893442f3b9f)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Discount.php b/civicrm/CRM/Core/DAO/Discount.php
index 17250c3cb3bc674801db8df7d0d1ea3d4fdda6b3..5bf27a0e0f828a8e0e4f8caf2852e22a81debed2 100644
--- a/civicrm/CRM/Core/DAO/Discount.php
+++ b/civicrm/CRM/Core/DAO/Discount.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Discount.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a414d91af17f5a6cfd69e3a0fc8fb8ca)
+ * (GenCodeChecksum:52242814cd1a9a62887775cac86c997d)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Domain.php b/civicrm/CRM/Core/DAO/Domain.php
index e3e5c13014e2d9b921f27a82571acbb101eda80a..d816f9962704632029571f764a4e791e0a758d5b 100644
--- a/civicrm/CRM/Core/DAO/Domain.php
+++ b/civicrm/CRM/Core/DAO/Domain.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Domain.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:74b35dfcc8ad2ade69e9bcb75e2f407b)
+ * (GenCodeChecksum:6319fa49fc8028ac8c0467e07843eab4)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Email.php b/civicrm/CRM/Core/DAO/Email.php
index 1d36308a3081484cc41927c273a918e2c42ce718..b305a8eace840365420f4289cd309e74aef552da 100644
--- a/civicrm/CRM/Core/DAO/Email.php
+++ b/civicrm/CRM/Core/DAO/Email.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Email.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:6da9864657d2b5e46956386ab414d8d6)
+ * (GenCodeChecksum:31a4028aeb68cd445f890635d1cb7989)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/EntityFile.php b/civicrm/CRM/Core/DAO/EntityFile.php
index 9ab75998b90f7420b27874c1e0f63d097fba4be4..a31b7ae3da6ca8a6b83eaa0bdffa428a268a4685 100644
--- a/civicrm/CRM/Core/DAO/EntityFile.php
+++ b/civicrm/CRM/Core/DAO/EntityFile.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/EntityFile.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7a5ef1cb4866290ba8edac3fd92f1102)
+ * (GenCodeChecksum:29535e630a2b0126ea96c998cee79332)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/EntityTag.php b/civicrm/CRM/Core/DAO/EntityTag.php
index e3ea7a3fe5ba0c61c66f71f746ca78764494afb7..dd8ded639fd10b51562537bb3df21b867558a719 100644
--- a/civicrm/CRM/Core/DAO/EntityTag.php
+++ b/civicrm/CRM/Core/DAO/EntityTag.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/EntityTag.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:16302a8c63dcb3978dbc0d089397be50)
+ * (GenCodeChecksum:df3b278f0f356ee3e148605b8b05fa1a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Extension.php b/civicrm/CRM/Core/DAO/Extension.php
index 67f396493f18d140678e73446bd8e9007c945b78..86d42298c9c5afe0aa1c29f2cafdceaf71ecf0e2 100644
--- a/civicrm/CRM/Core/DAO/Extension.php
+++ b/civicrm/CRM/Core/DAO/Extension.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Extension.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:d7421ef144f074ada5688f6e56ab8418)
+ * (GenCodeChecksum:3bfb8f235237e4e59499a8303488a046)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/File.php b/civicrm/CRM/Core/DAO/File.php
index 508a449a0d5092a605d305a253a808fe1a37d9f5..c893c81d1a1cebce1ec4dc92623d0afa6b488c4f 100644
--- a/civicrm/CRM/Core/DAO/File.php
+++ b/civicrm/CRM/Core/DAO/File.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/File.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:0ddebff42aa9d0c2fe3114281ca95e70)
+ * (GenCodeChecksum:85766eaf78c18044c8e9a6cb485ea117)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/IM.php b/civicrm/CRM/Core/DAO/IM.php
index 6d4583a6a1f17ec3b92ca0577ac7900c0fb1d42d..dccac7b49b9e0bd2c5cf9e29725e2a2dec7c4a57 100644
--- a/civicrm/CRM/Core/DAO/IM.php
+++ b/civicrm/CRM/Core/DAO/IM.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/IM.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5a7b60741331c475603af3bb180d2bd7)
+ * (GenCodeChecksum:77c810f15f9a1a849bc8ec0af13c649c)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Job.php b/civicrm/CRM/Core/DAO/Job.php
index 3f4fe93d7525822ca6f7198469b81b55e4f01f0e..6625fa2574115ca6a9da2c24dc058190bc2c5fdc 100644
--- a/civicrm/CRM/Core/DAO/Job.php
+++ b/civicrm/CRM/Core/DAO/Job.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Job.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:752f86f1ad35917f008e81c0bc45786e)
+ * (GenCodeChecksum:a3f0b5ea127818a0f275d56af569eb1b)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/JobLog.php b/civicrm/CRM/Core/DAO/JobLog.php
index 6fd510f4fea30ce70e02d92c1d819e26a00fa10f..00531bbd4bfd4213af1bb67139bc6f816bb2bc3a 100644
--- a/civicrm/CRM/Core/DAO/JobLog.php
+++ b/civicrm/CRM/Core/DAO/JobLog.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/JobLog.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:647390b654065a0cc421975a24ae14f9)
+ * (GenCodeChecksum:b860ad46594114d854eb1d2fc37e24d1)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/LocBlock.php b/civicrm/CRM/Core/DAO/LocBlock.php
index 4c281a54c79cd7d872b2e8ef6c3aeed8f38f1936..0a1a4be726b5477ab04f3fd5b6e0028d28b49fef 100644
--- a/civicrm/CRM/Core/DAO/LocBlock.php
+++ b/civicrm/CRM/Core/DAO/LocBlock.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/LocBlock.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f2893cf360fe552d5ff1d90e2eb9272c)
+ * (GenCodeChecksum:35011d111ee9dcccc7ab60f48880b6c8)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/LocationType.php b/civicrm/CRM/Core/DAO/LocationType.php
index 55f9e0c5fec1307cdafd08360f93782fe3ca411f..305e0763b0da4fb9da18a9750a3a630e2c8ebb98 100644
--- a/civicrm/CRM/Core/DAO/LocationType.php
+++ b/civicrm/CRM/Core/DAO/LocationType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/LocationType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:aa147acf0dac148b113c33d4ca12876c)
+ * (GenCodeChecksum:a77b2a2dbc2f53a177867ce469704e8d)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Log.php b/civicrm/CRM/Core/DAO/Log.php
index 9193116deff66f43248f05ebd9db75f9c1232288..f114b8cc7fe44f0d181af7c8b84321828638ff0d 100644
--- a/civicrm/CRM/Core/DAO/Log.php
+++ b/civicrm/CRM/Core/DAO/Log.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Log.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ffaccbd0ebaf86e07a6302fe32e05ea8)
+ * (GenCodeChecksum:4831d3f4833c533032a5f562da1130d8)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/MailSettings.php b/civicrm/CRM/Core/DAO/MailSettings.php
index a3aa181b9f2b9997b559af715314a3dd43d43ac5..a6b6b834ddeaedd3066167b6f4ab0dc530913129 100644
--- a/civicrm/CRM/Core/DAO/MailSettings.php
+++ b/civicrm/CRM/Core/DAO/MailSettings.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/MailSettings.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:1818e655bde2e2a0ecd15e7d645ba58a)
+ * (GenCodeChecksum:483283fce07ef3bebe93af487bd250fc)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Managed.php b/civicrm/CRM/Core/DAO/Managed.php
index 68272f34cfdd1135fda6ff3cb02ab3cf70856f3e..45009de133cbe47967eb48b518424ef6df838489 100644
--- a/civicrm/CRM/Core/DAO/Managed.php
+++ b/civicrm/CRM/Core/DAO/Managed.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Managed.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:79f57e32601e72d62755569fbf58c801)
+ * (GenCodeChecksum:0a3426b03618a0a253555cc5a36879d1)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Mapping.php b/civicrm/CRM/Core/DAO/Mapping.php
index d3b2da95e608c57e11c32060ebef5ae5d22ffd10..84e6234c7052334cd5e3112e96cfa65929d9dd89 100644
--- a/civicrm/CRM/Core/DAO/Mapping.php
+++ b/civicrm/CRM/Core/DAO/Mapping.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Mapping.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e0576a33199627f5846830d076b12229)
+ * (GenCodeChecksum:af46f571b67dd7d13fe399df24780ed0)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/MappingField.php b/civicrm/CRM/Core/DAO/MappingField.php
index afa1179d87f20aada969d7acc95a74358b5c3e0d..571f5941dbba06e34d3b8a67a979669da2ea5c07 100644
--- a/civicrm/CRM/Core/DAO/MappingField.php
+++ b/civicrm/CRM/Core/DAO/MappingField.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/MappingField.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e18a4d7c43e3fded3e10bed98437577e)
+ * (GenCodeChecksum:91eb77fb56523f90c6640c1f61732f3a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Menu.php b/civicrm/CRM/Core/DAO/Menu.php
index 1aca8e4b087b5e289d65444f09c47a8f112d78b4..45d6dab55e19c69893b8ddfa780b2d02e076d4cc 100644
--- a/civicrm/CRM/Core/DAO/Menu.php
+++ b/civicrm/CRM/Core/DAO/Menu.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Menu.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2ba374f38c5906a6338e2c0de34208f6)
+ * (GenCodeChecksum:19bdd29c98ad52486377dc77170324c6)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/MessageTemplate.php b/civicrm/CRM/Core/DAO/MessageTemplate.php
index 5b4604881fffdf682715ade889cd1bf74150d64c..39c04a727fb1cfeea1cc495fe4c37a47dd41d79e 100644
--- a/civicrm/CRM/Core/DAO/MessageTemplate.php
+++ b/civicrm/CRM/Core/DAO/MessageTemplate.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/MessageTemplate.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:334135bbbd8614a2501e1cf56715eb46)
+ * (GenCodeChecksum:c940d61105caa25d6e3ccc4aee660f62)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Navigation.php b/civicrm/CRM/Core/DAO/Navigation.php
index 2aa3fc3d0d21a88c4deac3842258647ceda39609..16e227b64e3d7bb1959c6e765fccafdb84c72607 100644
--- a/civicrm/CRM/Core/DAO/Navigation.php
+++ b/civicrm/CRM/Core/DAO/Navigation.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Navigation.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:377bbf9cfce4cb146a9638344c718b11)
+ * (GenCodeChecksum:a28573fd104aa9d86d59ef2ecf89de65)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Note.php b/civicrm/CRM/Core/DAO/Note.php
index 4fe2a823cc530298bdf1ab278fbae964f8c1172e..0c8e270cf15539acb2a2ae961aa692e85692e40b 100644
--- a/civicrm/CRM/Core/DAO/Note.php
+++ b/civicrm/CRM/Core/DAO/Note.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Note.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c5b4c2796ae7a974e822e74d9e5b4338)
+ * (GenCodeChecksum:4809780ce0ff76ab175d5a8e338063e1)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/OpenID.php b/civicrm/CRM/Core/DAO/OpenID.php
index 542d774e9fa65cec5313f47bcfd0d73107137b09..52014b7fa08d9c159c8e83f1207a9379716a27cb 100644
--- a/civicrm/CRM/Core/DAO/OpenID.php
+++ b/civicrm/CRM/Core/DAO/OpenID.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/OpenID.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:d63a37d228f3faa87726f65906737301)
+ * (GenCodeChecksum:4e19fb6ba4dd25d91a724e28f3520de5)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/OptionGroup.php b/civicrm/CRM/Core/DAO/OptionGroup.php
index 9908d873aebb9496f38ba0e6cb7e4149e949488a..a3d07c2bde90573912d3f17464a409d45dc327d2 100644
--- a/civicrm/CRM/Core/DAO/OptionGroup.php
+++ b/civicrm/CRM/Core/DAO/OptionGroup.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/OptionGroup.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c9ed24515dcc4ce676fb21518bd90791)
+ * (GenCodeChecksum:15efcffb2511a210d1d612ed1b75e794)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/OptionValue.php b/civicrm/CRM/Core/DAO/OptionValue.php
index 3f62e140d3ea650e68062634495a3d07f27a4810..f98c38b2bfd1b2699e8604d5bd367896154da6bb 100644
--- a/civicrm/CRM/Core/DAO/OptionValue.php
+++ b/civicrm/CRM/Core/DAO/OptionValue.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/OptionValue.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:803748252a3d5c50be80b18ccdb3132c)
+ * (GenCodeChecksum:c23dc115f67f29dd89f33504f3521dbf)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Persistent.php b/civicrm/CRM/Core/DAO/Persistent.php
index 41ffa70f1b3806638358e949da17c50017826387..6b2661dcd0d0c22a08ef4c30790010575f3fc0b9 100644
--- a/civicrm/CRM/Core/DAO/Persistent.php
+++ b/civicrm/CRM/Core/DAO/Persistent.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Persistent.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:4044954800a1201a4e3c376d48342f4c)
+ * (GenCodeChecksum:3058ae9acc0aeaed4fd2783130822ad5)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Phone.php b/civicrm/CRM/Core/DAO/Phone.php
index f85772ce62fa9cb84522bfaaf8199afcf587dd09..e204d3b3f54286c378cae1f2eef508d89846ba70 100644
--- a/civicrm/CRM/Core/DAO/Phone.php
+++ b/civicrm/CRM/Core/DAO/Phone.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Phone.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ac451e083bb4bbf26f53556086b266bf)
+ * (GenCodeChecksum:0534130e8e98264b63217e03811d6fce)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/PreferencesDate.php b/civicrm/CRM/Core/DAO/PreferencesDate.php
index 2441d6c0327cc313dc1dc7c6fe44f1383efec85c..d0124645e5c97b693cb98dbca7bdc1eee3bd3d40 100644
--- a/civicrm/CRM/Core/DAO/PreferencesDate.php
+++ b/civicrm/CRM/Core/DAO/PreferencesDate.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/PreferencesDate.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:18663ed2b585f1598a26a5a491c67ea6)
+ * (GenCodeChecksum:714e30a9fca325cee6f343d8d3795558)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/PrevNextCache.php b/civicrm/CRM/Core/DAO/PrevNextCache.php
index 190c88939592666958c6dbc747a6dee15a754cf0..5e0d62a6ddff67506edae74172dc9e2825a3d76c 100644
--- a/civicrm/CRM/Core/DAO/PrevNextCache.php
+++ b/civicrm/CRM/Core/DAO/PrevNextCache.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/PrevNextCache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f67e7fde19a780da589bcf8a0fdd77bf)
+ * (GenCodeChecksum:a7da8d1ee42e2d8fb5e5c1908ea0ba42)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/PrintLabel.php b/civicrm/CRM/Core/DAO/PrintLabel.php
index 55916812524c153c6f88e66fb1b5c35ac89f1553..6ba14b1e324d4da412f4c28bee88cc757ca84bf8 100644
--- a/civicrm/CRM/Core/DAO/PrintLabel.php
+++ b/civicrm/CRM/Core/DAO/PrintLabel.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/PrintLabel.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2bf1df61a7093242ac2cde0d4d8ef1e0)
+ * (GenCodeChecksum:d17db2be65263186b2b4974afe67cff2)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/RecurringEntity.php b/civicrm/CRM/Core/DAO/RecurringEntity.php
index cd514f9b3da5014a00c66c2a48be596cf9afd12d..9fad6c8240cb4948f957460f0d5013ca880a8ea2 100644
--- a/civicrm/CRM/Core/DAO/RecurringEntity.php
+++ b/civicrm/CRM/Core/DAO/RecurringEntity.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/RecurringEntity.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:9e730db130a597de8528532d06f2ad54)
+ * (GenCodeChecksum:75a6072b6cdbce96d00f5e08e160d038)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Setting.php b/civicrm/CRM/Core/DAO/Setting.php
index bb9401d1a5bfebe549ce1d91fe37b6a40c700ab5..6f1be9bfd17d09ce639594bd0e352ef030d3f49d 100644
--- a/civicrm/CRM/Core/DAO/Setting.php
+++ b/civicrm/CRM/Core/DAO/Setting.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Setting.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7bbe096eb48d3744aa86453cccb99bfb)
+ * (GenCodeChecksum:bfd7ba95e46874ca5fb1d30ab43949f6)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/StateProvince.php b/civicrm/CRM/Core/DAO/StateProvince.php
index bf17bcd93603cdd9a2e8dc11875e44ddedae5c9f..9cc7565717245bd4f8d3cddd0292902d614b1e5d 100644
--- a/civicrm/CRM/Core/DAO/StateProvince.php
+++ b/civicrm/CRM/Core/DAO/StateProvince.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/StateProvince.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:38620d39135bc4e42f0cc688dff9cb5b)
+ * (GenCodeChecksum:37b637b11e8eba970e40de0b20c5083a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/StatusPreference.php b/civicrm/CRM/Core/DAO/StatusPreference.php
index 94f5d599380225a0b79496ef9b9edd46f8f33ad3..721b5e56b91686bcbf8d94f46b7a69114d09988d 100644
--- a/civicrm/CRM/Core/DAO/StatusPreference.php
+++ b/civicrm/CRM/Core/DAO/StatusPreference.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/StatusPreference.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:777d59b72a077ecb4d4caa60e13bb479)
+ * (GenCodeChecksum:9a60c9ad936d80034142b5eda6ea1789)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/SystemLog.php b/civicrm/CRM/Core/DAO/SystemLog.php
index c1587e0bdd68d79e4c92ce7e5ceadb5825e82295..b2e95c358d332508904deeb04d99b32ab953c9e6 100644
--- a/civicrm/CRM/Core/DAO/SystemLog.php
+++ b/civicrm/CRM/Core/DAO/SystemLog.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/SystemLog.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a2276bcf3bb39a3947bf54b043fa0a05)
+ * (GenCodeChecksum:efe1ac6318085ebd0529f41d394c693f)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Tag.php b/civicrm/CRM/Core/DAO/Tag.php
index 826157f63cca11d665df383873d63fbdbfd73b23..3e365698db8acf5c8ccbda23bc967eea5b278191 100644
--- a/civicrm/CRM/Core/DAO/Tag.php
+++ b/civicrm/CRM/Core/DAO/Tag.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Tag.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3abd98f177e35fd993b77bf08b115e4a)
+ * (GenCodeChecksum:0f07d0631c95bf8c7405a4dd61e7694a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Timezone.php b/civicrm/CRM/Core/DAO/Timezone.php
index 0c33a2f11d8d2008f4cc19b30ca482ac7fc0d7d3..a688d9c82024786e6c953f67f4d3f944d2008959 100644
--- a/civicrm/CRM/Core/DAO/Timezone.php
+++ b/civicrm/CRM/Core/DAO/Timezone.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Timezone.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7a377d04c1e9cfede74c42b155e301f5)
+ * (GenCodeChecksum:8a3cd87d8bc1150a732876fa093fc370)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/UFField.php b/civicrm/CRM/Core/DAO/UFField.php
index 7f06eb7a50cbc05c61d594d88e0800f0368767cd..1773c9f32f125487887ec8160ebc5e4ae6f0077a 100644
--- a/civicrm/CRM/Core/DAO/UFField.php
+++ b/civicrm/CRM/Core/DAO/UFField.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/UFField.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:4e6400ee9a0d081541d8e14366129502)
+ * (GenCodeChecksum:b46a1d1d1ff00165a23db2776df9e678)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/UFGroup.php b/civicrm/CRM/Core/DAO/UFGroup.php
index 792c2abb1f5631f41bd8edbf191ed251403797d0..0a1c5b72e0140511774f831c6c83d24da0e1f5c0 100644
--- a/civicrm/CRM/Core/DAO/UFGroup.php
+++ b/civicrm/CRM/Core/DAO/UFGroup.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/UFGroup.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2a382dd695bc7d2ad3dca96996c5258b)
+ * (GenCodeChecksum:6725768569ed10f4aba92aaca9a2339f)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/UFJoin.php b/civicrm/CRM/Core/DAO/UFJoin.php
index 05bf4704f9970a9384e77c9e9402b812ea7caabf..8f3589a09b81802698f616ea522df30a1e2b328b 100644
--- a/civicrm/CRM/Core/DAO/UFJoin.php
+++ b/civicrm/CRM/Core/DAO/UFJoin.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/UFJoin.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:00acc4bbb42aee2a24981b30456458c1)
+ * (GenCodeChecksum:5cf4b4cb3d7d0a1769ad81e458007844)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/UFMatch.php b/civicrm/CRM/Core/DAO/UFMatch.php
index fc1d60dc1aed9c07a5bcd5fad190c812d1fdc1fc..0066c7080e295113bd31dfa099e3d169ea068433 100644
--- a/civicrm/CRM/Core/DAO/UFMatch.php
+++ b/civicrm/CRM/Core/DAO/UFMatch.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/UFMatch.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:b7305bf7df97967d214db393a34f740f)
+ * (GenCodeChecksum:647c57bc3c8e3ddb2cc71842ae71f43a)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Website.php b/civicrm/CRM/Core/DAO/Website.php
index 31b4d03d4ebfa7d575281cd003962524ac115928..c73eb2040d1c0b61856f954fbd980cac7a95ef1d 100644
--- a/civicrm/CRM/Core/DAO/Website.php
+++ b/civicrm/CRM/Core/DAO/Website.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Website.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:22c11a2bc194d075912df3279acc6a97)
+ * (GenCodeChecksum:4ab7ed5d71178e5706dd4ae767b94442)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/WordReplacement.php b/civicrm/CRM/Core/DAO/WordReplacement.php
index 637bcceb5b375cf94c3621df985d73138ffbc863..54071564001a1c7e5c18c1184468e6b1aedfbab0 100644
--- a/civicrm/CRM/Core/DAO/WordReplacement.php
+++ b/civicrm/CRM/Core/DAO/WordReplacement.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/WordReplacement.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:1f2d0542e46494b542dce1c0132a1643)
+ * (GenCodeChecksum:acca77263288fe75fc59483f036e21e0)
  */
 
 /**
diff --git a/civicrm/CRM/Core/DAO/Worldregion.php b/civicrm/CRM/Core/DAO/Worldregion.php
index 05665f23037ebbdae162c6bb00388a8b4cd96778..9782972aedee6d4fd8d4c35ca9a5aa16f08a9f2d 100644
--- a/civicrm/CRM/Core/DAO/Worldregion.php
+++ b/civicrm/CRM/Core/DAO/Worldregion.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Worldregion.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:b607c0ba0b25b3f785779384fc6a6887)
+ * (GenCodeChecksum:13bc78085a61efbbcc04fd4d7a27450e)
  */
 
 /**
diff --git a/civicrm/CRM/Core/Exception/PrematureExitException.php b/civicrm/CRM/Core/Exception/PrematureExitException.php
index 3b0f574d1625596f66e8853f84c627c307635fb6..854b2334812608d0e849d91fee600ee7c5bb467e 100644
--- a/civicrm/CRM/Core/Exception/PrematureExitException.php
+++ b/civicrm/CRM/Core/Exception/PrematureExitException.php
@@ -41,4 +41,19 @@
  */
 class CRM_Core_Exception_PrematureExitException extends RuntimeException {
 
+  /**
+   * Construct the exception. Note: The message is NOT binary safe.
+   *
+   * @link https://php.net/manual/en/exception.construct.php
+   *
+   * @param string $message [optional] The Exception message to throw.
+   * @param array $errorData
+   * @param int $error_code
+   * @param throwable $previous [optional] The previous throwable used for the exception chaining.
+   */
+  public function __construct($message = "", $errorData = [], $error_code = 0, throwable $previous = NULL) {
+    parent::__construct($message, $error_code, $previous);
+    $this->errorData = $errorData + ['error_code' => $error_code];
+  }
+
 }
diff --git a/civicrm/CRM/Core/Form.php b/civicrm/CRM/Core/Form.php
index 91d8cf883075abbb4f185a15ff63349e75772b47..6d5e6e5a14ca02265b4cda218e1c2256f464542c 100644
--- a/civicrm/CRM/Core/Form.php
+++ b/civicrm/CRM/Core/Form.php
@@ -189,6 +189,11 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
    */
   protected $context;
 
+  /**
+   * @var bool
+   */
+  public $submitOnce = FALSE;
+
   /**
    * @return string
    */
@@ -627,6 +632,10 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     ) {
       $this->setAttribute('data-warn-changes', 'true');
     }
+
+    if ($this->submitOnce) {
+      $this->setAttribute('data-submit-once', 'true');
+    }
   }
 
   /**
@@ -642,7 +651,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     $prevnext = $spacing = [];
     foreach ($params as $button) {
       if (!empty($button['submitOnce'])) {
-        $button['js']['onclick'] = "return submitOnce(this,'{$this->_name}','" . ts('Processing') . "');";
+        $this->submitOnce = TRUE;
       }
 
       $attrs = ['class' => 'crm-form-submit'] + (array) CRM_Utils_Array::value('js', $button);
@@ -837,6 +846,8 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
       $this->_params = array_merge($this->_params, $addressParams);
     }
 
+    // @fixme it would be really nice to have a comment here so I had a clue why we are setting $fields[$name] = 1
+    // Also how does relate to similar code in CRM_Contact_BAO_Contact::addBillingNameFieldsIfOtherwiseNotSet()
     $nameFields = ['first_name', 'middle_name', 'last_name'];
     foreach ($nameFields as $name) {
       $fields[$name] = 1;
@@ -1253,7 +1264,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
    * @param string $nextType
    *   Button type for the form after processing.
    * @param string $backType
-   * @param bool|string $submitOnce If true, add javascript to next button submit which prevents it from being clicked more than once
+   * @param bool|string $submitOnce
    */
   public function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
     $buttons = [];
@@ -1270,7 +1281,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
         'isDefault' => TRUE,
       ];
       if ($submitOnce) {
-        $nextButton['js'] = ['onclick' => "return submitOnce(this,'{$this->_name}','" . ts('Processing') . "');"];
+        $this->submitOnce = TRUE;
       }
       $buttons[] = $nextButton;
     }
diff --git a/civicrm/CRM/Core/Form/Search.php b/civicrm/CRM/Core/Form/Search.php
index 865cb9e694d265d6300b4b4f21e1c868e0c96946..29576459915cfee6c6a56140e64429962e73d3fe 100644
--- a/civicrm/CRM/Core/Form/Search.php
+++ b/civicrm/CRM/Core/Form/Search.php
@@ -132,7 +132,11 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    * @throws \Exception
    */
   public function setDefaultValues() {
-    return array_merge($this->getEntityDefaults($this->getDefaultEntity()), (array) $this->_formValues);
+    $defaults = (array) $this->_formValues;
+    foreach (['Contact', $this->getDefaultEntity()] as $entity) {
+      $defaults = array_merge($this->getEntityDefaults($entity), $defaults);
+    }
+    return $defaults;
   }
 
   /**
@@ -251,19 +255,19 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    */
   protected function getEntityDefaults($entity) {
     $defaults = [];
-    foreach ($this->getSearchFieldMetadata()[$entity] as $fieldSpec) {
-      if (empty($_POST[$fieldSpec['name']])) {
-        $value = CRM_Utils_Request::retrieveValue($fieldSpec['name'], $this->getValidationTypeForField($entity, $fieldSpec['name']), FALSE, NULL, 'GET');
-        if ($value !== FALSE) {
-          $defaults[$fieldSpec['name']] = $value;
+    foreach (CRM_Utils_Array::value($entity, $this->getSearchFieldMetadata(), []) as $fieldName => $fieldSpec) {
+      if (empty($_POST[$fieldName])) {
+        $value = CRM_Utils_Request::retrieveValue($fieldName, $this->getValidationTypeForField($entity, $fieldName), NULL, NULL, 'GET');
+        if ($value !== NULL) {
+          $defaults[$fieldName] = $value;
         }
         if ($fieldSpec['type'] === CRM_Utils_Type::T_DATE || ($fieldSpec['type'] === CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME)) {
-          $low = CRM_Utils_Request::retrieveValue($fieldSpec['name'] . '_low', 'Timestamp', FALSE, NULL, 'GET');
-          $high = CRM_Utils_Request::retrieveValue($fieldSpec['name'] . '_high', 'Timestamp', FALSE, NULL, 'GET');
-          if ($low !== FALSE || $high !== FALSE) {
-            $defaults[$fieldSpec['name'] . '_relative'] = 0;
-            $defaults[$fieldSpec['name'] . '_low'] = $low ? date('Y-m-d H:i:s', strtotime($low)) : NULL;
-            $defaults[$fieldSpec['name'] . '_high'] = $high ? date('Y-m-d H:i:s', strtotime($high)) : NULL;
+          $low = CRM_Utils_Request::retrieveValue($fieldName . '_low', 'Timestamp', NULL, NULL, 'GET');
+          $high = CRM_Utils_Request::retrieveValue($fieldName . '_high', 'Timestamp', NULL, NULL, 'GET');
+          if ($low !== NULL || $high !== NULL) {
+            $defaults[$fieldName . '_relative'] = 0;
+            $defaults[$fieldName . '_low'] = $low ? date('Y-m-d H:i:s', strtotime($low)) : NULL;
+            $defaults[$fieldName . '_high'] = $high ? date('Y-m-d H:i:s', strtotime($high)) : NULL;
           }
         }
       }
@@ -327,12 +331,14 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
    * to define the string.
    */
   protected function addSortNameField() {
+    $title = civicrm_api3('setting', 'getvalue', ['name' => 'includeEmailInName', 'group' => 'Search Preferences']) ? $this->getSortNameLabelWithEmail() : $this->getSortNameLabelWithOutEmail();
     $this->addElement(
       'text',
       'sort_name',
-      civicrm_api3('setting', 'getvalue', ['name' => 'includeEmailInName', 'group' => 'Search Preferences']) ? $this->getSortNameLabelWithEmail() : $this->getSortNameLabelWithOutEmail(),
+      $title,
       CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')
     );
+    $this->searchFieldMetadata['Contact']['sort_name'] = ['name' => 'sort_name', 'title' => $title, 'type' => CRM_Utils_Type::T_STRING];
   }
 
   /**
diff --git a/civicrm/CRM/Core/I18n/Form.php b/civicrm/CRM/Core/I18n/Form.php
index bc8b776af1fa4bbdcaff6dc63c9675836e792e34..dd7aa9bd31dccdc8147002b54a9d8cca10e28df5 100644
--- a/civicrm/CRM/Core/I18n/Form.php
+++ b/civicrm/CRM/Core/I18n/Form.php
@@ -78,7 +78,10 @@ class CRM_Core_I18n_Form extends CRM_Core_Form {
 
     if ($widget['type'] == 'RichTextEditor') {
       $widget['type'] = 'wysiwyg';
-      $attributes['class'] .= ' collapsed';
+      $attributes['class'] = 'collapsed';
+    }
+    elseif ($widget['type'] == 'Text') {
+      $attributes['class'] = 'huge';
     }
 
     $languages = CRM_Core_I18n::languages(TRUE);
diff --git a/civicrm/CRM/Core/I18n/SchemaStructure.php b/civicrm/CRM/Core/I18n/SchemaStructure.php
index 439e5ec58f74f29b67a4e486982ea2f64dcf443d..899d84423106df2dbaf00257263ce7ab3eb4c7ea 100644
--- a/civicrm/CRM/Core/I18n/SchemaStructure.php
+++ b/civicrm/CRM/Core/I18n/SchemaStructure.php
@@ -46,161 +46,161 @@ class CRM_Core_I18n_SchemaStructure {
     if (!$result) {
       $result = [
         'civicrm_location_type' => [
-          'display_name' => "varchar(64)",
+          'display_name' => "varchar(64) COMMENT 'Location Type Display Name.'",
         ],
         'civicrm_option_group' => [
-          'title' => "varchar(255)",
-          'description' => "varchar(255)",
+          'title' => "varchar(255) COMMENT 'Option Group title.'",
+          'description' => "varchar(255) COMMENT 'Option group description.'",
         ],
         'civicrm_relationship_type' => [
-          'label_a_b' => "varchar(64)",
-          'label_b_a' => "varchar(64)",
-          'description' => "varchar(255)",
+          'label_a_b' => "varchar(64) COMMENT 'label for relationship of contact_a to contact_b.'",
+          'label_b_a' => "varchar(64) COMMENT 'Optional label for relationship of contact_b to contact_a.'",
+          'description' => "varchar(255) COMMENT 'Optional verbose description of the relationship type.'",
         ],
         'civicrm_contact_type' => [
-          'label' => "varchar(64)",
-          'description' => "text",
+          'label' => "varchar(64) COMMENT 'localized Name of Contact Type.'",
+          'description' => "text COMMENT 'localized Optional verbose description of the type.'",
         ],
         'civicrm_batch' => [
-          'title' => "varchar(255)",
-          'description' => "text",
+          'title' => "varchar(255) COMMENT 'Friendly Name.'",
+          'description' => "text COMMENT 'Description of this batch set.'",
         ],
         'civicrm_premiums' => [
-          'premiums_intro_title' => "varchar(255)",
-          'premiums_intro_text' => "text",
-          'premiums_nothankyou_label' => "varchar(255)",
+          'premiums_intro_title' => "varchar(255) COMMENT 'Title for Premiums section.'",
+          'premiums_intro_text' => "text COMMENT 'Displayed in <div> at top of Premiums section of page. Text and HTML allowed.'",
+          'premiums_nothankyou_label' => "varchar(255) COMMENT 'Label displayed for No Thank-you option in premiums block (e.g. No thank you)'",
         ],
         'civicrm_membership_status' => [
-          'label' => "varchar(128)",
+          'label' => "varchar(128) COMMENT 'Label for Membership Status'",
         ],
         'civicrm_survey' => [
-          'title' => "varchar(255)",
-          'instructions' => "text",
-          'thankyou_title' => "varchar(255)",
-          'thankyou_text' => "text",
+          'title' => "varchar(255) NOT NULL COMMENT 'Title of the Survey.'",
+          'instructions' => "text COMMENT 'Script instructions for volunteers to use for the survey.'",
+          'thankyou_title' => "varchar(255) COMMENT 'Title for Thank-you page (header title tag, and display at the top of the page).'",
+          'thankyou_text' => "text COMMENT 'text and html allowed. displayed above result on success page'",
         ],
         'civicrm_participant_status_type' => [
-          'label' => "varchar(255)",
+          'label' => "varchar(255) COMMENT 'localized label for display of this status type'",
         ],
         'civicrm_case_type' => [
-          'title' => "varchar(64)",
-          'description' => "varchar(255)",
+          'title' => "varchar(64) NOT NULL COMMENT 'Natural language name for Case Type'",
+          'description' => "varchar(255) COMMENT 'Description of the Case Type'",
         ],
         'civicrm_tell_friend' => [
           'title' => "varchar(255)",
-          'intro' => "text",
-          'suggested_message' => "text",
-          'thankyou_title' => "varchar(255)",
-          'thankyou_text' => "text",
+          'intro' => "text COMMENT 'Introductory message to contributor or participant displayed on the Tell a Friend form.'",
+          'suggested_message' => "text COMMENT 'Suggested message to friends, provided as default on the Tell A Friend form.'",
+          'thankyou_title' => "varchar(255) COMMENT 'Text for Tell a Friend thank you page header and HTML title.'",
+          'thankyou_text' => "text COMMENT 'Thank you message displayed on success page.'",
         ],
         'civicrm_custom_group' => [
-          'title' => "varchar(64)",
-          'help_pre' => "text",
-          'help_post' => "text",
+          'title' => "varchar(64) NOT NULL COMMENT 'Friendly Name.'",
+          'help_pre' => "text COMMENT 'Description and/or help text to display before fields in form.'",
+          'help_post' => "text COMMENT 'Description and/or help text to display after fields in form.'",
         ],
         'civicrm_custom_field' => [
-          'label' => "varchar(255)",
-          'help_pre' => "text",
-          'help_post' => "text",
+          'label' => "varchar(255) NOT NULL COMMENT 'Text for form field label (also friendly name for administering this custom property).'",
+          'help_pre' => "text COMMENT 'Description and/or help text to display before this field.'",
+          'help_post' => "text COMMENT 'Description and/or help text to display after this field.'",
         ],
         'civicrm_option_value' => [
-          'label' => "varchar(512)",
-          'description' => "text",
+          'label' => "varchar(512) NOT NULL COMMENT 'Option string as displayed to users - e.g. the label in an HTML OPTION tag.'",
+          'description' => "text COMMENT 'Optional description.'",
         ],
         'civicrm_group' => [
-          'title' => "varchar(64)",
+          'title' => "varchar(64) COMMENT 'Name of Group.'",
         ],
         'civicrm_contribution_page' => [
-          'title' => "varchar(255)",
-          'intro_text' => "text",
-          'pay_later_text' => "text",
-          'pay_later_receipt' => "text",
-          'initial_amount_label' => "varchar(255)",
-          'initial_amount_help_text' => "text",
-          'thankyou_title' => "varchar(255)",
-          'thankyou_text' => "text",
-          'thankyou_footer' => "text",
-          'receipt_from_name' => "varchar(255)",
-          'receipt_text' => "text",
-          'footer_text' => "text",
+          'title' => "varchar(255) COMMENT 'Contribution Page title. For top of page display'",
+          'intro_text' => "text COMMENT 'Text and html allowed. Displayed below title.'",
+          'pay_later_text' => "text COMMENT 'The text displayed to the user in the main form'",
+          'pay_later_receipt' => "text COMMENT 'The receipt sent to the user instead of the normal receipt text'",
+          'initial_amount_label' => "varchar(255) COMMENT 'Initial amount label for partial payment'",
+          'initial_amount_help_text' => "text COMMENT 'Initial amount help text for partial payment'",
+          'thankyou_title' => "varchar(255) COMMENT 'Title for Thank-you page (header title tag, and display at the top of the page).'",
+          'thankyou_text' => "text COMMENT 'text and html allowed. displayed above result on success page'",
+          'thankyou_footer' => "text COMMENT 'Text and html allowed. displayed at the bottom of the success page. Common usage is to include link(s) to other pages such as tell-a-friend, etc.'",
+          'receipt_from_name' => "varchar(255) COMMENT 'FROM email name used for receipts generated by contributions to this contribution page.'",
+          'receipt_text' => "text COMMENT 'text to include above standard receipt info on receipt email. emails are text-only, so do not allow html for now'",
+          'footer_text' => "text COMMENT 'Text and html allowed. Displayed at the bottom of the first page of the contribution wizard.'",
         ],
         'civicrm_product' => [
-          'name' => "varchar(255)",
-          'description' => "text",
-          'options' => "text",
+          'name' => "varchar(255) NOT NULL COMMENT 'Required product/premium name'",
+          'description' => "text COMMENT 'Optional description of the product/premium.'",
+          'options' => "text COMMENT 'Store comma-delimited list of color, size, etc. options for the product.'",
         ],
         'civicrm_payment_processor' => [
-          'title' => "varchar(127)",
+          'title' => "varchar(127) COMMENT 'Payment Processor Descriptive Name.'",
         ],
         'civicrm_membership_type' => [
-          'name' => "varchar(128)",
-          'description' => "varchar(255)",
+          'name' => "varchar(128) COMMENT 'Name of Membership Type'",
+          'description' => "varchar(255) COMMENT 'Description of Membership Type'",
         ],
         'civicrm_membership_block' => [
-          'new_title' => "varchar(255)",
-          'new_text' => "text",
-          'renewal_title' => "varchar(255)",
-          'renewal_text' => "text",
+          'new_title' => "varchar(255) COMMENT 'Title to display at top of block'",
+          'new_text' => "text COMMENT 'Text to display below title'",
+          'renewal_title' => "varchar(255) COMMENT 'Title for renewal'",
+          'renewal_text' => "text COMMENT 'Text to display for member renewal'",
         ],
         'civicrm_price_set' => [
-          'title' => "varchar(255)",
-          'help_pre' => "text",
-          'help_post' => "text",
+          'title' => "varchar(255) NOT NULL COMMENT 'Displayed title for the Price Set.'",
+          'help_pre' => "text COMMENT 'Description and/or help text to display before fields in form.'",
+          'help_post' => "text COMMENT 'Description and/or help text to display after fields in form.'",
         ],
         'civicrm_dashboard' => [
-          'label' => "varchar(255)",
+          'label' => "varchar(255) COMMENT 'dashlet title'",
         ],
         'civicrm_uf_group' => [
-          'title' => "varchar(64)",
-          'frontend_title' => "varchar(64)",
-          'help_pre' => "text",
-          'help_post' => "text",
-          'cancel_button_text' => "varchar(64)",
-          'submit_button_text' => "varchar(64)",
+          'title' => "varchar(64) NOT NULL COMMENT 'Form title.'",
+          'frontend_title' => "varchar(64) COMMENT 'Profile Form Public title'",
+          'help_pre' => "text COMMENT 'Description and/or help text to display before fields in form.'",
+          'help_post' => "text COMMENT 'Description and/or help text to display after fields in form.'",
+          'cancel_button_text' => "varchar(64) DEFAULT NULL COMMENT 'Custom Text to display on the Cancel button when used in create or edit mode'",
+          'submit_button_text' => "varchar(64) DEFAULT NULL COMMENT 'Custom Text to display on the submit button on profile edit/create screens'",
         ],
         'civicrm_uf_field' => [
-          'help_post' => "text",
-          'help_pre' => "text",
-          'label' => "varchar(255)",
+          'help_post' => "text COMMENT 'Description and/or help text to display after this field.'",
+          'help_pre' => "text COMMENT 'Description and/or help text to display before this field.'",
+          'label' => "varchar(255) NOT NULL COMMENT 'To save label for fields.'",
         ],
         'civicrm_price_field' => [
-          'label' => "varchar(255)",
-          'help_pre' => "text",
-          'help_post' => "text",
+          'label' => "varchar(255) NOT NULL COMMENT 'Text for form field label (also friendly name for administering this field).'",
+          'help_pre' => "text COMMENT 'Description and/or help text to display before this field.'",
+          'help_post' => "text COMMENT 'Description and/or help text to display after this field.'",
         ],
         'civicrm_price_field_value' => [
-          'label' => "varchar(255)",
-          'description' => "text",
-          'help_pre' => "text",
-          'help_post' => "text",
+          'label' => "varchar(255) COMMENT 'Price field option label'",
+          'description' => "text DEFAULT NULL COMMENT 'Price field option description.'",
+          'help_pre' => "text DEFAULT NULL COMMENT 'Price field option pre help text.'",
+          'help_post' => "text DEFAULT NULL COMMENT 'Price field option post field help.'",
         ],
         'civicrm_pcp_block' => [
-          'link_text' => "varchar(255)",
+          'link_text' => "varchar(255) DEFAULT NULL COMMENT 'Link text for PCP.'",
         ],
         'civicrm_event' => [
-          'title' => "varchar(255)",
-          'summary' => "text",
-          'description' => "text",
-          'registration_link_text' => "varchar(255)",
-          'event_full_text' => "text",
+          'title' => "varchar(255) COMMENT 'Event Title (e.g. Fall Fundraiser Dinner)'",
+          'summary' => "text COMMENT 'Brief summary of event. Text and html allowed. Displayed on Event Registration form and can be used on other CMS pages which need an event summary.'",
+          'description' => "text COMMENT 'Full description of event. Text and html allowed. Displayed on built-in Event Information screens.'",
+          'registration_link_text' => "varchar(255) COMMENT 'Text for link to Event Registration form which is displayed on Event Information screen when is_online_registration is true.'",
+          'event_full_text' => "text COMMENT 'Message to display on Event Information page and INSTEAD OF Event Registration form if maximum participants are signed up. Can include email address/info about getting on a waiting list, etc. Text and html allowed.'",
           'fee_label' => "varchar(255)",
-          'intro_text' => "text",
-          'footer_text' => "text",
-          'confirm_title' => "varchar(255)",
-          'confirm_text' => "text",
-          'confirm_footer_text' => "text",
-          'confirm_email_text' => "text",
-          'confirm_from_name' => "varchar(255)",
-          'thankyou_title' => "varchar(255)",
-          'thankyou_text' => "text",
-          'thankyou_footer_text' => "text",
-          'pay_later_text' => "text",
-          'pay_later_receipt' => "text",
-          'initial_amount_label' => "varchar(255)",
-          'initial_amount_help_text' => "text",
-          'waitlist_text' => "text",
-          'approval_req_text' => "text",
-          'template_title' => "varchar(255)",
+          'intro_text' => "text COMMENT 'Introductory message for Event Registration page. Text and html allowed. Displayed at the top of Event Registration form.'",
+          'footer_text' => "text COMMENT 'Footer message for Event Registration page. Text and html allowed. Displayed at the bottom of Event Registration form.'",
+          'confirm_title' => "varchar(255) DEFAULT NULL COMMENT 'Title for Confirmation page.'",
+          'confirm_text' => "text COMMENT 'Introductory message for Event Registration page. Text and html allowed. Displayed at the top of Event Registration form.'",
+          'confirm_footer_text' => "text COMMENT 'Footer message for Event Registration page. Text and html allowed. Displayed at the bottom of Event Registration form.'",
+          'confirm_email_text' => "text COMMENT 'text to include above standard event info on confirmation email. emails are text-only, so do not allow html for now'",
+          'confirm_from_name' => "varchar(255) COMMENT 'FROM email name used for confirmation emails.'",
+          'thankyou_title' => "varchar(255) DEFAULT NULL COMMENT 'Title for ThankYou page.'",
+          'thankyou_text' => "text COMMENT 'ThankYou Text.'",
+          'thankyou_footer_text' => "text COMMENT 'Footer message.'",
+          'pay_later_text' => "text COMMENT 'The text displayed to the user in the main form'",
+          'pay_later_receipt' => "text COMMENT 'The receipt sent to the user instead of the normal receipt text'",
+          'initial_amount_label' => "varchar(255) COMMENT 'Initial amount label for partial payment'",
+          'initial_amount_help_text' => "text COMMENT 'Initial amount help text for partial payment'",
+          'waitlist_text' => "text COMMENT 'Text to display when the event is full, but participants can signup for a waitlist.'",
+          'approval_req_text' => "text COMMENT 'Text to display when the approval is required to complete registration for an event.'",
+          'template_title' => "varchar(255) COMMENT 'Event Template Title'",
         ],
       ];
     }
diff --git a/civicrm/CRM/Core/OptionGroup.php b/civicrm/CRM/Core/OptionGroup.php
index 1bf006722df30446c60697cf145ac7212254387c..2a4324e6cdd3839ce950371cbc379d3eba61fae9 100644
--- a/civicrm/CRM/Core/OptionGroup.php
+++ b/civicrm/CRM/Core/OptionGroup.php
@@ -416,10 +416,8 @@ WHERE  v.option_group_id = g.id
     ];
     $dao = CRM_Core_DAO::executeQuery($query, $p);
     if ($dao->fetch()) {
-      $dao->free();
       return $dao->value;
     }
-    $dao->free();
     return NULL;
   }
 
diff --git a/civicrm/CRM/Core/Page.php b/civicrm/CRM/Core/Page.php
index 145c91af53352081c761e203fa89511e411f4e26..b19388283fc8d073aea22b09bf970108467c3857 100644
--- a/civicrm/CRM/Core/Page.php
+++ b/civicrm/CRM/Core/Page.php
@@ -214,6 +214,10 @@ class CRM_Core_Page {
 
     $config = CRM_Core_Config::singleton();
 
+    // @fixme this is probably the wrong place for this.  It is required by jsortable.tpl which is inherited from many page templates.
+    //   So we have to add it here to deprecate $config->defaultCurrencySymbol
+    $this->assign('defaultCurrencySymbol', CRM_Core_BAO_Country::defaultCurrencySymbol());
+
     // Intermittent alert to admins
     CRM_Utils_Check::singleton()->showPeriodicAlerts();
 
diff --git a/civicrm/CRM/Core/Payment.php b/civicrm/CRM/Core/Payment.php
index eaa4cce0ee3804a27ee118d1d1ba518b9320ccfd..502d332df305b91535b98bb04b91b191ca6d991f 100644
--- a/civicrm/CRM/Core/Payment.php
+++ b/civicrm/CRM/Core/Payment.php
@@ -261,7 +261,14 @@ abstract class CRM_Core_Payment {
     }
 
     $log = new CRM_Utils_SystemLogger();
-    $log->alert($message, $_REQUEST);
+    // $_REQUEST doesn't handle JSON, to support providers that POST JSON we need the raw POST data.
+    $rawRequestData = file_get_contents("php://input");
+    if (CRM_Utils_JSON::isValidJSON($rawRequestData)) {
+      $log->alert($message, json_decode($rawRequestData, TRUE));
+    }
+    else {
+      $log->alert($message, $_REQUEST);
+    }
   }
 
   /**
diff --git a/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php b/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php
index a6beaf12316b4b0f3be9be2a56c17c88e1825949..d09276b9b24446e7f8c0a8e65d1e7b4eade3909e 100644
--- a/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php
+++ b/civicrm/CRM/Core/Payment/AuthorizeNetIPN.php
@@ -230,6 +230,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
    * @param array $ids
    *
    * @return bool
+   * @throws \CRM_Core_Exception
    */
   public function getInput(&$input, &$ids) {
     $input['amount'] = $this->retrieve('x_amount', 'String');
@@ -241,7 +242,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
     $input['subscription_paynum'] = $this->retrieve('x_subscription_paynum', 'Integer', FALSE, 0);
     $input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
     $input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
-    $input['receive_date'] = $this->retrieve('receive_date', 'String', FALSE, 'now');
+    $input['receive_date'] = $this->retrieve('receive_date', 'String', FALSE, date('YmdHis', strtotime('now')));
 
     if ($input['trxn_id']) {
       $input['is_test'] = 0;
diff --git a/civicrm/CRM/Core/Payment/Dummy.php b/civicrm/CRM/Core/Payment/Dummy.php
index d2f8c5c00d444fd97f6bbd447fd2989d85e23698..7c260074a2007c56f3a0006c4d36457e44cdbd20 100644
--- a/civicrm/CRM/Core/Payment/Dummy.php
+++ b/civicrm/CRM/Core/Payment/Dummy.php
@@ -105,7 +105,7 @@ class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
     if ($this->_mode == 'test') {
       $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test\\_%'";
       $p = [];
-      $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p));
+      $trxn_id = strval(CRM_Core_DAO::singleValueQuery($query, $p));
       $trxn_id = str_replace('test_', '', $trxn_id);
       $trxn_id = intval($trxn_id) + 1;
       $params['trxn_id'] = 'test_' . $trxn_id . '_' . uniqid();
@@ -113,7 +113,7 @@ class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
     else {
       $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'live_%'";
       $p = [];
-      $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p));
+      $trxn_id = strval(CRM_Core_DAO::singleValueQuery($query, $p));
       $trxn_id = str_replace('live_', '', $trxn_id);
       $trxn_id = intval($trxn_id) + 1;
       $params['trxn_id'] = 'live_' . $trxn_id . '_' . uniqid();
diff --git a/civicrm/CRM/Core/Payment/Elavon.php b/civicrm/CRM/Core/Payment/Elavon.php
index 8d9df671c4dae8634edd2a8aeafe0bdeef0c6f61..d0c4bbccfbd3dce8b08ece8ace90775778d5fcc1 100644
--- a/civicrm/CRM/Core/Payment/Elavon.php
+++ b/civicrm/CRM/Core/Payment/Elavon.php
@@ -231,7 +231,7 @@ class CRM_Core_Payment_Elavon extends CRM_Core_Payment {
       if ($this->_mode == 'test') {
         $query = "SELECT MAX(trxn_id) FROM civicrm_contribution WHERE trxn_id LIKE 'test%'";
         $p = [];
-        $trxn_id = strval(CRM_Core_Dao::singleValueQuery($query, $p));
+        $trxn_id = strval(CRM_Core_DAO::singleValueQuery($query, $p));
         $trxn_id = str_replace('test', '', $trxn_id);
         $trxn_id = intval($trxn_id) + 1;
         $params['trxn_id'] = sprintf('test%08d', $trxn_id);
diff --git a/civicrm/CRM/Core/Payment/PayPalIPN.php b/civicrm/CRM/Core/Payment/PayPalIPN.php
index 5e0a1034be1feaba173335be77e25f0e6474da8e..3ad4c74d27597804fffa4dc7c95db0f2dc055270 100644
--- a/civicrm/CRM/Core/Payment/PayPalIPN.php
+++ b/civicrm/CRM/Core/Payment/PayPalIPN.php
@@ -398,9 +398,7 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
        * The `payment_date` that Paypal sends back is in their timezone. Example return: 08:23:05 Jan 11, 2019 PST
        * Subsequently, we need to account for that, otherwise the recieve time will be incorrect for the local system
        */
-      $systemTimeZone = new DateTimeZone(CRM_Core_Config::singleton()->userSystem->getTimeZoneString());
-      $receiveDateTime->setTimezone($systemTimeZone);
-      $input['receive_date'] = $receiveDateTime->format('YmdHis');
+      $input['receive_date'] = CRM_Utils_Date::convertDateToLocalTime($receiveDateTime);
     }
   }
 
diff --git a/civicrm/CRM/Core/PseudoConstant.php b/civicrm/CRM/Core/PseudoConstant.php
index 9950cf10f540e0ef8a741bc548373fdf2cfa0401..5df5e7f2751611d75f881a4876510e3ab900114b 100644
--- a/civicrm/CRM/Core/PseudoConstant.php
+++ b/civicrm/CRM/Core/PseudoConstant.php
@@ -486,7 +486,7 @@ class CRM_Core_PseudoConstant {
         WHERE page_callback LIKE '%CRM_Admin_Page_$child%' OR page_callback LIKE '%CRM_{$parent}_Page_$child%'
         ORDER BY page_callback
         LIMIT 1";
-      return CRM_Core_Dao::singleValueQuery($sql);
+      return CRM_Core_DAO::singleValueQuery($sql);
     }
     return NULL;
   }
diff --git a/civicrm/CRM/Core/Resources.php b/civicrm/CRM/Core/Resources.php
index 3066d3331ca3ffd568b1ef59e20fcf60ba9823c7..5a67b904c4a4b221c327ccdcdd6665e66a5fa4df 100644
--- a/civicrm/CRM/Core/Resources.php
+++ b/civicrm/CRM/Core/Resources.php
@@ -211,8 +211,8 @@ class CRM_Core_Resources {
       $domain = ($translate === TRUE) ? $ext : $translate;
       $this->addString($this->strings->get($domain, $this->getPath($ext, $file), 'text/javascript'), $domain);
     }
-    $this->resolveFileName($file, $ext);
-    return $this->addScriptUrl($this->getUrl($ext, $file, TRUE), $weight, $region);
+    $url = $this->getUrl($ext, $this->filterMinify($ext, $file), TRUE);
+    return $this->addScriptUrl($url, $weight, $region);
   }
 
   /**
@@ -427,8 +427,12 @@ class CRM_Core_Resources {
    * @return CRM_Core_Resources
    */
   public function addStyleFile($ext, $file, $weight = self::DEFAULT_WEIGHT, $region = self::DEFAULT_REGION) {
-    $this->resolveFileName($file, $ext);
-    return $this->addStyleUrl($this->getUrl($ext, $file, TRUE), $weight, $region);
+    /** @var Civi\Core\Themes $theme */
+    $theme = Civi::service('themes');
+    foreach ($theme->resolveUrls($theme->getActiveThemeKey(), $ext, $file) as $url) {
+      $this->addStyleUrl($url, $weight, $region);
+    }
+    return $this;
   }
 
   /**
@@ -785,12 +789,13 @@ class CRM_Core_Resources {
       $items[] = 'bower_components/smartmenus/dist/jquery.smartmenus.min.js';
       $items[] = 'bower_components/smartmenus/dist/addons/keyboard/jquery.smartmenus.keyboard.min.js';
       $items[] = 'js/crm.menubar.js';
+      // @see CRM_Core_Resources::renderMenubarStylesheet
       $items[] = Civi::service('asset_builder')->getUrl('crm-menubar.css', [
-        'color' => Civi::settings()->get('menubar_color'),
+        'menubarColor' => Civi::settings()->get('menubar_color'),
         'height' => 40,
         'breakpoint' => 768,
-        'opacity' => .88,
       ]);
+      // Variables for crm.menubar.js
       $items[] = [
         'menubar' => [
           'position' => $position,
@@ -857,7 +862,7 @@ class CRM_Core_Resources {
       return;
     }
     $e->mimeType = 'text/css';
-    $e->content = '';
+    $content = '';
     $config = CRM_Core_Config::singleton();
     $cms = strtolower($config->userFramework);
     $cms = $cms === 'drupal' ? 'drupal7' : $cms;
@@ -867,26 +872,23 @@ class CRM_Core_Resources {
       "css/menubar-$cms.css",
     ];
     foreach ($items as $item) {
-      $e->content .= file_get_contents(self::singleton()->getPath('civicrm', $item));
-    }
-    $color = $e->params['color'];
-    if (!CRM_Utils_Rule::color($color)) {
-      $color = Civi::settings()->getDefault('menubar_color');
+      $content .= file_get_contents(self::singleton()->getPath('civicrm', $item));
     }
+    $params = $e->params;
+    // "color" is deprecated in favor of the more specific "menubarColor"
+    $menubarColor = $params['color'] ?? $params['menubarColor'];
     $vars = [
-      'resourceBase' => rtrim($config->resourceBase, '/'),
-      'menubarHeight' => $e->params['height'] . 'px',
-      'breakMin' => $e->params['breakpoint'] . 'px',
-      'breakMax' => ($e->params['breakpoint'] - 1) . 'px',
-      'menubarColor' => $color,
-      'menuItemColor' => 'rgba(' . implode(', ', CRM_Utils_Color::getRgb($color)) . ", {$e->params['opacity']})",
-      'highlightColor' => CRM_Utils_Color::getHighlight($color),
-      'textColor' => CRM_Utils_Color::getContrast($color, '#333', '#ddd'),
+      '$resourceBase' => rtrim($config->resourceBase, '/'),
+      '$menubarHeight' => $params['height'] . 'px',
+      '$breakMin' => $params['breakpoint'] . 'px',
+      '$breakMax' => ($params['breakpoint'] - 1) . 'px',
+      '$menubarColor' => $menubarColor,
+      '$menuItemColor' => $params['menuItemColor'] ?? 'rgba(' . implode(', ', CRM_Utils_Color::getRgb($menubarColor)) . ", .9)",
+      '$highlightColor' => $params['highlightColor'] ?? CRM_Utils_Color::getHighlight($menubarColor),
+      '$textColor' => $params['textColor'] ?? CRM_Utils_Color::getContrast($menubarColor, '#333', '#ddd'),
     ];
-    $vars['highlightTextColor'] = CRM_Utils_Color::getContrast($vars['highlightColor'], '#333', '#ddd');
-    foreach ($vars as $var => $val) {
-      $e->content = str_replace('$' . $var, $val, $e->content);
-    }
+    $vars['$highlightTextColor'] = $params['highlightTextColor'] ?? CRM_Utils_Color::getContrast($vars['$highlightColor'], '#333', '#ddd');
+    $e->content = str_replace(array_keys($vars), array_values($vars), $content);
   }
 
   /**
@@ -937,18 +939,22 @@ class CRM_Core_Resources {
   }
 
   /**
-   * In debug mode, look for a non-minified version of this file
+   * Determine the minified file name.
    *
-   * @param string $fileName
-   * @param string $extName
-   */
-  private function resolveFileName(&$fileName, $extName) {
-    if (CRM_Core_Config::singleton()->debug && strpos($fileName, '.min.') !== FALSE) {
-      $nonMiniFile = str_replace('.min.', '.', $fileName);
-      if ($this->getPath($extName, $nonMiniFile)) {
-        $fileName = $nonMiniFile;
+   * @param string $ext
+   * @param string $file
+   * @return string
+   *   An updated $fileName. If a minified version exists and is supported by
+   *   system policy, the minified version will be returned. Otherwise, the original.
+   */
+  public function filterMinify($ext, $file) {
+    if (CRM_Core_Config::singleton()->debug && strpos($file, '.min.') !== FALSE) {
+      $nonMiniFile = str_replace('.min.', '.', $file);
+      if ($this->getPath($ext, $nonMiniFile)) {
+        $file = $nonMiniFile;
       }
     }
+    return $file;
   }
 
   /**
diff --git a/civicrm/CRM/Core/SelectValues.php b/civicrm/CRM/Core/SelectValues.php
index 497e0904fa0cb09543b51f5f7eb34f612e1b0100..65f7eb86bd6e7caaa24ecf96d464a6ddab0a87ae 100644
--- a/civicrm/CRM/Core/SelectValues.php
+++ b/civicrm/CRM/Core/SelectValues.php
@@ -730,7 +730,7 @@ class CRM_Core_SelectValues {
    * @return array
    */
   public static function getDatePluginInputFormats() {
-    $dateInputFormats = [
+    return [
       "mm/dd/yy" => ts('mm/dd/yyyy (12/31/2009)'),
       "dd/mm/yy" => ts('dd/mm/yyyy (31/12/2009)'),
       "yy-mm-dd" => ts('yyyy-mm-dd (2009-12-31)'),
@@ -747,21 +747,6 @@ class CRM_Core_SelectValues {
       'M yy' => ts('M yyyy (Dec 2009)'),
       "yy" => ts('yyyy (2009)'),
     ];
-
-    /*
-    Year greater than 2000 get wrong result for following format
-    echo date( 'Y-m-d', strtotime( '7 Nov, 2001') );
-    echo date( 'Y-m-d', strtotime( '7 November, 2001') );
-    Return current year
-    expected :: 2001-11-07
-    output   :: 2009-11-07
-    However
-    echo date( 'Y-m-d', strtotime( 'Nov 7, 2001') );
-    echo date( 'Y-m-d', strtotime( 'November 7, 2001') );
-    gives proper result
-     */
-
-    return $dateInputFormats;
   }
 
   /**
diff --git a/civicrm/CRM/Core/xml/Menu/Admin.xml b/civicrm/CRM/Core/xml/Menu/Admin.xml
index d23a10910bee29594132d9f217f38e0b89fa99da..34228dc51df8f512c7461e2c4f9ec1c86fdac041 100644
--- a/civicrm/CRM/Core/xml/Menu/Admin.xml
+++ b/civicrm/CRM/Core/xml/Menu/Admin.xml
@@ -550,7 +550,7 @@
   <item>
      <path>civicrm/admin/setting/preferences/multisite</path>
      <title>Multi Site Settings</title>
-     <page_callback>CRM_Admin_Form_Preferences_Multisite</page_callback>
+     <page_callback>CRM_Admin_Form_Generic</page_callback>
      <adminGroup>System Settings</adminGroup>
      <icon>admin/small/36.png</icon>
      <weight>130</weight>
@@ -558,7 +558,7 @@
   <item>
      <path>civicrm/admin/setting/preferences/campaign</path>
      <title>CiviCampaign Component Settings</title>
-     <page_callback>CRM_Admin_Form_Preferences_Campaign</page_callback>
+     <page_callback>CRM_Admin_Form_Generic</page_callback>
   </item>
   <item>
      <path>civicrm/admin/setting/preferences/event</path>
diff --git a/civicrm/CRM/Cxn/DAO/Cxn.php b/civicrm/CRM/Cxn/DAO/Cxn.php
index c75742e2383bac97fd23968e7476e3d971a7af07..342a01222afb44dbaf598f5fd31ff57069367e55 100644
--- a/civicrm/CRM/Cxn/DAO/Cxn.php
+++ b/civicrm/CRM/Cxn/DAO/Cxn.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Cxn/Cxn.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:bd6f3b0785ec9b05984d8ad32f3b8464)
+ * (GenCodeChecksum:519cb483cf9da3dceb979002d5f5d344)
  */
 
 /**
diff --git a/civicrm/CRM/Dedupe/DAO/Exception.php b/civicrm/CRM/Dedupe/DAO/Exception.php
index c68c5d0647a53dcaab655be8c4df886df3ffb762..3d4743273ab1db8dc6a3943c334139356bb12c49 100644
--- a/civicrm/CRM/Dedupe/DAO/Exception.php
+++ b/civicrm/CRM/Dedupe/DAO/Exception.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Dedupe/Exception.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a82b6fb86d1d7149b0f553ac6b87ac14)
+ * (GenCodeChecksum:c2bdf0b5dc00abebb9c5de4a55c6e718)
  */
 
 /**
diff --git a/civicrm/CRM/Dedupe/DAO/Rule.php b/civicrm/CRM/Dedupe/DAO/Rule.php
index 5d513b1aaf25183a0c73b0ed2d4a2fd9d01d0aac..e9b3fd7cf9edefc64c5c27fbbaf2fb787b0a7dc2 100644
--- a/civicrm/CRM/Dedupe/DAO/Rule.php
+++ b/civicrm/CRM/Dedupe/DAO/Rule.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Dedupe/Rule.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a7697e9d93641b3240e23f97f4f92329)
+ * (GenCodeChecksum:f51604da4ecc188a040e1c84ad44fc22)
  */
 
 /**
diff --git a/civicrm/CRM/Dedupe/DAO/RuleGroup.php b/civicrm/CRM/Dedupe/DAO/RuleGroup.php
index bb54789c0b7a7198a7480244e77b276d9641ab82..3d1b6fc2d2f8c69dd0b51463c82fc6fed64fc3d5 100644
--- a/civicrm/CRM/Dedupe/DAO/RuleGroup.php
+++ b/civicrm/CRM/Dedupe/DAO/RuleGroup.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Dedupe/RuleGroup.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a0c7d9e893a3aec240db9ec4b0e8729d)
+ * (GenCodeChecksum:f0256f996783b78fd4f360fd80fe2119)
  */
 
 /**
diff --git a/civicrm/CRM/Dedupe/Merger.php b/civicrm/CRM/Dedupe/Merger.php
index e6b07b91435a5d9c0d8586a73dccc89cd3196de6..a57d64e1001de5254a66b4e6d665f8f2d5457e09 100644
--- a/civicrm/CRM/Dedupe/Merger.php
+++ b/civicrm/CRM/Dedupe/Merger.php
@@ -919,22 +919,16 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *  An empty array to be filed with conflict information.
    *
    * @return bool
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   * @throws \API_Exception
    */
   public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe', &$conflicts = []) {
 
     $conflicts = self::getConflicts($migrationInfo, $mainId, $otherId, $mode);
 
     if (!empty($conflicts)) {
-      foreach ($conflicts as $key => $val) {
-        if ($val === NULL and $mode == 'safe') {
-          // un-resolved conflicts still present. Lets skip this merge after saving the conflict / reason.
-          return TRUE;
-        }
-        else {
-          // copy over the resolved values
-          $migrationInfo[$key] = $val;
-        }
-      }
       // if there are conflicts and mode is aggressive, allow hooks to decide if to skip merges
       return (bool) $migrationInfo['skip_merge'];
     }
@@ -950,15 +944,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    * @return bool
    */
   public static function locationIsSame($mainAddress, $comparisonAddress) {
-    $keysToIgnore = [
-      'id',
-      'is_primary',
-      'is_billing',
-      'manual_geo_code',
-      'contact_id',
-      'reset_date',
-      'hold_date',
-    ];
+    $keysToIgnore = self::ignoredFields();
     foreach ($comparisonAddress as $field => $value) {
       if (in_array($field, $keysToIgnore)) {
         continue;
@@ -1679,8 +1665,8 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       if (!isset($submitted['suffix_id']) && !empty($migrationInfo['main_details']['suffix_id'])) {
         $submitted['suffix_id'] = $migrationInfo['main_details']['suffix_id'];
       }
-
-      CRM_Contact_BAO_Contact::createProfileContact($submitted, CRM_Core_DAO::$_nullArray, $mainId);
+      $null = [];
+      CRM_Contact_BAO_Contact::createProfileContact($submitted, $null, $mainId);
     }
     $transaction->commit();
     CRM_Utils_Hook::post('merge', 'Contact', $mainId);
@@ -2106,6 +2092,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
+   * @throws \API_Exception
    */
   protected static function dedupePair(&$resultStats, &$deletedContacts, $mode, $checkPermissions, $mainId, $otherId, $cacheKeyString) {
 
@@ -2128,10 +2115,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
 
     // store any conflicts
     if (!empty($conflicts)) {
-      foreach ($conflicts as $key => $dnc) {
-        $conflicts[$key] = "{$migrationInfo['rows'][$key]['title']}: '{$migrationInfo['rows'][$key]['main']}' vs. '{$migrationInfo['rows'][$key]['other']}'";
-      }
-      CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts);
+      CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts, $mode);
     }
     else {
       CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString);
@@ -2420,8 +2404,69 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     $conflicts = $migrationData['fields_in_conflict'];
     // allow hook to override / manipulate migrationInfo as well
     $migrationInfo = $migrationData['migration_info'];
-    $migrationInfo['skip_merge'] = CRM_Utils_Array::value('skip_merge', $migrationData);
-    return $conflicts;
+    foreach ($conflicts as $key => $val) {
+      if ($val !== NULL || $mode !== 'safe') {
+        // copy over the resolved values
+        $migrationInfo[$key] = $val;
+        unset($conflicts[$key]);
+      }
+    }
+    $migrationInfo['skip_merge'] = $migrationData['skip_merge'] ?? !empty($conflicts);
+    return self::formatConflictArray($conflicts, $migrationInfo['rows'], $migrationInfo['main_details']['location_blocks'], $migrationInfo['other_details']['location_blocks'], $mainId, $otherId);
+  }
+
+  /**
+   * @param array $conflicts
+   * @param array $migrationInfo
+   * @param $toKeepContactLocationBlocks
+   * @param $toRemoveContactLocationBlocks
+   * @param $toKeepID
+   * @param $toRemoveID
+   *
+   * @return mixed
+   * @throws \CRM_Core_Exception
+   */
+  protected static function formatConflictArray($conflicts, $migrationInfo, $toKeepContactLocationBlocks, $toRemoveContactLocationBlocks, $toKeepID, $toRemoveID) {
+    $return = [];
+    foreach (array_keys($conflicts) as $index) {
+      if (substr($index, 0, 14) === 'move_location_') {
+        $parts = explode('_', $index);
+        $entity = $parts[2];
+        $blockIndex = $parts[3];
+        $locationTypeID = $toKeepContactLocationBlocks[$entity][$blockIndex]['location_type_id'];
+        $entityConflicts = [
+          'location_type_id' => $locationTypeID,
+          'title' => $migrationInfo[$index]['title'],
+        ];
+        foreach ($toKeepContactLocationBlocks[$entity][$blockIndex] as $fieldName => $fieldValue) {
+          if (in_array($fieldName, self::ignoredFields())) {
+            continue;
+          }
+          $toRemoveValue = CRM_Utils_Array::value($fieldName, $toRemoveContactLocationBlocks[$entity][$blockIndex]);
+          if ($fieldValue !== $toRemoveValue) {
+            $entityConflicts[$fieldName] = [
+              $toKeepID => $fieldValue,
+              $toRemoveID => $toRemoveValue,
+            ];
+          }
+        }
+        $return[$entity][] = $entityConflicts;
+      }
+      elseif (substr($index, 0, 5) === 'move_') {
+        $contactFieldsToCompare[] = str_replace('move_', '', $index);
+        $return['contact'][str_replace('move_', '', $index)] = [
+          'title' => $migrationInfo[$index]['title'],
+          $toKeepID => $migrationInfo[$index]['main'],
+          $toRemoveID => $migrationInfo[$index]['other'],
+        ];
+      }
+      else {
+        // Can't think of why this would be the case but perhaps it's ensuring it isn't as we
+        // refactor this.
+        throw new CRM_Core_Exception(ts('Unknown parameter') . $index);
+      }
+    }
+    return $return;
   }
 
   /**
@@ -2448,4 +2493,20 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     );
   }
 
+  /**
+   * @return array
+   */
+  protected static function ignoredFields(): array {
+    $keysToIgnore = [
+      'id',
+      'is_primary',
+      'is_billing',
+      'manual_geo_code',
+      'contact_id',
+      'reset_date',
+      'hold_date',
+    ];
+    return $keysToIgnore;
+  }
+
 }
diff --git a/civicrm/CRM/Event/BAO/Event.php b/civicrm/CRM/Event/BAO/Event.php
index 2729d09693898b09922341e1d215caf6ec347bc4..cf52a5f32cc057dad9088c673c292575837c5b2d 100644
--- a/civicrm/CRM/Event/BAO/Event.php
+++ b/civicrm/CRM/Event/BAO/Event.php
@@ -921,15 +921,15 @@ WHERE civicrm_event.is_active = 1
    *
    * @param int $id
    *   The event id to copy.
-   *        boolean $afterCreate call to copy after the create function
    * @param array $params
+   *
    * @return CRM_Event_DAO_Event
    * @throws \CRM_Core_Exception
    */
   public static function copy($id, $params = []) {
     $eventValues = [];
 
-    //get the require event values.
+    //get the required event values.
     $eventParams = ['id' => $id];
     $returnProperties = [
       'loc_block_id',
@@ -946,11 +946,15 @@ WHERE civicrm_event.is_active = 1
       $fieldsFix['prefix']['is_show_location'] = 0;
     }
 
+    $blockCopyOfCustomValue = (!empty($params['custom']));
+
     $copyEvent = CRM_Core_DAO::copyGeneric('CRM_Event_DAO_Event',
       ['id' => $id],
       // since the location is sharable, lets use the same loc_block_id.
       ['loc_block_id' => CRM_Utils_Array::value('loc_block_id', $eventValues)] + $params,
-      $fieldsFix
+      $fieldsFix,
+      NULL,
+      $blockCopyOfCustomValue
     );
     CRM_Price_BAO_PriceSet::copyPriceSet('civicrm_event', $id, $copyEvent->id);
     CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
@@ -991,6 +995,10 @@ WHERE civicrm_event.is_active = 1
 
     $copyEvent->save();
 
+    if ($blockCopyOfCustomValue) {
+      CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_event', $copyEvent->id);
+    }
+
     CRM_Utils_System::flushCache();
     CRM_Utils_Hook::copy('Event', $copyEvent);
 
@@ -1638,6 +1646,10 @@ WHERE  id = $cfID
                   }
                   $skip = TRUE;
                 }
+                // for checkboxes, change array of [key => bool] to array of [idx => key]
+                elseif ($dao->html_type == 'CheckBox') {
+                  $customVal = array_keys(array_filter($params[$name]));
+                }
                 else {
                   $customVal = $params[$name];
                 }
diff --git a/civicrm/CRM/Event/BAO/Participant.php b/civicrm/CRM/Event/BAO/Participant.php
index db4bf4f7c2c1f8c57c3b2e192cea16dc7a995ee2..9819a2712fe22c13bc47b5b67325644445bd98ea 100644
--- a/civicrm/CRM/Event/BAO/Participant.php
+++ b/civicrm/CRM/Event/BAO/Participant.php
@@ -161,7 +161,7 @@ class CRM_Event_BAO_Participant extends CRM_Event_DAO_Participant {
    *
    * @return CRM_Event_BAO_Participant|null the found object or null
    */
-  public static function getValues(&$params, &$values, &$ids) {
+  public static function getValues(&$params, &$values = [], &$ids = []) {
     if (empty($params)) {
       return NULL;
     }
diff --git a/civicrm/CRM/Event/BAO/Query.php b/civicrm/CRM/Event/BAO/Query.php
index 77fa886ea1f652ceaedd80d25c3761e8e1aada39..45cfa1a22630c536e1f2bb58f0965324e03a9ab7 100644
--- a/civicrm/CRM/Event/BAO/Query.php
+++ b/civicrm/CRM/Event/BAO/Query.php
@@ -238,7 +238,7 @@ class CRM_Event_BAO_Query extends CRM_Core_BAO_Query {
       if (substr($query->_params[$id][0], 0, 6) == 'event_' ||
         substr($query->_params[$id][0], 0, 12) == 'participant_'
       ) {
-        if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) {
+        if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) {
           $query->_useDistinct = TRUE;
         }
         $grouping = $query->_params[$id][3];
diff --git a/civicrm/CRM/Event/Cart/DAO/Cart.php b/civicrm/CRM/Event/Cart/DAO/Cart.php
index 92684931dcd1a0a36fd857ffa7b443c3da2e5581..8531b9ecc7f3f7c6c792a7339ad9a0773c2347ea 100644
--- a/civicrm/CRM/Event/Cart/DAO/Cart.php
+++ b/civicrm/CRM/Event/Cart/DAO/Cart.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Event/Cart/Cart.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:71454cbda07a2fefd75041815b95ed0c)
+ * (GenCodeChecksum:0c19d3833a1e69a4e514d8f28f329626)
  */
 
 /**
diff --git a/civicrm/CRM/Event/Cart/DAO/EventInCart.php b/civicrm/CRM/Event/Cart/DAO/EventInCart.php
index c0147b76dc74dbab39b62543224eb02ff8d3ca0b..6f3812b365bab06546b535b46b7fa5bc46ef9dbd 100644
--- a/civicrm/CRM/Event/Cart/DAO/EventInCart.php
+++ b/civicrm/CRM/Event/Cart/DAO/EventInCart.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Event/Cart/EventInCart.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:b9da5d3acb0b71b79cc3f8d2f7e5ec50)
+ * (GenCodeChecksum:b5fd29f887cfd20b67dcc75088800607)
  */
 
 /**
diff --git a/civicrm/CRM/Event/DAO/Event.php b/civicrm/CRM/Event/DAO/Event.php
index 598001578dc494d7a57e347d201ea718e1390cfb..f28c91c2f1e802093c741e93d69fa01b6870f6fb 100644
--- a/civicrm/CRM/Event/DAO/Event.php
+++ b/civicrm/CRM/Event/DAO/Event.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Event/Event.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f3c11a01d973394dacd923cc65d9a3dc)
+ * (GenCodeChecksum:6fc495deedb92d867cbfb452e52e1106)
  */
 
 /**
diff --git a/civicrm/CRM/Event/DAO/Participant.php b/civicrm/CRM/Event/DAO/Participant.php
index cba5311348d0fe7fdf9d13759b2a898bf785727a..66d2acf1a7c5dda74377e49264440bfb82e67066 100644
--- a/civicrm/CRM/Event/DAO/Participant.php
+++ b/civicrm/CRM/Event/DAO/Participant.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Event/Participant.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2c9fa9a933df6d5c4ec745b8031f9297)
+ * (GenCodeChecksum:b848cf2d8ba84cd10dae7a056b1b0c68)
  */
 
 /**
diff --git a/civicrm/CRM/Event/DAO/ParticipantPayment.php b/civicrm/CRM/Event/DAO/ParticipantPayment.php
index d9b126bb5cd37cf559cd1c446ddc83c0157bb566..cf4e80bc85dbb2a6d8d925af0d8c4302b9ed97de 100644
--- a/civicrm/CRM/Event/DAO/ParticipantPayment.php
+++ b/civicrm/CRM/Event/DAO/ParticipantPayment.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Event/ParticipantPayment.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:26f5438e86ca3500888b49650bc6d9e8)
+ * (GenCodeChecksum:16048a6d761c165c57861d09d81b15bd)
  */
 
 /**
diff --git a/civicrm/CRM/Event/DAO/ParticipantStatusType.php b/civicrm/CRM/Event/DAO/ParticipantStatusType.php
index 7a09e16739e1eede3c5d72638fd242d2400ad718..ac353201e2be47d38f81ca515e4534e0e112f939 100644
--- a/civicrm/CRM/Event/DAO/ParticipantStatusType.php
+++ b/civicrm/CRM/Event/DAO/ParticipantStatusType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Event/ParticipantStatusType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a42abc9dbf891aa6cbb6513ca18067b9)
+ * (GenCodeChecksum:41d33d3b2c1ac5b32faab197d3b59398)
  */
 
 /**
diff --git a/civicrm/CRM/Event/Form/EventFees.php b/civicrm/CRM/Event/Form/EventFees.php
index f5972943bfdef98855b698d5f467ec6a8f5ccc61..dec7b6fd3c00ddcd2fed1c03baad4c223f08e5f8 100644
--- a/civicrm/CRM/Event/Form/EventFees.php
+++ b/civicrm/CRM/Event/Form/EventFees.php
@@ -347,7 +347,7 @@ SELECT  id, html_type
         $form->_pId, 'contribution_id', 'participant_id'
       )
       ) {
-        $form->_online = TRUE;
+        $form->_online = !$form->isBackOffice;
       }
     }
 
diff --git a/civicrm/CRM/Event/Form/ManageEvent.php b/civicrm/CRM/Event/Form/ManageEvent.php
index 9e065f4cc16612d808b96c1912248e58feae6fd9..17c9b9e78daa1be588f72450b8d9113e90649e99 100644
--- a/civicrm/CRM/Event/Form/ManageEvent.php
+++ b/civicrm/CRM/Event/Form/ManageEvent.php
@@ -100,6 +100,21 @@ class CRM_Event_Form_ManageEvent extends CRM_Core_Form {
     return 'create';
   }
 
+  /**
+   * Set the active tab
+   *
+   * @param string $default
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function setSelectedChild($default = NULL) {
+    $selectedChild = CRM_Utils_Request::retrieve('selectedChild', 'Alphanumeric', $this, FALSE, $default);
+    if (!empty($selectedChild)) {
+      $this->set('selectedChild', $selectedChild);
+      $this->assign('selectedChild', $selectedChild);
+    }
+  }
+
   /**
    * Set variables up before form is built.
    */
diff --git a/civicrm/CRM/Event/Form/ManageEvent/EventInfo.php b/civicrm/CRM/Event/Form/ManageEvent/EventInfo.php
index 31317c09aa8d0fff18bea5c9a54815b1f1b79ca2..0bf756f151a2447f52591d70965e6a7d1b914a41 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/EventInfo.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/EventInfo.php
@@ -46,12 +46,13 @@ class CRM_Event_Form_ManageEvent_EventInfo extends CRM_Event_Form_ManageEvent {
    */
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'settings');
+    $this->setSelectedChild('settings');
 
-    if ($this->_id) {
-      $this->assign('entityID', $this->_id);
+    $entityID = $this->_id ?: $this->_templateId;
+    if ($entityID) {
+      $this->assign('entityID', $entityID);
       $eventType = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event',
-        $this->_id,
+        $entityID,
         'event_type_id'
       );
     }
@@ -127,7 +128,6 @@ class CRM_Event_Form_ManageEvent_EventInfo extends CRM_Event_Form_ManageEvent {
     if ($this->_eventType) {
       $this->assign('customDataSubType', $this->_eventType);
     }
-    $this->assign('entityId', $this->_id);
 
     $this->_first = TRUE;
     $this->applyFilter('__ALL__', 'trim');
@@ -228,7 +228,7 @@ class CRM_Event_Form_ManageEvent_EventInfo extends CRM_Event_Form_ManageEvent {
    * Process the form submission.
    */
   public function postProcess() {
-    $params = $this->controller->exportValues($this->_name);
+    $params = array_merge($this->controller->exportValues($this->_name), $this->_submitValues);
 
     //format params
     $params['start_date'] = CRM_Utils_Array::value('start_date', $params);
@@ -241,19 +241,23 @@ class CRM_Event_Form_ManageEvent_EventInfo extends CRM_Event_Form_ManageEvent {
     $params['default_role_id'] = CRM_Utils_Array::value('default_role_id', $params, FALSE);
     $params['id'] = $this->_id;
 
-    $customFields = CRM_Core_BAO_CustomField::getFields('Event', FALSE, FALSE,
-      CRM_Utils_Array::value('event_type_id', $params)
-    );
-    $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
-      $this->_id,
-      'Event'
-    );
-
     //merge params with defaults from templates
     if (!empty($params['template_id'])) {
       $params = array_merge(CRM_Event_BAO_Event::getTemplateDefaultValues($params['template_id']), $params);
+      foreach ($params as $key => $value) {
+        $customFieldInfo = CRM_Core_BAO_CustomField::getKeyID($key, TRUE);
+        if (!empty($customFieldInfo[1])) {
+          $params[str_replace($customFieldInfo[1], '-' . $customFieldInfo[1], $key)] = $value;
+          unset($params[$key]);
+        }
+      }
     }
 
+    $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
+      $this->_id,
+      'Event'
+    );
+
     // now that we have the event’s id, do some more template-based stuff
     if (!empty($params['template_id'])) {
       $event = CRM_Event_BAO_Event::copy($params['template_id'], $params);
diff --git a/civicrm/CRM/Event/Form/ManageEvent/Fee.php b/civicrm/CRM/Event/Form/ManageEvent/Fee.php
index ddc1c2da065fec87d9e8aa72b922785207cd76bc..46420b809a33d9ac4eb5e017517f3a1097b3ac09 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/Fee.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/Fee.php
@@ -62,7 +62,7 @@ class CRM_Event_Form_ManageEvent_Fee extends CRM_Event_Form_ManageEvent {
    */
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'fee');
+    $this->setSelectedChild('fee');
   }
 
   /**
diff --git a/civicrm/CRM/Event/Form/ManageEvent/Location.php b/civicrm/CRM/Event/Form/ManageEvent/Location.php
index b33eafe0a4205523283ec64a8849b865a2b4b397..7e2c8a8889dc968e6707625c4c9c560e743dc646 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/Location.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/Location.php
@@ -73,7 +73,7 @@ class CRM_Event_Form_ManageEvent_Location extends CRM_Event_Form_ManageEvent {
    */
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'location');
+    $this->setSelectedChild('location');
 
     $this->_values = $this->get('values');
     if ($this->_id && empty($this->_values)) {
diff --git a/civicrm/CRM/Event/Form/ManageEvent/Registration.php b/civicrm/CRM/Event/Form/ManageEvent/Registration.php
index 0c62605713f5d74781a32d6ffa6fe48deeae1e6e..0c03c4f9f963e62e776bc1d509430916c8682f52 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/Registration.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/Registration.php
@@ -55,7 +55,7 @@ class CRM_Event_Form_ManageEvent_Registration extends CRM_Event_Form_ManageEvent
     $this->_profileBottomNumAdd = CRM_Utils_Array::value('addProfileNumAdd', $_GET, 0);
 
     parent::preProcess();
-    $this->assign('selectedChild', 'registration');
+    $this->setSelectedChild('registration');
 
     $this->assign('addProfileBottom', $this->_addProfileBottom);
     $this->assign('profileBottomNum', $this->_profileBottomNum);
diff --git a/civicrm/CRM/Event/Form/ManageEvent/Repeat.php b/civicrm/CRM/Event/Form/ManageEvent/Repeat.php
index f02716591d66fde53b21c62a0f7da0a8c40e298b..9aad1cd161c099a6f28fe5c057e27c72a9578bdb 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/Repeat.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/Repeat.php
@@ -26,7 +26,7 @@ class CRM_Event_Form_ManageEvent_Repeat extends CRM_Event_Form_ManageEvent {
 
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'repeat');
+    $this->setSelectedChild('repeat');
     $this->assign('currentEventId', $this->_id);
 
     $checkParentExistsForThisId = CRM_Core_BAO_RecurringEntity::getParentFor($this->_id, 'civicrm_event');
diff --git a/civicrm/CRM/Event/Form/ManageEvent/ScheduleReminders.php b/civicrm/CRM/Event/Form/ManageEvent/ScheduleReminders.php
index 483f275de624a21e197ef85cc3d4ff905cfbfbcc..4129564e57392c4f233bf6573d9afcc9c7a5b7ef 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/ScheduleReminders.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/ScheduleReminders.php
@@ -47,7 +47,7 @@ class CRM_Event_Form_ManageEvent_ScheduleReminders extends CRM_Event_Form_Manage
    */
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'reminder');
+    $this->setSelectedChild('reminder');
     $setTab = CRM_Utils_Request::retrieve('setTab', 'Int', $this, FALSE, 0);
 
     $mapping = CRM_Utils_Array::first(CRM_Core_BAO_ActionSchedule::getMappings([
diff --git a/civicrm/CRM/Event/Form/ManageEvent/TabHeader.php b/civicrm/CRM/Event/Form/ManageEvent/TabHeader.php
index c966147e4fc70a7ff684c1ef57d3d98acbd8bf40..d77440c1a06d7510ff6bc6ae435999d223433ba0 100644
--- a/civicrm/CRM/Event/Form/ManageEvent/TabHeader.php
+++ b/civicrm/CRM/Event/Form/ManageEvent/TabHeader.php
@@ -45,8 +45,6 @@ class CRM_Event_Form_ManageEvent_TabHeader {
    * @throws \CRM_Core_Exception
    */
   public static function build(&$form) {
-    $form->assign('selectedChild', CRM_Utils_Request::retrieve('selectedChild', 'Alphanumeric', $form));
-
     $tabs = $form->get('tabHeader');
     if (!$tabs || empty($_GET['reset'])) {
       $tabs = self::process($form);
diff --git a/civicrm/CRM/Event/Form/Participant.php b/civicrm/CRM/Event/Form/Participant.php
index d0426e4caa2404a37390ad39b5accca79c634251..02b6a75f2f3fa3c0306cfea893170f064d66dac8 100644
--- a/civicrm/CRM/Event/Form/Participant.php
+++ b/civicrm/CRM/Event/Form/Participant.php
@@ -594,6 +594,7 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
    * @throws \CiviCRM_API3_Exception
    */
   public function buildQuickForm() {
+
     $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
     $partiallyPaidStatusId = array_search('Partially paid', $participantStatuses);
     $this->assign('partiallyPaidStatusId', $partiallyPaidStatusId);
diff --git a/civicrm/CRM/Event/Form/ParticipantFeeSelection.php b/civicrm/CRM/Event/Form/ParticipantFeeSelection.php
index 50511fba177e14eedee1eae5890f27a3ef491471..d79cc636e17da6f121a06ce7666f69fffd75b8ef 100644
--- a/civicrm/CRM/Event/Form/ParticipantFeeSelection.php
+++ b/civicrm/CRM/Event/Form/ParticipantFeeSelection.php
@@ -159,8 +159,7 @@ class CRM_Event_Form_ParticipantFeeSelection extends CRM_Core_Form {
     $this->assign('pendingRefund', array_search('Pending refund', $statuses));
     $this->assign('participantStatus', $this->_participantStatus);
 
-    $config = CRM_Core_Config::singleton();
-    $this->assign('currencySymbol', $config->defaultCurrencySymbol);
+    $this->assign('currencySymbol', CRM_Core_BAO_Country::defaultCurrencySymbol());
 
     // line items block
     $lineItem = $event = [];
@@ -244,7 +243,7 @@ class CRM_Event_Form_ParticipantFeeSelection extends CRM_Core_Form {
     // email sending
     if (!empty($params['send_receipt'])) {
       $fetchParticipantVals = ['id' => $this->_participantId];
-      CRM_Event_BAO_Participant::getValues($fetchParticipantVals, $participantDetails, CRM_Core_DAO::$_nullArray);
+      CRM_Event_BAO_Participant::getValues($fetchParticipantVals, $participantDetails);
       $participantParams = array_merge($params, $participantDetails[$this->_participantId]);
       $mailSent = $this->emailReceipt($participantParams);
     }
diff --git a/civicrm/CRM/Event/Form/Registration.php b/civicrm/CRM/Event/Form/Registration.php
index af19e4423678c7e15eeed927f4c16284670f9115..b29b6c7bc289864244bdb0f43b1e820e91f87b2a 100644
--- a/civicrm/CRM/Event/Form/Registration.php
+++ b/civicrm/CRM/Event/Form/Registration.php
@@ -419,10 +419,7 @@ class CRM_Event_Form_Registration extends CRM_Core_Form {
     $this->assign('bltID', $this->_bltID);
     $isShowLocation = CRM_Utils_Array::value('is_show_location', $this->_values['event']);
     $this->assign('isShowLocation', $isShowLocation);
-    //CRM-6907
-    $config->defaultCurrency = CRM_Utils_Array::value('currency', $this->_values['event'],
-      $config->defaultCurrency
-    );
+    CRM_Contribute_BAO_Contribution_Utils::overrideDefaultCurrency($this->_values['event']);
 
     //lets allow user to override campaign.
     $campID = CRM_Utils_Request::retrieve('campID', 'Positive', $this);
@@ -519,9 +516,7 @@ class CRM_Event_Form_Registration extends CRM_Core_Form {
 
     // also assign all participantIDs to the template
     // useful in generating confirmation numbers if needed
-    $this->assign('participantIDs',
-      $this->_participantIDS
-    );
+    $this->assign('participantIDs', $this->_participantIDS);
   }
 
   /**
@@ -618,9 +613,7 @@ class CRM_Event_Form_Registration extends CRM_Core_Form {
       }
 
       if ($addCaptcha && !$viewOnly) {
-        $captcha = CRM_Utils_ReCAPTCHA::singleton();
-        $captcha->add($this);
-        $this->assign('isCaptcha', TRUE);
+        CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
       }
     }
   }
@@ -820,23 +813,6 @@ class CRM_Event_Form_Registration extends CRM_Core_Form {
     $params = $form->_params;
     $transaction = new CRM_Core_Transaction();
 
-    $groupName = 'participant_role';
-    $query = "
-SELECT  v.label as label ,v.value as value
-FROM   civicrm_option_value v,
-       civicrm_option_group g
-WHERE  v.option_group_id = g.id
-  AND  g.name            = %1
-  AND  v.is_active       = 1
-  AND  g.is_active       = 1
-";
-    $p = array(1 => array($groupName, 'String'));
-
-    $dao = CRM_Core_DAO::executeQuery($query, $p);
-    if ($dao->fetch()) {
-      $roleID = $dao->value;
-    }
-
     // handle register date CRM-4320
     $registerDate = NULL;
     if (!empty($form->_allowConfirmation) && $form->_participantId) {
@@ -857,9 +833,7 @@ WHERE  v.option_group_id = g.id
       'status_id' => CRM_Utils_Array::value('participant_status',
         $params, 1
       ),
-      'role_id' => CRM_Utils_Array::value('participant_role_id',
-        $params, $roleID
-      ),
+      'role_id' => CRM_Utils_Array::value('participant_role_id', $params) ?: self::getDefaultRoleID(),
       'register_date' => ($registerDate) ? $registerDate : date('YmdHis'),
       'source' => CRM_Utils_String::ellipsify(
         isset($params['participant_source']) ? CRM_Utils_Array::value('participant_source', $params) : CRM_Utils_Array::value('description', $params),
@@ -911,6 +885,21 @@ WHERE  v.option_group_id = g.id
     return $participant;
   }
 
+  /**
+   * Get the ID of the default (first) participant role
+   *
+   * @return int
+   * @throws \CiviCRM_API3_Exception
+   */
+  private static function getDefaultRoleID() {
+    return (int) civicrm_api3('OptionValue', 'getvalue', [
+      'return' => "value",
+      'option_group_id' => "participant_role",
+      'is_active' => 1,
+      'options' => ['limit' => 1, 'sort' => "is_default DESC"],
+    ]);
+  }
+
   /**
    * Calculate the total participant count as per params.
    *
@@ -1247,7 +1236,7 @@ WHERE  v.option_group_id = g.id
    *
    * @param string $elementName
    * @param array $optionIds
-   * @param CRM_Core_form $form
+   * @param CRM_Core_Form $form
    */
   public static function resetSubmittedValue($elementName, $optionIds = array(), &$form) {
     if (empty($elementName) ||
diff --git a/civicrm/CRM/Event/Form/Registration/AdditionalParticipant.php b/civicrm/CRM/Event/Form/Registration/AdditionalParticipant.php
index afaaf1a4d4ff8e5af2c408043fb9bf9da1c4e1d2..5e665f0175ea218e08f5eb6a1f0e1565910adb62 100644
--- a/civicrm/CRM/Event/Form/Registration/AdditionalParticipant.php
+++ b/civicrm/CRM/Event/Form/Registration/AdditionalParticipant.php
@@ -210,7 +210,7 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R
     //add buttons
     $js = NULL;
     if ($this->isLastParticipant(TRUE) && empty($this->_values['event']['is_monetary'])) {
-      $js = ['onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"];
+      $this->submitOnce = TRUE;
     }
 
     //handle case where user might sart with waiting by group
@@ -361,7 +361,6 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R
           'name' => ts('Continue'),
           'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
           'isDefault' => TRUE,
-          'js' => $js,
         ],
       ]);
       if ($includeSkipButton) {
diff --git a/civicrm/CRM/Event/Form/Registration/Confirm.php b/civicrm/CRM/Event/Form/Registration/Confirm.php
index 1b35d29fe31ad87732edba464161e1a1d5643ecb..55e2e91e690ee405fa8db193578ea2097cb3b7b3 100644
--- a/civicrm/CRM/Event/Form/Registration/Confirm.php
+++ b/civicrm/CRM/Event/Form/Registration/Confirm.php
@@ -34,6 +34,7 @@
  * This class generates form components for processing Event.
  */
 class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
+  use CRM_Financial_Form_FrontEndPaymentFormTrait;
 
   /**
    * The values for the contribution db object.
@@ -49,6 +50,8 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
    */
   public $_totalAmount;
 
+  public $submitOnce = TRUE;
+
   /**
    * Monetary fields that may be submitted.
    *
@@ -84,61 +87,7 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
       $this->assign('hookDiscount', $this->_params[0]['discount']);
     }
 
-    // The concept of contributeMode is deprecated.
-    if ($this->_contributeMode == 'express') {
-      $params = [];
-      // rfp == redirect from paypal
-      // rfp is probably not required - the getPreApprovalDetails should deal with any payment-processor specific 'stuff'
-      $rfp = CRM_Utils_Request::retrieve('rfp', 'Boolean',
-        CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'
-      );
-
-      //we lost rfp in case of additional participant. So set it explicitly.
-      if ($rfp || CRM_Utils_Array::value('additional_participants', $this->_params[0], FALSE)) {
-        if (!empty($this->_paymentProcessor) &&  $this->_paymentProcessor['object']->supports('preApproval')) {
-          $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
-          $params = array_merge($this->_params, $preApprovalParams);
-        }
-        CRM_Core_Payment_Form::mapParams($this->_bltID, $params, $params, FALSE);
-
-        // set a few other parameters that are not really specific to this method because we don't know what
-        // will break if we change this.
-        $params['amount'] = $this->_params[0]['amount'];
-        if (!empty($this->_params[0]['discount'])) {
-          $params['discount'] = $this->_params[0]['discount'];
-          $params['discountAmount'] = $this->_params[0]['discountAmount'];
-          $params['discountMessage'] = $this->_params[0]['discountMessage'];
-        }
-
-        $params['amount_level'] = $this->_params[0]['amount_level'];
-        $params['currencyID'] = $this->_params[0]['currencyID'];
-
-        // also merge all the other values from the profile fields
-        $values = $this->controller->exportValues('Register');
-        $skipFields = [
-          'amount',
-          "street_address-{$this->_bltID}",
-          "city-{$this->_bltID}",
-          "state_province_id-{$this->_bltID}",
-          "postal_code-{$this->_bltID}",
-          "country_id-{$this->_bltID}",
-        ];
-
-        foreach ($values as $name => $value) {
-          // skip amount field
-          if (!in_array($name, $skipFields)) {
-            $params[$name] = $value;
-          }
-          if (substr($name, 0, 6) == 'price_') {
-            $params[$name] = $this->_params[0][$name];
-          }
-        }
-        $this->set('getExpressCheckoutDetails', $params);
-      }
-      $this->_params[0] = array_merge($this->_params[0], $params);
-      $this->_params[0]['is_primary'] = 1;
-    }
-    else {
+    if (!$this->preProcessExpress()) {
       //process only primary participant params.
       $registerParams = $this->_params[0];
       if (isset($registerParams["billing_state_province_id-{$this->_bltID}"])
@@ -180,6 +129,7 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
       CRM_Utils_System::setTitle($this->_values['event']['confirm_title']);
     }
 
+    // Personal campaign page
     if ($this->_pcpId) {
       $params = CRM_Contribute_Form_Contribution_Confirm::processPcp($this, $this->_params[0]);
       $this->_params[0] = $params;
@@ -188,6 +138,69 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
     $this->set('params', $this->_params);
   }
 
+  /**
+   * Pre process function for Paypal Express confirm.
+   * @todo this is just a step in refactor as payment processor specific code does not belong in generic forms
+   *
+   * @return bool
+   * @throws \CRM_Core_Exception
+   */
+  private function preProcessExpress() {
+    if ($this->_contributeMode !== 'express') {
+      return FALSE;
+    }
+    $params = [];
+    // rfp == redirect from paypal
+    // @fixme rfp is probably not required - the getPreApprovalDetails should deal with any payment-processor specific 'stuff'
+    $rfp = CRM_Utils_Request::retrieve('rfp', 'Boolean', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET');
+
+    //we lost rfp in case of additional participant. So set it explicitly.
+    if ($rfp || CRM_Utils_Array::value('additional_participants', $this->_params[0], FALSE)) {
+      if (!empty($this->_paymentProcessor) &&  $this->_paymentProcessor['object']->supports('preApproval')) {
+        $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
+        $params = array_merge($this->_params, $preApprovalParams);
+      }
+      CRM_Core_Payment_Form::mapParams($this->_bltID, $params, $params, FALSE);
+
+      // set a few other parameters that are not really specific to this method because we don't know what
+      // will break if we change this.
+      $params['amount'] = $this->_params[0]['amount'];
+      if (!empty($this->_params[0]['discount'])) {
+        $params['discount'] = $this->_params[0]['discount'];
+        $params['discountAmount'] = $this->_params[0]['discountAmount'];
+        $params['discountMessage'] = $this->_params[0]['discountMessage'];
+      }
+
+      $params['amount_level'] = $this->_params[0]['amount_level'];
+      $params['currencyID'] = $this->_params[0]['currencyID'];
+
+      // also merge all the other values from the profile fields
+      $values = $this->controller->exportValues('Register');
+      $skipFields = [
+        'amount',
+        "street_address-{$this->_bltID}",
+        "city-{$this->_bltID}",
+        "state_province_id-{$this->_bltID}",
+        "postal_code-{$this->_bltID}",
+        "country_id-{$this->_bltID}",
+      ];
+
+      foreach ($values as $name => $value) {
+        // skip amount field
+        if (!in_array($name, $skipFields)) {
+          $params[$name] = $value;
+        }
+        if (substr($name, 0, 6) == 'price_') {
+          $params[$name] = $this->_params[0][$name];
+        }
+      }
+      $this->set('getExpressCheckoutDetails', $params);
+    }
+    $this->_params[0] = array_merge($this->_params[0], $params);
+    $this->_params[0]['is_primary'] = 1;
+    return TRUE;
+  }
+
   /**
    * Overwrite action, since we are only showing elements in frozen mode no help display needed.
    *
@@ -287,25 +300,16 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
 
     if ($this->_priceSetId && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) {
       $lineItemForTemplate = [];
-      $getTaxDetails = FALSE;
       if (!empty($this->_lineItem) && is_array($this->_lineItem)) {
         foreach ($this->_lineItem as $key => $value) {
           if (!empty($value)) {
             $lineItemForTemplate[$key] = $value;
           }
-          if ($invoicing) {
-            foreach ($value as $v) {
-              if (isset($v['tax_rate'])) {
-                $getTaxDetails = TRUE;
-              }
-            }
-          }
         }
       }
       if (!empty($lineItemForTemplate)) {
-        $this->assign('lineItem', $lineItemForTemplate);
+        $this->assignLineItemsToTemplate($lineItemForTemplate);
       }
-      $this->assign('getTaxDetails', $getTaxDetails);
     }
 
     //display additional participants profile.
@@ -324,7 +328,6 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
         'type' => 'next',
         'name' => $contribButton,
         'isDefault' => TRUE,
-        'js' => ['onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"],
       ],
     ]);
 
diff --git a/civicrm/CRM/Event/Form/Registration/Register.php b/civicrm/CRM/Event/Form/Registration/Register.php
index 080ecb98c4d561fde3adbe2e77b36937f5a4963b..2fcd458f8408cbeb7d4daad12a4febc8c946fd66 100644
--- a/civicrm/CRM/Event/Form/Registration/Register.php
+++ b/civicrm/CRM/Event/Form/Registration/Register.php
@@ -463,10 +463,8 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
     ) {
 
       //freeze button to avoid multiple calls.
-      $js = NULL;
-
       if (empty($this->_values['event']['is_monetary'])) {
-        $js = ['onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"];
+        $this->submitOnce = TRUE;
       }
 
       // CRM-11182 - Optional confirmation screen
@@ -488,7 +486,6 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
           'name' => $buttonLabel,
           'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
           'isDefault' => TRUE,
-          'js' => $js,
         ],
       ]);
     }
diff --git a/civicrm/CRM/Event/Form/Registration/ThankYou.php b/civicrm/CRM/Event/Form/Registration/ThankYou.php
index 7c13ada6f6a86b267cd217665132766da0c04d74..00a1d89afa36030e082bcc9b0e5bc1edd69d40a8 100644
--- a/civicrm/CRM/Event/Form/Registration/ThankYou.php
+++ b/civicrm/CRM/Event/Form/Registration/ThankYou.php
@@ -39,6 +39,7 @@
  *
  */
 class CRM_Event_Form_Registration_ThankYou extends CRM_Event_Form_Registration {
+  use CRM_Financial_Form_FrontEndPaymentFormTrait;
 
   /**
    * Set variables up before form is built.
@@ -97,7 +98,6 @@ class CRM_Event_Form_Registration_ThankYou extends CRM_Event_Form_Registration {
     $this->assignToTemplate();
 
     $invoicing = CRM_Invoicing_Utils::isInvoicingEnabled();
-    $getTaxDetails = FALSE;
     $taxAmount = 0;
 
     $lineItemForTemplate = [];
@@ -109,7 +109,6 @@ class CRM_Event_Form_Registration_ThankYou extends CRM_Event_Form_Registration {
             foreach ($value as $v) {
               if (isset($v['tax_amount']) || isset($v['tax_rate'])) {
                 $taxAmount += $v['tax_amount'];
-                $getTaxDetails = TRUE;
               }
             }
           }
@@ -121,13 +120,11 @@ class CRM_Event_Form_Registration_ThankYou extends CRM_Event_Form_Registration {
       !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config') &&
       !empty($lineItemForTemplate)
     ) {
-      $this->assign('lineItem', $lineItemForTemplate);
+      $this->assignLineItemsToTemplate($lineItemForTemplate);
     }
 
     if ($invoicing) {
-      $this->assign('getTaxDetails', $getTaxDetails);
       $this->assign('totalTaxAmount', $taxAmount);
-      $this->assign('taxTerm', CRM_Invoicing_Utils::getTaxTerm());
     }
     $this->assign('totalAmount', $this->_totalAmount);
 
diff --git a/civicrm/CRM/Event/Form/Search.php b/civicrm/CRM/Event/Form/Search.php
index 412590c22a540444d3985f524a2c223d29e56c13..e53572d90d2f8353d1fec5ed244e550a487d9f64 100644
--- a/civicrm/CRM/Event/Form/Search.php
+++ b/civicrm/CRM/Event/Form/Search.php
@@ -419,19 +419,6 @@ class CRM_Event_Form_Search extends CRM_Core_Form_Search {
   public function addRules() {
   }
 
-  /**
-   * Set the default form values.
-   *
-   *
-   * @return array
-   *   the default array reference
-   */
-  public function setDefaultValues() {
-    $defaults = [];
-    $defaults = $this->_formValues;
-    return $defaults;
-  }
-
   public function fixFormValues() {
     // if this search has been forced
     // then see if there are any get values, and if so over-ride the post values
diff --git a/civicrm/CRM/Event/Form/SelfSvcTransfer.php b/civicrm/CRM/Event/Form/SelfSvcTransfer.php
index c3af950956bf15b805d848a6eccd8400d01c3374..a0e629e0aaf6e82ae09a15e128aa27debe96d811 100644
--- a/civicrm/CRM/Event/Form/SelfSvcTransfer.php
+++ b/civicrm/CRM/Event/Form/SelfSvcTransfer.php
@@ -365,7 +365,11 @@ class CRM_Event_Form_SelfSvcTransfer extends CRM_Core_Form {
     }
     $value_to['contact_id'] = $contact_id;
     $value_to['event_id'] = $this->_event_id;
-    $value_to['status_id'] = 1;
+    $value_to['status_id'] = CRM_Core_PseudoConstant::getKey(
+      'CRM_Event_BAO_Participant',
+      'status_id',
+      'Registered'
+    );
     $value_to['register_date'] = date("Y-m-d");
     //first create the new participant row -don't set registered_by yet or email won't be sent
     $participant = CRM_Event_BAO_Participant::create($value_to);
diff --git a/civicrm/CRM/Event/Page/EventInfo.php b/civicrm/CRM/Event/Page/EventInfo.php
index 6cdcab5bdddce18675ef83e893c642c4bda15369..b6f02a0688ca4a4c337fa84ec4d5ee8e6ea8da54 100644
--- a/civicrm/CRM/Event/Page/EventInfo.php
+++ b/civicrm/CRM/Event/Page/EventInfo.php
@@ -96,12 +96,7 @@ class CRM_Event_Page_EventInfo extends CRM_Core_Page {
 
     // show event fees.
     if ($this->_id && !empty($values['event']['is_monetary'])) {
-      //CRM-6907
-      $config = CRM_Core_Config::singleton();
-      $config->defaultCurrency = CRM_Utils_Array::value('currency',
-        $values['event'],
-        $config->defaultCurrency
-      );
+      CRM_Contribute_BAO_Contribution_Utils::overrideDefaultCurrency($values['event']);
 
       //CRM-10434
       $discountId = CRM_Core_BAO_Discount::findSet($this->_id, 'civicrm_event');
diff --git a/civicrm/CRM/Event/PseudoConstant.php b/civicrm/CRM/Event/PseudoConstant.php
index 23143f637d0bb08889f50d2b5584e9cc565f8b67..8a8e556313c29084c88dc195bdba08a74b855dbe 100644
--- a/civicrm/CRM/Event/PseudoConstant.php
+++ b/civicrm/CRM/Event/PseudoConstant.php
@@ -193,7 +193,7 @@ class CRM_Event_PseudoConstant extends CRM_Core_PseudoConstant {
    * @param int $id
    * @param null $cond
    *
-   * @return array
+   * @return array|string
    *   array reference of all participant roles if any
    */
   public static function &participantRole($id = NULL, $cond = NULL) {
@@ -224,7 +224,7 @@ class CRM_Event_PseudoConstant extends CRM_Core_PseudoConstant {
    *
    * @param int $id
    *
-   * @return array
+   * @return array|string
    *   array reference of all participant listings if any
    */
   public static function &participantListing($id = NULL) {
@@ -245,7 +245,7 @@ class CRM_Event_PseudoConstant extends CRM_Core_PseudoConstant {
    *
    *
    * @param int $id
-   * @return array
+   * @return array|string
    *   array reference of all event types.
    */
   public static function &eventType($id = NULL) {
diff --git a/civicrm/CRM/Export/BAO/Export.php b/civicrm/CRM/Export/BAO/Export.php
index eb1e98a5c8d265856185f71de36c0332715eb238..207fea22189f56e4c8a3f0328ac4b70d383f7029 100644
--- a/civicrm/CRM/Export/BAO/Export.php
+++ b/civicrm/CRM/Export/BAO/Export.php
@@ -334,6 +334,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       $processor->setHouseholdMergeReturnProperties(array_diff_key($returnProperties, array_fill_keys(['location_type', 'im_provider'], 1)));
     }
 
+    // This perhaps only needs calling when $mergeSameHousehold == 1
     self::buildRelatedContactArray($selectAll, $ids, $processor, $componentTable);
 
     // make sure the groups stuff is included only if specifically specified
@@ -349,32 +350,26 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       );
     }
 
+    $whereClauses = ['trash_clause' => "contact_a.is_deleted != 1"];
     if (!$selectAll && $componentTable) {
       $from .= " INNER JOIN $componentTable ctTable ON ctTable.contact_id = contact_a.id ";
     }
     elseif ($componentClause) {
-      if (empty($where)) {
-        $where = "WHERE $componentClause";
-      }
-      else {
-        $where .= " AND $componentClause";
-      }
+      $whereClauses[] = $componentClause;
     }
 
     // CRM-13982 - check if is deleted
-    $excludeTrashed = TRUE;
     foreach ($params as $value) {
       if ($value[0] == 'contact_is_deleted') {
-        $excludeTrashed = FALSE;
+        unset($whereClauses['trash_clause']);
       }
     }
-    $trashClause = $excludeTrashed ? "contact_a.is_deleted != 1" : "( 1 )";
 
     if (empty($where)) {
-      $where = "WHERE $trashClause";
+      $where = "WHERE " . implode(' AND ', $whereClauses);
     }
     else {
-      $where .= " AND $trashClause";
+      $where .= " AND " . implode(' AND ', $whereClauses);
     }
 
     $queryString = "$select $from $where $having";
@@ -439,7 +434,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
 
     $headerRows = $processor->getHeaderRows();
     $sqlColumns = $processor->getSQLColumns();
-    $exportTempTable = self::createTempTable($sqlColumns);
+    $processor->setTemporaryTable(self::createTempTable($sqlColumns));
     $limitReached = FALSE;
 
     while (!$limitReached) {
@@ -465,7 +460,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
 
         // output every $tempRowCount rows
         if ($count % $tempRowCount == 0) {
-          self::writeDetailsToTable($exportTempTable, $componentDetails, $sqlColumns);
+          self::writeDetailsToTable($processor, $componentDetails, $sqlColumns);
           $componentDetails = [];
         }
       }
@@ -475,32 +470,37 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       $offset += $rowCount;
     }
 
-    if ($exportTempTable) {
-      self::writeDetailsToTable($exportTempTable, $componentDetails, $sqlColumns);
+    if ($processor->getTemporaryTable()) {
+      self::writeDetailsToTable($processor, $componentDetails, $sqlColumns);
 
       // do merge same address and merge same household processing
       if ($mergeSameAddress) {
-        self::mergeSameAddress($exportTempTable, $sqlColumns, $exportParams);
+        self::mergeSameAddress($processor, $sqlColumns, $exportParams);
       }
 
       // call export hook
-      CRM_Utils_Hook::export($exportTempTable, $headerRows, $sqlColumns, $exportMode, $componentTable, $ids);
+      $table = $processor->getTemporaryTable();
+      CRM_Utils_Hook::export($table, $headerRows, $sqlColumns, $exportMode, $componentTable, $ids);
+      if ($table !== $processor->getTemporaryTable()) {
+        CRM_Core_Error::deprecatedFunctionWarning('altering the export table in the hook is deprecated (in some flows the table itself will be)');
+        $processor->setTemporaryTable($table);
+      }
 
       // In order to be able to write a unit test against this function we need to suppress
       // the csv writing. In future hopefully the csv writing & the main processing will be in separate functions.
       if (empty($exportParams['suppress_csv_for_testing'])) {
-        self::writeCSVFromTable($exportTempTable, $headerRows, $sqlColumns, $processor);
+        self::writeCSVFromTable($headerRows, $sqlColumns, $processor);
       }
       else {
         // return tableName sqlColumns headerRows in test context
-        return [$exportTempTable, $sqlColumns, $headerRows, $processor];
+        return [$processor->getTemporaryTable(), $sqlColumns, $headerRows, $processor];
       }
 
       // delete the export temp table and component table
-      $sql = "DROP TABLE IF EXISTS {$exportTempTable}";
+      $sql = "DROP TABLE IF EXISTS " . $processor->getTemporaryTable();
       CRM_Core_DAO::executeQuery($sql);
       CRM_Core_DAO::reenableFullGroupByMode();
-      CRM_Utils_System::civiExit();
+      CRM_Utils_System::civiExit(0, ['processor' => $processor]);
     }
     else {
       CRM_Core_DAO::reenableFullGroupByMode();
@@ -599,11 +599,12 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
   }
 
   /**
-   * @param string $tableName
+   * @param \CRM_Export_BAO_ExportProcessor $processor
    * @param $details
    * @param $sqlColumns
    */
-  public static function writeDetailsToTable($tableName, $details, $sqlColumns) {
+  public static function writeDetailsToTable($processor, $details, $sqlColumns) {
+    $tableName = $processor->getTemporaryTable();
     if (empty($details)) {
       return;
     }
@@ -684,11 +685,12 @@ VALUES $sqlValueString
   }
 
   /**
-   * @param string $tableName
+   * @param \CRM_Export_BAO_ExportProcessor $processor
    * @param $sqlColumns
    * @param array $exportParams
    */
-  public static function mergeSameAddress($tableName, &$sqlColumns, $exportParams) {
+  public static function mergeSameAddress($processor, &$sqlColumns, $exportParams) {
+    $tableName = $processor->getTemporaryTable();
     // check if any records are present based on if they have used shared address feature,
     // and not based on if city / state .. matches.
     $sql = "
@@ -966,12 +968,12 @@ WHERE  id IN ( $deleteIDString )
   }
 
   /**
-   * @param $exportTempTable
    * @param $headerRows
    * @param $sqlColumns
    * @param \CRM_Export_BAO_ExportProcessor $processor
    */
-  public static function writeCSVFromTable($exportTempTable, $headerRows, $sqlColumns, $processor) {
+  public static function writeCSVFromTable($headerRows, $sqlColumns, $processor) {
+    $exportTempTable = $processor->getTemporaryTable();
     $exportMode = $processor->getExportMode();
     $writeHeader = TRUE;
     $offset = 0;
diff --git a/civicrm/CRM/Export/BAO/ExportProcessor.php b/civicrm/CRM/Export/BAO/ExportProcessor.php
index 8e2489172aa469a297f281c5eae4af0ec68e31b0..8034f215a265bbcc7bd58592bd88598a67e23911 100644
--- a/civicrm/CRM/Export/BAO/ExportProcessor.php
+++ b/civicrm/CRM/Export/BAO/ExportProcessor.php
@@ -111,6 +111,13 @@ class CRM_Export_BAO_ExportProcessor {
    */
   protected $exportedHouseholds = [];
 
+  /**
+   * Households to skip during export as they will be exported via their relationships anyway.
+   *
+   * @var array
+   */
+  protected $householdsToSkip = [];
+
   /**
    * Get return properties by relationship.
    * @return array
@@ -136,6 +143,31 @@ class CRM_Export_BAO_ExportProcessor {
    */
   protected $outputSpecification = [];
 
+  /**
+   * Name of a temporary table created to hold the results.
+   *
+   * Current decision making on when to create a temp table is kinda bad so this might change
+   * a bit as it is reviewed but basically we need a temp table or similar to calculate merging
+   * addresses. Merging households is handled in php. We create a temp table even when we don't need them.
+   *
+   * @var string
+   */
+  protected $temporaryTable;
+
+  /**
+   * @return string
+   */
+  public function getTemporaryTable(): string {
+    return $this->temporaryTable;
+  }
+
+  /**
+   * @param string $temporaryTable
+   */
+  public function setTemporaryTable(string $temporaryTable) {
+    $this->temporaryTable = $temporaryTable;
+  }
+
   /**
    * CRM_Export_BAO_ExportProcessor constructor.
    *
@@ -233,6 +265,9 @@ class CRM_Export_BAO_ExportProcessor {
    */
   public function setRelationshipValue($relationshipType, $contactID, $field, $value) {
     $this->relatedContactValues[$relationshipType][$contactID][$field] = $value;
+    if ($field === 'id') {
+      $this->householdsToSkip[] = $value;
+    }
   }
 
   /**
@@ -640,6 +675,9 @@ class CRM_Export_BAO_ExportProcessor {
    * @return array|bool
    */
   public function buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader, $paymentTableId) {
+    if ($this->isHouseholdToSkip($iterationDAO->contact_id)) {
+      return FALSE;
+    }
     $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
     $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
 
@@ -1356,4 +1394,15 @@ class CRM_Export_BAO_ExportProcessor {
     }
   }
 
+  /**
+   * Is this contact a household that is already set to be exported by virtue of it's household members.
+   *
+   * @param int $contactID
+   *
+   * @return bool
+   */
+  protected function isHouseholdToSkip($contactID) {
+    return in_array($contactID, $this->householdsToSkip);
+  }
+
 }
diff --git a/civicrm/CRM/Financial/BAO/FinancialAccount.php b/civicrm/CRM/Financial/BAO/FinancialAccount.php
index c8f33573705bddb7a493a7e4964308ccf38ddc01..42a97669b418f6057965a99227a00dcc84e811c8 100644
--- a/civicrm/CRM/Financial/BAO/FinancialAccount.php
+++ b/civicrm/CRM/Financial/BAO/FinancialAccount.php
@@ -49,7 +49,7 @@ class CRM_Financial_BAO_FinancialAccount extends CRM_Financial_DAO_FinancialAcco
    *
    * @return CRM_Financial_BAO_FinancialAccount
    */
-  public static function retrieve(&$params, &$defaults) {
+  public static function retrieve(&$params, $defaults = []) {
     $financialAccount = new CRM_Financial_DAO_FinancialAccount();
     $financialAccount->copyValues($params);
     if ($financialAccount->find(TRUE)) {
diff --git a/civicrm/CRM/Financial/BAO/FinancialTypeAccount.php b/civicrm/CRM/Financial/BAO/FinancialTypeAccount.php
index faa84e3f69f619208a13f3a7707a7e2e27c81f67..be81d888e154c19526c2aa790ffe9ebadf673d9b 100644
--- a/civicrm/CRM/Financial/BAO/FinancialTypeAccount.php
+++ b/civicrm/CRM/Financial/BAO/FinancialTypeAccount.php
@@ -51,7 +51,7 @@ class CRM_Financial_BAO_FinancialTypeAccount extends CRM_Financial_DAO_EntityFin
    *
    * @return CRM_Contribute_BAO_ContributionType
    */
-  public static function retrieve(&$params, &$defaults, &$allValues = []) {
+  public static function retrieve(&$params, &$defaults = [], &$allValues = []) {
     $financialTypeAccount = new CRM_Financial_DAO_EntityFinancialAccount();
     $financialTypeAccount->copyValues($params);
     $financialTypeAccount->find();
diff --git a/civicrm/CRM/Financial/BAO/Payment.php b/civicrm/CRM/Financial/BAO/Payment.php
index 1683e2e31b957e3b63218fea17a314423cd1a05a..d3f5dc3119d0a214ad919fd0b8c0abd76197e433 100644
--- a/civicrm/CRM/Financial/BAO/Payment.php
+++ b/civicrm/CRM/Financial/BAO/Payment.php
@@ -65,8 +65,29 @@ class CRM_Financial_BAO_Payment {
     $isSkipRecordingPaymentHereForLegacyHandlingReasons = ($contributionStatus == 'Pending' && $isPaymentCompletesContribution);
 
     if (!$isSkipRecordingPaymentHereForLegacyHandlingReasons && $params['total_amount'] > 0) {
-      $trxn = CRM_Contribute_BAO_Contribution::recordPartialPayment($contribution, $params);
+      $balanceTrxnParams['to_financial_account_id'] = CRM_Contribute_BAO_Contribution::getToFinancialAccount($contribution, $params);
+      $balanceTrxnParams['from_financial_account_id'] = CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship($contribution['financial_type_id'], 'Accounts Receivable Account is');
+      $balanceTrxnParams['total_amount'] = $params['total_amount'];
+      $balanceTrxnParams['contribution_id'] = $params['contribution_id'];
+      $balanceTrxnParams['trxn_date'] = CRM_Utils_Array::value('trxn_date', $params, CRM_Utils_Array::value('contribution_receive_date', $params, date('YmdHis')));
+      $balanceTrxnParams['fee_amount'] = CRM_Utils_Array::value('fee_amount', $params);
+      $balanceTrxnParams['net_amount'] = CRM_Utils_Array::value('total_amount', $params);
+      $balanceTrxnParams['currency'] = $contribution['currency'];
+      $balanceTrxnParams['trxn_id'] = CRM_Utils_Array::value('contribution_trxn_id', $params, NULL);
+      $balanceTrxnParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Completed');
+      $balanceTrxnParams['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $params, $contribution['payment_instrument_id']);
+      $balanceTrxnParams['check_number'] = CRM_Utils_Array::value('check_number', $params);
+      $balanceTrxnParams['is_payment'] = 1;
+
+      if (!empty($params['payment_processor'])) {
+        // I can't find evidence this is passed in - I was gonna just remove it but decided to deprecate  as I see getToFinancialAccount
+        // also anticipates it.
+        CRM_Core_Error::deprecatedFunctionWarning('passing payment_processor is deprecated - use payment_processor_id');
+        $balanceTrxnParams['payment_processor_id'] = $params['payment_processor'];
+      }
+      $trxn = CRM_Core_BAO_FinancialTrxn::create($balanceTrxnParams);
 
+      // @todo - this is just weird & historical & inconsistent - why 2 tracks?
       if (CRM_Utils_Array::value('line_item', $params) && !empty($trxn)) {
         foreach ($params['line_item'] as $values) {
           foreach ($values as $id => $amount) {
@@ -97,12 +118,21 @@ class CRM_Financial_BAO_Payment {
         }
       }
       elseif (!empty($trxn)) {
-        CRM_Contribute_BAO_Contribution::assignProportionalLineItems($params, $trxn->id, $contribution['total_amount']);
+        $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($params['contribution_id']);
+        if (!empty($lineItems)) {
+          // get financial item
+          list($ftIds, $taxItems) = CRM_Contribute_BAO_Contribution::getLastFinancialItemIds($params['contribution_id']);
+          $entityParams = [
+            'contribution_total_amount' => $contribution['total_amount'],
+            'trxn_total_amount' => $params['total_amount'],
+            'trxn_id' => $trxn->id,
+          ];
+          CRM_Contribute_BAO_Contribution::createProportionalFinancialEntries($entityParams, $lineItems, $ftIds, $taxItems);
+        }
       }
     }
     elseif ($params['total_amount'] < 0) {
       $trxn = self::recordRefundPayment($params['contribution_id'], $params, FALSE);
-      CRM_Contribute_BAO_Contribution::recordPaymentActivity($params['contribution_id'], CRM_Utils_Array::value('participant_id', $params), $params['total_amount'], $trxn->currency, $trxn->trxn_date);
     }
 
     if ($isPaymentCompletesContribution) {
@@ -122,7 +152,7 @@ class CRM_Financial_BAO_Payment {
         // Get the trxn
         $trxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
         $ftParams = ['id' => $trxnId['financialTrxnId']];
-        $trxn = CRM_Core_BAO_FinancialTrxn::retrieve($ftParams, CRM_Core_DAO::$_nullArray);
+        $trxn = CRM_Core_BAO_FinancialTrxn::retrieve($ftParams);
       }
     }
     elseif ($contributionStatus === 'Pending') {
@@ -133,7 +163,7 @@ class CRM_Financial_BAO_Payment {
         ]
       );
     }
-
+    CRM_Contribute_BAO_Contribution::recordPaymentActivity($params['contribution_id'], CRM_Utils_Array::value('participant_id', $params), $params['total_amount'], $trxn->currency, $trxn->trxn_date);
     return $trxn;
   }
 
@@ -350,7 +380,10 @@ class CRM_Financial_BAO_Payment {
         if ($lineItemValue['qty'] == 0) {
           continue;
         }
-        $paid = $lineItemValue['line_total'] * ($financialTrxn->total_amount / $contributionDAO->total_amount);
+        $paid = $financialTrxn->total_amount;
+        if (!empty(floatval($contributionDAO->total_amount))) {
+          $paid = $lineItemValue['line_total'] * ($financialTrxn->total_amount / $contributionDAO->total_amount);
+        }
         $addFinancialEntry = [
           'transaction_date' => $financialTrxn->trxn_date,
           'contact_id' => $contributionDAO->contact_id,
@@ -490,7 +523,7 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
   protected static function getContributionAndParamsInFormatForRecordFinancialTransaction($contributionId) {
     $getInfoOf['id'] = $contributionId;
     $defaults = [];
-    $contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults, CRM_Core_DAO::$_nullArray);
+    $contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults);
 
     // build params for recording financial trxn entry
     $params['contribution'] = $contributionDAO;
diff --git a/civicrm/CRM/Financial/DAO/Currency.php b/civicrm/CRM/Financial/DAO/Currency.php
index 4192856b86815828ece131cd0d8e51417fad8896..ae929e059db7fe561f0731b4bf05f36487fb721e 100644
--- a/civicrm/CRM/Financial/DAO/Currency.php
+++ b/civicrm/CRM/Financial/DAO/Currency.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/Currency.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5490d115dbd495ebb39ce46a4149cbc2)
+ * (GenCodeChecksum:862b5aae448d4eb4ce0456a25cb71cc7)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/EntityFinancialAccount.php b/civicrm/CRM/Financial/DAO/EntityFinancialAccount.php
index 13b31ce00c27b144433929d02b85d594f6c5548e..b1e8b0ddb02611683d24952b01bf5089fc83abbd 100644
--- a/civicrm/CRM/Financial/DAO/EntityFinancialAccount.php
+++ b/civicrm/CRM/Financial/DAO/EntityFinancialAccount.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/EntityFinancialAccount.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3e195b6b8f9a99b338219723c2b509a7)
+ * (GenCodeChecksum:402c8a166ba3809a371a29959f1b9799)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/EntityFinancialTrxn.php b/civicrm/CRM/Financial/DAO/EntityFinancialTrxn.php
index 5387669dafaccd14bbc7543a4e2768b2093b7b68..14724a83a202bf970a37d1fc70069dd2cfc989be 100644
--- a/civicrm/CRM/Financial/DAO/EntityFinancialTrxn.php
+++ b/civicrm/CRM/Financial/DAO/EntityFinancialTrxn.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/EntityFinancialTrxn.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:14582d82c08fe5e2c4242e4bafc146d4)
+ * (GenCodeChecksum:aaf1fadaa10b8555005cd59f0e14a568)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/FinancialAccount.php b/civicrm/CRM/Financial/DAO/FinancialAccount.php
index 5f0f5f1dc4e37a4b89d283ead2ab2f7461ec1e21..d5522bce08243f47a48707f76e99b61c6690cb77 100644
--- a/civicrm/CRM/Financial/DAO/FinancialAccount.php
+++ b/civicrm/CRM/Financial/DAO/FinancialAccount.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/FinancialAccount.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:be1c13919aa1ff84b28ef61832132842)
+ * (GenCodeChecksum:b2c229b871107d223bcf8af8419ee792)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/FinancialItem.php b/civicrm/CRM/Financial/DAO/FinancialItem.php
index d3fdc69d1d76c76d7168b719ebed4fcd02e681c5..b8a7537c236e2c0de5429b8dc9b7492e1b2ec7e1 100644
--- a/civicrm/CRM/Financial/DAO/FinancialItem.php
+++ b/civicrm/CRM/Financial/DAO/FinancialItem.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/FinancialItem.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:49a455dafedd73005f06e17dcc99c365)
+ * (GenCodeChecksum:89451392c63f3412435530a1d0deae5d)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/FinancialTrxn.php b/civicrm/CRM/Financial/DAO/FinancialTrxn.php
index fefd72cbdbafff08244eadd7742753531da9d059..deb67cd909ab5c9efebe7b79bb91ec4b61fd7330 100644
--- a/civicrm/CRM/Financial/DAO/FinancialTrxn.php
+++ b/civicrm/CRM/Financial/DAO/FinancialTrxn.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/FinancialTrxn.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e130935b88e96b99dc58cb9003666e18)
+ * (GenCodeChecksum:fc0ec729cc84b9593f4cdeed22807f59)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/FinancialType.php b/civicrm/CRM/Financial/DAO/FinancialType.php
index 636069efbefbdd99649341ba430a17b6ba622076..3ffc40e40ec41600ee337a5014fed478023a0bea 100644
--- a/civicrm/CRM/Financial/DAO/FinancialType.php
+++ b/civicrm/CRM/Financial/DAO/FinancialType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/FinancialType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:9395c8fe3d749ad60136065301a5c44f)
+ * (GenCodeChecksum:468c9e0af29dcdfa4f9b419dda690325)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/PaymentProcessor.php b/civicrm/CRM/Financial/DAO/PaymentProcessor.php
index 4a09521775afaf22c18c3a7d6909654a6c4a7953..c103b7703fc18eabcd8cd7f2451a8576bc631923 100644
--- a/civicrm/CRM/Financial/DAO/PaymentProcessor.php
+++ b/civicrm/CRM/Financial/DAO/PaymentProcessor.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/PaymentProcessor.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2d3189beedf083b35929eded03907d9f)
+ * (GenCodeChecksum:3255e0cd1750d234a4cec7d73182990c)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/PaymentProcessorType.php b/civicrm/CRM/Financial/DAO/PaymentProcessorType.php
index 3c3a7bb227325a505499468b7cbe2a8ac35028d9..e870cc631feeceb17a0fb197146198ffd520047d 100644
--- a/civicrm/CRM/Financial/DAO/PaymentProcessorType.php
+++ b/civicrm/CRM/Financial/DAO/PaymentProcessorType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/PaymentProcessorType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f412f0beac8a6387450f8fe19279d0ce)
+ * (GenCodeChecksum:c70062f305d7cf04e48745fdc3df6504)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/DAO/PaymentToken.php b/civicrm/CRM/Financial/DAO/PaymentToken.php
index 17aa223d2c316fbef5c8f1b6500f47770fe5b974..3bea1c6e46d70489bec7e6f91a1340b0f51f01c4 100644
--- a/civicrm/CRM/Financial/DAO/PaymentToken.php
+++ b/civicrm/CRM/Financial/DAO/PaymentToken.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Financial/PaymentToken.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:9ef72f3d1fba1b5b89841d36382c3eb6)
+ * (GenCodeChecksum:3b1f3c099b464b808e36b41673b98c1a)
  */
 
 /**
diff --git a/civicrm/CRM/Financial/Form/FinancialAccount.php b/civicrm/CRM/Financial/Form/FinancialAccount.php
index f304e7fcfa8d4c5c63739f7e960145032d26cc52..227e6d01432b63ea59bb9bc61b5e7942fc72b363 100644
--- a/civicrm/CRM/Financial/Form/FinancialAccount.php
+++ b/civicrm/CRM/Financial/Form/FinancialAccount.php
@@ -53,7 +53,7 @@ class CRM_Financial_Form_FinancialAccount extends CRM_Contribute_Form {
       $params = [
         'id' => $this->_id,
       ];
-      $financialAccount = CRM_Financial_BAO_FinancialAccount::retrieve($params, CRM_Core_DAO::$_nullArray);
+      $financialAccount = CRM_Financial_BAO_FinancialAccount::retrieve($params);
       $financialAccountTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' "));
       if ($financialAccount->financial_account_type_id == $financialAccountTypeId
         && strtolower($financialAccount->account_type_code) == 'ar'
diff --git a/civicrm/CRM/Financial/Form/PaymentEdit.php b/civicrm/CRM/Financial/Form/PaymentEdit.php
index 105b98641c14eeb3e1bf3a720adf1f9b213fe894..22a38b9be59cd043ae3a40d8a3dab17cc50f6876 100644
--- a/civicrm/CRM/Financial/Form/PaymentEdit.php
+++ b/civicrm/CRM/Financial/Form/PaymentEdit.php
@@ -181,7 +181,12 @@ class CRM_Financial_Form_PaymentEdit extends CRM_Core_Form {
 
     $this->submit($params);
 
-    CRM_Core_Session::singleton()->pushUserContext(CRM_Utils_System::url(CRM_Utils_System::currentPath()));
+    $contactId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->_contributionID, 'contact_id');
+    $url = CRM_Utils_System::url(
+      "civicrm/contact/view/contribution",
+      "reset=1&action=update&id={$this->_contributionID}&cid={$contactId}&context=contribution"
+    );
+    CRM_Core_Session::singleton()->pushUserContext($url);
   }
 
   /**
diff --git a/civicrm/CRM/Financial/Page/FinancialType.php b/civicrm/CRM/Financial/Page/FinancialType.php
index 6bb3b325ff793461cbd0f9cdc5ca11d19c7ce5a9..f0e1f1823214186f0c091af5ea1d724961baa01a 100644
--- a/civicrm/CRM/Financial/Page/FinancialType.php
+++ b/civicrm/CRM/Financial/Page/FinancialType.php
@@ -121,7 +121,8 @@ class CRM_Financial_Page_FinancialType extends CRM_Core_Page_Basic {
 
       $params['entity_id'] = $dao->id;
       $params['entity_table'] = 'civicrm_financial_type';
-      CRM_Financial_BAO_FinancialTypeAccount::retrieve($params, CRM_Core_DAO::$_nullArray, $financialAccountIds);
+      $null = [];
+      CRM_Financial_BAO_FinancialTypeAccount::retrieve($params, $null, $financialAccountIds);
 
       foreach ($financialAccountIds as $key => $values) {
         if (!empty($financialAccounts[$values['financial_account_id']])) {
diff --git a/civicrm/CRM/Friend/BAO/Friend.php b/civicrm/CRM/Friend/BAO/Friend.php
index b817cae9091116de4a27f1ae20cd914aa1d0850d..2e8328255df8039b28d6263b42276513ceaad0c0 100644
--- a/civicrm/CRM/Friend/BAO/Friend.php
+++ b/civicrm/CRM/Friend/BAO/Friend.php
@@ -64,7 +64,7 @@ class CRM_Friend_BAO_Friend extends CRM_Friend_DAO_Friend {
    * @return int
    */
   public static function add(&$params) {
-    return CRM_Contact_BAO_Contact::createProfileContact($params, CRM_Core_DAO::$_nullArray);
+    return CRM_Contact_BAO_Contact::createProfileContact($params);
   }
 
   /**
diff --git a/civicrm/CRM/Friend/DAO/Friend.php b/civicrm/CRM/Friend/DAO/Friend.php
index d072051971aa77b343960ac72a1452040d9bcc09..0e1cc3af6ca71aaaa6ecf9480a98be9eb8282bec 100644
--- a/civicrm/CRM/Friend/DAO/Friend.php
+++ b/civicrm/CRM/Friend/DAO/Friend.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Friend/Friend.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a662628e986758095dcbfa2e56597acb)
+ * (GenCodeChecksum:04bbd009e4d68da0f7e966ee3c780dcb)
  */
 
 /**
diff --git a/civicrm/CRM/Friend/Form.php b/civicrm/CRM/Friend/Form.php
index 70cd21086dc5109a098aaee6f2fedca8f44f01ff..4509acd993377f7c524565a73b6d7279d99d51d2 100644
--- a/civicrm/CRM/Friend/Form.php
+++ b/civicrm/CRM/Friend/Form.php
@@ -129,7 +129,6 @@ class CRM_Friend_Form extends CRM_Core_Form {
       while ($pcp->fetch()) {
         $this->_title = $pcp->title;
         $this->_campaignId = $pcp->campaign_id;
-        $pcp->free();
       }
 
       $this->assign('pcpTitle', $this->_title);
diff --git a/civicrm/CRM/Friend/Form/Event.php b/civicrm/CRM/Friend/Form/Event.php
index bf5b6cb51828b5769d8703a026f0a936180b01cd..2e68f80dc88d9ccd6cff7fdedfb8ce3b500222c1 100644
--- a/civicrm/CRM/Friend/Form/Event.php
+++ b/civicrm/CRM/Friend/Form/Event.php
@@ -48,7 +48,7 @@ class CRM_Friend_Form_Event extends CRM_Event_Form_ManageEvent {
 
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'friend');
+    $this->setSelectedChild('friend');
   }
 
   /**
diff --git a/civicrm/CRM/Grant/DAO/Grant.php b/civicrm/CRM/Grant/DAO/Grant.php
index d889f2ad6f48ea67d0e2b0544944335f1905ff82..b05255eca64733b940c2904470ed4641a6dc315e 100644
--- a/civicrm/CRM/Grant/DAO/Grant.php
+++ b/civicrm/CRM/Grant/DAO/Grant.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Grant/Grant.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:46934eeb5b7cc864460135cbbf1679ca)
+ * (GenCodeChecksum:33e12de8a892435e7d199da439efefe6)
  */
 
 /**
diff --git a/civicrm/CRM/Grant/Page/Tab.php b/civicrm/CRM/Grant/Page/Tab.php
index 914879716cd62a8b9a3b6a35940663d573e96d19..c2134c06b5b25fa2a75f85618741dc88ccb36183 100644
--- a/civicrm/CRM/Grant/Page/Tab.php
+++ b/civicrm/CRM/Grant/Page/Tab.php
@@ -177,7 +177,7 @@ class CRM_Grant_Page_Tab extends CRM_Contact_Page_View {
         break;
 
       case 'edit':
-        $url = CRM_utils_System::url('civicrm/contact/view/grant', 'reset=1&id=' . $this->_id . '&cid=' . $this->_contactId . '&action=view&context=grant&selectedChild=grant');
+        $url = CRM_Utils_System::url('civicrm/contact/view/grant', 'reset=1&id=' . $this->_id . '&cid=' . $this->_contactId . '&action=view&context=grant&selectedChild=grant');
         break;
 
       case 'grant':
diff --git a/civicrm/CRM/Logging/Schema.php b/civicrm/CRM/Logging/Schema.php
index 9ce4883b18131419b00686628361d7aa97a1259a..0f7f3ac3931b755f13aee651a0a52b64f6889be9 100644
--- a/civicrm/CRM/Logging/Schema.php
+++ b/civicrm/CRM/Logging/Schema.php
@@ -31,6 +31,14 @@
  * @copyright CiviCRM LLC (c) 2004-2019
  */
 class CRM_Logging_Schema {
+
+  /**
+   * Default storage engine for log tables
+   *
+   * @var string
+   */
+  const ENGINE = 'InnoDB';
+
   private $logs = [];
   private $tables = [];
 
@@ -58,7 +66,7 @@ class CRM_Logging_Schema {
 
   /**
    * Specifications of all log table including
-   *  - engine (default is archive, if not set.)
+   *  - engine (default is InnoDB, if not set.)
    *  - engine_config, a string appended to the engine type.
    *    For INNODB  space can be saved with 'ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4'
    *  - indexes (default is none and they cannot be added unless engine is innodb. If they are added and
@@ -302,23 +310,31 @@ AND    (TABLE_NAME LIKE 'log_civicrm_%' $nonStandardTableNameString )
    * and also implements the engine change defined by the hook (i.e. INNODB).
    *
    * Note changing engine & adding hook-defined indexes, but not changing back
-   * to ARCHIVE if engine has not been deliberately set (by hook) and not dropping
-   * indexes. Sysadmin will need to manually intervene to revert to defaults.
+   * to INNODB if engine has not been deliberately set (by hook) and not
+   * dropping indexes. Sysadmin will need to manually intervene to revert to
+   * defaults.
    *
    * @param array $params
-   *     'updateChangedEngineConfig' - update if the engine config changes, default FALSE
+   *     'updateChangedEngineConfig' - update if the engine config changes?
+   *     'forceEngineMigration' - force engine upgrade from ARCHIVE to InnoDB?
    *
    * @return int $updateTablesCount
+   * @throws \CiviCRM_API3_Exception
    */
-  public function updateLogTableSchema($params = []) {
-    isset($params['updateChangedEngineConfig']) ? NULL : $params['updateChangedEngineConfig'] = FALSE;
-
+  public function updateLogTableSchema($params) {
     $updateLogConn = FALSE;
     $updatedTablesCount = 0;
     foreach ($this->logs as $mainTable => $logTable) {
       $alterSql = [];
       $tableSpec = $this->logTableSpec[$mainTable];
-      $engineChanged = isset($tableSpec['engine']) && (strtoupper($tableSpec['engine']) != $this->getEngineForLogTable($logTable));
+      $currentEngine = strtoupper($this->getEngineForLogTable($logTable));
+      if (!isset($tableSpec['engine']) && $currentEngine == 'ARCHIVE' && $params['forceEngineMigration']) {
+        // table uses ARCHIVE engine (the previous default) and no one set an
+        // alternative engine via hook_civicrm_alterLogTables => force change to
+        // new default
+        $tableSpec['engine'] = self::ENGINE;
+      }
+      $engineChanged = isset($tableSpec['engine']) && (strtoupper($tableSpec['engine']) != $currentEngine);
       $engineConfigChanged = isset($tableSpec['engine_config']) && (strtoupper($tableSpec['engine_config']) != $this->getEngineConfigForLogTable($logTable));
       if ($engineChanged || ($engineConfigChanged && $params['updateChangedEngineConfig'])) {
         $alterSql[] = "ENGINE=" . $tableSpec['engine'] . " " . CRM_Utils_Array::value('engine_config', $tableSpec);
@@ -581,13 +597,13 @@ AND    (TABLE_NAME LIKE 'log_civicrm_%' $nonStandardTableNameString )
     if ($force || !isset(\Civi::$statics[__CLASS__]['columnsOf'][$table])) {
       $from = (substr($table, 0, 4) == 'log_') ? "`{$this->db}`.$table" : $table;
       CRM_Core_TemporaryErrorScope::ignoreException();
-      $dao = CRM_Core_DAO::executeQuery("SHOW COLUMNS FROM $from", CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
+      $dao = CRM_Core_DAO::executeQuery("SHOW COLUMNS FROM $from", [], TRUE, NULL, FALSE, FALSE);
       if (is_a($dao, 'DB_Error')) {
         return [];
       }
       \Civi::$statics[__CLASS__]['columnsOf'][$table] = [];
       while ($dao->fetch()) {
-        \Civi::$statics[__CLASS__]['columnsOf'][$table][] = CRM_Utils_type::escape($dao->Field, 'MysqlColumnNameOrAlias');
+        \Civi::$statics[__CLASS__]['columnsOf'][$table][] = CRM_Utils_Type::escape($dao->Field, 'MysqlColumnNameOrAlias');
       }
     }
     return \Civi::$statics[__CLASS__]['columnsOf'][$table];
@@ -737,7 +753,7 @@ WHERE  table_schema IN ('{$this->db}', '{$civiDB}')";
    * @param string $table
    */
   private function createLogTableFor($table) {
-    $dao = CRM_Core_DAO::executeQuery("SHOW CREATE TABLE $table", CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
+    $dao = CRM_Core_DAO::executeQuery("SHOW CREATE TABLE $table", [], TRUE, NULL, FALSE, FALSE);
     $dao->fetch();
     $query = $dao->Create_Table;
 
@@ -762,7 +778,7 @@ COLS;
     // - prepend the name with log_
     // - drop AUTO_INCREMENT columns
     // - drop non-column rows of the query (keys, constraints, etc.)
-    // - set the ENGINE to the specified engine (default is archive or if archive is disabled or nor installed INNODB)
+    // - set the ENGINE to the specified engine (default is INNODB)
     // - add log-specific columns (at the end of the table)
     $mysqlEngines = [];
     $engines = CRM_Core_DAO::executeQuery("SHOW ENGINES");
@@ -771,11 +787,10 @@ COLS;
         $mysqlEngines[] = $engines->Engine;
       }
     }
-    $logEngine = in_array('ARCHIVE', $mysqlEngines) ? 'ARCHIVE' : 'INNODB';
     $query = preg_replace("/^CREATE TABLE `$table`/i", "CREATE TABLE `{$this->db}`.log_$table", $query);
     $query = preg_replace("/ AUTO_INCREMENT/i", '', $query);
     $query = preg_replace("/^  [^`].*$/m", '', $query);
-    $engine = strtoupper(CRM_Utils_Array::value('engine', $this->logTableSpec[$table], $logEngine));
+    $engine = strtoupper(CRM_Utils_Array::value('engine', $this->logTableSpec[$table], self::ENGINE));
     $engine .= " " . CRM_Utils_Array::value('engine_config', $this->logTableSpec[$table]);
     $query = preg_replace("/^\) ENGINE=[^ ]+ /im", ') ENGINE=' . $engine . ' ', $query);
 
@@ -785,10 +800,10 @@ COLS;
     $query = self::fixTimeStampAndNotNullSQL($query);
     $query = preg_replace("/(,*\n*\) )ENGINE/m", "$cols\n) ENGINE", $query);
 
-    CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
+    CRM_Core_DAO::executeQuery($query, [], TRUE, NULL, FALSE, FALSE);
 
     $columns = implode(', ', $this->columnsOf($table));
-    CRM_Core_DAO::executeQuery("INSERT INTO `{$this->db}`.log_$table ($columns, log_conn_id, log_user_id, log_action) SELECT $columns, @uniqueID, @civicrm_user_id, 'Initialization' FROM {$table}", CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
+    CRM_Core_DAO::executeQuery("INSERT INTO `{$this->db}`.log_$table ($columns, log_conn_id, log_user_id, log_action) SELECT $columns, @uniqueID, @civicrm_user_id, 'Initialization' FROM {$table}", [], TRUE, NULL, FALSE, FALSE);
 
     $this->tables[] = $table;
     if (empty($this->logs)) {
diff --git a/civicrm/CRM/Mailing/BAO/Mailing.php b/civicrm/CRM/Mailing/BAO/Mailing.php
index 21d10f7c5f77d2aab9ed34ad29bb15daed6f7446..9a24f8a9a821fff24f22d26346cd1a306dbd5d44 100644
--- a/civicrm/CRM/Mailing/BAO/Mailing.php
+++ b/civicrm/CRM/Mailing/BAO/Mailing.php
@@ -863,14 +863,12 @@ ORDER BY   civicrm_email.is_bulkmail DESC
       $this->header = new CRM_Mailing_BAO_MailingComponent();
       $this->header->id = $this->header_id;
       $this->header->find(TRUE);
-      $this->header->free();
     }
 
     if (!$this->footer and $this->footer_id) {
       $this->footer = new CRM_Mailing_BAO_MailingComponent();
       $this->footer->id = $this->footer_id;
       $this->footer->find(TRUE);
-      $this->footer->free();
     }
   }
 
@@ -1451,7 +1449,6 @@ ORDER BY   civicrm_email.is_bulkmail DESC
     while ($mg->fetch()) {
       $groups[] = $mg->name;
     }
-    $mg->free();
     return $groups;
   }
 
@@ -3067,6 +3064,13 @@ ORDER BY civicrm_mailing.name";
       'id' => $id,
       'return' => 'visibility',
     ])) === 'Public Pages') {
+
+      // if hash setting is on then we change the public url into a hash
+      $hash = CRM_Mailing_BAO_Mailing::getMailingHash($id);
+      if (!empty($hash)) {
+        $id = $hash;
+      }
+
       return CRM_Utils_System::url('civicrm/mailing/view', ['id' => $id], $absolute, NULL, TRUE, TRUE);
     }
   }
diff --git a/civicrm/CRM/Mailing/BAO/MailingJob.php b/civicrm/CRM/Mailing/BAO/MailingJob.php
index 6bbf83947436e4cb31e58d022382a08a2abc80d8..f14eb00c7e263f9fa9f79337056dfbbde7a5e3c8 100644
--- a/civicrm/CRM/Mailing/BAO/MailingJob.php
+++ b/civicrm/CRM/Mailing/BAO/MailingJob.php
@@ -501,7 +501,6 @@ VALUES (%1, %2, %3, %4, %5, %6, %7)
     $mailing = new CRM_Mailing_BAO_Mailing();
     $mailing->id = $this->mailing_id;
     $mailing->find(TRUE);
-    $mailing->free();
 
     $config = NULL;
 
@@ -542,7 +541,6 @@ VALUES (%1, %2, %3, %4, %5, %6, %7)
         if (!empty($fields)) {
           $this->deliverGroup($fields, $mailing, $mailer, $job_date, $attachments);
         }
-        $eq->free();
         return FALSE;
       }
       self::$mailsProcessed++;
@@ -557,15 +555,12 @@ VALUES (%1, %2, %3, %4, %5, %6, %7)
       if (count($fields) == self::MAX_CONTACTS_TO_PROCESS) {
         $isDelivered = $this->deliverGroup($fields, $mailing, $mailer, $job_date, $attachments);
         if (!$isDelivered) {
-          $eq->free();
           return $isDelivered;
         }
         $fields = [];
       }
     }
 
-    $eq->free();
-
     if (!empty($fields)) {
       $isDelivered = $this->deliverGroup($fields, $mailing, $mailer, $job_date, $attachments);
     }
diff --git a/civicrm/CRM/Mailing/BAO/Query.php b/civicrm/CRM/Mailing/BAO/Query.php
index ff1e5a8dd07848454e3c6f3635dbd0b908a89071..aadb018caf012b813f5f55078aeecb7345e321fa 100644
--- a/civicrm/CRM/Mailing/BAO/Query.php
+++ b/civicrm/CRM/Mailing/BAO/Query.php
@@ -137,7 +137,7 @@ class CRM_Mailing_BAO_Query {
         continue;
       }
       if (substr($query->_params[$id][0], 0, 8) == 'mailing_') {
-        if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) {
+        if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) {
           $query->_useDistinct = TRUE;
         }
         $grouping = $query->_params[$id][3];
diff --git a/civicrm/CRM/Mailing/DAO/BouncePattern.php b/civicrm/CRM/Mailing/DAO/BouncePattern.php
index e54fa43aa3049f7797430dff00666cd788e9a051..34bf17983bf2234f7520775cde81f6a7fac7ebd9 100644
--- a/civicrm/CRM/Mailing/DAO/BouncePattern.php
+++ b/civicrm/CRM/Mailing/DAO/BouncePattern.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/BouncePattern.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:767f24673857e91d2b76de45fce55649)
+ * (GenCodeChecksum:6b50d60bdaf70f0d826e4f71fb7e1b8d)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/BounceType.php b/civicrm/CRM/Mailing/DAO/BounceType.php
index db710ffeb948a044d7a8a982bb3c93fc039ce091..073e78f4dae7a6e6fbef6878f97d03ff4d6e702f 100644
--- a/civicrm/CRM/Mailing/DAO/BounceType.php
+++ b/civicrm/CRM/Mailing/DAO/BounceType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/BounceType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:32b467be869aa9e4539fe7f0824f96b3)
+ * (GenCodeChecksum:2c73785c27d9d0b8980c27443691b8b1)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/Mailing.php b/civicrm/CRM/Mailing/DAO/Mailing.php
index d6aef45f9eb81974eb502089006b09fef0cae4c8..83f0211943bb31ea1d3e041574981bab8e047e42 100644
--- a/civicrm/CRM/Mailing/DAO/Mailing.php
+++ b/civicrm/CRM/Mailing/DAO/Mailing.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Mailing.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:c6f26fcb49da86f49a4a1ac885070ed6)
+ * (GenCodeChecksum:9e3f016db0a2ac72e2c25c9c5e3821a5)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/MailingAB.php b/civicrm/CRM/Mailing/DAO/MailingAB.php
index 9fb96960e1bc8a249867fc8fe95a173b00062def..89080d583e3885d244e3c89f77a24f7a47c93a6c 100644
--- a/civicrm/CRM/Mailing/DAO/MailingAB.php
+++ b/civicrm/CRM/Mailing/DAO/MailingAB.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/MailingAB.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:a45895256f23784bb86ae1b4659abbe6)
+ * (GenCodeChecksum:45cbf7496c9fc0390db80c90911972e4)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/MailingComponent.php b/civicrm/CRM/Mailing/DAO/MailingComponent.php
index 8a5e52eb204b96f8e7746c18418842dd92c6f529..858090bb13c62145961dc03cbd4880d5c52584d5 100644
--- a/civicrm/CRM/Mailing/DAO/MailingComponent.php
+++ b/civicrm/CRM/Mailing/DAO/MailingComponent.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/MailingComponent.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e3b5498354f50a2badfa4425958511af)
+ * (GenCodeChecksum:e082d5c712aadfb34ce2dedafeee74b9)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/MailingGroup.php b/civicrm/CRM/Mailing/DAO/MailingGroup.php
index 75bdc7f2b3fd39a063cdb24250a011a5bb066a66..045b6cd524bff2c16f7ddf33c7994e8efa8d2094 100644
--- a/civicrm/CRM/Mailing/DAO/MailingGroup.php
+++ b/civicrm/CRM/Mailing/DAO/MailingGroup.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/MailingGroup.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:22f18bdbfea712ba8a6e1f0220ffb016)
+ * (GenCodeChecksum:251b8dd5f585f69b32ebc5d5e509135e)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/MailingJob.php b/civicrm/CRM/Mailing/DAO/MailingJob.php
index ebec9368ab07ad75ee4dec09a19282a1303f8a0b..40c9eca89e95aea7f2dda3eeb259df5410980702 100644
--- a/civicrm/CRM/Mailing/DAO/MailingJob.php
+++ b/civicrm/CRM/Mailing/DAO/MailingJob.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/MailingJob.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e7dbe1ca234cec93cb54192911b87297)
+ * (GenCodeChecksum:d974b81d2de971b10634794130261b3e)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/Recipients.php b/civicrm/CRM/Mailing/DAO/Recipients.php
index 8ca9fe6ec0b22f4da7917d059c62047327bd5ea2..9b539a0f5b0278ea762a5ab6750c25e90b7e8e00 100644
--- a/civicrm/CRM/Mailing/DAO/Recipients.php
+++ b/civicrm/CRM/Mailing/DAO/Recipients.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Recipients.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:006015b0e117746e7c97d656150badc3)
+ * (GenCodeChecksum:b5e7e162aa5154171c57d7de1e484d77)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/Spool.php b/civicrm/CRM/Mailing/DAO/Spool.php
index 20053007af3d836091df00cb332e60929d4dc9db..e2f960cf3f0a4ad6dfc4e7566be50e902ed141d0 100644
--- a/civicrm/CRM/Mailing/DAO/Spool.php
+++ b/civicrm/CRM/Mailing/DAO/Spool.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Spool.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:55c696d855ff602c9e097bd9ccff0971)
+ * (GenCodeChecksum:328c2bef8b4227378923d9d9e6fc5307)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/DAO/TrackableURL.php b/civicrm/CRM/Mailing/DAO/TrackableURL.php
index 751d21e744a33d1e0d4b5a2e8d5b850eb708ad5c..faa50c5362428cb9e85830959f71c643e8275304 100644
--- a/civicrm/CRM/Mailing/DAO/TrackableURL.php
+++ b/civicrm/CRM/Mailing/DAO/TrackableURL.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/TrackableURL.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:36f444ad863c1eae8db4e8e1c768eb27)
+ * (GenCodeChecksum:627457119055a90330a2ac9befafd679)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/BAO/Bounce.php b/civicrm/CRM/Mailing/Event/BAO/Bounce.php
index 9a162c83dea1b8582482230d49441268ba4a8678..1f3c8ba8c24f027616cc2de966f99eb12f748c19 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Bounce.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Bounce.php
@@ -180,7 +180,7 @@ class CRM_Mailing_Event_BAO_Bounce extends CRM_Mailing_Event_DAO_Bounce {
     $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL
   ) {
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $bounce = self::getTableName();
     $bounceType = CRM_Mailing_DAO_BounceType::getTableName();
diff --git a/civicrm/CRM/Mailing/Event/BAO/Delivered.php b/civicrm/CRM/Mailing/Event/BAO/Delivered.php
index e8c9a4cc19b6a1e285f250661d43f073b40d17fe..237f3a27fcb20aff61e81a505afc972b6d6ae0cd 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Delivered.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Delivered.php
@@ -163,7 +163,7 @@ class CRM_Mailing_Event_BAO_Delivered extends CRM_Mailing_Event_DAO_Delivered {
     $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL, $is_test = 0
   ) {
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $delivered = self::getTableName();
     $bounce = CRM_Mailing_Event_BAO_Bounce::getTableName();
@@ -280,7 +280,7 @@ class CRM_Mailing_Event_BAO_Delivered extends CRM_Mailing_Event_DAO_Delivered {
    *   Consider mailings that were completed not more than $maxDays ago.
    */
   public static function updateEmailResetDate($minDays = 3, $maxDays = 7) {
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $query = "
 CREATE TEMPORARY TABLE civicrm_email_temp_values (
diff --git a/civicrm/CRM/Mailing/Event/BAO/Forward.php b/civicrm/CRM/Mailing/Event/BAO/Forward.php
index 8d8532ea8da75ddf8013cfa83644dfc6c3d2530e..4c79b03db44b3875c1a5897fe51cd0e9f55e47bb 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Forward.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Forward.php
@@ -72,7 +72,7 @@ class CRM_Mailing_Event_BAO_Forward extends CRM_Mailing_Event_DAO_Forward {
 
     $domain = CRM_Core_BAO_Domain::getDomain();
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
     $dao->query("
                 SELECT      $contact.id as contact_id,
                             $email.id as email_id,
@@ -298,7 +298,7 @@ class CRM_Mailing_Event_BAO_Forward extends CRM_Mailing_Event_DAO_Forward {
     $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL
   ) {
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $forward = self::getTableName();
     $queue = CRM_Mailing_Event_BAO_Queue::getTableName();
diff --git a/civicrm/CRM/Mailing/Event/BAO/Opened.php b/civicrm/CRM/Mailing/Event/BAO/Opened.php
index a2a1e01b30ed6b8d758b2fb3308685e6c48fd29a..9188dadaa22bf7bde994400c8a4a4e60bc6e8493 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Opened.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Opened.php
@@ -232,7 +232,7 @@ class CRM_Mailing_Event_BAO_Opened extends CRM_Mailing_Event_DAO_Opened {
     $mailing_id, $job_id = NULL,
     $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL, $contact_id = NULL
   ) {
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $open = self::getTableName();
     $queue = CRM_Mailing_Event_BAO_Queue::getTableName();
diff --git a/civicrm/CRM/Mailing/Event/BAO/Queue.php b/civicrm/CRM/Mailing/Event/BAO/Queue.php
index 41cefaf8ee4505a5dccc8bdc9164dfda2a04898c..59e979f0804cae10b7581f9b6f929538cd6c8c0d 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Queue.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Queue.php
@@ -186,7 +186,7 @@ class CRM_Mailing_Event_BAO_Queue extends CRM_Mailing_Event_DAO_Queue {
     $mailing_id, $job_id = NULL, $offset = NULL,
     $rowCount = NULL, $sort = NULL
   ) {
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $queue = self::getTableName();
     $mailing = CRM_Mailing_BAO_Mailing::getTableName();
diff --git a/civicrm/CRM/Mailing/Event/BAO/Reply.php b/civicrm/CRM/Mailing/Event/BAO/Reply.php
index 03a54c9431e669caf56c2982d1c67f7da4f5a3cb..f02d1ffe60c1ccd7256d3d8a2a7f826034889e06 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Reply.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Reply.php
@@ -371,7 +371,7 @@ class CRM_Mailing_Event_BAO_Reply extends CRM_Mailing_Event_DAO_Reply {
     $is_distinct = FALSE, $offset = NULL, $rowCount = NULL, $sort = NULL
   ) {
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $reply = self::getTableName();
     $queue = CRM_Mailing_Event_BAO_Queue::getTableName();
diff --git a/civicrm/CRM/Mailing/Event/BAO/TrackableURLOpen.php b/civicrm/CRM/Mailing/Event/BAO/TrackableURLOpen.php
index 29a907d29afe52fb7200884d3b5a89bcbbba068a..7237c7390fab6f4467369242d014f8f29f482ff5 100644
--- a/civicrm/CRM/Mailing/Event/BAO/TrackableURLOpen.php
+++ b/civicrm/CRM/Mailing/Event/BAO/TrackableURLOpen.php
@@ -292,7 +292,7 @@ class CRM_Mailing_Event_BAO_TrackableURLOpen extends CRM_Mailing_Event_DAO_Track
     $offset = NULL, $rowCount = NULL, $sort = NULL, $contact_id = NULL
   ) {
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $click = self::getTableName();
     $url = CRM_Mailing_BAO_TrackableURL::getTableName();
diff --git a/civicrm/CRM/Mailing/Event/BAO/Unsubscribe.php b/civicrm/CRM/Mailing/Event/BAO/Unsubscribe.php
index 415ae8535064b5a1569a86ab63062c127451def3..f6c4771e28f569ec648047e35af2fa5d1e654a9d 100644
--- a/civicrm/CRM/Mailing/Event/BAO/Unsubscribe.php
+++ b/civicrm/CRM/Mailing/Event/BAO/Unsubscribe.php
@@ -532,7 +532,7 @@ WHERE  email = %2
     $org_unsubscribe = NULL
   ) {
 
-    $dao = new CRM_Core_Dao();
+    $dao = new CRM_Core_DAO();
 
     $unsub = self::$_tableName;
     $queueObject = new CRM_Mailing_Event_BAO_Queue();
diff --git a/civicrm/CRM/Mailing/Event/DAO/Bounce.php b/civicrm/CRM/Mailing/Event/DAO/Bounce.php
index 8efd8fddb357196597670dd05fee28381ed3095d..bcf3cf915a874e9f9d9b3089f86c23d6b1ffd5cc 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Bounce.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Bounce.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Bounce.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:0b39ada8498cdc95e5eab7a4f060686a)
+ * (GenCodeChecksum:242dfeae734755f1cacb3af7b08c331d)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Confirm.php b/civicrm/CRM/Mailing/Event/DAO/Confirm.php
index b80f8fc3198a50c1a7e9aef01ef6a66b7cc3db01..7180aaf75f6acdb2e9325a34c7bcc98ecd0e1d8d 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Confirm.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Confirm.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Confirm.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:dd5f6d9d5ca3115b92e9f87a1d5bf503)
+ * (GenCodeChecksum:c14a004f07a27f4c43e85c325cb2eaa1)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Delivered.php b/civicrm/CRM/Mailing/Event/DAO/Delivered.php
index 5a3008d751f94318df94a1d56cafef154e52c103..f10840e8f5f9d6ac63cd490095650477d1d05e17 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Delivered.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Delivered.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Delivered.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:6327ad9e20e94a06bd9609fd3f56a3b4)
+ * (GenCodeChecksum:1e8b764f8ec28d81bdc4eb721988b4f8)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Forward.php b/civicrm/CRM/Mailing/Event/DAO/Forward.php
index 059c6b3a4a1c373c0ba8b863943b4c9e978922bb..f409781aecf211faf57fb6097daa3011de32914e 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Forward.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Forward.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Forward.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:b178f318b31d833f478b236f268cbcec)
+ * (GenCodeChecksum:fbff44da80d2e268d0fcb1514dc41ffd)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Opened.php b/civicrm/CRM/Mailing/Event/DAO/Opened.php
index 69fb725731031a7efb487d486ff9954f7a8b0d00..e001bc82e278d8ce738ff2e695d104749f63aba9 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Opened.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Opened.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Opened.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:77cca50f0bb75aecfc26f8e62037b93d)
+ * (GenCodeChecksum:3137f709d2d90310071417bf1ba3fd2f)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Queue.php b/civicrm/CRM/Mailing/Event/DAO/Queue.php
index efe1d0867d8f46d9cc408df1c4009e1288df272e..69e1401c33c5476e5879bab0f478da44874c2cc2 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Queue.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Queue.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Queue.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:6ce46b44932d8dcdbf39af7d91a57a03)
+ * (GenCodeChecksum:10e0744e0adb4393d37a8fbbbe585e4b)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Reply.php b/civicrm/CRM/Mailing/Event/DAO/Reply.php
index 27ec175e906a1fc6bf3553637ff1cb54afec3466..f125bf148343401a4a6bc6aa9a06fbfc140ba7e6 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Reply.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Reply.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Reply.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:0ddff564744f8da4c3d5030ceb692b9c)
+ * (GenCodeChecksum:98fb3b43e0d0fb2cd6692dced2e6e976)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Subscribe.php b/civicrm/CRM/Mailing/Event/DAO/Subscribe.php
index 3162104cfc4bc0962bd4bb908431813e50fcd016..f40c444a741190020745373c896807e4d22d5376 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Subscribe.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Subscribe.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Subscribe.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:3f9398df2e81f38e0a24330928f85b47)
+ * (GenCodeChecksum:b11ac04360acd1807fd79c83dac6378e)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/TrackableURLOpen.php b/civicrm/CRM/Mailing/Event/DAO/TrackableURLOpen.php
index cce8241d1a3bd3ff41afd0558185730966e596df..0a7ba546a2f93131e194df1cac0a4bad149c019b 100644
--- a/civicrm/CRM/Mailing/Event/DAO/TrackableURLOpen.php
+++ b/civicrm/CRM/Mailing/Event/DAO/TrackableURLOpen.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/TrackableURLOpen.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ed0344e6d9483abfca366a5ba9735e56)
+ * (GenCodeChecksum:1f5cdd9da44ad1fe0fa03b6d1833e0c2)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Event/DAO/Unsubscribe.php b/civicrm/CRM/Mailing/Event/DAO/Unsubscribe.php
index 8e7d40ddd7e37a1a72cf43d498217a6788fb7352..c62df7d7e7ac285d90271c670a4ef3e0e8a13161 100644
--- a/civicrm/CRM/Mailing/Event/DAO/Unsubscribe.php
+++ b/civicrm/CRM/Mailing/Event/DAO/Unsubscribe.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Mailing/Event/Unsubscribe.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:f3f2e48cc72b5cacff2aad1e146e70f8)
+ * (GenCodeChecksum:3b8b2645e8dea3913117ab02495540b5)
  */
 
 /**
diff --git a/civicrm/CRM/Mailing/Form/Subscribe.php b/civicrm/CRM/Mailing/Form/Subscribe.php
index 6a8feae66b2e2668470f562bea6a334f63d9d881..56e34f1e26910fc2980d85ba31ecad8eca924d21 100644
--- a/civicrm/CRM/Mailing/Form/Subscribe.php
+++ b/civicrm/CRM/Mailing/Form/Subscribe.php
@@ -147,10 +147,7 @@ ORDER BY title";
     }
 
     if ($addCaptcha) {
-      // add captcha
-      $captcha = CRM_Utils_ReCAPTCHA::singleton();
-      $captcha->add($this);
-      $this->assign('isCaptcha', TRUE);
+      CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
     }
 
     $this->addButtons([
diff --git a/civicrm/CRM/Mailing/Page/View.php b/civicrm/CRM/Mailing/Page/View.php
index a6f03660f2be884beae482f9fa07989ccfb9215b..878434004ea5d9b30c4aa23fe393b885621d41dc 100644
--- a/civicrm/CRM/Mailing/Page/View.php
+++ b/civicrm/CRM/Mailing/Page/View.php
@@ -113,7 +113,14 @@ class CRM_Mailing_Page_View extends CRM_Core_Page {
       $this->_mailing = new CRM_Mailing_BAO_Mailing();
 
       if (!is_numeric($this->_mailingID)) {
+
+        //lets get the id from the hash
+        $result_id = civicrm_api3('Mailing', 'get', [
+          'return' => ['id'],
+          'hash' => $this->_mailingID,
+        ]);
         $this->_mailing->hash = $this->_mailingID;
+        $this->_mailingID     = $result_id['id'];
       }
       elseif (is_numeric($this->_mailingID)) {
         $this->_mailing->id = $this->_mailingID;
diff --git a/civicrm/CRM/Mailing/Selector/Browse.php b/civicrm/CRM/Mailing/Selector/Browse.php
index 1f4aa41c55cb6826ef8e402527df6bac861bb5db..a0ae8f5b656ecd48e891a260e3de5921e7fd0676 100644
--- a/civicrm/CRM/Mailing/Selector/Browse.php
+++ b/civicrm/CRM/Mailing/Selector/Browse.php
@@ -444,17 +444,21 @@ LEFT JOIN  civicrm_contact scheduledContact ON ( $mailing.scheduled_id = schedul
           $validLinks[CRM_Core_Action::BROWSE] = [
             'name' => ts('Public View'),
             'url' => 'civicrm/mailing/view',
-            'qs' => 'id=%%mid%%&reset=1',
+            'qs' => 'id=%%hashOrMid%%&reset=1',
             'title' => ts('Public View'),
             'fe' => TRUE,
           ];
           $actionMask |= CRM_Core_Action::BROWSE;
         }
 
+        $hash = CRM_Mailing_BAO_Mailing::getMailingHash($row['id']);
         $rows[$key]['action'] = CRM_Core_Action::formLink(
           $validLinks,
           $actionMask,
-          ['mid' => $row['id']],
+          [
+            'mid' => $row['id'],
+            'hashOrMid' => $hash ? $hash : $row['id'],
+          ],
           "more",
           FALSE,
           $opString,
diff --git a/civicrm/CRM/Member/BAO/Membership.php b/civicrm/CRM/Member/BAO/Membership.php
index 49e5181b8be41e3632a807459c1d369e201b7b2f..833b049fa29fecdd0c9087996d7e12fe3212097f 100644
--- a/civicrm/CRM/Member/BAO/Membership.php
+++ b/civicrm/CRM/Member/BAO/Membership.php
@@ -261,7 +261,7 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
    *
    * @return CRM_Member_BAO_Membership|CRM_Core_Error
    */
-  public static function create(&$params, &$ids, $skipRedirect = FALSE) {
+  public static function create(&$params, &$ids = [], $skipRedirect = FALSE) {
     // always calculate status if is_override/skipStatusCal is not true.
     // giving respect to is_override during import.  CRM-4012
 
@@ -1249,9 +1249,7 @@ SELECT c.contribution_page_id as pageID
    AND mp.membership_id = " . CRM_Utils_Type::escape($membershipID, 'Integer')
       . " ORDER BY mp.id DESC";
 
-    return CRM_Core_DAO::singleValueQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    return CRM_Core_DAO::singleValueQuery($query);
   }
 
   /**
diff --git a/civicrm/CRM/Member/BAO/MembershipStatus.php b/civicrm/CRM/Member/BAO/MembershipStatus.php
index c3508a7e17765b0a40aa52538626090cc8cfdd09..e6310ae68ee1dfde982bdc5832bbe9e45bce437c 100644
--- a/civicrm/CRM/Member/BAO/MembershipStatus.php
+++ b/civicrm/CRM/Member/BAO/MembershipStatus.php
@@ -137,9 +137,7 @@ class CRM_Member_BAO_MembershipStatus extends CRM_Member_DAO_MembershipStatus {
     // set all other defaults to false.
     if (!empty($params['is_default'])) {
       $query = "UPDATE civicrm_membership_status SET is_default = 0";
-      CRM_Core_DAO::executeQuery($query,
-        CRM_Core_DAO::$_nullArray
-      );
+      CRM_Core_DAO::executeQuery($query);
     }
 
     // action is taken depending upon the mode
diff --git a/civicrm/CRM/Member/BAO/Query.php b/civicrm/CRM/Member/BAO/Query.php
index 3294569e6c523f498dbf407b94243bb29d8a0003..9edfe64693e7f31f15b798094175bc710668d654 100644
--- a/civicrm/CRM/Member/BAO/Query.php
+++ b/civicrm/CRM/Member/BAO/Query.php
@@ -146,7 +146,7 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
         continue;
       }
       if (substr($query->_params[$id][0], 0, 7) == 'member_' || substr($query->_params[$id][0], 0, 11) == 'membership_') {
-        if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) {
+        if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) {
           $query->_useDistinct = TRUE;
         }
         self::whereClauseSingle($query->_params[$id], $query);
diff --git a/civicrm/CRM/Member/DAO/Membership.php b/civicrm/CRM/Member/DAO/Membership.php
index 696e8ad635db8e5f30ec0c5266abafc952d6113f..28dfaa8a02fc0d5323998c91509ab85b281559fc 100644
--- a/civicrm/CRM/Member/DAO/Membership.php
+++ b/civicrm/CRM/Member/DAO/Membership.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/Membership.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:458e89b098dbf4f91369a293406c38ba)
+ * (GenCodeChecksum:c68c3f9a34e0ff4431b3da64013f14ae)
  */
 
 /**
diff --git a/civicrm/CRM/Member/DAO/MembershipBlock.php b/civicrm/CRM/Member/DAO/MembershipBlock.php
index 117d8a7cc7c4fdafee70889d71c7b141eb7b49ce..ea027ff2168f99527bdfa0f6eeabf33e75cb6b58 100644
--- a/civicrm/CRM/Member/DAO/MembershipBlock.php
+++ b/civicrm/CRM/Member/DAO/MembershipBlock.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/MembershipBlock.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:0e7f3965fe1382ec1f850a9489b3f236)
+ * (GenCodeChecksum:edf144d99fad0880e2896643b00645c5)
  */
 
 /**
diff --git a/civicrm/CRM/Member/DAO/MembershipLog.php b/civicrm/CRM/Member/DAO/MembershipLog.php
index ef491cc13595f2534bc1b34ce060dc9c7479d241..ff1f7611a1a59e3afadaa25a802efb3d6de8c328 100644
--- a/civicrm/CRM/Member/DAO/MembershipLog.php
+++ b/civicrm/CRM/Member/DAO/MembershipLog.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/MembershipLog.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:82b26091e0c62f81060ae15de5a4a010)
+ * (GenCodeChecksum:0d7db89ce437b460a04fd053016c6815)
  */
 
 /**
diff --git a/civicrm/CRM/Member/DAO/MembershipPayment.php b/civicrm/CRM/Member/DAO/MembershipPayment.php
index d6369491b9d69062491e8cee1e8c3ef5907e1624..ab0075768310934a82905553b5d278a43f5b73a5 100644
--- a/civicrm/CRM/Member/DAO/MembershipPayment.php
+++ b/civicrm/CRM/Member/DAO/MembershipPayment.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/MembershipPayment.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:63aaccfeac39fe31a88f69693e8b4302)
+ * (GenCodeChecksum:8f70a311f1a6ec877d053b01431d98cc)
  */
 
 /**
diff --git a/civicrm/CRM/Member/DAO/MembershipStatus.php b/civicrm/CRM/Member/DAO/MembershipStatus.php
index d238e87ac178b339b54510cab64b92cf5e1b8619..2f4b03014435ef9ce6256bb71bbab7decde24264 100644
--- a/civicrm/CRM/Member/DAO/MembershipStatus.php
+++ b/civicrm/CRM/Member/DAO/MembershipStatus.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/MembershipStatus.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:0cb23348cde6fff261da37c8cb309da1)
+ * (GenCodeChecksum:03028177503f64a5c50d7ed10858c614)
  */
 
 /**
diff --git a/civicrm/CRM/Member/DAO/MembershipType.php b/civicrm/CRM/Member/DAO/MembershipType.php
index fb3cddba56e684927d635cb55b66e114ff629765..e5d60dc87b6af632242e2d46c17d4f5a41446448 100644
--- a/civicrm/CRM/Member/DAO/MembershipType.php
+++ b/civicrm/CRM/Member/DAO/MembershipType.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/MembershipType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:371e68c0fca2803c9b273bb25991a060)
+ * (GenCodeChecksum:fc870f663bc281a6973667061867b590)
  */
 
 /**
diff --git a/civicrm/CRM/Member/Form/Membership.php b/civicrm/CRM/Member/Form/Membership.php
index ec39152a44185b6bf86f0260299ab2fdba97cbab..cf5bf72ffce9e0d781c022f39d5d4fc489c801d6 100644
--- a/civicrm/CRM/Member/Form/Membership.php
+++ b/civicrm/CRM/Member/Form/Membership.php
@@ -418,7 +418,7 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
   public function buildQuickForm() {
 
     $this->buildQuickEntityForm();
-    $this->assign('currency', CRM_Core_Config::singleton()->defaultCurrencySymbol);
+    $this->assign('currency', CRM_Core_BAO_Country::defaultCurrencySymbol());
     $isUpdateToExistingRecurringMembership = $this->isUpdateToExistingRecurringMembership();
     // build price set form.
     $buildPriceSet = FALSE;
diff --git a/civicrm/CRM/PCP/BAO/PCP.php b/civicrm/CRM/PCP/BAO/PCP.php
index 367fa10429a323da27c4bb643746e70a860c93c7..c747805cbc59179ab7630c2e26235466e29ec9ab 100644
--- a/civicrm/CRM/PCP/BAO/PCP.php
+++ b/civicrm/CRM/PCP/BAO/PCP.php
@@ -224,14 +224,22 @@ ORDER BY target_entity_type, target_entity_id
    *   Total amount
    */
   public static function thermoMeter($pcpId) {
+    $completedStatusId = CRM_Core_PseudoConstant::getKey(
+      'CRM_Contribute_BAO_Contribution',
+      'contribution_status_id',
+      'Completed'
+    );
     $query = "
 SELECT SUM(cc.total_amount) as total
 FROM civicrm_pcp pcp
 LEFT JOIN civicrm_contribution_soft cs ON ( pcp.id = cs.pcp_id )
 LEFT JOIN civicrm_contribution cc ON ( cs.contribution_id = cc.id)
-WHERE pcp.id = %1 AND cc.contribution_status_id =1 AND cc.is_test = 0";
+WHERE pcp.id = %1 AND cc.contribution_status_id = %2 AND cc.is_test = 0";
 
-    $params = [1 => [$pcpId, 'Integer']];
+    $params = [
+      1 => [$pcpId, 'Integer'],
+      2 => [$completedStatusId, 'Integer'],
+    ];
     return CRM_Core_DAO::singleValueQuery($query, $params);
   }
 
@@ -244,16 +252,25 @@ WHERE pcp.id = %1 AND cc.contribution_status_id =1 AND cc.is_test = 0";
    * @return array
    */
   public static function honorRoll($pcpId) {
+    $completedStatusId = CRM_Core_PseudoConstant::getKey(
+      'CRM_Contribute_BAO_Contribution',
+      'contribution_status_id',
+      'Completed'
+    );
     $query = "
             SELECT cc.id, cs.pcp_roll_nickname, cs.pcp_personal_note,
                    cc.total_amount, cc.currency
             FROM civicrm_contribution cc
                  LEFT JOIN civicrm_contribution_soft cs ON cc.id = cs.contribution_id
-            WHERE cs.pcp_id = {$pcpId}
+            WHERE cs.pcp_id = %1
                   AND cs.pcp_display_in_roll = 1
-                  AND contribution_status_id = 1
+                  AND contribution_status_id = %2
                   AND is_test = 0";
-    $dao = CRM_Core_DAO::executeQuery($query);
+    $params = [
+      1 => [$pcpId, 'Integer'],
+      2 => [$completedStatusId, 'Integer'],
+    ];
+    $dao = CRM_Core_DAO::executeQuery($query, $params);
     $honor = [];
     while ($dao->fetch()) {
       $honor[$dao->id]['nickname'] = ucwords($dao->pcp_roll_nickname);
diff --git a/civicrm/CRM/PCP/DAO/PCP.php b/civicrm/CRM/PCP/DAO/PCP.php
index f6dc90a8d8d6aa87c6522f85ce7c859ad6158a6c..981687b04eb0bbfb3e1c5e1ba3262fcc4e975566 100644
--- a/civicrm/CRM/PCP/DAO/PCP.php
+++ b/civicrm/CRM/PCP/DAO/PCP.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/PCP/PCP.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:e130d04d9fad8bcec628fac504ff9da7)
+ * (GenCodeChecksum:55e3c2126bb5f4c9f93161660977a4d1)
  */
 
 /**
diff --git a/civicrm/CRM/PCP/DAO/PCPBlock.php b/civicrm/CRM/PCP/DAO/PCPBlock.php
index 14e478a5b5f5d9b201bb601e07a6b0d554b0ddfd..19b6dbc2cc4511ac54c23300a2fc042a2cb2e7c1 100644
--- a/civicrm/CRM/PCP/DAO/PCPBlock.php
+++ b/civicrm/CRM/PCP/DAO/PCPBlock.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/PCP/PCPBlock.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:deacae800c52be5e0de763f8bccf4578)
+ * (GenCodeChecksum:540832625ac42de5f986853162733eb3)
  */
 
 /**
diff --git a/civicrm/CRM/PCP/Form/Event.php b/civicrm/CRM/PCP/Form/Event.php
index da7802382bd5f39d92d255d89a08c4062d040820..f242036b3e04d32918513961cc795f07de5531ed 100644
--- a/civicrm/CRM/PCP/Form/Event.php
+++ b/civicrm/CRM/PCP/Form/Event.php
@@ -48,7 +48,7 @@ class CRM_PCP_Form_Event extends CRM_Event_Form_ManageEvent {
 
   public function preProcess() {
     parent::preProcess();
-    $this->assign('selectedChild', 'pcp');
+    $this->setSelectedChild('pcp');
   }
 
   /**
diff --git a/civicrm/CRM/Pledge/BAO/PledgePayment.php b/civicrm/CRM/Pledge/BAO/PledgePayment.php
index ec637d58b70b7d9143bcfc3d7beeb766b0c20e9c..7de77302e0a6c9fcf3d44fee30a4aa373c188cf4 100644
--- a/civicrm/CRM/Pledge/BAO/PledgePayment.php
+++ b/civicrm/CRM/Pledge/BAO/PledgePayment.php
@@ -306,7 +306,6 @@ WHERE     pledge_id = %1
       $pledgeStatusID = self::calculatePledgeStatus($pledgeID);
       CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_Pledge', $pledgeID, 'status_id', $pledgeStatusID);
 
-      $payment->free();
     }
 
     $transaction->commit();
diff --git a/civicrm/CRM/Pledge/BAO/Query.php b/civicrm/CRM/Pledge/BAO/Query.php
index 902872d1c1b33fc3d879e56b58924ea89e871bbf..1b3779060efd029774b8d3ff0df36b2f2467cc7b 100644
--- a/civicrm/CRM/Pledge/BAO/Query.php
+++ b/civicrm/CRM/Pledge/BAO/Query.php
@@ -229,7 +229,7 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
         continue;
       }
       if (substr($query->_params[$id][0], 0, 7) == 'pledge_') {
-        if ($query->_mode == CRM_Contact_BAO_QUERY::MODE_CONTACTS) {
+        if ($query->_mode == CRM_Contact_BAO_Query::MODE_CONTACTS) {
           $query->_useDistinct = TRUE;
         }
         $grouping = $query->_params[$id][3];
@@ -524,10 +524,30 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
   }
 
   /**
-   * @param CRM_Core_Form $form
+   * Get the metadata for fields to be included on the grant search form.
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  public static function getSearchFieldMetadata() {
+    $fields = [
+      'pledge_status_id',
+    ];
+    $metadata = civicrm_api3('Pledge', 'getfields', [])['values'];
+    return array_intersect_key($metadata, array_flip($fields));
+  }
+
+  /**
+   * Build the search for for pledges.
+   *
+   * @param CRM_Pledge_Form_Search|\CRM_Contact_Form_Search_Advanced $form
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public static function buildSearchForm(&$form) {
     // pledge related dates
+    $form->addSearchFieldMetadata(['Pledge' => self::getSearchFieldMetadata()]);
+    $form->addFormFieldsFromMetadata();
     CRM_Core_Form_Date::buildDateRange($form, 'pledge_start_date', 1, '_low', '_high', ts('From'), FALSE);
     CRM_Core_Form_Date::buildDateRange($form, 'pledge_end_date', 1, '_low', '_high', ts('From'), FALSE);
     CRM_Core_Form_Date::buildDateRange($form, 'pledge_create_date', 1, '_low', '_high', ts('From'), FALSE);
@@ -542,11 +562,6 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
     $form->add('text', 'pledge_amount_high', ts('To'), ['size' => 8, 'maxlength' => 8]);
     $form->addRule('pledge_amount_high', ts('Please enter a valid money value (e.g. %1).', [1 => CRM_Utils_Money::format('99.99', ' ')]), 'money');
 
-    $form->add('select', 'pledge_status_id',
-      ts('Pledge Status'), CRM_Pledge_BAO_Pledge::buildOptions('status_id'),
-      FALSE, ['class' => 'crm-select2', 'multiple' => 'multiple']
-    );
-
     $form->addYesNo('pledge_acknowledge_date_is_not_null', ts('Acknowledgement sent?'), TRUE);
 
     $form->add('text', 'pledge_installments_low', ts('From'), ['size' => 8, 'maxlength' => 8]);
diff --git a/civicrm/CRM/Pledge/DAO/Pledge.php b/civicrm/CRM/Pledge/DAO/Pledge.php
index b18050474a2b9f8af77c02f7360da517bfee8185..9a8cc6e54eeec903cb899c88857e8e9b771523dc 100644
--- a/civicrm/CRM/Pledge/DAO/Pledge.php
+++ b/civicrm/CRM/Pledge/DAO/Pledge.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Pledge/Pledge.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:877e6098c175e69f385b22f61958b70c)
+ * (GenCodeChecksum:d6e715c100f3ce5b366029ec6f45a654)
  */
 
 /**
@@ -561,6 +561,9 @@ class CRM_Pledge_DAO_Pledge extends CRM_Core_DAO {
           'entity' => 'Pledge',
           'bao' => 'CRM_Pledge_BAO_Pledge',
           'localizable' => 0,
+          'html' => [
+            'type' => 'Select',
+          ],
           'pseudoconstant' => [
             'optionGroupName' => 'pledge_status',
             'optionEditPath' => 'civicrm/admin/options/pledge_status',
diff --git a/civicrm/CRM/Pledge/DAO/PledgeBlock.php b/civicrm/CRM/Pledge/DAO/PledgeBlock.php
index 77e6525ca7e9d465664c6816661a347e55f497c6..ff335a0cb2df09c597d55854807e067cbaec6b01 100644
--- a/civicrm/CRM/Pledge/DAO/PledgeBlock.php
+++ b/civicrm/CRM/Pledge/DAO/PledgeBlock.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Pledge/PledgeBlock.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:0ba3eca2bf0f4b6ebd0f9b3617d5bef0)
+ * (GenCodeChecksum:82e5abfad86a7c111364d89d53a7148e)
  */
 
 /**
diff --git a/civicrm/CRM/Pledge/DAO/PledgePayment.php b/civicrm/CRM/Pledge/DAO/PledgePayment.php
index a43fade0541f57b32d21494e7bab0fa5bedd9451..2a46fab3315f6efd59a32457a671a767d5dead2d 100644
--- a/civicrm/CRM/Pledge/DAO/PledgePayment.php
+++ b/civicrm/CRM/Pledge/DAO/PledgePayment.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Pledge/PledgePayment.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:afb095a766df0f45f3aed1ff3b24e852)
+ * (GenCodeChecksum:42ab1e4af6c75121cdd4800019ea328d)
  */
 
 /**
diff --git a/civicrm/CRM/Pledge/Form/Search.php b/civicrm/CRM/Pledge/Form/Search.php
index c101d33a6d9a0a22c4013492d0d849908113f0da..ecf8f503e4645e2a62320be59b044a6265667ded 100644
--- a/civicrm/CRM/Pledge/Form/Search.php
+++ b/civicrm/CRM/Pledge/Form/Search.php
@@ -43,6 +43,13 @@ class CRM_Pledge_Form_Search extends CRM_Core_Form_Search {
    */
   protected $_queryParams;
 
+  /**
+   * @return string
+   */
+  public function getDefaultEntity() {
+    return 'Pledge';
+  }
+
   /**
    * Are we restricting ourselves to a single contact.
    *
diff --git a/civicrm/CRM/Price/BAO/LineItem.php b/civicrm/CRM/Price/BAO/LineItem.php
index 6119f194780c5f9855566a8c2b68c1b0eb3a61ab..08d4b2e0328a99795703de012bf24b44a2378843 100644
--- a/civicrm/CRM/Price/BAO/LineItem.php
+++ b/civicrm/CRM/Price/BAO/LineItem.php
@@ -119,7 +119,7 @@ class CRM_Price_BAO_LineItem extends CRM_Price_DAO_LineItem {
    *
    * @return CRM_Price_BAO_LineItem
    */
-  public static function retrieve(&$params, &$defaults) {
+  public static function retrieve(&$params = [], &$defaults = []) {
     $lineItem = new CRM_Price_BAO_LineItem();
     $lineItem->copyValues($params);
     if ($lineItem->find(TRUE)) {
@@ -427,7 +427,7 @@ WHERE li.contribution_id = %1";
    */
   public static function processPriceSet($entityId, $lineItem, $contributionDetails = NULL, $entityTable = 'civicrm_contribution', $update = FALSE) {
     if (!$entityId || !is_array($lineItem)
-      || CRM_Utils_system::isNull($lineItem)
+      || CRM_Utils_System::isNull($lineItem)
     ) {
       return;
     }
@@ -1212,9 +1212,7 @@ WHERE li.contribution_id = %1";
       $updatedContributionDAO->save();
       // adjusted amount financial_trxn creation
       $updatedContribution = CRM_Contribute_BAO_Contribution::getValues(
-        ['id' => $contributionId],
-        CRM_Core_DAO::$_nullArray,
-        CRM_Core_DAO::$_nullArray
+        ['id' => $contributionId]
       );
       $toFinancialAccount = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($updatedContribution->financial_type_id, 'Accounts Receivable Account is');
       $adjustedTrxnValues = [
@@ -1279,7 +1277,7 @@ WHERE li.contribution_id = %1";
         $tempFinancialTrxnID = ['id' => $adjustedTrxn->id];
       }
     }
-    $lineObj = CRM_Price_BAO_LineItem::retrieve($lineParams, CRM_Core_DAO::$_nullArray);
+    $lineObj = CRM_Price_BAO_LineItem::retrieve($lineParams);
     // insert financial items
     // ensure entity_financial_trxn table has a linking of it.
     CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, NULL, $tempFinancialTrxnID);
diff --git a/civicrm/CRM/Price/DAO/LineItem.php b/civicrm/CRM/Price/DAO/LineItem.php
index ea4e67719a266781169756c5c5b36150da726005..9813a743dbbdd8bd5a1484e0da29352feb40ef06 100644
--- a/civicrm/CRM/Price/DAO/LineItem.php
+++ b/civicrm/CRM/Price/DAO/LineItem.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Price/LineItem.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:6345c550c1c0605c0c25be1cc0382183)
+ * (GenCodeChecksum:af73e12b37d09f2872023bb12d01f5a2)
  */
 
 /**
diff --git a/civicrm/CRM/Price/DAO/PriceField.php b/civicrm/CRM/Price/DAO/PriceField.php
index e823c87c396037313bc73c4079e65ac6c66514ec..9df77e7cb4217d74773c7f4651fcb519d8d08568 100644
--- a/civicrm/CRM/Price/DAO/PriceField.php
+++ b/civicrm/CRM/Price/DAO/PriceField.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Price/PriceField.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ccea318a7e83c8fd6d03734e20798b15)
+ * (GenCodeChecksum:4708670ea69ac42ea2c5a57d2c98b658)
  */
 
 /**
diff --git a/civicrm/CRM/Price/DAO/PriceFieldValue.php b/civicrm/CRM/Price/DAO/PriceFieldValue.php
index 0543497f1f10118d41f38d25721f80d7701e4715..795230bb4a2d079d6857f04967519f6942750417 100644
--- a/civicrm/CRM/Price/DAO/PriceFieldValue.php
+++ b/civicrm/CRM/Price/DAO/PriceFieldValue.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Price/PriceFieldValue.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:6c2bd575335eeb9915683296952b2c3e)
+ * (GenCodeChecksum:2c8649ea76f5f5b5548c1aae5c29e26e)
  */
 
 /**
diff --git a/civicrm/CRM/Price/DAO/PriceSet.php b/civicrm/CRM/Price/DAO/PriceSet.php
index 1593408b04eefb043bd019c9a16ba756b82b237c..1384fad77cb0cf0028dc9d0327e1c814aee2d681 100644
--- a/civicrm/CRM/Price/DAO/PriceSet.php
+++ b/civicrm/CRM/Price/DAO/PriceSet.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Price/PriceSet.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5dcf30888df8309f20fa347780f16f4d)
+ * (GenCodeChecksum:8349105b7c9354cccdf8dac30d9ffd8a)
  */
 
 /**
diff --git a/civicrm/CRM/Price/DAO/PriceSetEntity.php b/civicrm/CRM/Price/DAO/PriceSetEntity.php
index 0e6750dc84a784562b69346163d8bdaf2d7f186a..1824e53eb48d1e5e26af082a015eadf734246733 100644
--- a/civicrm/CRM/Price/DAO/PriceSetEntity.php
+++ b/civicrm/CRM/Price/DAO/PriceSetEntity.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Price/PriceSetEntity.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:8bd26effd43fe4ee752addf11e6a4769)
+ * (GenCodeChecksum:a986b1e45928f1ed8034c498506955a0)
  */
 
 /**
diff --git a/civicrm/CRM/Price/Form/Option.php b/civicrm/CRM/Price/Form/Option.php
index f159c37bdc945828b6faf123aac949db8cf51db9..1ad15e8ddcfd4afdef248182fcbf053435c9b3d7 100644
--- a/civicrm/CRM/Price/Form/Option.php
+++ b/civicrm/CRM/Price/Form/Option.php
@@ -314,10 +314,10 @@ class CRM_Price_Form_Option extends CRM_Core_Form {
         $publicCount++;
       }
     }
-    if ($visibilityOptions[$priceField->visibility_id] == 'public' && $publicCount == 0) {
+    if ($visibilityOptions[$priceField->visibility_id] == 'public' && $publicCount == 0 && $visibilityOptions[$fields['visibility_id']] == 'admin') {
       $errors['visibility_id'] = ts('All other options for this \'Public\' field have \'Admin\' visibility. There should at least be one \'Public\' option, or make the field \'Admin\' only.');
     }
-    elseif ($visibilityOptions[$priceField->visibility_id] == 'admin' && $publicCount > 0) {
+    elseif ($visibilityOptions[$priceField->visibility_id] == 'admin' && $visibilityOptions[$fields['visibility_id']] == 'public') {
       $errors['visibility_id'] = ts('You must choose \'Admin\' visibility for this price option, as it belongs to a field with \'Admin\' visibility.');
     }
 
diff --git a/civicrm/CRM/Profile/Form.php b/civicrm/CRM/Profile/Form.php
index 4c110de5d40298124b7e6d14df29932ccf298f4f..9052831d2b5b41fe4b6aaad0a30fa622f1aea15f 100644
--- a/civicrm/CRM/Profile/Form.php
+++ b/civicrm/CRM/Profile/Form.php
@@ -372,7 +372,6 @@ class CRM_Profile_Form extends CRM_Core_Form {
         $this->_isAddCaptcha = $dao->add_captcha;
         $this->_ufGroup = (array) $dao;
       }
-      $dao->free();
 
       if (!CRM_Utils_Array::value('is_active', $this->_ufGroup)) {
         CRM_Core_Error::fatal(ts('The requested profile (gid=%1) is inactive or does not exist.', [
@@ -892,10 +891,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
 
     //finally add captcha to form.
     if ($this->_isAddCaptcha) {
-      $captcha = CRM_Utils_ReCAPTCHA::singleton();
-      $captcha->add($this);
+      CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
     }
-    $this->assign("isCaptcha", $this->_isAddCaptcha);
 
     if ($this->_mode != self::MODE_SEARCH) {
       if (isset($addToGroupId)) {
diff --git a/civicrm/CRM/Queue/DAO/QueueItem.php b/civicrm/CRM/Queue/DAO/QueueItem.php
index f866a92be52d8834a46ae9eef4769772f5e4dec8..08e281d69d5797be3f2150f5c147822f8cc1d9f4 100644
--- a/civicrm/CRM/Queue/DAO/QueueItem.php
+++ b/civicrm/CRM/Queue/DAO/QueueItem.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Queue/QueueItem.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:375c90f10f805de0cc712cad771cf15e)
+ * (GenCodeChecksum:84cb9a5dd61744311fda1a002b85a6d1)
  */
 
 /**
diff --git a/civicrm/CRM/Queue/Queue/Sql.php b/civicrm/CRM/Queue/Queue/Sql.php
index 6be0e23aa275beb6b15807b31ea1ea23b5ed7fc9..a77ba055feecce5f9065041aa514cbaa515bbffe 100644
--- a/civicrm/CRM/Queue/Queue/Sql.php
+++ b/civicrm/CRM/Queue/Queue/Sql.php
@@ -199,7 +199,6 @@ class CRM_Queue_Queue_Sql extends CRM_Queue_Queue {
    */
   public function deleteItem($dao) {
     $dao->delete();
-    $dao->free();
   }
 
   /**
@@ -214,7 +213,6 @@ class CRM_Queue_Queue_Sql extends CRM_Queue_Queue {
       1 => [$dao->id, 'Integer'],
     ];
     CRM_Core_DAO::executeQuery($sql, $params);
-    $dao->free();
   }
 
 }
diff --git a/civicrm/CRM/Report/BAO/ReportInstance.php b/civicrm/CRM/Report/BAO/ReportInstance.php
index da56063bc76d1c0532c5030329db7eeffef29484..1fd77605c8bd29ecf7b67d737777b2da7812dbf5 100644
--- a/civicrm/CRM/Report/BAO/ReportInstance.php
+++ b/civicrm/CRM/Report/BAO/ReportInstance.php
@@ -267,7 +267,6 @@ class CRM_Report_BAO_ReportInstance extends CRM_Report_DAO_ReportInstance {
 
     if ($instance->find(TRUE)) {
       CRM_Core_DAO::storeValues($instance, $defaults);
-      $instance->free();
       return $instance;
     }
     return NULL;
diff --git a/civicrm/CRM/Report/DAO/ReportInstance.php b/civicrm/CRM/Report/DAO/ReportInstance.php
index 45199eff782516dacaa414c8c1ccaa164e4cc4de..8c79fd67b9d47ac6776534d5f29f806c692b7259 100644
--- a/civicrm/CRM/Report/DAO/ReportInstance.php
+++ b/civicrm/CRM/Report/DAO/ReportInstance.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Report/ReportInstance.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:22eeac140cc540874af36a422c548078)
+ * (GenCodeChecksum:459056d6f22bc2f222f719dadc27f21e)
  */
 
 /**
diff --git a/civicrm/CRM/Report/Form.php b/civicrm/CRM/Report/Form.php
index 7c370c5cad47f0c31a7a7cbf8bf73382752e896b..eff1db9aef57c97e820d64ec51e279350a369a28 100644
--- a/civicrm/CRM/Report/Form.php
+++ b/civicrm/CRM/Report/Form.php
@@ -155,9 +155,6 @@ class CRM_Report_Form extends CRM_Core_Form {
    */
   protected $_groupFilter = FALSE;
 
-  // [ML] Required for civiexportexcel
-  public $supportsExportExcel = TRUE;
-
   /**
    * Has the report been optimised for group filtering.
    *
@@ -2845,11 +2842,6 @@ WHERE cg.extends IN ('" . implode("','", $this->_customGroupExtends) . "') AND
       $this->_absoluteUrl = TRUE;
       $this->addPaging = FALSE;
     }
-    elseif ($this->_outputMode == 'excel2007') {
-      $printOnly = TRUE;
-      $this->_absoluteUrl = TRUE;
-      $this->addPaging = FALSE;
-    }
     elseif ($this->_outputMode == 'group') {
       $this->assign('outputMode', 'group');
     }
@@ -3502,9 +3494,6 @@ WHERE cg.extends IN ('" . implode("','", $this->_customGroupExtends) . "') AND
     elseif ($this->_outputMode == 'csv') {
       CRM_Report_Utils_Report::export2csv($this, $rows);
     }
-    elseif ($this->_outputMode == 'excel2007') {
-      CRM_CiviExportExcel_Utils_Report::export2excel2007($this, $rows);
-    }
     elseif ($this->_outputMode == 'group') {
       $group = $this->_params['groups'];
       $this->add2group($group);
@@ -4329,7 +4318,8 @@ LEFT JOIN civicrm_contact {$field['alias']} ON {$field['alias']}.id = {$this->_a
         }
         if (array_key_exists('filters', $table)) {
           foreach ($table['filters'] as $filterName => $filter) {
-            if (!empty($this->_params["{$filterName}_value"])
+            if ((isset($this->_params["{$filterName}_value"])
+                && !CRM_Utils_System::isNull($this->_params["{$filterName}_value"]))
               || !empty($this->_params["{$filterName}_relative"])
               || CRM_Utils_Array::value("{$filterName}_op", $this->_params) ==
               'nll'
diff --git a/civicrm/CRM/Report/Form/Case/Summary.php b/civicrm/CRM/Report/Form/Case/Summary.php
index 1db23629ce08d7622e51cdf22a5ba0e96f4cca48..286fe3b2332b86cbf4f10a1c44293a86da69abcb 100644
--- a/civicrm/CRM/Report/Form/Case/Summary.php
+++ b/civicrm/CRM/Report/Form/Case/Summary.php
@@ -229,6 +229,9 @@ class CRM_Report_Form_Case_Summary extends CRM_Report_Form {
             if ($fieldName == 'duration') {
               $select[] = "IF({$table['fields']['end_date']['dbAlias']} Is Null, '', DATEDIFF({$table['fields']['end_date']['dbAlias']}, {$table['fields']['start_date']['dbAlias']})) as {$tableName}_{$fieldName}";
             }
+            elseif ($tableName == 'civicrm_relationship_type') {
+              $select[] = "  IF(contact_civireport.id = relationship_civireport.contact_id_a, relationship_type_civireport.label_b_a, relationship_type_civireport.label_a_b) as civicrm_relationship_type_label_b_a";
+            }
             else {
               $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
             }
@@ -290,7 +293,7 @@ class CRM_Report_Form_Case_Summary extends CRM_Report_Form {
     if ($this->_relField) {
       $this->_from = "
             FROM civicrm_contact $c
-inner join civicrm_relationship $cr on {$c}.id = ${cr}.contact_id_b
+inner join civicrm_relationship $cr on {$c}.id = ${cr}.contact_id_b OR {$c}.id = ${cr}.contact_id_a
 inner join civicrm_case $cc on ${cc}.id = ${cr}.case_id
 inner join civicrm_relationship_type $crt on ${crt}.id=${cr}.relationship_type_id
 inner join civicrm_case_contact $ccc on ${ccc}.case_id = ${cc}.id
@@ -308,6 +311,9 @@ inner join civicrm_contact $c2 on ${c2}.id=${ccc}.contact_id
 
   public function where() {
     $clauses = [];
+    if (!empty($this->_params['fields']['label_b_a']) && $this->_params['fields']['label_b_a'] == 1) {
+      $clauses[] = 'contact_civireport.sort_name !=  c2_civireport.sort_name';
+    }
     $this->_having = '';
     foreach ($this->_columns as $tableName => $table) {
       if (array_key_exists('filters', $table)) {
diff --git a/civicrm/CRM/Report/Form/Contribute/DeferredRevenue.php b/civicrm/CRM/Report/Form/Contribute/DeferredRevenue.php
index 321c5378e3bce0e5effb19a7aa9d72a2ad84ff31..75718bb1373b7914710f917da910d35ba241e0c5 100644
--- a/civicrm/CRM/Report/Form/Contribute/DeferredRevenue.php
+++ b/civicrm/CRM/Report/Form/Contribute/DeferredRevenue.php
@@ -95,6 +95,7 @@ class CRM_Report_Form_Contribute_DeferredRevenue extends CRM_Report_Form {
             'type' => CRM_Utils_Type::T_DATE,
           ],
           'cancel_date' => [
+            'name' => 'contribution_cancel_date',
             'title' => ts('Cancel Date'),
             'type' => CRM_Utils_Type::T_DATE,
           ],
@@ -113,6 +114,7 @@ class CRM_Report_Form_Contribute_DeferredRevenue extends CRM_Report_Form {
             'title' => ts('Cancel Date'),
             'operatorType' => CRM_Report_Form::OP_DATE,
             'type' => CRM_Utils_Type::T_DATE,
+            'name' => 'contribution_cancel_date',
           ],
           'revenue_recognition_date' => [
             'title' => ts('Revenue Recognition Date'),
diff --git a/civicrm/CRM/Report/Form/Contribute/Detail.php b/civicrm/CRM/Report/Form/Contribute/Detail.php
index 82060fafdd8b98eb755d7358cde2ef0e9d960ce1..a4c6e0d31f4bbe02ef8165248fb38384fb346e49 100644
--- a/civicrm/CRM/Report/Form/Contribute/Detail.php
+++ b/civicrm/CRM/Report/Form/Contribute/Detail.php
@@ -180,6 +180,7 @@ class CRM_Report_Form_Contribute_Detail extends CRM_Report_Form {
           ],
           'cancel_date' => [
             'title' => ts('Cancelled / Refunded Date'),
+            'name' => 'contribution_cancel_date',
           ],
           'cancel_reason' => [
             'title' => ts('Cancellation / Refund Reason'),
@@ -243,6 +244,7 @@ class CRM_Report_Form_Contribute_Detail extends CRM_Report_Form {
           'cancel_date' => [
             'title' => ts('Cancelled / Refunded Date'),
             'operatorType' => CRM_Report_Form::OP_DATE,
+            'name' => 'contribution_cancel_date',
           ],
           'cancel_reason' => [
             'title' => ts('Cancellation / Refund Reason'),
diff --git a/civicrm/CRM/Report/Form/Member/ContributionDetail.php b/civicrm/CRM/Report/Form/Member/ContributionDetail.php
index beabdbc122f6b83a2328315707d368ffb1a1d638..3b92f9b633f4a128091d4a16ad80da7c82d917cd 100644
--- a/civicrm/CRM/Report/Form/Member/ContributionDetail.php
+++ b/civicrm/CRM/Report/Form/Member/ContributionDetail.php
@@ -315,7 +315,7 @@ class CRM_Report_Form_Member_ContributionDetail extends CRM_Report_Form {
           'membership_start_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'membership_end_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'owner_membership_id' => [
-            'title' => ts('Membership Owner ID'),
+            'title' => ts('Primary Membership'),
             'operatorType' => CRM_Report_Form::OP_INT,
           ],
           'tid' => [
@@ -612,6 +612,25 @@ class CRM_Report_Form_Member_ContributionDetail extends CRM_Report_Form {
     return $statistics;
   }
 
+  public function getOperationPair($type = "string", $fieldName = NULL) {
+    //re-name IS NULL/IS NOT NULL for clarity
+    if ($fieldName == 'owner_membership_id') {
+      $result = [];
+      $result['nll'] = ts('Primary members only');
+      $result['nnll'] = ts('Non-primary members only');
+      $options = parent::getOperationPair($type, $fieldName);
+      foreach ($options as $key => $label) {
+        if (!array_key_exists($key, $result)) {
+          $result[$key] = $label;
+        }
+      }
+    }
+    else {
+      $result = parent::getOperationPair($type, $fieldName);
+    }
+    return $result;
+  }
+
   public function postProcess() {
     // get the acl clauses built before we assemble the query
     $this->buildACLClause($this->_aliases['civicrm_contact']);
diff --git a/civicrm/CRM/Report/Form/Member/Detail.php b/civicrm/CRM/Report/Form/Member/Detail.php
index 4d816ee3db969eb74f2371510df65e4701129623..cdb100c8f28703ac391929e4ef6bf77e2dcf80a7 100644
--- a/civicrm/CRM/Report/Form/Member/Detail.php
+++ b/civicrm/CRM/Report/Form/Member/Detail.php
@@ -119,7 +119,7 @@ class CRM_Report_Form_Member_Detail extends CRM_Report_Form {
           'membership_start_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'membership_end_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'owner_membership_id' => [
-            'title' => ts('Membership Owner ID'),
+            'title' => ts('Primary Membership'),
             'operatorType' => CRM_Report_Form::OP_INT,
           ],
           'tid' => [
@@ -284,6 +284,25 @@ class CRM_Report_Form_Member_Detail extends CRM_Report_Form {
     }
   }
 
+  public function getOperationPair($type = "string", $fieldName = NULL) {
+    //re-name IS NULL/IS NOT NULL for clarity
+    if ($fieldName == 'owner_membership_id') {
+      $result = [];
+      $result['nll'] = ts('Primary members only');
+      $result['nnll'] = ts('Non-primary members only');
+      $options = parent::getOperationPair($type, $fieldName);
+      foreach ($options as $key => $label) {
+        if (!array_key_exists($key, $result)) {
+          $result[$key] = $label;
+        }
+      }
+    }
+    else {
+      $result = parent::getOperationPair($type, $fieldName);
+    }
+    return $result;
+  }
+
   /**
    * Alter display of rows.
    *
diff --git a/civicrm/CRM/Report/Form/Member/Summary.php b/civicrm/CRM/Report/Form/Member/Summary.php
index 9ad2a41fb3cdf61266149e6e146db8f1a0a264cc..e4fb27ac9b995c02c2dc8d5a6c14486053cd6b33 100644
--- a/civicrm/CRM/Report/Form/Member/Summary.php
+++ b/civicrm/CRM/Report/Form/Member/Summary.php
@@ -91,7 +91,7 @@ class CRM_Report_Form_Member_Summary extends CRM_Report_Form {
             'operatorType' => CRM_Report_Form::OP_DATE,
           ],
           'owner_membership_id' => [
-            'title' => ts('Membership Owner ID'),
+            'title' => ts('Primary Membership'),
             'type' => CRM_Utils_Type::T_INT,
             'operatorType' => CRM_Report_Form::OP_INT,
           ],
@@ -436,6 +436,25 @@ GROUP BY    {$this->_aliases['civicrm_contribution']}.currency
     parent::postProcess();
   }
 
+  public function getOperationPair($type = "string", $fieldName = NULL) {
+    //re-name IS NULL/IS NOT NULL for clarity
+    if ($fieldName == 'owner_membership_id') {
+      $result = [];
+      $result['nll'] = ts('Primary members only');
+      $result['nnll'] = ts('Non-primary members only');
+      $options = parent::getOperationPair($type, $fieldName);
+      foreach ($options as $key => $label) {
+        if (!array_key_exists($key, $result)) {
+          $result[$key] = $label;
+        }
+      }
+    }
+    else {
+      $result = parent::getOperationPair($type, $fieldName);
+    }
+    return $result;
+  }
+
   /**
    * @param $rows
    */
diff --git a/civicrm/CRM/SMS/DAO/Provider.php b/civicrm/CRM/SMS/DAO/Provider.php
index 81a2b07603b8e2582f5e59ade15d5b9f92cf9f4b..3e9d2b1123f136f8addc6d3d0893f7440c733229 100644
--- a/civicrm/CRM/SMS/DAO/Provider.php
+++ b/civicrm/CRM/SMS/DAO/Provider.php
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/SMS/Provider.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:73f7f33374bc59a6251529cd2ba704cf)
+ * (GenCodeChecksum:84ab732be9b0567de8927ab96bb656ba)
  */
 
 /**
diff --git a/civicrm/CRM/SMS/Form/Schedule.php b/civicrm/CRM/SMS/Form/Schedule.php
index 4a1fdefb4fe56b7b30b1d575ccbb333cbdc3de1a..1f6e8f14516ff05a9c86741bb605eda1a393f672 100644
--- a/civicrm/CRM/SMS/Form/Schedule.php
+++ b/civicrm/CRM/SMS/Form/Schedule.php
@@ -32,6 +32,8 @@
  */
 class CRM_SMS_Form_Schedule extends CRM_Core_Form {
 
+  public $submitOnce = TRUE;
+
   /**
    * Set variables up before form is built.
    */
@@ -86,7 +88,6 @@ class CRM_SMS_Form_Schedule extends CRM_Core_Form {
         'name' => ts('Submit Mass SMS'),
         'spacing' => '&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;',
         'isDefault' => TRUE,
-        'js' => ['onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');"],
       ],
       [
         'type' => 'cancel',
diff --git a/civicrm/CRM/Upgrade/Form.php b/civicrm/CRM/Upgrade/Form.php
index 47f71da3eacf855824472ac6665ef962483fa857..008d42210a4fb5c4dad952e6694b9d1d03124644 100644
--- a/civicrm/CRM/Upgrade/Form.php
+++ b/civicrm/CRM/Upgrade/Form.php
@@ -272,9 +272,7 @@ class CRM_Upgrade_Form extends CRM_Core_Form {
    * @return Object
    */
   public function runQuery($query) {
-    return CRM_Core_DAO::executeQuery($query,
-      CRM_Core_DAO::$_nullArray
-    );
+    return CRM_Core_DAO::executeQuery($query);
   }
 
   /**
diff --git a/civicrm/CRM/Upgrade/Incremental/SmartGroups.php b/civicrm/CRM/Upgrade/Incremental/SmartGroups.php
index a92aa9e649c117f43c01c798f2828ab37b585e7a..feb9c6438a103a369505f9eeb991f9ab0e498108 100644
--- a/civicrm/CRM/Upgrade/Incremental/SmartGroups.php
+++ b/civicrm/CRM/Upgrade/Incremental/SmartGroups.php
@@ -39,7 +39,14 @@ class CRM_Upgrade_Incremental_SmartGroups {
    */
   public function updateGroups($actions) {
     foreach ($actions as $func => $fields) {
-      $this->{$func}($fields);
+      if ($func == 'renameField') {
+        foreach ($fields as $fieldConversion) {
+          $this->{$func}($fieldConversion['old'], $fieldConversion['new']);
+        }
+      }
+      else {
+        $this->{$func}($fields);
+      }
     }
   }
 
@@ -57,6 +64,8 @@ class CRM_Upgrade_Incremental_SmartGroups {
     $relativeDateMappings = [
       'activity_date_time' => 'activity',
       'participant_register_date' => 'participant',
+      'receive_date' => 'contribution',
+      'contribution_cancel_date' => 'contribution_cancel',
     ];
 
     foreach ($fields as $field) {
diff --git a/civicrm/CRM/Upgrade/Incremental/php/FiveSixteen.php b/civicrm/CRM/Upgrade/Incremental/php/FiveSixteen.php
new file mode 100644
index 0000000000000000000000000000000000000000..554d884b62200d7bc1859e4d7aa957f042c44754
--- /dev/null
+++ b/civicrm/CRM/Upgrade/Incremental/php/FiveSixteen.php
@@ -0,0 +1,110 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5                                                  |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2019                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007.                                       |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License along with this program; if not, contact CiviCRM LLC       |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Upgrade logic for FiveSixteen */
+class CRM_Upgrade_Incremental_php_FiveSixteen extends CRM_Upgrade_Incremental_Base {
+
+  /**
+   * Compute any messages which should be displayed beforeupgrade.
+   *
+   * Note: This function is called iteratively for each upcoming
+   * revision to the database.
+   *
+   * @param string $preUpgradeMessage
+   * @param string $rev
+   *   a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
+   * @param null $currentVer
+   */
+  public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
+    // Example: Generate a pre-upgrade message.
+    // if ($rev == '5.12.34') {
+    //   $preUpgradeMessage .= '<p>' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '</p>';
+    // }
+  }
+
+  /**
+   * Compute any messages which should be displayed after upgrade.
+   *
+   * @param string $postUpgradeMessage
+   *   alterable.
+   * @param string $rev
+   *   an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
+   */
+  public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
+    // Example: Generate a post-upgrade message.
+    // if ($rev == '5.12.34') {
+    //   $postUpgradeMessage .= '<br /><br />' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
+    // }
+  }
+
+  /*
+   * Important! All upgrade functions MUST add a 'runSql' task.
+   * Uncomment and use the following template for a new upgrade version
+   * (change the x in the function name):
+   */
+
+  //  /**
+  //   * Upgrade function.
+  //   *
+  //   * @param string $rev
+  //   */
+  //  public function upgrade_5_0_x($rev) {
+  //    $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+  //    $this->addTask('Do the foo change', 'taskFoo', ...);
+  //    // Additional tasks here...
+  //    // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
+  //    // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
+  //  }
+
+  /**
+   * Upgrade function.
+   *
+   * @param string $rev
+   */
+  public function upgrade_5_16_alpha1($rev) {
+    $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+    $this->addTask('Update smart groups to rename filters on contribution_date to receive_date', 'updateSmartGroups', [
+      'renameField' => [
+        ['old' => 'contribution_date', 'new' => 'receive_date'],
+        ['old' => 'contribution_date_low', 'new' => 'receive_date_low'],
+        ['old' => 'contribution_date_high', 'new' => 'receive_date_high'],
+        ['old' => 'contribution_date_relative', 'new' => 'receive_date_relative'],
+      ],
+    ]);
+    $this->addTask('Update smart groups where jcalendar fields have been converted to datepicker', 'updateSmartGroups', [
+      'datepickerConversion' => [
+        'receive_date',
+        'contribution_cancel_date',
+      ],
+    ]);
+  }
+
+  // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
+  //   return TRUE;
+  // }
+
+}
diff --git a/civicrm/CRM/Upgrade/Incremental/php/FourFive.php b/civicrm/CRM/Upgrade/Incremental/php/FourFive.php
index f5b9aada4155a31a7044824339a520787b134b01..cd9f0368a267ea09420c5619b00a873240c4d400 100644
--- a/civicrm/CRM/Upgrade/Incremental/php/FourFive.php
+++ b/civicrm/CRM/Upgrade/Incremental/php/FourFive.php
@@ -84,7 +84,7 @@ AND TABLE_SCHEMA = %1
         $sqlDropFK = "ALTER TABLE `civicrm_msg_template`
 DROP FOREIGN KEY `{$dao->CONSTRAINT_NAME}`,
 DROP KEY `{$dao->CONSTRAINT_NAME}`";
-        CRM_Core_DAO::executeQuery($sqlDropFK, CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
+        CRM_Core_DAO::executeQuery($sqlDropFK, [], TRUE, NULL, FALSE, FALSE);
       }
     }
 
diff --git a/civicrm/CRM/Upgrade/Incremental/php/FourThree.php b/civicrm/CRM/Upgrade/Incremental/php/FourThree.php
index a444e4962bafc8d5a9973a989b2c5e2068828621..a86316e1db80b9d9252632827f4076c6301445b9 100644
--- a/civicrm/CRM/Upgrade/Incremental/php/FourThree.php
+++ b/civicrm/CRM/Upgrade/Incremental/php/FourThree.php
@@ -834,7 +834,7 @@ FROM   civicrm_financial_item fi";
     $query = "
 ALTER TABLE civicrm_domain ADD contact_id INT( 10 ) UNSIGNED NULL DEFAULT NULL COMMENT 'FK to Contact ID. This is specifically not an FK to avoid circular constraints',
  ADD CONSTRAINT FK_civicrm_domain_contact_id FOREIGN KEY (contact_id) REFERENCES civicrm_contact(id);";
-    CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
+    CRM_Core_DAO::executeQuery($query, [], TRUE, NULL, FALSE, FALSE);
 
     $query = '
 SELECT cd.id, cd.name, ce.email FROM civicrm_domain cd
diff --git a/civicrm/CRM/Upgrade/Incremental/sql/5.15.1.mysql.tpl b/civicrm/CRM/Upgrade/Incremental/sql/5.15.1.mysql.tpl
deleted file mode 100644
index 68abb9418aa35f4b7d972a8e19b29e4e5d65d9af..0000000000000000000000000000000000000000
--- a/civicrm/CRM/Upgrade/Incremental/sql/5.15.1.mysql.tpl
+++ /dev/null
@@ -1 +0,0 @@
-{* file to handle db changes in 5.15.1 during upgrade *}
diff --git a/civicrm/CRM/Upgrade/Incremental/sql/5.15.2.mysql.tpl b/civicrm/CRM/Upgrade/Incremental/sql/5.15.2.mysql.tpl
deleted file mode 100644
index 8b49e8402d385a3f74e0860f821ab8e45bb7ad2e..0000000000000000000000000000000000000000
--- a/civicrm/CRM/Upgrade/Incremental/sql/5.15.2.mysql.tpl
+++ /dev/null
@@ -1 +0,0 @@
-{* file to handle db changes in 5.15.2 during upgrade *}
diff --git a/civicrm/CRM/Upgrade/Incremental/sql/5.16.0.mysql.tpl b/civicrm/CRM/Upgrade/Incremental/sql/5.16.0.mysql.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..c553cb35454d0bead554b44692995c789c4bf141
--- /dev/null
+++ b/civicrm/CRM/Upgrade/Incremental/sql/5.16.0.mysql.tpl
@@ -0,0 +1 @@
+{* file to handle db changes in 5.16.0 during upgrade *}
diff --git a/civicrm/CRM/Upgrade/Incremental/sql/5.16.alpha1.mysql.tpl b/civicrm/CRM/Upgrade/Incremental/sql/5.16.alpha1.mysql.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..be013c10a8beb7bd5887c5f9cd2813e153e63969
--- /dev/null
+++ b/civicrm/CRM/Upgrade/Incremental/sql/5.16.alpha1.mysql.tpl
@@ -0,0 +1,5 @@
+{* file to handle db changes in 5.16.alpha1 during upgrade *}
+
+-- dev/core#561 Update fields to take into account receive_date and cancel_date have unique names now
+UPDATE civicrm_uf_field SET field_name = 'contribution_cancel_date' WHERE field_name = 'cancel_date';
+UPDATE civicrm_mapping_field SET name = 'contribution_cancel_date' WHERE name = 'cancel_date';
diff --git a/civicrm/CRM/Upgrade/Incremental/sql/5.16.beta1.mysql.tpl b/civicrm/CRM/Upgrade/Incremental/sql/5.16.beta1.mysql.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..22be6dcfb8bb04047b4196342da7217dded27d23
--- /dev/null
+++ b/civicrm/CRM/Upgrade/Incremental/sql/5.16.beta1.mysql.tpl
@@ -0,0 +1 @@
+{* file to handle db changes in 5.16.beta1 during upgrade *}
diff --git a/civicrm/CRM/Utils/Address/BatchUpdate.php b/civicrm/CRM/Utils/Address/BatchUpdate.php
index 9b16c0d2f4c2b985a6fcf1ef6a76812b9e96141d..4e3a47331fa810a1b8fbd824002a7ec5e29e2a9e 100644
--- a/civicrm/CRM/Utils/Address/BatchUpdate.php
+++ b/civicrm/CRM/Utils/Address/BatchUpdate.php
@@ -254,7 +254,6 @@ class CRM_Utils_Address_BatchUpdate {
         $address->id = $dao->address_id;
         $address->copyValues($addressParams);
         $address->save();
-        $address->free();
       }
     }
 
diff --git a/civicrm/CRM/Utils/Cache.php b/civicrm/CRM/Utils/Cache.php
index 23975cae4d2adb302dbc3e40e9c024f967bf1fe7..26bdc6c3b7dd76e68fea0cf846868309ea66f36a 100644
--- a/civicrm/CRM/Utils/Cache.php
+++ b/civicrm/CRM/Utils/Cache.php
@@ -171,7 +171,7 @@ class CRM_Utils_Cache {
    *     Support varies by driver:
    *       - For most memory backed caches, this option is meaningful.
    *       - For SqlGroup, this option is ignored. SqlGroup has equivalent behavior built-in.
-   *       - For Arraycache, this option is ignored. It's redundant.
+   *       - For ArrayCache, this option is ignored. It's redundant.
    *      If this is a short-lived process in which TTL's don't matter, you might
    *      use 'fast' mode. It sacrifices some PSR-16 compliance and cache-coherency
    *      protections to improve performance.
diff --git a/civicrm/CRM/Utils/Cache/ArrayCache.php b/civicrm/CRM/Utils/Cache/ArrayCache.php
index 92badc0cda9b3edae774ecf2edef9ce17f0fa2c0..c83f3f1f4eb63448bfaef67f2226ffd78e14f2e7 100644
--- a/civicrm/CRM/Utils/Cache/ArrayCache.php
+++ b/civicrm/CRM/Utils/Cache/ArrayCache.php
@@ -32,9 +32,9 @@
  */
 
 /**
- * Class CRM_Utils_Cache_Arraycache
+ * Class CRM_Utils_Cache_ArrayCache
  */
-class CRM_Utils_Cache_Arraycache implements CRM_Utils_Cache_Interface {
+class CRM_Utils_Cache_ArrayCache implements CRM_Utils_Cache_Interface {
 
   use CRM_Utils_Cache_NaiveMultipleTrait;
   // TODO Native implementation
@@ -56,7 +56,7 @@ class CRM_Utils_Cache_Arraycache implements CRM_Utils_Cache_Interface {
    * @param array $config
    *   An array of configuration params.
    *
-   * @return \CRM_Utils_Cache_Arraycache
+   * @return \CRM_Utils_Cache_ArrayCache
    */
   public function __construct($config) {
     $this->_cache = [];
diff --git a/civicrm/CRM/Utils/Cache/SerializeCache.php b/civicrm/CRM/Utils/Cache/SerializeCache.php
deleted file mode 100644
index f17b4591076e7a4f96935986a7654b0d03a943d3..0000000000000000000000000000000000000000
--- a/civicrm/CRM/Utils/Cache/SerializeCache.php
+++ /dev/null
@@ -1,151 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2019
- */
-
-/**
- * Class CRM_Utils_Cache_SerializeCache
- */
-class CRM_Utils_Cache_SerializeCache implements CRM_Utils_Cache_Interface {
-
-  use CRM_Utils_Cache_NaiveMultipleTrait;
-  // TODO Native implementation
-  use CRM_Utils_Cache_NaiveHasTrait;
-
-  /**
-   * The cache storage container, an array by default, stored in a file under templates
-   * @var array
-   */
-  private $_cache;
-
-  /**
-   * Constructor.
-   *
-   * @param array $config
-   *   An array of configuration params.
-   *
-   * @return \CRM_Utils_Cache_SerializeCache
-   */
-  public function __construct($config) {
-    $this->_cache = [];
-  }
-
-  /**
-   * @param $key
-   *
-   * @return string
-   */
-  public function fileName($key) {
-    if (strlen($key) > 50) {
-      return CIVICRM_TEMPLATE_COMPILEDIR . "CRM_" . md5($key) . ".php";
-    }
-    return CIVICRM_TEMPLATE_COMPILEDIR . $key . ".php";
-  }
-
-  /**
-   * @param string $key
-   * @param mixed $default
-   *
-   * @return mixed
-   */
-  public function get($key, $default = NULL) {
-    if ($default !== NULL) {
-      throw new \RuntimeException("FIXME: " . __CLASS__ . "::get() only supports NULL default");
-    }
-
-    if (array_key_exists($key, $this->_cache)) {
-      return $this->_cache[$key];
-    }
-
-    if (!file_exists($this->fileName($key))) {
-      return;
-    }
-    $this->_cache[$key] = unserialize(substr(file_get_contents($this->fileName($key)), 8));
-    return $this->_cache[$key];
-  }
-
-  /**
-   * @param string $key
-   * @param mixed $value
-   * @param null|int|\DateInterval $ttl
-   * @return bool
-   */
-  public function set($key, $value, $ttl = NULL) {
-    if ($ttl !== NULL) {
-      throw new \RuntimeException("FIXME: " . __CLASS__ . "::set() should support non-NULL TTL");
-    }
-    if (file_exists($this->fileName($key))) {
-      // WTF, write-once cache?!
-      return FALSE;
-    }
-    $this->_cache[$key] = $value;
-    $bytes = file_put_contents($this->fileName($key), "<?php //" . serialize($value));
-    return ($bytes !== FALSE);
-  }
-
-  /**
-   * @param string $key
-   * @return bool
-   */
-  public function delete($key) {
-    if (file_exists($this->fileName($key))) {
-      unlink($this->fileName($key));
-    }
-    unset($this->_cache[$key]);
-    return TRUE;
-  }
-
-  /**
-   * @param null $key
-   * @return bool
-   */
-  public function flush($key = NULL) {
-    $prefix = "CRM_";
-    if (!$handle = opendir(CIVICRM_TEMPLATE_COMPILEDIR)) {
-      // die? Error?
-      return FALSE;
-    }
-    while (FALSE !== ($entry = readdir($handle))) {
-      if (substr($entry, 0, 4) == $prefix) {
-        unlink(CIVICRM_TEMPLATE_COMPILEDIR . $entry);
-      }
-    }
-    closedir($handle);
-    unset($this->_cache);
-    $this->_cache = [];
-    return TRUE;
-  }
-
-  public function clear() {
-    return $this->flush();
-  }
-
-}
diff --git a/civicrm/CRM/Utils/Cache/SqlGroup.php b/civicrm/CRM/Utils/Cache/SqlGroup.php
index 6c0b6960ff635f9885f7e5d8abd48bb3f8135908..fe34b5290cad593670e6df5258de8ad66c297553 100644
--- a/civicrm/CRM/Utils/Cache/SqlGroup.php
+++ b/civicrm/CRM/Utils/Cache/SqlGroup.php
@@ -159,8 +159,6 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface {
 
     $lock->release();
 
-    $dao->free();
-
     $this->valueCache[$key] = CRM_Core_BAO_Cache::decode($dataSerialized);
     $this->expiresCache[$key] = $expires;
     return TRUE;
@@ -181,7 +179,6 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface {
         $this->expiresCache[$key] = $dao->expires;
         $this->valueCache[$key] = CRM_Core_BAO_Cache::decode($dao->data);
       }
-      $dao->free();
     }
     return (isset($this->expiresCache[$key]) && time() < $this->expiresCache[$key]) ? $this->reobjectify($this->valueCache[$key]) : $default;
   }
@@ -216,6 +213,11 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface {
    */
   public function delete($key) {
     CRM_Utils_Cache::assertValidKey($key);
+    // If we are triggering a deletion of a prevNextCache key in the civicrm_cache tabl
+    // Alssure that the relevant prev_next_cache values are also removed.
+    if ($this->group == CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache')) {
+      Civi::service('prevnext')->deleteItem(NULL, $key);
+    }
     CRM_Core_DAO::executeQuery("DELETE FROM {$this->table} WHERE {$this->where($key)}");
     unset($this->valueCache[$key]);
     unset($this->expiresCache[$key]);
@@ -223,7 +225,14 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface {
   }
 
   public function flush() {
-    CRM_Core_DAO::executeQuery("DELETE FROM {$this->table} WHERE {$this->where()}");
+    if ($this->group == CRM_Core_BAO_Cache::cleanKey('CiviCRM Search PrevNextCache') &&
+      Civi::service('prevnext') instanceof CRM_Core_PrevNextCache_Sql) {
+      // Use the standard PrevNextCache cleanup function here not just delete from civicrm_cache
+      CRM_Core_BAO_PrevNextCache::cleanupCache();
+    }
+    else {
+      CRM_Core_DAO::executeQuery("DELETE FROM {$this->table} WHERE {$this->where()}");
+    }
     $this->valueCache = [];
     $this->expiresCache = [];
     return TRUE;
@@ -241,7 +250,6 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface {
       $this->valueCache[$dao->path] = CRM_Core_BAO_Cache::decode($dao->data);
       $this->expiresCache[$dao->path] = $dao->expires;
     }
-    $dao->free();
   }
 
   protected function where($path = NULL) {
diff --git a/civicrm/CRM/Utils/Check/Component/Timestamps.php b/civicrm/CRM/Utils/Check/Component/Timestamps.php
index 932d33f070c413b252f5319d65ec72885c13747c..8bf32c12046fab4bda8ef155013137e6aad4a8df 100644
--- a/civicrm/CRM/Utils/Check/Component/Timestamps.php
+++ b/civicrm/CRM/Utils/Check/Component/Timestamps.php
@@ -104,7 +104,6 @@ class CRM_Utils_Check_Component_Timestamps extends CRM_Utils_Check_Component {
         $result = TRUE;
       }
     }
-    $dao->free();
     return $result;
   }
 
diff --git a/civicrm/CRM/Utils/Color.php b/civicrm/CRM/Utils/Color.php
index 2cceca9ff33468d6027255e2f5361fa96bfc96fc..95872433f52598cc65e7334f0850928545d5de4e 100644
--- a/civicrm/CRM/Utils/Color.php
+++ b/civicrm/CRM/Utils/Color.php
@@ -36,49 +36,65 @@
  */
 class CRM_Utils_Color {
 
+  const COLOR_FILE = '[civicrm.root]/bower_components/css-color-names/css-color-names.json';
+
   /**
    * Determine the appropriate text color for a given background.
    *
    * Based on YIQ value.
    *
-   * @param string $hexcolor
+   * @param string $color
    * @param string $black
    * @param string $white
    * @return string
    */
-  public static function getContrast($hexcolor, $black = 'black', $white = 'white') {
-    list($r, $g, $b) = self::getRgb($hexcolor);
+  public static function getContrast($color, $black = 'black', $white = 'white') {
+    list($r, $g, $b) = self::getRgb($color);
     $yiq = (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
     return ($yiq >= 128) ? $black : $white;
   }
 
   /**
-   * Convert hex color to decimal
+   * Parse any color string into rgb decimal values
+   *
+   * Accepted formats:
+   *   Full hex:     "#ffffff"
+   *   Short hex:    "#fff"
+   *   Color name    "white"
+   *   RGB notation: "rgb(255, 255, 255)"
    *
-   * @param string $hexcolor
-   * @return array
+   * @param string $color
+   * @return int[]|null
    *   [red, green, blue]
    */
-  public static function getRgb($hexcolor) {
-    $hexcolor = trim($hexcolor, ' #');
-    if (strlen($hexcolor) === 3) {
-      $hexcolor = $hexcolor[0] . $hexcolor[0] . $hexcolor[1] . $hexcolor[1] . $hexcolor[2] . $hexcolor[2];
+  public static function getRgb($color) {
+    $color = str_replace(' ', '', $color);
+    $color = self::nameToHex($color) ?? $color;
+    if (strpos($color, 'rgb(') === 0) {
+      return explode(',', substr($color, 4, strpos($color, ')') - 4));
+    }
+    $color = ltrim($color, '#');
+    if (strlen($color) === 3) {
+      $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2];
+    }
+    if (!CRM_Utils_Rule::color('#' . $color)) {
+      return NULL;
     }
     return [
-      hexdec(substr($hexcolor, 0, 2)),
-      hexdec(substr($hexcolor, 2, 2)),
-      hexdec(substr($hexcolor, 4, 2)),
+      hexdec(substr($color, 0, 2)),
+      hexdec(substr($color, 2, 2)),
+      hexdec(substr($color, 4, 2)),
     ];
   }
 
   /**
    * Calculate a highlight color from a base color
    *
-   * @param $hexcolor
+   * @param $color
    * @return string
    */
-  public static function getHighlight($hexcolor) {
-    $rgb = CRM_Utils_Color::getRgb($hexcolor);
+  public static function getHighlight($color) {
+    $rgb = self::getRgb($color);
     $avg = array_sum($rgb) / 3;
     foreach ($rgb as &$v) {
       if ($avg > 242) {
@@ -90,7 +106,52 @@ class CRM_Utils_Color {
         $v = min(255, intval((-.0035 * ($v - 242) ** 2) + 260));
       }
     }
-    return '#' . implode(array_map('dechex', $rgb));
+    return self::rgbToHex($rgb);
+  }
+
+  /**
+   * Convert named color (e.g. springgreen) to hex
+   *
+   * @param $colorName
+   * @return string|null
+   */
+  public static function nameToHex($colorName) {
+    if (strpos($colorName, '#') !== FALSE || strpos($colorName, '(') !== FALSE) {
+      return NULL;
+    }
+    if (empty(Civi::$statics[__CLASS__]['names'])) {
+      Civi::$statics[__CLASS__]['names'] = json_decode(file_get_contents(Civi::paths()->getPath(self::COLOR_FILE)), TRUE);
+    }
+    return Civi::$statics[__CLASS__]['names'][strtolower($colorName)] ?? NULL;
+  }
+
+  /**
+   * Converts rgb array to hex string
+   *
+   * @param int[] $rgb
+   * @return string
+   */
+  public static function rgbToHex($rgb) {
+    $ret = '#';
+    foreach ($rgb as $dec) {
+      $ret .= str_pad(dechex($dec), 2, '0', STR_PAD_LEFT);
+    }
+    return $ret;
+  }
+
+  /**
+   * Validate color input and convert it to standard hex notation
+   *
+   * @param string $color
+   * @return bool
+   */
+  public static function normalize(&$color) {
+    $rgb = self::getRgb($color);
+    if ($rgb) {
+      $color = self::rgbToHex($rgb);
+      return TRUE;
+    }
+    return FALSE;
   }
 
 }
diff --git a/civicrm/CRM/Utils/Date.php b/civicrm/CRM/Utils/Date.php
index 24b2f7388072276ff11abec6307c7d3a34ba6b84..fa96fca47fa1a0394a2bd4cd7b6c781a3101d498 100644
--- a/civicrm/CRM/Utils/Date.php
+++ b/civicrm/CRM/Utils/Date.php
@@ -2204,4 +2204,17 @@ class CRM_Utils_Date {
     }
   }
 
+  /**
+   * Print out a date object in specified format in local timezone
+   *
+   * @param DateTimeObject $dateObject
+   * @param string $format
+   * @return string
+   */
+  public static function convertDateToLocalTime($dateObject, $format = 'YmdHis') {
+    $systemTimeZone = new DateTimeZone(CRM_Core_Config::singleton()->userSystem->getTimeZoneString());
+    $dateObject->setTimezone($systemTimeZone);
+    return $dateObject->format($format);
+  }
+
 }
diff --git a/civicrm/CRM/Utils/Hook.php b/civicrm/CRM/Utils/Hook.php
index e2abd5a79ffa43cbe1f4efb7aef21e78f30d9741..2595679938fcdc3a6a06ca56d7168363c22feb2d 100644
--- a/civicrm/CRM/Utils/Hook.php
+++ b/civicrm/CRM/Utils/Hook.php
@@ -602,6 +602,63 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * A theme is a set of CSS files which are loaded on CiviCRM pages. To register a new
+   * theme, add it to the $themes array. Use these properties:
+   *
+   *  - ext: string (required)
+   *         The full name of the extension which defines the theme.
+   *         Ex: "org.civicrm.themes.greenwich".
+   *  - title: string (required)
+   *         Visible title.
+   *  - help: string (optional)
+   *         Description of the theme's appearance.
+   *  - url_callback: mixed (optional)
+   *         A function ($themes, $themeKey, $cssExt, $cssFile) which returns the URL(s) for a CSS resource.
+   *         Returns either an array of URLs or PASSTHRU.
+   *         Ex: \Civi\Core\Themes\Resolvers::simple (default)
+   *         Ex: \Civi\Core\Themes\Resolvers::none
+   *  - prefix: string (optional)
+   *         A prefix within the extension folder to prepend to the file name.
+   *  - search_order: array (optional)
+   *         A list of themes to search.
+   *         Generally, the last theme should be "*fallback*" (Civi\Core\Themes::FALLBACK).
+   *  - excludes: array (optional)
+   *         A list of files (eg "civicrm:css/bootstrap.css" or "$ext:$file") which should never
+   *         be returned (they are excluded from display).
+   *
+   * @param array $themes
+   *   List of themes, keyed by name.
+   * @return null
+   *   the return value is ignored
+   */
+  public static function themes(&$themes) {
+    return self::singleton()->invoke(1, $themes,
+      self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_themes'
+    );
+  }
+
+  /**
+   * The activeTheme hook determines which theme is active.
+   *
+   * @param string $theme
+   *   The identifier for the theme. Alterable.
+   *   Ex: 'greenwich'.
+   * @param array $context
+   *   Information about the current page-request. Includes some mix of:
+   *   - page: the relative path of the current Civi page (Ex: 'civicrm/dashboard').
+   *   - themes: an instance of the Civi\Core\Themes service.
+   * @return null
+   *   the return value is ignored
+   */
+  public static function activeTheme(&$theme, $context) {
+    return self::singleton()->invoke(array('theme', 'context'), $theme, $context,
+      self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_activeTheme'
+    );
+  }
+
   /**
    * This hook is called for declaring managed entities via API.
    *
diff --git a/civicrm/CRM/Utils/JS.php b/civicrm/CRM/Utils/JS.php
index 95340e36a38b6f7cdecb619d3a9a60c5529aa3e6..06331b5a2c343b32f68cf200b58ee02b2a4da0e6 100644
--- a/civicrm/CRM/Utils/JS.php
+++ b/civicrm/CRM/Utils/JS.php
@@ -126,4 +126,151 @@ class CRM_Utils_JS {
     return preg_replace(":^\\s*//[^\n]+$:m", "", $script);
   }
 
+  /**
+   * Decodes a js variable (not necessarily strict json but valid js) into a php variable.
+   *
+   * This is similar to using json_decode($js, TRUE) but more forgiving about syntax.
+   *
+   * ex. {a: 'Apple', 'b': "Banana", c: [1, 2, 3]}
+   * Returns: [
+   *   'a' => 'Apple',
+   *   'b' => 'Banana',
+   *   'c' => [1, 2, 3],
+   * ]
+   *
+   * @param string $js
+   * @return mixed
+   */
+  public static function decode($js) {
+    $js = trim($js);
+    if ($js[0] === "'" || $js[0] === '"') {
+      // Use a temp placeholder for escaped backslashes
+      return str_replace(['\\\\', "\\'", '\\"', '\\&', '\\/', '**backslash**'], ['**backslash**', "'", '"', '&', '/', '\\'], substr($js, 1, -1));
+    }
+    if ($js[0] === '{' || $js[0] === '[') {
+      $obj = self::getRawProps($js);
+      foreach ($obj as $idx => $item) {
+        $obj[$idx] = self::decode($item);
+      }
+      return $obj;
+    }
+    return json_decode($js);
+  }
+
+  /**
+   * Gets the properties of a javascript object/array WITHOUT decoding them.
+   *
+   * Useful when the object might contain js functions, expressions, etc. which cannot be decoded.
+   * Returns an array with keys as property names and values as raw strings of js.
+   *
+   * Ex Input: {foo: getFoo(arg), 'bar': function() {return "bar";}}
+   * Returns: [
+   *   'foo' => 'getFoo(arg)',
+   *   'bar' => 'function() {return "bar";}',
+   * ]
+   *
+   * @param $js
+   * @return array
+   * @throws \Exception
+   */
+  public static function getRawProps($js) {
+    $js = trim($js);
+    if (!is_string($js) || $js === '' || !($js[0] === '{' || $js[0] === '[')) {
+      throw new Exception("Invalid js object string passed to CRM_Utils_JS::getRawProps");
+    }
+    $chars = str_split(substr($js, 1));
+    $isEscaped = $quote = NULL;
+    $type = $js[0] === '{' ? 'object' : 'array';
+    $key = $type == 'array' ? 0 : NULL;
+    $item = '';
+    $end = strlen($js) - 2;
+    $quotes = ['"', "'", '/'];
+    $brackets = [
+      '}' => '{',
+      ')' => '(',
+      ']' => '[',
+      ':' => '?',
+    ];
+    $enclosures = array_fill_keys($brackets, 0);
+    $result = [];
+    foreach ($chars as $index => $char) {
+      if (!$isEscaped && in_array($char, $quotes, TRUE)) {
+        // Open quotes, taking care not to mistake the division symbol for opening a regex
+        if (!$quote && !($char == '/' && preg_match('{[\w)]\s*$}', $item))) {
+          $quote = $char;
+        }
+        // Close quotes
+        elseif ($char === $quote) {
+          $quote = NULL;
+        }
+      }
+      if (!$quote) {
+        // Delineates property key
+        if ($char == ':' && !array_filter($enclosures) && !$key) {
+          $key = $item;
+          $item = '';
+          continue;
+        }
+        // Delineates property value
+        if (($char == ',' || $index == $end) && !array_filter($enclosures) && isset($key) && trim($item) !== '') {
+          // Trim, unquote, and unescape characters in key
+          if ($type == 'object') {
+            $key = trim($key);
+            $key = in_array($key[0], $quotes) ? self::decode($key) : $key;
+          }
+          $result[$key] = trim($item);
+          $key = $type == 'array' ? $key + 1 : NULL;
+          $item = '';
+          continue;
+        }
+        // Open brackets - we'll ignore delineators inside
+        if (isset($enclosures[$char])) {
+          $enclosures[$char]++;
+        }
+        // Close brackets
+        if (isset($brackets[$char]) && $enclosures[$brackets[$char]]) {
+          $enclosures[$brackets[$char]]--;
+        }
+      }
+      $item .= $char;
+      // We are escaping the next char if this is a backslash not preceded by an odd number of backslashes
+      $isEscaped = $char === '\\' && ((strlen($item) - strlen(rtrim($item, '\\'))) % 2);
+    }
+    return $result;
+  }
+
+  /**
+   * Converts a php array to javascript object/array notation (not strict JSON).
+   *
+   * Does not encode keys unless they contain special characters.
+   * Does not encode values by default, so either specify $encodeValues = TRUE,
+   * or pass strings of valid js/json as values (per output from getRawProps).
+   * @see CRM_Utils_JS::getRawProps
+   *
+   * @param array $obj
+   * @param bool $encodeValues
+   * @return string
+   */
+  public static function writeObject($obj, $encodeValues = FALSE) {
+    $js = [];
+    $brackets = isset($obj[0]) && array_keys($obj) === range(0, count($obj) - 1) ? ['[', ']'] : ['{', '}'];
+    foreach ($obj as $key => $val) {
+      if ($encodeValues) {
+        $val = json_encode($val, JSON_UNESCAPED_SLASHES);
+      }
+      if ($brackets[0] == '{') {
+        // Enclose the key in quotes unless it is purely alphanumeric
+        if (preg_match('/\W/', $key)) {
+          // Prefer single quotes
+          $key = preg_match('/^[\w "]+$/', $key) ? "'" . $key . "'" : json_encode($key, JSON_UNESCAPED_SLASHES);
+        }
+        $js[] = "$key: $val";
+      }
+      else {
+        $js[] = $val;
+      }
+    }
+    return $brackets[0] . implode(', ', $js) . $brackets[1];
+  }
+
 }
diff --git a/civicrm/CRM/Utils/JSON.php b/civicrm/CRM/Utils/JSON.php
index d771de94e4e6f35ab7b50301bf0fccf991d3ee2c..7ec004714fe3fe1d56f392006509254b66ede7e2 100644
--- a/civicrm/CRM/Utils/JSON.php
+++ b/civicrm/CRM/Utils/JSON.php
@@ -46,6 +46,16 @@ class CRM_Utils_JSON {
     CRM_Utils_System::civiExit();
   }
 
+  /**
+   * Test whether the input string is valid JSON.
+   * @param string $str
+   * @return boolean
+   */
+  public static function isValidJSON($str) {
+    json_decode($str);
+    return json_last_error() == JSON_ERROR_NONE;
+  }
+
   /**
    * Do not use this function. See CRM-16353.
    * @deprecated
diff --git a/civicrm/CRM/Utils/Mail/Incoming.php b/civicrm/CRM/Utils/Mail/Incoming.php
index 0c5e5300e183b9ad2942b2be343d12800b139c05..eed6ec807509c607987d4c5eeb58ffdce7dec248 100644
--- a/civicrm/CRM/Utils/Mail/Incoming.php
+++ b/civicrm/CRM/Utils/Mail/Incoming.php
@@ -497,9 +497,7 @@ class CRM_Utils_Mail_Incoming {
 
     CRM_Utils_String::extractName($name, $params);
 
-    return CRM_Contact_BAO_Contact::createProfileContact($params,
-      CRM_Core_DAO::$_nullArray
-    );
+    return CRM_Contact_BAO_Contact::createProfileContact($params);
   }
 
 }
diff --git a/civicrm/CRM/Utils/Migrate/ExportJSON.php b/civicrm/CRM/Utils/Migrate/ExportJSON.php
index ffaa63065b77d5fbe970e6edc4ee9ab83d62bffe..24ba0aa76406ee3aa25714d058a647a0e0571d3d 100644
--- a/civicrm/CRM/Utils/Migrate/ExportJSON.php
+++ b/civicrm/CRM/Utils/Migrate/ExportJSON.php
@@ -236,7 +236,6 @@ SELECT *
       }
       $this->appendValue($dao->id, $tableName, $value);
     }
-    $dao->free();
   }
 
   /**
@@ -440,7 +439,6 @@ AND    entity_table = 'civicrm_contact'
         $additionalContacts
       );
     }
-    $dao->free();
   }
 
   /**
@@ -499,7 +497,6 @@ WHERE ac.contact_id IN ( $ids )
       // append activity value
       $this->appendValue($dao->id, 'civicrm_activity', $activity);
     }
-    $dao->free();
   }
 
   /**
diff --git a/civicrm/CRM/Utils/OpenFlashChart.php b/civicrm/CRM/Utils/OpenFlashChart.php
index 26e34292ebfcbab0f338e35dd5c76278ff1457fa..178f093bb0b7e832469004dc387aca9faacce11d 100644
--- a/civicrm/CRM/Utils/OpenFlashChart.php
+++ b/civicrm/CRM/Utils/OpenFlashChart.php
@@ -98,8 +98,7 @@ class CRM_Utils_OpenFlashChart {
     $ySteps = $yMax / 5;
 
     $bars = [];
-    $config = CRM_Core_Config::singleton();
-    $symbol = $config->defaultCurrencySymbol;
+    $symbol = CRM_Core_BAO_Country::defaultCurrencySymbol();
     foreach ($values as $barCount => $barVal) {
       $bars[$barCount] = new bar_glass();
 
@@ -214,8 +213,7 @@ class CRM_Utils_OpenFlashChart {
     $graphTitle = !empty($params['legend']) ? $params['legend'] : ts('Pie Chart');
 
     // get the currency.
-    $config = CRM_Core_Config::singleton();
-    $symbol = $config->defaultCurrencySymbol;
+    $symbol = CRM_Core_BAO_Country::defaultCurrencySymbol();
 
     $pie = new pie();
     $pie->radius(100);
@@ -296,8 +294,7 @@ class CRM_Utils_OpenFlashChart {
     }
 
     // get the currency.
-    $config = CRM_Core_Config::singleton();
-    $symbol = $config->defaultCurrencySymbol;
+    $symbol = CRM_Core_BAO_Country::defaultCurrencySymbol();
 
     // set the tooltip.
     $tooltip = CRM_Utils_Array::value('tip', $params, "$symbol #val#");
diff --git a/civicrm/CRM/Utils/ReCAPTCHA.php b/civicrm/CRM/Utils/ReCAPTCHA.php
index 31980430149b6dd4364f04e586d2f3aae921aef2..fab82510ce85e98c4a5cae8f4b9495a9f648782b 100644
--- a/civicrm/CRM/Utils/ReCAPTCHA.php
+++ b/civicrm/CRM/Utils/ReCAPTCHA.php
@@ -120,4 +120,17 @@ class CRM_Utils_ReCAPTCHA {
     }
   }
 
+  /**
+   * Enable ReCAPTCHA on Contribution form
+   *
+   * @param CRM_Core_Form $form
+   */
+  public static function enableCaptchaOnForm(&$form) {
+    $captcha = CRM_Utils_ReCAPTCHA::singleton();
+    if ($captcha->hasSettingsAvailable()) {
+      $captcha->add($form);
+      $form->assign('isCaptcha', TRUE);
+    }
+  }
+
 }
diff --git a/civicrm/CRM/Utils/SQL/BaseParamQuery.php b/civicrm/CRM/Utils/SQL/BaseParamQuery.php
index f48d05556c6de6ba1e89153729ad5a187e215666..159f56a5fad60f2832034fc54a100a36023f2d06 100644
--- a/civicrm/CRM/Utils/SQL/BaseParamQuery.php
+++ b/civicrm/CRM/Utils/SQL/BaseParamQuery.php
@@ -95,10 +95,10 @@ class CRM_Utils_SQL_BaseParamQuery implements ArrayAccess {
 
       $select = $this;
       return preg_replace_callback('/([#!@])([a-zA-Z0-9_]+)/', function($m) use ($select, $args) {
-        if (isset($args[$m[2]])) {
+        if (array_key_exists($m[2], $args)) {
           $values = $args[$m[2]];
         }
-        elseif (isset($args[$m[1] . $m[2]])) {
+        elseif (array_key_exists($m[1] . $m[2], $args)) {
           // Backward compat. Keys in $args look like "#myNumber" or "@myString".
           $values = $args[$m[1] . $m[2]];
         }
diff --git a/civicrm/CRM/Utils/String.php b/civicrm/CRM/Utils/String.php
index c740e72a1f3849556d2c6dcf4532d6364947b7dc..d0f295dd18048cd8121fd3bc9b959124572d2ae0 100644
--- a/civicrm/CRM/Utils/String.php
+++ b/civicrm/CRM/Utils/String.php
@@ -295,7 +295,7 @@ class CRM_Utils_String {
       }
       return $match;
     }
-    return CRM_Core_DAO::$_nullArray;
+    return [];
   }
 
   /**
diff --git a/civicrm/CRM/Utils/System.php b/civicrm/CRM/Utils/System.php
index 7508fe1573cc765dd134cffb6b55c0a8566ca82c..602c88276bda30cc7c4000cb6d6ae812366e2598 100644
--- a/civicrm/CRM/Utils/System.php
+++ b/civicrm/CRM/Utils/System.php
@@ -1396,12 +1396,12 @@ class CRM_Utils_System {
    * @param int $status
    *   (optional) Code with which to exit.
    *
-   * @throws \CRM_Core_PrematureExit_Exception
+   * @param array $testParameters
    */
-  public static function civiExit($status = 0) {
+  public static function civiExit($status = 0, $testParameters = []) {
 
     if (CIVICRM_UF === 'UnitTests') {
-      throw new CRM_Core_Exception_PrematureExitException('civiExit called');
+      throw new CRM_Core_Exception_PrematureExitException('civiExit called', $testParameters);
     }
     if ($status > 0) {
       http_response_code(500);
@@ -1432,13 +1432,14 @@ class CRM_Utils_System {
     // zealous about destroying *all* memory-backed caches during a flush().
     // These flushes simulate that legacy behavior. However, they should probably
     // be removed at some point.
-    $localDrivers = ['CRM_Utils_Cache_Arraycache', 'CRM_Utils_Cache_NoCache'];
+    $localDrivers = ['CRM_Utils_Cache_ArrayCache', 'CRM_Utils_Cache_NoCache'];
     if (Civi\Core\Container::isContainerBooted()
       && !in_array(get_class(CRM_Utils_Cache::singleton()), $localDrivers)) {
       Civi::cache('long')->flush();
       Civi::cache('settings')->flush();
       Civi::cache('js_strings')->flush();
       Civi::cache('community_messages')->flush();
+      Civi::cache('groups')->flush();
       CRM_Extension_System::singleton()->getCache()->flush();
       CRM_Cxn_CiviCxnHttp::singleton()->getCache()->flush();
     }
diff --git a/civicrm/CRM/Utils/System/Base.php b/civicrm/CRM/Utils/System/Base.php
index 2e675243c58ad5f7adbd33ad482a2dcd4575bd0d..0dca55f65783de6748b4d123644fcfb4a0c467c8 100644
--- a/civicrm/CRM/Utils/System/Base.php
+++ b/civicrm/CRM/Utils/System/Base.php
@@ -414,6 +414,19 @@ abstract class CRM_Utils_System_Base {
     return FALSE;
   }
 
+  /**
+   * Is a front end page being accessed.
+   *
+   * Generally this would be a contribution form or other public page as opposed to a backoffice page (like contact edit).
+   *
+   * @todo Drupal uses the is_public setting - clarify & rationalise. See https://github.com/civicrm/civicrm-drupal/pull/546/files
+   *
+   * @return bool
+   */
+  public function isFrontEndPage() {
+    return CRM_Core_Config::singleton()->userFrameworkFrontend;
+  }
+
   /**
    * Get user login URL for hosting CMS (method declared in each CMS system class)
    *
diff --git a/civicrm/CRM/Utils/System/Drupal8.php b/civicrm/CRM/Utils/System/Drupal8.php
index 4eb885592a3050d02034f5c582b52edd0b4e7803..a8b8a0e94734b45cd36817f4377e1403c598c1f7 100644
--- a/civicrm/CRM/Utils/System/Drupal8.php
+++ b/civicrm/CRM/Utils/System/Drupal8.php
@@ -317,14 +317,6 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
       \Drupal::logger('civicrm')->error($e->getMessage());
     }
 
-    // Special case: CiviCRM passes us "*path*?*query*" as a skeleton, but asterisks
-    // are invalid and Drupal will attempt to escape them. We unescape them here:
-    if ($path == '*path*') {
-      // First remove trailing equals sign that has been added since the key '?*query*' has no value.
-      $url = rtrim($url, '=');
-      $url = urldecode($url);
-    }
-
     return $url;
   }
 
@@ -636,6 +628,16 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
     ];
   }
 
+  /**
+   * @inheritDoc
+   */
+  public function setMessage($message) {
+    // CiviCRM sometimes includes markup in messages (ex: Event Cart)
+    // it needs to be rendered before being displayed.
+    $message = \Drupal\Core\Render\Markup::create($message);
+    \Drupal::messenger()->addMessage($message);
+  }
+
   /**
    * Drupal 8 has a different function to get current path, hence
    * overriding the postURL function
diff --git a/civicrm/CRM/Utils/System/DrupalBase.php b/civicrm/CRM/Utils/System/DrupalBase.php
index 75d04ca71252e942cccc759c2bedf7522b2bc964..829b3870d152bfcb32e46d6261bd23cc61408baf 100644
--- a/civicrm/CRM/Utils/System/DrupalBase.php
+++ b/civicrm/CRM/Utils/System/DrupalBase.php
@@ -663,4 +663,26 @@ abstract class CRM_Utils_System_DrupalBase extends CRM_Utils_System_Base {
     return (!empty($language->language)) ? $language->language : $language;
   }
 
+  /**
+   * Is a front end page being accessed.
+   *
+   * Generally this would be a contribution form or other public page as opposed to a backoffice page (like contact edit).
+   *
+   * See https://github.com/civicrm/civicrm-drupal/pull/546/files
+   *
+   * @return bool
+   */
+  public function isFrontEndPage() {
+    // Get the menu items.
+    $args = explode('?', $_GET['q']);
+    $path = $args[0];
+
+    // Get the menu for above URL.
+    $item = CRM_Core_Menu::get($path);
+    if (!empty(CRM_Utils_Array::value('is_public', $item))) {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
 }
diff --git a/civicrm/CRM/Utils/System/WordPress.php b/civicrm/CRM/Utils/System/WordPress.php
index c65c3a057b8a8434d280886fdab8c94b79bcfd62..bf35954360efa02b4711d693867b1103ffcc9a9d 100644
--- a/civicrm/CRM/Utils/System/WordPress.php
+++ b/civicrm/CRM/Utils/System/WordPress.php
@@ -270,11 +270,7 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
       // pre-existing logic
       if (isset($path)) {
         $queryParts[] = 'page=CiviCRM';
-        // Encode all but the *path* placeholder
-        if ($path !== '*path*') {
-          $path = rawurlencode($path);
-        }
-        $queryParts[] = "q={$path}";
+        $queryParts[] = 'q=' . rawurlencode($path);
       }
       if ($wpPageParam) {
         $queryParts[] = $wpPageParam;
@@ -831,13 +827,11 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
     $contactCreated = 0;
     $contactMatching = 0;
 
-    // previously used $wpdb - which means WordPress *must* be bootstrapped
-    $wpUsers = get_users(array(
-      'blog_id' => get_current_blog_id(),
-      'number' => -1,
-    ));
+    global $wpdb;
+    $wpUserIds = $wpdb->get_col("SELECT $wpdb->users.ID FROM $wpdb->users");
 
-    foreach ($wpUsers as $wpUserData) {
+    foreach ($wpUserIds as $wpUserId) {
+      $wpUserData = get_userdata($wpUserId);
       $contactCount++;
       if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($wpUserData,
         $wpUserData->$id,
diff --git a/civicrm/CRM/Utils/VersionCheck.php b/civicrm/CRM/Utils/VersionCheck.php
index eb72bd94518a904b816b8c3d11311746722e40ea..9d2fe9f6f2c832c4b5f3b6510894fa91afbbc1c9 100644
--- a/civicrm/CRM/Utils/VersionCheck.php
+++ b/civicrm/CRM/Utils/VersionCheck.php
@@ -160,7 +160,7 @@ class CRM_Utils_VersionCheck {
         'co' => $config->defaultContactCountry,
         'ufv' => $config->userSystem->getVersion(),
         'PHP' => phpversion(),
-        'MySQL' => CRM_CORE_DAO::singleValueQuery('SELECT VERSION()'),
+        'MySQL' => CRM_Core_DAO::singleValueQuery('SELECT VERSION()'),
         'communityMessagesUrl' => Civi::settings()->get('communityMessagesUrl'),
       ];
       $this->getDomainStats();
diff --git a/civicrm/Civi/API/Subscriber/APIv3SchemaAdapter.php b/civicrm/Civi/API/Subscriber/APIv3SchemaAdapter.php
index e6428711eb4dfb846002957b4ef275cd669f2c7f..3831cdf4d8b9a8af98c0d19d5473c9e2b794a9a9 100644
--- a/civicrm/Civi/API/Subscriber/APIv3SchemaAdapter.php
+++ b/civicrm/Civi/API/Subscriber/APIv3SchemaAdapter.php
@@ -82,6 +82,9 @@ class APIv3SchemaAdapter implements EventSubscriberInterface {
    */
   public function onApiPrepare_validate(\Civi\API\Event\Event $event) {
     $apiRequest = $event->getApiRequest();
+    if ($apiRequest['version'] > 3) {
+      return;
+    }
     // Not sure why this is omitted for generic actions. It would make sense
     // to omit 'getfields', but that's only one generic action.
 
diff --git a/civicrm/Civi/API/Subscriber/I18nSubscriber.php b/civicrm/Civi/API/Subscriber/I18nSubscriber.php
index c430928202ba17ce3ee49a709a0485c305d2b003..02c4d7e79799d52ce2cc2fa20da36f014ac2f5a1 100644
--- a/civicrm/Civi/API/Subscriber/I18nSubscriber.php
+++ b/civicrm/Civi/API/Subscriber/I18nSubscriber.php
@@ -36,16 +36,26 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  */
 class I18nSubscriber implements EventSubscriberInterface {
 
+  /**
+   * Used for rolling back language to its original setting after the api call.
+   *
+   * @var array
+   */
+  public $originalLang = [];
+
   /**
    * @return array
    */
   public static function getSubscribedEvents() {
     return [
       Events::PREPARE => ['onApiPrepare', Events::W_MIDDLE],
+      Events::RESPOND => ['onApiRespond', Events::W_LATE],
     ];
   }
 
   /**
+   * Support multi-lingual requests
+   *
    * @param \Civi\API\Event\Event $event
    *   API preparation event.
    *
@@ -54,9 +64,33 @@ class I18nSubscriber implements EventSubscriberInterface {
   public function onApiPrepare(\Civi\API\Event\Event $event) {
     $apiRequest = $event->getApiRequest();
 
-    // support multi-lingual requests
-    if ($language = \CRM_Utils_Array::value('option.language', $apiRequest['params'])) {
-      $this->setLocale($language);
+    $params = $apiRequest['params'];
+    if ($apiRequest['version'] < 4) {
+      $language = !empty($params['options']['language']) ? $params['options']['language'] : \CRM_Utils_Array::value('option.language', $params);
+    }
+    else {
+      $language = \CRM_Utils_Array::value('language', $params);
+    }
+    if ($language) {
+      $this->setLocale($language, $apiRequest['id']);
+    }
+  }
+
+  /**
+   * Reset language to the default.
+   *
+   * @param \Civi\API\Event\Event $event
+   *
+   * @throws \API_Exception
+   */
+  public function onApiRespond(\Civi\API\Event\Event $event) {
+    $apiRequest = $event->getApiRequest();
+
+    if (!empty($this->originalLang[$apiRequest['id']])) {
+      global $tsLocale;
+      global $dbLocale;
+      $tsLocale = $this->originalLang[$apiRequest['id']]['tsLocale'];
+      $dbLocale = $this->originalLang[$apiRequest['id']]['dbLocale'];
     }
   }
 
@@ -65,9 +99,10 @@ class I18nSubscriber implements EventSubscriberInterface {
    * Some code duplication from CRM/Core/BAO/ConfigSetting.php retrieve()
    * to avoid regressions from refactoring.
    * @param $lcMessagesRequest
+   * @param int $requestId
    * @throws \API_Exception
    */
-  public function setLocale($lcMessagesRequest) {
+  public function setLocale($lcMessagesRequest, $requestId) {
     // We must validate whether the locale is valid, otherwise setting a bad
     // dbLocale could probably lead to sql-injection.
     $domain = new \CRM_Core_DAO_Domain();
@@ -94,14 +129,20 @@ class I18nSubscriber implements EventSubscriberInterface {
       }
     }
 
-    global $dbLocale;
-
-    // set suffix for table names - use views if more than one language
     if ($lcMessages) {
-      $dbLocale = $multiLang && $lcMessages ? "_{$lcMessages}" : '';
-
-      // FIXME: an ugly hack to fix CRM-4041
+      global $dbLocale;
       global $tsLocale;
+
+      // Store original value to be restored in $this->onApiRespond
+      $this->originalLang[$requestId] = [
+        'tsLocale' => $tsLocale,
+        'dbLocale' => $dbLocale,
+      ];
+
+      // Set suffix for table names - use views if more than one language
+      $dbLocale = "_{$lcMessages}";
+
+      // Also set tsLocale - CRM-4041
       $tsLocale = $lcMessages;
     }
   }
diff --git a/civicrm/Civi/Angular/ChangeSet.php b/civicrm/Civi/Angular/ChangeSet.php
index f0eb38148cbfad59d628659ff8451b0732663d93..27c92a5867b16395213863d24e732d7a197cd4d3 100644
--- a/civicrm/Civi/Angular/ChangeSet.php
+++ b/civicrm/Civi/Angular/ChangeSet.php
@@ -55,9 +55,6 @@ class ChangeSet implements ChangeSetInterface {
           if (preg_match($filter['regex'], $path)) {
             if ($doc === NULL) {
               $doc = \phpQuery::newDocument($html, 'text/html');
-              if (\CRM_Core_Config::singleton()->debug && !$coder->checkConsistentHtml($html)) {
-                throw new \CRM_Core_Exception("Cannot process $path: inconsistent markup. Use check-angular.php to investigate.");
-              }
             }
             call_user_func($filter['callback'], $doc, $path);
           }
diff --git a/civicrm/Civi/Angular/Manager.php b/civicrm/Civi/Angular/Manager.php
index 5d019a0318e4c9e1869aab82d15c3ae9bfb4e2a8..c44b854aa694dd788ec7da294c21eab260d359ea 100644
--- a/civicrm/Civi/Angular/Manager.php
+++ b/civicrm/Civi/Angular/Manager.php
@@ -50,7 +50,7 @@ class Manager {
    */
   public function __construct($res, \CRM_Utils_Cache_Interface $cache = NULL) {
     $this->res = $res;
-    $this->cache = $cache ? $cache : new \CRM_Utils_Cache_Arraycache([]);
+    $this->cache = $cache ? $cache : new \CRM_Utils_Cache_ArrayCache([]);
   }
 
   /**
@@ -80,6 +80,7 @@ class Manager {
 
       $angularModules = [];
       $angularModules['angularFileUpload'] = include "$civicrm_root/ang/angularFileUpload.ang.php";
+      $angularModules['checklist-model'] = include "$civicrm_root/ang/checklist-model.ang.php";
       $angularModules['crmApp'] = include "$civicrm_root/ang/crmApp.ang.php";
       $angularModules['crmAttachment'] = include "$civicrm_root/ang/crmAttachment.ang.php";
       $angularModules['crmAutosave'] = include "$civicrm_root/ang/crmAutosave.ang.php";
diff --git a/civicrm/Civi/Core/Container.php b/civicrm/Civi/Core/Container.php
index 9ce531d1bb776fc3ad3994afe6e9c98a2435afdf..853299498b870c9a89287d537d39df6ed8c377a9 100644
--- a/civicrm/Civi/Core/Container.php
+++ b/civicrm/Civi/Core/Container.php
@@ -156,19 +156,38 @@ class Container {
       'checks' => 'checks',
       'session' => 'CiviCRM Session',
       'long' => 'long',
+      'groups' => 'contact groups',
     ];
     foreach ($basicCaches as $cacheSvc => $cacheGrp) {
+      $definitionParams = [
+        'name' => $cacheGrp,
+        'type' => ['*memory*', 'SqlGroup', 'ArrayCache'],
+      ];
+      // For Caches that we don't really care about the ttl for and/or maybe accessed
+      // fairly often we use the fastArrayDecorator which improves reads and writes, these
+      // caches should also not have concurrency risk.
+      $fastArrayCaches = ['groups'];
+      if (in_array($cacheSvc, $fastArrayCaches)) {
+        $definitionParams['withArray'] = 'fast';
+      }
       $container->setDefinition("cache.{$cacheSvc}", new Definition(
         'CRM_Utils_Cache_Interface',
-        [
-          [
-            'name' => $cacheGrp,
-            'type' => ['*memory*', 'SqlGroup', 'ArrayCache'],
-          ],
-        ]
+        [$definitionParams]
       ))->setFactory('CRM_Utils_Cache::create');
     }
 
+    // PrevNextCache cannot use memory or array cache at the moment because the
+    // Code in CRM_Core_BAO_PrevNextCache assumes that this cache is sql backed.
+    $container->setDefinition("cache.prevNextCache", new Definition(
+      'CRM_Utils_Cache_Interface',
+      [
+        [
+          'name' => 'CiviCRM Search PrevNextCache',
+          'type' => ['SqlGroup'],
+        ],
+      ]
+    ))->setFactory('CRM_Utils_Cache::create');
+
     $container->setDefinition('sql_triggers', new Definition(
       'Civi\Core\SqlTriggers',
       []
@@ -179,6 +198,11 @@ class Container {
       []
     ));
 
+    $container->setDefinition('themes', new Definition(
+      'Civi\Core\Themes',
+      []
+    ));
+
     $container->setDefinition('pear_mail', new Definition('Mail'))
       ->setFactory('CRM_Utils_Mail::createMailer');
 
diff --git a/civicrm/Civi/Core/Themes.php b/civicrm/Civi/Core/Themes.php
new file mode 100644
index 0000000000000000000000000000000000000000..16968eb7a382469c0a9a4e1a3c39f29595a1d462
--- /dev/null
+++ b/civicrm/Civi/Core/Themes.php
@@ -0,0 +1,283 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2016                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Core;
+
+use Civi;
+
+/**
+ *
+ * @package CiviCRM_Hook
+ * @copyright CiviCRM LLC (c) 2004-2016
+ */
+class Themes {
+
+  /**
+   * The "default" theme adapts based on the latest recommendation from civicrm.org
+   * by switching to DEFAULT_THEME at runtime.
+   */
+  const DEFAULT_THEME = 'greenwich';
+
+  /**
+   * Fallback is a pseudotheme which can be included in "search_order".
+   * It locates files in the core/extension (non-theme) codebase.
+   */
+  const FALLBACK_THEME = '_fallback_';
+
+  const PASSTHRU = 'PASSTHRU';
+
+  /**
+   * @var string
+   *   Ex: 'judy', 'liza'.
+   */
+  private $activeThemeKey = NULL;
+
+  /**
+   * @var array
+   *   Array(string $themeKey => array $themeSpec).
+   */
+  private $themes = NULL;
+
+  /**
+   * @var \CRM_Utils_Cache_Interface
+   */
+  private $cache = NULL;
+
+  /**
+   * Theme constructor.
+   * @param \CRM_Utils_Cache_Interface $cache
+   */
+  public function __construct($cache = NULL) {
+    $this->cache = $cache ? $cache : Civi::cache('long');
+  }
+
+  /**
+   * Determine the name of active theme.
+   *
+   * @return string
+   *   Ex: "greenwich".
+   */
+  public function getActiveThemeKey() {
+    if ($this->activeThemeKey === NULL) {
+      // Ambivalent: is it better to use $config->userFrameworkFrontend or $template->get('urlIsPublic')?
+      $config = \CRM_Core_Config::singleton();
+      $settingKey = $config->userSystem->isFrontEndPage() ? 'theme_frontend' : 'theme_backend';
+
+      $themeKey = Civi::settings()->get($settingKey);
+      if ($themeKey === 'default') {
+        $themeKey = self::DEFAULT_THEME;
+      }
+
+      \CRM_Utils_Hook::activeTheme($themeKey, [
+        'themes' => $this,
+        'page' => \CRM_Utils_Array::value(\CRM_Core_Config::singleton()->userFrameworkURLVar, $_GET),
+      ]);
+
+      $themes = $this->getAll();
+      $this->activeThemeKey = isset($themes[$themeKey]) ? $themeKey : self::DEFAULT_THEME;
+    }
+    return $this->activeThemeKey;
+  }
+
+  /**
+   * Get the definition of the theme.
+   *
+   * @param string $themeKey
+   *   Ex: 'greenwich', 'shoreditch'.
+   * @return array|NULL
+   * @see CRM_Utils_Hook::themes
+   */
+  public function get($themeKey) {
+    $all = $this->getAll();
+    return isset($all[$themeKey]) ? $all[$themeKey] : NULL;
+  }
+
+  /**
+   * Get a list of all known themes, including hidden base themes.
+   *
+   * @return array
+   *   List of themes, keyed by name. Same format as CRM_Utils_Hook::themes(),
+   *   but any default values are filled in.
+   * @see CRM_Utils_Hook::themes
+   */
+  public function getAll() {
+    if ($this->themes === NULL) {
+      // Cache includes URLs/paths, which change with runtime.
+      $cacheKey = 'theme_list_' . \CRM_Core_Config_Runtime::getId();
+      $this->themes = $this->cache->get($cacheKey);
+      if ($this->themes === NULL) {
+        $this->themes = $this->buildAll();
+        $this->cache->set($cacheKey, $this->themes);
+      }
+    }
+    return $this->themes;
+  }
+
+  /**
+   * Get a list of available themes, excluding hidden base themes.
+   *
+   * This is the same as getAll(), but abstract themes like "_fallback_"
+   * or "_newyork_base_" are omitted.
+   *
+   * @return array
+   *   List of themes.
+   *   Ex: ['greenwich' => 'Greenwich', 'shoreditch' => 'Shoreditch'].
+   * @see CRM_Utils_Hook::themes
+   */
+  public function getAvailable() {
+    $result = array();
+    foreach ($this->getAll() as $key => $theme) {
+      if ($key{0} !== '_') {
+        $result[$key] = $theme['title'];
+      }
+    }
+    return $result;
+  }
+
+  /**
+   * Get the URL(s) for a themed CSS file.
+   *
+   * This implements a prioritized search, in order:
+   *  - Check for the specified theme.
+   *  - If that doesn't exist, check for the default theme.
+   *  - If that doesn't exist, use the 'none' theme.
+   *
+   * @param string $active
+   *   Active theme key.
+   *   Ex: 'greenwich'.
+   * @param string $cssExt
+   *   Ex: 'civicrm'.
+   * @param string $cssFile
+   *   Ex: 'css/bootstrap.css' or 'css/civicrm.css'.
+   * @return array
+   *   List of URLs to display.
+   *   Ex: array(string $url)
+   */
+  public function resolveUrls($active, $cssExt, $cssFile) {
+    $all = $this->getAll();
+    if (!isset($all[$active])) {
+      return array();
+    }
+
+    $cssId = $this->cssId($cssExt, $cssFile);
+
+    foreach ($all[$active]['search_order'] as $themeKey) {
+      if (isset($all[$themeKey]['excludes']) && in_array($cssId, $all[$themeKey]['excludes'])) {
+        $result = array();
+      }
+      else {
+        $result = Civi\Core\Resolver::singleton()
+          ->call($all[$themeKey]['url_callback'], array($this, $themeKey, $cssExt, $cssFile));
+      }
+
+      if ($result !== self::PASSTHRU) {
+        return $result;
+      }
+    }
+
+    throw new \RuntimeException("Failed to resolve URL. Theme metadata may be incomplete.");
+  }
+
+  /**
+   * Construct the list of available themes.
+   *
+   * @return array
+   *   List of themes, keyed by name.
+   * @see CRM_Utils_Hook::themes
+   */
+  protected function buildAll() {
+    $themes = array(
+      'default' => array(
+        'ext' => 'civicrm',
+        'title' => ts('Automatic'),
+        'help' => ts('Determine a system default automatically'),
+        // This is an alias. url_callback, search_order don't matter.
+      ),
+      'greenwich' => array(
+        'ext' => 'civicrm',
+        'title' => 'Greenwich',
+        'help' => ts('CiviCRM 4.x look-and-feel'),
+      ),
+      'none' => array(
+        'ext' => 'civicrm',
+        'title' => ts('None (Unstyled)'),
+        'help' => ts('Disable CiviCRM\'s built-in CSS files.'),
+        'search_order' => array('none', self::FALLBACK_THEME),
+        'excludes' => array(
+          "css/civicrm.css",
+          "css/bootstrap.css",
+        ),
+      ),
+      self::FALLBACK_THEME => array(
+        'ext' => 'civicrm',
+        'title' => 'Fallback (Abstract Base Theme)',
+        'url_callback' => '\Civi\Core\Themes\Resolvers::fallback',
+        'search_order' => array(self::FALLBACK_THEME),
+      ),
+    );
+
+    \CRM_Utils_Hook::themes($themes);
+
+    foreach (array_keys($themes) as $themeKey) {
+      $themes[$themeKey] = $this->build($themeKey, $themes[$themeKey]);
+    }
+
+    return $themes;
+  }
+
+  /**
+   * Apply defaults for a given them.
+   *
+   * @param string $themeKey
+   *   The name of the theme. Ex: 'greenwich'.
+   * @param array $theme
+   *   The original theme definition of the theme (per CRM_Utils_Hook::themes).
+   * @return array
+   *   The full theme definition of the theme (per CRM_Utils_Hook::themes).
+   * @see CRM_Utils_Hook::themes
+   */
+  protected function build($themeKey, $theme) {
+    $defaults = array(
+      'name' => $themeKey,
+      'url_callback' => '\Civi\Core\Themes\Resolvers::simple',
+      'search_order' => array($themeKey, self::FALLBACK_THEME),
+    );
+    $theme = array_merge($defaults, $theme);
+
+    return $theme;
+  }
+
+  /**
+   * @param string $cssExt
+   * @param string $cssFile
+   * @return string
+   */
+  public function cssId($cssExt, $cssFile) {
+    return ($cssExt === 'civicrm') ? $cssFile : "$cssExt-$cssFile";
+  }
+
+}
diff --git a/civicrm/Civi/Core/Themes/Resolvers.php b/civicrm/Civi/Core/Themes/Resolvers.php
new file mode 100644
index 0000000000000000000000000000000000000000..4671b92002e5b0a9b0e37942bb228fff72d10fb6
--- /dev/null
+++ b/civicrm/Civi/Core/Themes/Resolvers.php
@@ -0,0 +1,97 @@
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2016                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Core\Themes;
+
+use Civi;
+
+/**
+ *
+ * @package CiviCRM_Hook
+ * @copyright CiviCRM LLC (c) 2004-2016
+ */
+class Resolvers {
+
+  /**
+   * In the simple format, the CSS file is loaded from the extension's "css" subdir;
+   * if it's missing, then it searches the parents.
+   *
+   * To use an alternate subdir, override "prefix".
+   *
+   * Simple themes may use the "search_order" to assimilate content from other themes.
+   *
+   * @param \Civi\Core\Themes $themes
+   *   The theming subsystem.
+   * @param string $themeKey
+   *   The active/desired theme key.
+   * @param string $cssExt
+   *   The extension for which we want a themed CSS file (e.g. "civicrm").
+   * @param string $cssFile
+   *   File name (e.g. "css/bootstrap.css").
+   * @return array|string
+   *   List of CSS URLs, or PASSTHRU.
+   */
+  public static function simple($themes, $themeKey, $cssExt, $cssFile) {
+    $res = Civi::resources();
+    $theme = $themes->get($themeKey);
+    $file = '';
+    if (isset($theme['prefix'])) {
+      $file .= $theme['prefix'];
+    }
+    $file .= $themes->cssId($cssExt, $cssFile);
+    $file = $res->filterMinify($theme['ext'], $file);
+
+    if ($res->getPath($theme['ext'], $file)) {
+      return array($res->getUrl($theme['ext'], $file, TRUE));
+    }
+    else {
+      return Civi\Core\Themes::PASSTHRU;
+    }
+  }
+
+  /**
+   * The base handler falls back to loading files from the main application (rather than
+   * using the theme).
+   *
+   * @param \Civi\Core\Themes $themes
+   *   The theming subsystem.
+   * @param string $themeKey
+   *   The active/desired theme key.
+   * @param string $cssExt
+   *   The extension for which we want a themed CSS file (e.g. "civicrm").
+   * @param string $cssFile
+   *   File name (e.g. "css/bootstrap.css").
+   * @return array|string
+   *   List of CSS URLs, or PASSTHRU.
+   */
+  public static function fallback($themes, $themeKey, $cssExt, $cssFile) {
+    $res = Civi::resources();
+    return array($res->getUrl($cssExt, $cssFile, TRUE));
+  }
+
+}
diff --git a/civicrm/Civi/Test/Api3TestTrait.php b/civicrm/Civi/Test/Api3TestTrait.php
index aeb4247275a3a4748639637c0c9369a454c2c6a9..1c99c0490b42d3e61f84014020a4704a7d43216e 100644
--- a/civicrm/Civi/Test/Api3TestTrait.php
+++ b/civicrm/Civi/Test/Api3TestTrait.php
@@ -169,10 +169,13 @@ trait Api3TestTrait {
    * This function exists to wrap api getValue function & check the result
    * so we can ensure they succeed & throw exceptions without litterering the test with checks
    * There is a type check in this
+   *
    * @param string $entity
    * @param array $params
-   * @param null $count
-   * @throws \Exception
+   * @param int $count
+   *
+   * @throws \CRM_Core_Exception
+   *
    * @return array|int
    */
   public function callAPISuccessGetCount($entity, $params, $count = NULL) {
@@ -182,7 +185,7 @@ trait Api3TestTrait {
     ];
     $result = $this->civicrm_api($entity, 'getcount', $params);
     if (!is_int($result) || !empty($result['is_error']) || isset($result['values'])) {
-      throw new \Exception('Invalid getcount result : ' . print_r($result, TRUE) . " type :" . gettype($result));
+      throw new \CRM_Core_Exception('Invalid getcount result : ' . print_r($result, TRUE) . " type :" . gettype($result));
     }
     if (is_int($count)) {
       $this->assertEquals($count, $result, "incorrect count returned from $entity getcount");
@@ -205,7 +208,8 @@ trait Api3TestTrait {
    *   - array
    *   - object
    *
-   * @throws \Exception
+   * @throws \CRM_Core_Exception
+   *
    * @return array|int
    */
   public function callAPISuccessGetSingle($entity, $params, $checkAgainst = NULL) {
@@ -214,8 +218,8 @@ trait Api3TestTrait {
     ];
     $result = $this->civicrm_api($entity, 'getsingle', $params);
     if (!is_array($result) || !empty($result['is_error']) || isset($result['values'])) {
-      $unfilteredResult = $this->civicrm_api($entity, 'get', $params);
-      throw new \Exception(
+      $unfilteredResult = $this->civicrm_api($entity, 'get', ['version' => $this->_apiversion]);
+      throw new \CRM_Core_Exception(
         'Invalid getsingle result' . print_r($result, TRUE)
         . "\n entity: $entity . \n params \n " . print_r($params, TRUE)
         . "\n entities retrieved with blank params \n" . print_r($unfilteredResult, TRUE)
@@ -245,6 +249,7 @@ trait Api3TestTrait {
    *   - object
    *
    * @return array|int
+   * @throws \CRM_Core_Exception
    */
   public function callAPISuccessGetValue($entity, $params, $type = NULL) {
     $params += [
@@ -253,10 +258,10 @@ trait Api3TestTrait {
     ];
     $result = $this->civicrm_api($entity, 'getvalue', $params);
     if (is_array($result) && (!empty($result['is_error']) || isset($result['values']))) {
-      throw new \Exception('Invalid getvalue result' . print_r($result, TRUE));
+      throw new \CRM_Core_Exception('Invalid getvalue result' . print_r($result, TRUE));
     }
     if ($type) {
-      if ($type == 'integer') {
+      if ($type === 'integer') {
         // api seems to return integers as strings
         $this->assertTrue(is_numeric($result), "expected a numeric value but got " . print_r($result, 1));
       }
@@ -302,9 +307,13 @@ trait Api3TestTrait {
     $indexBy = in_array($v3Action, ['get', 'create', 'replace']) && !$sequential ? 'id' : NULL;
     $onlyId = !empty($v3Params['format.only_id']);
     $onlySuccess = !empty($v3Params['format.is_success']);
-    if (!empty($v3Params['filters']['is_current']) || !empty($params['isCurrent'])) {
+    if (!empty($v3Params['filters']['is_current']) || !empty($v3Params['isCurrent'])) {
       $v4Params['current'] = TRUE;
     }
+    $language = !empty($v3Params['options']['language']) ? $v3Params['options']['language'] : \CRM_Utils_Array::value('option.language', $v3Params);
+    if ($language) {
+      $v4Params['language'] = $language;
+    }
     $toRemove = ['option.', 'return', 'api.', 'format.'];
     $chains = [];
     $custom = [];
diff --git a/civicrm/Civi/Test/ContactTestTrait.php b/civicrm/Civi/Test/ContactTestTrait.php
index c98e457b05d76247544ae7461cbd6475572e0e6f..8fee27bc2d03f2c7492c6837b427f8b781cb946b 100644
--- a/civicrm/Civi/Test/ContactTestTrait.php
+++ b/civicrm/Civi/Test/ContactTestTrait.php
@@ -71,7 +71,8 @@ trait ContactTestTrait {
    *
    * @return int
    *   id of Individual created
-   * @throws \Exception
+   *
+   * @throws \CRM_Core_Exception
    */
   public function individualCreate($params = array(), $seq = 0, $random = FALSE) {
     $params = array_merge($this->sampleContact('Individual', $seq, $random), $params);
@@ -151,7 +152,7 @@ trait ContactTestTrait {
    * @param array $params
    *   For civicrm_contact_add api function call.
    *
-   * @throws \Exception
+   * @throws CRM_Core_Exception
    *
    * @return int
    *   id of Household created
@@ -159,7 +160,7 @@ trait ContactTestTrait {
   private function _contactCreate($params) {
     $result = $this->callAPISuccess('contact', 'create', $params);
     if (!empty($result['is_error']) || empty($result['id'])) {
-      throw new \Exception('Could not create test contact, with message: ' . \CRM_Utils_Array::value('error_message', $result) . "\nBacktrace:" . \CRM_Utils_Array::value('trace', $result));
+      throw new \CRM_Core_Exception('Could not create test contact, with message: ' . \CRM_Utils_Array::value('error_message', $result) . "\nBacktrace:" . \CRM_Utils_Array::value('trace', $result));
     }
     return $result['id'];
   }
diff --git a/civicrm/Civi/Test/DbTestTrait.php b/civicrm/Civi/Test/DbTestTrait.php
index 06b5e60b3c635fefcd663156b0d9ad82248bc7c2..3e97931cfe078e6b2c453e2440dc15dd73a6098c 100644
--- a/civicrm/Civi/Test/DbTestTrait.php
+++ b/civicrm/Civi/Test/DbTestTrait.php
@@ -169,10 +169,13 @@ trait DbTestTrait {
    *
    * Example: $this->assertSql(2, 'select count(*) from foo where foo.bar like "%1"',
    * array(1 => array("Whiz", "String")));
+   *
    * @param $expected
    * @param $query
    * @param array $params
    * @param string $message
+   *
+   * @throws \Exception
    */
   public function assertDBQuery($expected, $query, $params = array(), $message = '') {
     if ($message) {
diff --git a/civicrm/ang/checklist-model.ang.php b/civicrm/ang/checklist-model.ang.php
new file mode 100644
index 0000000000000000000000000000000000000000..ffa8613bda5d49fe58285d65a74cd70e77a8ca3a
--- /dev/null
+++ b/civicrm/ang/checklist-model.ang.php
@@ -0,0 +1,10 @@
+<?php
+// This file declares an Angular module which can be autoloaded
+// in CiviCRM. See also:
+// http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_angularModules
+
+return [
+  'ext' => 'civicrm',
+  'basePages' => [],
+  'js' => ['bower_components/checklist-model/checklist-model.js'],
+];
diff --git a/civicrm/ang/crmCaseType.ang.php b/civicrm/ang/crmCaseType.ang.php
index 21596810d419bb04afdf1b7e3b1e8788e05c8a78..c71e9c6678b50fb97fd47ae9312e75babaa8d8d0 100644
--- a/civicrm/ang/crmCaseType.ang.php
+++ b/civicrm/ang/crmCaseType.ang.php
@@ -5,12 +5,6 @@
 
 // ODDITY: This only loads if CiviCase is active.
 
-CRM_Core_Resources::singleton()->addSetting([
-  'crmCaseType' => [
-    'REL_TYPE_CNAME' => CRM_Case_XMLProcessor::REL_TYPE_CNAME,
-  ],
-]);
-
 return [
   'ext' => 'civicrm',
   'js' => ['ang/crmCaseType.js'],
diff --git a/civicrm/ang/crmCaseType.js b/civicrm/ang/crmCaseType.js
index ee2344ece81a7fd2e4a975319e9f0283c0bb36ca..a1ff51ae5749074c93fd2d019b1e93a5950f9815 100644
--- a/civicrm/ang/crmCaseType.js
+++ b/civicrm/ang/crmCaseType.js
@@ -78,7 +78,7 @@
               sequential: 1,
               is_active: 1,
               options: {
-                sort: CRM.crmCaseType.REL_TYPE_CNAME,
+                sort: 'label_a_b',
                 limit: 0
               }
             }];
@@ -238,11 +238,9 @@
   });
 
   crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls, crmUiHelp) {
-    var REL_TYPE_CNAME, defaultAssigneeDefaultValue, ts;
+    var defaultAssigneeDefaultValue, ts;
 
     (function init () {
-      // CRM_Case_XMLProcessor::REL_TYPE_CNAME
-      REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME;
 
       ts = $scope.ts = CRM.ts(null);
       $scope.hs = crmUiHelp({file: 'CRM/Case/CaseType'});
@@ -263,33 +261,56 @@
       $scope.activityTypes = _.indexBy(apiCalls.actTypes.values, 'name');
       $scope.activityTypeOptions = _.map(apiCalls.actTypes.values, formatActivityTypeOption);
       $scope.defaultAssigneeTypes = apiCalls.defaultAssigneeTypes.values;
-      $scope.relationshipTypeOptions = _.map(apiCalls.relTypes.values, function(type) {
-        return {id: type[REL_TYPE_CNAME], text: type.label_b_a};
-      });
-      $scope.defaultRelationshipTypeOptions = getDefaultRelationshipTypeOptions();
+      $scope.relationshipTypeOptions = getRelationshipTypeOptions(false);
+      $scope.defaultRelationshipTypeOptions = getRelationshipTypeOptions(true);
       // stores the default assignee values indexed by their option name:
       $scope.defaultAssigneeTypeValues = _.chain($scope.defaultAssigneeTypes)
         .indexBy('name').mapValues('value').value();
     }
 
-    /// Returns the default relationship type options. If the relationship is
-    /// bidirectional (Ex: Spouse of) it adds a single option otherwise it adds
-    /// two options representing the relationship type directions
-    /// (Ex: Employee of, Employer is)
-    function getDefaultRelationshipTypeOptions() {
+    // Returns the relationship type options. If the relationship is
+    // bidirectional (Ex: Spouse of) it adds a single option otherwise it adds
+    // two options representing the relationship type directions (Ex: Employee
+    // of, Employer of).
+    //
+    // The default relationship field needs values that are IDs with direction,
+    // while the role field needs values that are names (with implicit
+    // direction).
+    //
+    // At any rate, the labels should follow the convention in the UI of
+    // describing case roles from the perspective of the client, while the
+    // values must follow the convention in the XML of describing case roles
+    // from the perspective of the non-client.
+    function getRelationshipTypeOptions($isDefault) {
       return _.transform(apiCalls.relTypes.values, function(result, relType) {
         var isBidirectionalRelationship = relType.label_a_b === relType.label_b_a;
-
-        result.push({
-          label: relType.label_b_a,
-          value: relType.id + '_b_a'
-        });
-
-        if (!isBidirectionalRelationship) {
+        if ($isDefault) {
           result.push({
-            label: relType.label_a_b,
+            label: relType.label_b_a,
             value: relType.id + '_a_b'
           });
+
+          if (!isBidirectionalRelationship) {
+            result.push({
+              label: relType.label_a_b,
+              value: relType.id + '_b_a'
+            });
+          }
+        }
+        // TODO The ids below really should use names not labels see
+        //  https://lab.civicrm.org/dev/core/issues/774
+        else {
+          result.push({
+            text: relType.label_b_a,
+            id: relType.label_a_b
+          });
+
+          if (!isBidirectionalRelationship) {
+            result.push({
+              text: relType.label_a_b,
+              id: relType.label_b_a
+            });
+          }
         }
       }, []);
     }
@@ -327,6 +348,15 @@
           }
         });
       });
+
+      // go lookup and add client-perspective labels for $scope.caseType.definition.caseRoles
+      _.each($scope.caseType.definition.caseRoles, function (set) {
+        _.each($scope.relationshipTypeOptions, function (relTypes) {
+          if (relTypes.text == set.name) {
+            set.displaylabel = relTypes.id;
+          }
+        });
+      });
     }
 
     /// initializes the selected statuses
@@ -427,18 +457,28 @@
       activity.default_assignee_contact = null;
     };
 
+    // TODO roleName passed to addRole is a misnomer, its passed as the
+    // label HOWEVER it should be saved to xml as the name see
+    // https://lab.civicrm.org/dev/core/issues/774
+
     /// Add a new role
     $scope.addRole = function(roles, roleName) {
       var names = _.pluck($scope.caseType.definition.caseRoles, 'name');
       if (!_.contains(names, roleName)) {
-        if (_.where($scope.relationshipTypeOptions, {id: roleName}).length) {
-          roles.push({name: roleName});
+        var matchingRoles = _.filter($scope.relationshipTypeOptions, {id: roleName});
+        if (matchingRoles.length) {
+          var matchingRole = matchingRoles.shift();
+          roles.push({name: roleName, displaylabel: matchingRole.text});
         } else {
-          CRM.loadForm(CRM.url('civicrm/admin/reltype', {action: 'add', reset: 1, label_a_b: roleName, label_b_a: roleName}))
+           CRM.loadForm(CRM.url('civicrm/admin/reltype', {action: 'add', reset: 1, label_a_b: roleName}))
             .on('crmFormSuccess', function(e, data) {
               var newType = _.values(data.relationshipType)[0];
-              roles.push({name: newType[REL_TYPE_CNAME]});
-              $scope.relationshipTypeOptions.push({id: newType[REL_TYPE_CNAME], text: newType.label_b_a});
+              roles.push({name: newType.label_b_a, displaylabel: newType.label_a_b});
+              // Assume that the case role should be A-B but add both directions as options.
+              $scope.relationshipTypeOptions.push({id: newType.label_a_b, text: newType.label_a_b});
+              if (newType.label_a_b != newType.label_b_a) {
+                $scope.relationshipTypeOptions.push({id: newType.label_b_a, text: newType.label_b_a});
+              }
               $scope.$digest();
             });
         }
@@ -534,6 +574,13 @@
         $scope.caseType.definition.activityAsgmtGrps = $scope.caseType.definition.activityAsgmtGrps.toString().split(",");
       }
 
+      function dropDisplaylabel (v) {
+        delete v.displaylabel;
+      }
+
+      // strip out labels from $scope.caseType.definition.caseRoles
+      _.map($scope.caseType.definition.caseRoles, dropDisplaylabel);
+
       var result = crmApi('CaseType', 'create', $scope.caseType, true);
       result.then(function(data) {
         if (data.is_error === 0 || data.is_error == '0') {
diff --git a/civicrm/ang/crmCaseType/caseTypeDetails.html b/civicrm/ang/crmCaseType/caseTypeDetails.html
index 0f74ff9a9b72b566052024bc322a9f3433c764e7..d11cc913c30604811727284dab98e429f6f77114 100644
--- a/civicrm/ang/crmCaseType/caseTypeDetails.html
+++ b/civicrm/ang/crmCaseType/caseTypeDetails.html
@@ -63,6 +63,5 @@ The original form used table layout; don't know if we have an alternative, CSS-b
         </div>
       </div>
     </fieldset>
-    </div>
   </div>
 </div>
diff --git a/civicrm/ang/crmCaseType/rolesTable.html b/civicrm/ang/crmCaseType/rolesTable.html
index cc64a60a8eb60c0170496d003411225c04559bc3..e7edee076e6ec7d905b9fb39163f2c2471764f97 100644
--- a/civicrm/ang/crmCaseType/rolesTable.html
+++ b/civicrm/ang/crmCaseType/rolesTable.html
@@ -13,7 +13,8 @@ Required vars: caseType
   </thead>
   <tbody>
 	  <tr ng-repeat="relType in caseType.definition.caseRoles | orderBy:'name'" ng-class-even="'crm-entity even-row even'" ng-class-odd="'crm-entity odd-row odd'">
-	    <td>{{relType.name}}</td>
+      <!-- display label (client-perspective) -->
+	    <td>{{relType.displaylabel}}</td>
 	    <td><input type="checkbox" ng-model="relType.creator" ng-true-value="'1'" ng-false-value="'0'"></td>
 	    <td><input type="radio" ng-model="relType.manager" value="1" ng-change="onManagerChange(relType)"></td>
 	    <td>
diff --git a/civicrm/api/v3/Address.php b/civicrm/api/v3/Address.php
index c480aee939893ce505cade71c1e6bd19ae7d5513..05586e2c37ddd429f2ec1216bc8725c75dc4feb7 100644
--- a/civicrm/api/v3/Address.php
+++ b/civicrm/api/v3/Address.php
@@ -42,7 +42,7 @@
  * @return array
  *   API result array
  */
-function civicrm_api3_address_create(&$params) {
+function civicrm_api3_address_create($params) {
   _civicrm_api3_check_edit_permissions('CRM_Core_BAO_Address', $params);
   /**
    * If street_parsing, street_address has to be parsed into
@@ -163,6 +163,6 @@ function civicrm_api3_address_delete($params) {
  * @return array
  *   API result array
  */
-function civicrm_api3_address_get(&$params) {
+function civicrm_api3_address_get($params) {
   return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, TRUE, 'Address');
 }
diff --git a/civicrm/api/v3/Contact.php b/civicrm/api/v3/Contact.php
index e52a46093f92ae2a65da993bb9337aa9ea99f941..3c2fc5bed28f07efda93bdbad960bf5de36a36e8 100644
--- a/civicrm/api/v3/Contact.php
+++ b/civicrm/api/v3/Contact.php
@@ -67,18 +67,6 @@ function civicrm_api3_contact_create($params) {
     return $values;
   }
 
-  if (array_key_exists('api_key', $params) && !empty($params['check_permissions'])) {
-    if (CRM_Core_Permission::check('edit api keys') || CRM_Core_Permission::check('administer CiviCRM')) {
-      // OK
-    }
-    elseif ($contactID && CRM_Core_Permission::check('edit own api keys') && CRM_Core_Session::singleton()->get('userID') == $contactID) {
-      // OK
-    }
-    else {
-      throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify api key');
-    }
-  }
-
   if (!$contactID) {
     // If we get here, we're ready to create a new contact
     if (($email = CRM_Utils_Array::value('email', $params)) && !is_array($params['email'])) {
@@ -129,8 +117,6 @@ function civicrm_api3_contact_create($params) {
     _civicrm_api3_object_to_array_unique_fields($contact, $values[$contact->id]);
   }
 
-  $values = _civicrm_api3_contact_formatResult($params, $values);
-
   return civicrm_api3_create_success($values, $params, 'Contact', 'create');
 }
 
@@ -182,37 +168,10 @@ function civicrm_api3_contact_get($params) {
   $options = [];
   _civicrm_api3_contact_get_supportanomalies($params, $options);
   $contacts = _civicrm_api3_get_using_query_object('Contact', $params, $options);
-  $contacts = _civicrm_api3_contact_formatResult($params, $contacts);
-  return civicrm_api3_create_success($contacts, $params, 'Contact');
-}
-
-/**
- * Filter the result.
- *
- * @param array $result
- *
- * @return array
- * @throws \CRM_Core_Exception
- */
-function _civicrm_api3_contact_formatResult($params, $result) {
-  $apiKeyPerms = ['edit api keys', 'administer CiviCRM'];
-  $allowApiKey = empty($params['check_permissions']) || CRM_Core_Permission::check([$apiKeyPerms]);
-  if (!$allowApiKey) {
-    if (is_array($result)) {
-      // Single-value $result
-      if (isset($result['api_key'])) {
-        unset($result['api_key']);
-      }
-
-      // Multi-value $result
-      foreach ($result as $key => $row) {
-        if (is_array($row)) {
-          unset($result[$key]['api_key']);
-        }
-      }
-    }
+  if (!empty($params['check_permissions'])) {
+    CRM_Contact_BAO_Contact::unsetProtectedFields($contacts);
   }
-  return $result;
+  return civicrm_api3_create_success($contacts, $params, 'Contact');
 }
 
 /**
@@ -1252,89 +1211,15 @@ function _civicrm_api3_contact_merge_spec(&$params) {
  */
 function civicrm_api3_contact_get_merge_conflicts($params) {
   $migrationInfo = [];
-  $contactFieldsToCompare = [];
-  $entitiesToCompare = [];
-  $return = [];
+  $result = [];
   foreach ((array) $params['mode'] as $mode) {
-    $result[$mode] = CRM_Dedupe_Merger::getConflicts(
+    $result[$mode]['conflicts'] = CRM_Dedupe_Merger::getConflicts(
       $migrationInfo,
       $params['to_remove_id'], $params['to_keep_id'],
-      $params['mode']
+      $mode
     );
-    $return = [];
-    foreach (array_keys($result[$mode]) as $index) {
-      if (substr($index, 0, 14) === 'move_location_') {
-        $parts = explode('_', $index);
-        $entity = $parts[2];
-        $locationTypeID = $migrationInfo['location_blocks'][$entity][$parts[3]]['locTypeId'];
-        $return[$mode]['conflicts'][$entity][] = ['location_type_id' => $locationTypeID];
-        $entitiesToCompare[$entity][] = $locationTypeID;
-      }
-      elseif (substr($index, 0, 5) === 'move_') {
-        $contactFieldsToCompare[] = str_replace('move_', '', $index);
-        $return[$mode]['conflicts']['contact'][0][str_replace('move_', '', $index)] = [];
-      }
-      else {
-        // Can't think of why this would be the case but perhaps it's ensuring it isn't as we
-        // refactor this.
-        throw new API_Exception(ts('Unknown parameter') . $index);
-      }
-    }
-  }
-  // We get the contact & location details once, now we know what we need for both modes (if both being fetched).
-  $contacts = civicrm_api3('Contact', 'get', [
-    'id' => [
-      'IN' => [
-        $params['to_keep_id'],
-        $params['to_remove_id'],
-      ],
-    ],
-    'return' => $contactFieldsToCompare,
-  ])['values'];
-  foreach ($contactFieldsToCompare as $fieldName) {
-    foreach ((array) $params['mode'] as $mode) {
-      if (isset($return[$mode]['conflicts']['contact'][0][$fieldName])) {
-        $return[$mode]['conflicts']['contact'][0][$fieldName][$params['to_keep_id']] = CRM_Utils_Array::value($fieldName, $contacts[$params['to_keep_id']]);
-        $return[$mode]['conflicts']['contact'][0][$fieldName][$params['to_remove_id']] = CRM_Utils_Array::value($fieldName, $contacts[$params['to_remove_id']]);
-      }
-    }
-  }
-  foreach ($entitiesToCompare as $entity => $locations) {
-    $contactLocationDetails = civicrm_api3($entity, 'get', [
-      'contact_id' => ['IN' => [$params['to_keep_id'], $params['to_remove_id']]],
-      'location_type_id' => ['IN' => $locations],
-    ])['values'];
-    $detailsByLocation = [];
-    foreach ($contactLocationDetails as $locationDetail) {
-      if ((int) $locationDetail['contact_id'] === $params['to_keep_id']) {
-        $detailsByLocation[$locationDetail['location_type_id']]['to_keep'] = $locationDetail;
-      }
-      elseif ((int) $locationDetail['contact_id'] === $params['to_remove_id']) {
-        $detailsByLocation[$locationDetail['location_type_id']]['to_remove'] = $locationDetail;
-      }
-      else {
-        // Can't think of why this would be the case but perhaps it's ensuring it isn't as we
-        // refactor this.
-        throw new API_Exception(ts('Unknown parameter') . $index);
-      }
-    }
-    foreach ((array) $params['mode'] as $mode) {
-      foreach ($return[$mode]['conflicts'][$entity] as $index => $entityData) {
-        $locationTypeID = $entityData['location_type_id'];
-        foreach ($detailsByLocation[$locationTypeID]['to_keep'] as $fieldName => $keepContactValue) {
-          $fieldsToIgnore = ['id', 'contact_id', 'is_primary', 'is_billing', 'manual_geo_code', 'contact_id', 'reset_date', 'hold_date'];
-          if (in_array($fieldName, $fieldsToIgnore)) {
-            continue;
-          }
-          $otherContactValue = $detailsByLocation[$locationTypeID]['to_remove'][$fieldName];
-          if (!empty($keepContactValue) && !empty($otherContactValue) && $keepContactValue !== $otherContactValue) {
-            $return[$mode]['conflicts'][$entity][$index][$fieldName] = [$params['to_keep_id'] => $keepContactValue, $params['to_remove_id'] => $otherContactValue];
-          }
-        }
-      }
-    }
   }
-  return civicrm_api3_create_success($return, $params);
+  return civicrm_api3_create_success($result, $params);
 }
 
 /**
@@ -1356,7 +1241,7 @@ function _civicrm_api3_contact_get_merge_conflicts_spec(&$params) {
   $params['mode'] = [
     'title' => ts('Dedupe mode'),
     'description' => ts("'safe' or 'aggressive'  - these modes map to the merge actions & may affect resolution done by hooks "),
-    'api.default' => ['safe'],
+    'api.default' => 'safe',
   ];
 }
 
diff --git a/civicrm/api/v3/Contribution.php b/civicrm/api/v3/Contribution.php
index 8366a44528cad7e9f00a223d29d137c53050ffa7..f59951194cb7a278f41774fd31ae6c2a19594cc6 100644
--- a/civicrm/api/v3/Contribution.php
+++ b/civicrm/api/v3/Contribution.php
@@ -41,7 +41,7 @@
  * @return array
  *   Api result array
  */
-function civicrm_api3_contribution_create(&$params) {
+function civicrm_api3_contribution_create($params) {
   $values = [];
   _civicrm_api3_custom_format_params($params, $values, 'Contribution');
   $params = array_merge($params, $values);
@@ -294,7 +294,7 @@ function civicrm_api3_contribution_get($params) {
 function _civicrm_api3_contribution_get_support_nonunique_returns($params) {
   $additionalOptions = [];
   $options = _civicrm_api3_get_options_from_params($params, TRUE);
-  foreach (['check_number', 'address_id'] as $changedVariable) {
+  foreach (['check_number', 'address_id', 'cancel_date'] as $changedVariable) {
     if (isset($options['return']) && !empty($options['return'][$changedVariable])) {
       $additionalOptions['return']['contribution_' . $changedVariable] = 1;
     }
@@ -316,6 +316,7 @@ function _civicrm_api3_contribution_add_supported_fields(&$contribution) {
     'contribution_check_number' => 'check_number',
     'contribution_address_id' => 'address_id',
     'payment_instrument_id' => 'instrument_id',
+    'contribution_cancel_date' => 'cancel_date',
   ];
   foreach ($outputAliases as $returnName => $copyTo) {
     if (array_key_exists($returnName, $contribution)) {
@@ -533,7 +534,7 @@ function _civicrm_api3_contribution_sendconfirmation_spec(&$params) {
  * @throws \CRM_Core_Exception
  * @throws \Exception
  */
-function civicrm_api3_contribution_completetransaction(&$params) {
+function civicrm_api3_contribution_completetransaction($params) {
   $input = $ids = [];
   if (isset($params['payment_processor_id'])) {
     $input['payment_processor_id'] = $params['payment_processor_id'];
@@ -628,7 +629,7 @@ function _civicrm_api3_contribution_completetransaction_spec(&$params) {
  *   Api result array.
  * @throws API_Exception
  */
-function civicrm_api3_contribution_repeattransaction(&$params) {
+function civicrm_api3_contribution_repeattransaction($params) {
   $input = $ids = [];
   civicrm_api3_verify_one_mandatory($params, NULL, ['contribution_recur_id', 'original_contribution_id']);
   if (empty($params['original_contribution_id'])) {
diff --git a/civicrm/api/v3/Dedupe.php b/civicrm/api/v3/Dedupe.php
index 0a27dcffeb0ae8447094b2a37059a32aada12f7c..00992069184055a2c76082a58ee96c3aa41189c9 100644
--- a/civicrm/api/v3/Dedupe.php
+++ b/civicrm/api/v3/Dedupe.php
@@ -51,7 +51,7 @@ function civicrm_api3_dedupe_get($params) {
   }
   foreach ($result as $index => $values) {
     if (isset($values['data']) && !empty($values['data'])) {
-      $result[$index]['data'] = unserialize($values['data']);
+      $result[$index]['data'] = CRM_Core_DAO::unSerializeField($values['data'], CRM_Core_DAO::SERIALIZE_PHP);
     }
   }
   return civicrm_api3_create_success($result, $params, 'PrevNextCache');
diff --git a/civicrm/api/v3/Email.php b/civicrm/api/v3/Email.php
index 095e082e7365e83de225ebbf719c9add9bfaaf7a..d1dd4ab669733a5a702393e10697b3ed2c02f9dc 100644
--- a/civicrm/api/v3/Email.php
+++ b/civicrm/api/v3/Email.php
@@ -57,6 +57,10 @@ function _civicrm_api3_email_create_spec(&$params) {
   $params['is_primary']['api.default'] = 0;
   $params['email']['api.required'] = 1;
   $params['contact_id']['api.required'] = 1;
+  $defaultLocation = CRM_Core_BAO_LocationType::getDefault();
+  if ($defaultLocation) {
+    $params['location_type_id']['api.default'] = $defaultLocation->id;
+  }
 }
 
 /**
diff --git a/civicrm/api/v3/Order.php b/civicrm/api/v3/Order.php
index e895e0fc1146d5ee3d6afd868f3be97d8b663a49..6d3b4bad5e36fce3c2b1d7395bc378c775699934 100644
--- a/civicrm/api/v3/Order.php
+++ b/civicrm/api/v3/Order.php
@@ -84,7 +84,7 @@ function _civicrm_api3_order_get_spec(&$params) {
  * @return array
  *   Api result array
  */
-function civicrm_api3_order_create(&$params) {
+function civicrm_api3_order_create($params) {
 
   $entity = NULL;
   $entityIds = [];
diff --git a/civicrm/api/v3/Payment.php b/civicrm/api/v3/Payment.php
index 73143111474d898f4cd1baafbeddf650fe1752c4..a2deaf562c77c84ddc4172074e4c7f5cea207d50 100644
--- a/civicrm/api/v3/Payment.php
+++ b/civicrm/api/v3/Payment.php
@@ -84,7 +84,7 @@ function civicrm_api3_payment_get($params) {
  * @return array
  *   Api result array
  */
-function civicrm_api3_payment_delete(&$params) {
+function civicrm_api3_payment_delete($params) {
   return civicrm_api3('FinancialTrxn', 'delete', $params);
 }
 
@@ -98,7 +98,7 @@ function civicrm_api3_payment_delete(&$params) {
  * @return array
  *   Api result array
  */
-function civicrm_api3_payment_cancel(&$params) {
+function civicrm_api3_payment_cancel($params) {
   $eftParams = [
     'entity_table' => 'civicrm_contribution',
     'financial_trxn_id' => $params['id'],
@@ -130,7 +130,7 @@ function civicrm_api3_payment_cancel(&$params) {
  * @return array
  *   Api result array
  */
-function civicrm_api3_payment_create(&$params) {
+function civicrm_api3_payment_create($params) {
   // Check if it is an update
   if (CRM_Utils_Array::value('id', $params)) {
     $amount = $params['total_amount'];
diff --git a/civicrm/api/v3/PledgePayment.php b/civicrm/api/v3/PledgePayment.php
index 4301305a6640ab58f7a2c1fb2a8afddb942ea156..3f43f4e40c4bf717fe37e8b1ce88402000844359 100644
--- a/civicrm/api/v3/PledgePayment.php
+++ b/civicrm/api/v3/PledgePayment.php
@@ -118,17 +118,3 @@ function civicrm_api3_pledge_payment_get($params) {
 
   return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
 }
-
-/**
- * Gets field for civicrm_pledge_payment functions.
- *
- * @param array $params
- *   Modifiable list of fields allowed for the PledgePayment.get action.
- */
-function civicrm_api3_pledge_payment_get_spec(&$params) {
-  $params['option.create_new'] = [
-    'title' => "Create New",
-    'description' => "Create new field rather than update an unpaid payment",
-    'type' => CRM_Utils_Type::T_BOOLEAN,
-  ];
-}
diff --git a/civicrm/api/v3/Setting.php b/civicrm/api/v3/Setting.php
index a7ce04b76fcd4356bdd4268096e20674851b1897..88e05cfad683104cae438cc9355dac45e129c50e 100644
--- a/civicrm/api/v3/Setting.php
+++ b/civicrm/api/v3/Setting.php
@@ -109,7 +109,7 @@ function _civicrm_api3_setting_getfields_spec(&$params) {
  * @throws \CiviCRM_API3_Exception
  * @throws \Exception
  */
-function civicrm_api3_setting_getdefaults(&$params) {
+function civicrm_api3_setting_getdefaults($params) {
   $settings = civicrm_api3('Setting', 'getfields', $params);
   $domains = _civicrm_api3_setting_getDomainArray($params);
   $defaults = [];
@@ -166,7 +166,7 @@ function civicrm_api3_setting_getoptions($params) {
  * @return array
  * @throws \Exception
  */
-function civicrm_api3_setting_revert(&$params) {
+function civicrm_api3_setting_revert($params) {
   $defaults = civicrm_api('Setting', 'getdefaults', $params);
   $fields = civicrm_api('Setting', 'getfields', $params);
   $fields = $fields['values'];
@@ -216,7 +216,7 @@ function _civicrm_api3_setting_revert_spec(&$params) {
  * @throws \CiviCRM_API3_Exception
  * @throws \Exception
  */
-function civicrm_api3_setting_fill(&$params) {
+function civicrm_api3_setting_fill($params) {
   $defaults = civicrm_api3('Setting', 'getdefaults', $params);
   $domains = _civicrm_api3_setting_getDomainArray($params);
   $result = [];
diff --git a/civicrm/api/v3/SurveyRespondant.php b/civicrm/api/v3/SurveyRespondant.php
index 5fccf6bc6f57a2d6f9388f60e0d10ce3ba903482..dd9b4fd7fd674d14b817e2f5eb62e8bda7eeb4be 100644
--- a/civicrm/api/v3/SurveyRespondant.php
+++ b/civicrm/api/v3/SurveyRespondant.php
@@ -54,7 +54,7 @@ function _civicrm_api3_survey_respondant_deprecation() {
  *
  * @return array
  */
-function civicrm_api3_survey_respondant_get(&$params) {
+function civicrm_api3_survey_respondant_get($params) {
 
   civicrm_api3_verify_one_mandatory($params, NULL, ['survey_id', 'id']);
 
diff --git a/civicrm/api/v3/System.php b/civicrm/api/v3/System.php
index 35238776820f4ffd12e90c16c7f936c02329938d..54faf069a1a39184c3ddfd3b9516964559a64c98 100644
--- a/civicrm/api/v3/System.php
+++ b/civicrm/api/v3/System.php
@@ -413,6 +413,13 @@ function _civicrm_api3_system_updatelogtables_spec(&$params) {
     'title' => 'Update Engine Config if changed?',
     'description' => 'By default, we only update if the ENGINE has changed, set this to TRUE to update if the ENGINE_CONFIG has changed.',
     'type' => CRM_Utils_Type::T_BOOLEAN,
+    'api.default' => FALSE,
+  ];
+  $params['forceEngineMigration'] = [
+    'title' => 'Force storage engine to upgrade to InnoDB?',
+    'description' => 'Older versions of CiviCRM used the ARCHIVE engine by default. Set this to TRUE to migrate the engine to the new default.',
+    'type' => CRM_Utils_Type::T_BOOLEAN,
+    'api.default' => FALSE,
   ];
 }
 
diff --git a/civicrm/api/v3/utils.php b/civicrm/api/v3/utils.php
index f28c07aeedf2f49387ddfe6caa234953aeabc3f7..5a8c0e54b75c6679425ed21816b1da15db8fc660 100644
--- a/civicrm/api/v3/utils.php
+++ b/civicrm/api/v3/utils.php
@@ -173,6 +173,10 @@ function civicrm_api3_create_success($values = 1, $params = [], $entity = NULL,
         // 4.3 legacy handling.
         $values[$key]['contribution_type_id'] = $item['financial_type_id'];
       }
+      if (!empty($item['contribution_cancel_date'])) {
+        // 5.16 legacy handling.
+        $values[$key]['cancel_date'] = $item['contribution_cancel_date'];
+      }
       if (!empty($item['next_sched_contribution_date'])) {
         // 4.4 legacy handling
         $values[$key]['next_sched_contribution'] = $item['next_sched_contribution_date'];
diff --git a/civicrm/bower.json b/civicrm/bower.json
index 80a5dbc3adee55847c6303d40f6dd10339eed05b..75e67552ef9e45a1fb85bc5491478d3526c406ee 100644
--- a/civicrm/bower.json
+++ b/civicrm/bower.json
@@ -33,7 +33,9 @@
     "smartmenus": "~1.1",
     "phantomjs-polyfill": "^0.0.2",
     "es6-promise": "^4.2.4",
-    "angular-xeditable": "^0.9.0"
+    "angular-xeditable": "^0.9.0",
+    "checklist-model": "~1",
+    "css-color-names": "~1"
   },
   "resolutions": {
     "angular": "~1.5.11",
diff --git a/civicrm/bower_components/checklist-model/.bower.json b/civicrm/bower_components/checklist-model/.bower.json
new file mode 100644
index 0000000000000000000000000000000000000000..94fdf460f46f533ee570fca6551b1bdce19ed559
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/.bower.json
@@ -0,0 +1,30 @@
+{
+  "name": "checklist-model",
+  "version": "1.0.0",
+  "description": "AngularJS directive for list of checkboxes",
+  "author": "https://github.com/vitalets",
+  "license": "MIT",
+  "homepage": "http://vitalets.github.io/checklist-model",
+  "main": "checklist-model.js",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "docs",
+    "Gruntfile.js",
+    "index.html",
+    "package.json"
+  ],
+  "dependencies": {
+    "angular": ">=1.0.8"
+  },
+  "devDependencies": {},
+  "_release": "1.0.0",
+  "_resolution": {
+    "type": "version",
+    "tag": "1.0.0",
+    "commit": "a8d28276ec7fa697947074ab7d8c5ec3de0c3bb4"
+  },
+  "_source": "https://github.com/vitalets/checklist-model.git",
+  "_target": "~1",
+  "_originalSource": "checklist-model"
+}
\ No newline at end of file
diff --git a/civicrm/bower_components/checklist-model/LICENSE.txt b/civicrm/bower_components/checklist-model/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..60d185fe361788078426c4efcd9fbfbac778dac9
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/LICENSE.txt
@@ -0,0 +1,23 @@
+
+
+The MIT License (MIT)
+
+Copyright (c) 2014 https://github.com/vitalets
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/civicrm/bower_components/checklist-model/bower.json b/civicrm/bower_components/checklist-model/bower.json
new file mode 100644
index 0000000000000000000000000000000000000000..f6f7c9ea03722d93834cffff4f99489be4ff80ff
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/bower.json
@@ -0,0 +1,22 @@
+{
+  "name": "checklist-model",
+  "version": "1.0.0",
+  "description": "AngularJS directive for list of checkboxes",
+  "author": "https://github.com/vitalets",
+  "license": "MIT",
+  "homepage": "http://vitalets.github.io/checklist-model",
+  "main": "checklist-model.js",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "docs",
+    "Gruntfile.js",
+    "index.html",
+    "package.json"
+  ],
+  "dependencies": {
+    "angular": ">=1.0.8"
+  },
+  "devDependencies": {
+  }
+}
diff --git a/civicrm/bower_components/checklist-model/checklist-model.js b/civicrm/bower_components/checklist-model/checklist-model.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab5b700555e1bf65711d739a478fadd14cad6051
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/checklist-model.js
@@ -0,0 +1,175 @@
+/**
+ * Checklist-model
+ * AngularJS directive for list of checkboxes
+ * https://github.com/vitalets/checklist-model
+ * License: MIT http://opensource.org/licenses/MIT
+ */
+
+ /* commonjs package manager support (eg componentjs) */
+ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
+   module.exports = 'checklist-model';
+ }
+
+angular.module('checklist-model', [])
+.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
+  // contains
+  function contains(arr, item, comparator) {
+    if (angular.isArray(arr)) {
+      for (var i = arr.length; i--;) {
+        if (comparator(arr[i], item)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  // add
+  function add(arr, item, comparator) {
+    arr = angular.isArray(arr) ? arr : [];
+      if(!contains(arr, item, comparator)) {
+          arr.push(item);
+      }
+    return arr;
+  }
+
+  // remove
+  function remove(arr, item, comparator) {
+    if (angular.isArray(arr)) {
+      for (var i = arr.length; i--;) {
+        if (comparator(arr[i], item)) {
+          arr.splice(i, 1);
+          break;
+        }
+      }
+    }
+    return arr;
+  }
+
+  // http://stackoverflow.com/a/19228302/1458162
+  function postLinkFn(scope, elem, attrs) {
+     // exclude recursion, but still keep the model
+    var checklistModel = attrs.checklistModel;
+    attrs.$set("checklistModel", null);
+    // compile with `ng-model` pointing to `checked`
+    $compile(elem)(scope);
+    attrs.$set("checklistModel", checklistModel);
+
+    // getter for original model
+    var checklistModelGetter = $parse(checklistModel);
+    var checklistChange = $parse(attrs.checklistChange);
+    var checklistBeforeChange = $parse(attrs.checklistBeforeChange);
+    var ngModelGetter = $parse(attrs.ngModel);
+
+
+
+    var comparator = function (a, b) {
+      if(!isNaN(a) && !isNaN(b)) {
+        return String(a) === String(b);
+      } else {
+        return angular.equals(a,b);
+      }
+    };
+
+    if (attrs.hasOwnProperty('checklistComparator')){
+      if (attrs.checklistComparator[0] == '.') {
+        var comparatorExpression = attrs.checklistComparator.substring(1);
+        comparator = function (a, b) {
+          return a[comparatorExpression] === b[comparatorExpression];
+        };
+
+      } else {
+        comparator = $parse(attrs.checklistComparator)(scope.$parent);
+      }
+    }
+
+    // watch UI checked change
+    var unbindModel = scope.$watch(attrs.ngModel, function(newValue, oldValue) {
+      if (newValue === oldValue) {
+        return;
+      }
+
+      if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) {
+        ngModelGetter.assign(scope, contains(checklistModelGetter(scope.$parent), getChecklistValue(), comparator));
+        return;
+      }
+
+      setValueInChecklistModel(getChecklistValue(), newValue);
+
+      if (checklistChange) {
+        checklistChange(scope);
+      }
+    });
+
+    // watches for value change of checklistValue
+    var unbindCheckListValue = scope.$watch(getChecklistValue, function(newValue, oldValue) {
+      if( newValue != oldValue && angular.isDefined(oldValue) && scope[attrs.ngModel] === true ) {
+        var current = checklistModelGetter(scope.$parent);
+        checklistModelGetter.assign(scope.$parent, remove(current, oldValue, comparator));
+        checklistModelGetter.assign(scope.$parent, add(current, newValue, comparator));
+      }
+    }, true);
+
+    var unbindDestroy = scope.$on('$destroy', destroy);
+
+    function destroy() {
+      unbindModel();
+      unbindCheckListValue();
+      unbindDestroy();
+    }
+
+    function getChecklistValue() {
+      return attrs.checklistValue ? $parse(attrs.checklistValue)(scope.$parent) : attrs.value;
+    }
+
+    function setValueInChecklistModel(value, checked) {
+      var current = checklistModelGetter(scope.$parent);
+      if (angular.isFunction(checklistModelGetter.assign)) {
+        if (checked === true) {
+          checklistModelGetter.assign(scope.$parent, add(current, value, comparator));
+        } else {
+          checklistModelGetter.assign(scope.$parent, remove(current, value, comparator));
+        }
+      }
+
+    }
+
+    // declare one function to be used for both $watch functions
+    function setChecked(newArr, oldArr) {
+      if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) {
+        setValueInChecklistModel(getChecklistValue(), ngModelGetter(scope));
+        return;
+      }
+      ngModelGetter.assign(scope, contains(newArr, getChecklistValue(), comparator));
+    }
+
+    // watch original model change
+    // use the faster $watchCollection method if it's available
+    if (angular.isFunction(scope.$parent.$watchCollection)) {
+        scope.$parent.$watchCollection(checklistModel, setChecked);
+    } else {
+        scope.$parent.$watch(checklistModel, setChecked, true);
+    }
+  }
+
+  return {
+    restrict: 'A',
+    priority: 1000,
+    terminal: true,
+    scope: true,
+    compile: function(tElement, tAttrs) {
+
+      if (!tAttrs.checklistValue && !tAttrs.value) {
+        throw 'You should provide `value` or `checklist-value`.';
+      }
+
+      // by default ngModel is 'checked', so we set it if not specified
+      if (!tAttrs.ngModel) {
+        // local scope var storing individual checkbox model
+        tAttrs.$set("ngModel", "checked");
+      }
+
+      return postLinkFn;
+    }
+  };
+}]);
diff --git a/civicrm/bower_components/checklist-model/checklist-model.nuspec b/civicrm/bower_components/checklist-model/checklist-model.nuspec
new file mode 100644
index 0000000000000000000000000000000000000000..e61c84a80b95ecfe3d891f029db9dc9a4b6939ce
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/checklist-model.nuspec
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
+  <metadata>
+    <id>checklist-model</id>
+    <version>0.11.0</version>
+    <title>AngularJS directive for list of checkboxes</title>
+    <authors>https://github.com/vitalets</authors>
+    <owners>Vitaliy Potapov (noginsk@rambler.ru)</owners>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <description>
+        In Angular one checkbox is linked with one model. But in practice
+        we usually want one model to store array of checked values from
+        several checkboxes. Checklist-model solves that task without
+        additional code in controller.
+    </description>
+    <licenseUrl>https://raw.githubusercontent.com/vitalets/checklist-model/master/LICENSE.txt</licenseUrl>
+    <tags>angularjs checklist model angular-checklist-model checklist-model checklistmodel</tags>
+    <dependencies>
+      <dependency id="AngularJS.Core" version="1.0.8" />
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="checklist-model.js" target="content\Scripts\checklist-model.js" />
+  </files>
+</package>
diff --git a/civicrm/bower_components/checklist-model/package-lock.json b/civicrm/bower_components/checklist-model/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..9740754256ab6b796801ff226699c93a8a26b391
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/package-lock.json
@@ -0,0 +1,3511 @@
+{
+  "name": "checklist-model",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+      "dev": true
+    },
+    "accepts": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
+      "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
+      "dev": true,
+      "requires": {
+        "mime-types": "2.1.18",
+        "negotiator": "0.6.1"
+      }
+    },
+    "acorn": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
+      "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=",
+      "dev": true
+    },
+    "acorn-globals": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz",
+      "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=",
+      "dev": true,
+      "requires": {
+        "acorn": "2.7.0"
+      }
+    },
+    "ajv": {
+      "version": "5.5.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+      "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "co": "4.6.0",
+        "fast-deep-equal": "1.1.0",
+        "fast-json-stable-stringify": "2.0.0",
+        "json-schema-traverse": "0.3.1"
+      }
+    },
+    "align-text": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+      "dev": true,
+      "requires": {
+        "kind-of": "3.2.2",
+        "longest": "1.0.1",
+        "repeat-string": "1.6.1"
+      }
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true
+    },
+    "applause": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/applause/-/applause-1.2.2.tgz",
+      "integrity": "sha1-qEaFeegfZzl7tWNMKZU77c0PVsA=",
+      "dev": true,
+      "requires": {
+        "cson-parser": "1.3.5",
+        "js-yaml": "3.5.5",
+        "lodash": "3.10.1"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "3.10.1",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+          "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+          "dev": true
+        }
+      }
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+      "dev": true
+    },
+    "archiver": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz",
+      "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=",
+      "dev": true,
+      "requires": {
+        "archiver-utils": "1.3.0",
+        "async": "2.6.0",
+        "buffer-crc32": "0.2.13",
+        "glob": "7.0.6",
+        "lodash": "4.17.5",
+        "readable-stream": "2.3.5",
+        "tar-stream": "1.5.5",
+        "walkdir": "0.0.11",
+        "zip-stream": "1.2.0"
+      },
+      "dependencies": {
+        "async": {
+          "version": "2.6.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
+          "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
+          "dev": true,
+          "requires": {
+            "lodash": "4.17.5"
+          }
+        }
+      }
+    },
+    "archiver-utils": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz",
+      "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=",
+      "dev": true,
+      "requires": {
+        "glob": "7.0.6",
+        "graceful-fs": "4.1.11",
+        "lazystream": "1.0.0",
+        "lodash": "4.17.5",
+        "normalize-path": "2.1.1",
+        "readable-stream": "2.3.5"
+      }
+    },
+    "are-we-there-yet": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
+      "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+      "dev": true,
+      "requires": {
+        "delegates": "1.0.0",
+        "readable-stream": "2.3.5"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "1.0.3"
+      },
+      "dependencies": {
+        "sprintf-js": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+          "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+          "dev": true
+        }
+      }
+    },
+    "array-find-index": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+      "dev": true
+    },
+    "asap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz",
+      "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=",
+      "dev": true
+    },
+    "asn1": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+      "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+      "dev": true,
+      "optional": true
+    },
+    "assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+      "dev": true
+    },
+    "async": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+      "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+      "dev": true
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true,
+      "optional": true
+    },
+    "aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+      "dev": true,
+      "optional": true
+    },
+    "aws4": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+      "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
+      "dev": true,
+      "optional": true
+    },
+    "babylon": {
+      "version": "7.0.0-beta.19",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz",
+      "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "basic-auth": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
+      "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "batch": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+      "dev": true
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+      "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "tweetnacl": "0.14.5"
+      }
+    },
+    "bl": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+      "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "2.3.5",
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "block-stream": {
+      "version": "0.0.9",
+      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "inherits": "2.0.3"
+      }
+    },
+    "bluebird": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+      "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",
+      "dev": true
+    },
+    "body-parser": {
+      "version": "1.14.2",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz",
+      "integrity": "sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk=",
+      "dev": true,
+      "requires": {
+        "bytes": "2.2.0",
+        "content-type": "1.0.4",
+        "debug": "2.2.0",
+        "depd": "1.1.2",
+        "http-errors": "1.3.1",
+        "iconv-lite": "0.4.13",
+        "on-finished": "2.3.0",
+        "qs": "5.2.0",
+        "raw-body": "2.1.7",
+        "type-is": "1.6.16"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+          "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+          "dev": true,
+          "requires": {
+            "ms": "0.7.1"
+          }
+        },
+        "http-errors": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+          "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+          "dev": true,
+          "requires": {
+            "inherits": "2.0.3",
+            "statuses": "1.3.1"
+          }
+        },
+        "iconv-lite": {
+          "version": "0.4.13",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+          "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=",
+          "dev": true
+        },
+        "ms": {
+          "version": "0.7.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+          "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
+          "dev": true
+        },
+        "qs": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz",
+          "integrity": "sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4=",
+          "dev": true
+        }
+      }
+    },
+    "boom": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
+      "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "hoek": "4.2.1"
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "browserify-zlib": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+      "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
+      "dev": true,
+      "requires": {
+        "pako": "0.2.9"
+      }
+    },
+    "buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+      "dev": true
+    },
+    "buffer-from": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
+      "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==",
+      "dev": true
+    },
+    "builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+      "dev": true
+    },
+    "bytes": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz",
+      "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+      "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+      "dev": true,
+      "requires": {
+        "camelcase": "2.1.1",
+        "map-obj": "1.0.1"
+      }
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+      "dev": true,
+      "optional": true
+    },
+    "catharsis": {
+      "version": "0.8.9",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz",
+      "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=",
+      "dev": true,
+      "requires": {
+        "underscore-contrib": "0.3.0"
+      }
+    },
+    "center-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+      "dev": true,
+      "requires": {
+        "align-text": "0.1.4",
+        "lazy-cache": "1.0.4"
+      }
+    },
+    "chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "2.2.1",
+        "escape-string-regexp": "1.0.5",
+        "has-ansi": "2.0.0",
+        "strip-ansi": "3.0.1",
+        "supports-color": "2.0.0"
+      }
+    },
+    "character-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz",
+      "integrity": "sha1-wN3kqxgnE7kZuXCVmhI+zBow/NY=",
+      "dev": true
+    },
+    "chownr": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
+      "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
+      "dev": true,
+      "optional": true
+    },
+    "clean-css": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz",
+      "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=",
+      "dev": true,
+      "requires": {
+        "source-map": "0.5.7"
+      }
+    },
+    "cli": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
+      "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=",
+      "dev": true,
+      "requires": {
+        "exit": "0.1.2",
+        "glob": "7.1.2"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.2",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+          "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        }
+      }
+    },
+    "cliui": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+      "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+      "dev": true,
+      "requires": {
+        "center-align": "0.1.3",
+        "right-align": "0.1.3",
+        "wordwrap": "0.0.2"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+          "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+          "dev": true
+        }
+      }
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "dev": true,
+      "optional": true
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+      "dev": true
+    },
+    "coffeescript": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
+      "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=",
+      "dev": true
+    },
+    "colors": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
+      "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+      "dev": true,
+      "requires": {
+        "delayed-stream": "1.0.0"
+      }
+    },
+    "commander": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz",
+      "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=",
+      "dev": true
+    },
+    "compress-commons": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz",
+      "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=",
+      "dev": true,
+      "requires": {
+        "buffer-crc32": "0.2.13",
+        "crc32-stream": "2.0.0",
+        "normalize-path": "2.1.1",
+        "readable-stream": "2.3.5"
+      }
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "1.0.0",
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.5",
+        "typedarray": "0.0.6"
+      }
+    },
+    "connect": {
+      "version": "3.6.6",
+      "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz",
+      "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "finalhandler": "1.1.0",
+        "parseurl": "1.3.2",
+        "utils-merge": "1.0.1"
+      }
+    },
+    "connect-livereload": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.5.4.tgz",
+      "integrity": "sha1-gBV9E3HJ83zBQDmrGJWXDRGdw7w=",
+      "dev": true
+    },
+    "console-browserify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+      "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+      "dev": true,
+      "requires": {
+        "date-now": "0.1.4"
+      }
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+      "dev": true
+    },
+    "constantinople": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz",
+      "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=",
+      "dev": true,
+      "requires": {
+        "acorn": "2.7.0"
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "crc": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/crc/-/crc-3.5.0.tgz",
+      "integrity": "sha1-mLi6fUiWZbo5efWbITgTdBAaGWQ=",
+      "dev": true
+    },
+    "crc32-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz",
+      "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=",
+      "dev": true,
+      "requires": {
+        "crc": "3.5.0",
+        "readable-stream": "2.3.5"
+      }
+    },
+    "cross-spawn": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
+      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
+      "dev": true,
+      "requires": {
+        "lru-cache": "4.1.2",
+        "which": "1.2.14"
+      }
+    },
+    "cryptiles": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
+      "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "boom": "5.2.0"
+      },
+      "dependencies": {
+        "boom": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
+          "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "hoek": "4.2.1"
+          }
+        }
+      }
+    },
+    "cson-parser": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-1.3.5.tgz",
+      "integrity": "sha1-fsZ14DkUVTO/KmqFYHPxWZ2cLSQ=",
+      "dev": true,
+      "requires": {
+        "coffee-script": "1.12.7"
+      },
+      "dependencies": {
+        "coffee-script": {
+          "version": "1.12.7",
+          "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
+          "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==",
+          "dev": true
+        }
+      }
+    },
+    "css": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz",
+      "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=",
+      "dev": true,
+      "requires": {
+        "css-parse": "1.0.4",
+        "css-stringify": "1.0.5"
+      }
+    },
+    "css-parse": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz",
+      "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=",
+      "dev": true
+    },
+    "css-stringify": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz",
+      "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=",
+      "dev": true
+    },
+    "currently-unhandled": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+      "dev": true,
+      "requires": {
+        "array-find-index": "1.0.2"
+      }
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "1.0.0"
+      }
+    },
+    "date-now": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+      "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+      "dev": true
+    },
+    "dateformat": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
+      "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "4.0.1",
+        "meow": "3.7.0"
+      }
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "decompress-response": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+      "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "mimic-response": "1.0.0"
+      }
+    },
+    "deep-extend": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
+      "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=",
+      "dev": true,
+      "optional": true
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+      "dev": true
+    },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+      "dev": true
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+      "dev": true
+    },
+    "detect-libc": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-0.2.0.tgz",
+      "integrity": "sha1-R/31ZzSKF+wl/L8LnkRjSKdvn7U=",
+      "dev": true,
+      "optional": true
+    },
+    "dom-serializer": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
+      "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1.1.3",
+        "entities": "1.1.1"
+      },
+      "dependencies": {
+        "domelementtype": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
+          "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
+          "dev": true
+        },
+        "entities": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
+          "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
+          "dev": true
+        }
+      }
+    },
+    "domelementtype": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
+      "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
+      "dev": true
+    },
+    "domhandler": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
+      "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1.3.0"
+      }
+    },
+    "domutils": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+      "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "0.1.0",
+        "domelementtype": "1.3.0"
+      }
+    },
+    "duplexer": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+      "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+      "dev": true
+    },
+    "ecc-jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+      "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "jsbn": "0.1.1"
+      }
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+      "dev": true
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true
+    },
+    "end-of-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+      "dev": true,
+      "requires": {
+        "once": "1.4.0"
+      }
+    },
+    "entities": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+      "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
+      "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "0.2.1"
+      }
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "esprima": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+      "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+      "dev": true
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "dev": true
+    },
+    "eventemitter2": {
+      "version": "0.4.14",
+      "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+      "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+      "dev": true
+    },
+    "exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+      "dev": true
+    },
+    "expand-template": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz",
+      "integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ==",
+      "dev": true,
+      "optional": true
+    },
+    "extend": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+      "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
+      "dev": true,
+      "optional": true
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+      "dev": true
+    },
+    "fast-deep-equal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+      "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+      "dev": true,
+      "optional": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true,
+      "optional": true
+    },
+    "faye-websocket": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+      "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+      "dev": true,
+      "requires": {
+        "websocket-driver": "0.7.0"
+      }
+    },
+    "figures": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+      "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "1.0.5",
+        "object-assign": "4.1.1"
+      }
+    },
+    "file-sync-cmp": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz",
+      "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=",
+      "dev": true
+    },
+    "finalhandler": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
+      "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "on-finished": "2.3.0",
+        "parseurl": "1.3.2",
+        "statuses": "1.3.1",
+        "unpipe": "1.0.0"
+      }
+    },
+    "find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+      "dev": true,
+      "requires": {
+        "path-exists": "2.1.0",
+        "pinkie-promise": "2.0.1"
+      }
+    },
+    "findup-sync": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+      "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+      "dev": true,
+      "requires": {
+        "glob": "5.0.15"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "5.0.15",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+          "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+          "dev": true,
+          "requires": {
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        }
+      }
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true,
+      "optional": true
+    },
+    "form-data": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
+      "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "asynckit": "0.4.0",
+        "combined-stream": "1.0.6",
+        "mime-types": "2.1.18"
+      }
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fstream": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
+      "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "inherits": "2.0.3",
+        "mkdirp": "0.5.1",
+        "rimraf": "2.2.8"
+      }
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "dev": true,
+      "requires": {
+        "aproba": "1.2.0",
+        "console-control-strings": "1.1.0",
+        "has-unicode": "2.0.1",
+        "object-assign": "4.1.1",
+        "signal-exit": "3.0.2",
+        "string-width": "1.0.2",
+        "strip-ansi": "3.0.1",
+        "wide-align": "1.1.2"
+      }
+    },
+    "gaze": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz",
+      "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=",
+      "dev": true,
+      "requires": {
+        "globule": "1.2.0"
+      }
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+      "dev": true
+    },
+    "getobject": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+      "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+      "dev": true
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "1.0.0"
+      }
+    },
+    "github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=",
+      "dev": true,
+      "optional": true
+    },
+    "glob": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+      "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "1.0.0",
+        "inflight": "1.0.6",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4",
+        "once": "1.4.0",
+        "path-is-absolute": "1.0.1"
+      }
+    },
+    "globule": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz",
+      "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=",
+      "dev": true,
+      "requires": {
+        "glob": "7.1.2",
+        "lodash": "4.17.5",
+        "minimatch": "3.0.4"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.2",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+          "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        }
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "dev": true
+    },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+      "dev": true
+    },
+    "grunt": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.2.tgz",
+      "integrity": "sha1-TmpeaVtwRy/VME9fqeNCNoNqc7w=",
+      "dev": true,
+      "requires": {
+        "coffeescript": "1.10.0",
+        "dateformat": "1.0.12",
+        "eventemitter2": "0.4.14",
+        "exit": "0.1.2",
+        "findup-sync": "0.3.0",
+        "glob": "7.0.6",
+        "grunt-cli": "1.2.0",
+        "grunt-known-options": "1.1.0",
+        "grunt-legacy-log": "1.0.1",
+        "grunt-legacy-util": "1.0.0",
+        "iconv-lite": "0.4.19",
+        "js-yaml": "3.5.5",
+        "minimatch": "3.0.4",
+        "nopt": "3.0.6",
+        "path-is-absolute": "1.0.1",
+        "rimraf": "2.2.8"
+      }
+    },
+    "grunt-bump": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/grunt-bump/-/grunt-bump-0.8.0.tgz",
+      "integrity": "sha1-0//gzzzws44JYHt4U49CpTHq/lU=",
+      "dev": true,
+      "requires": {
+        "semver": "5.5.0"
+      }
+    },
+    "grunt-cli": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
+      "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
+      "dev": true,
+      "requires": {
+        "findup-sync": "0.3.0",
+        "grunt-known-options": "1.1.0",
+        "nopt": "3.0.6",
+        "resolve": "1.1.7"
+      }
+    },
+    "grunt-contrib-clean": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz",
+      "integrity": "sha1-Vkq/LQN4qYOhW54/MO51tzjEBjg=",
+      "dev": true,
+      "requires": {
+        "async": "1.5.2",
+        "rimraf": "2.6.2"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "2.6.2",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+          "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+          "dev": true,
+          "requires": {
+            "glob": "7.0.6"
+          }
+        }
+      }
+    },
+    "grunt-contrib-compress": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-1.4.3.tgz",
+      "integrity": "sha1-Ac7/ucY39S5wgfRjdQmD0KOw+nM=",
+      "dev": true,
+      "requires": {
+        "archiver": "1.3.0",
+        "chalk": "1.1.3",
+        "iltorb": "1.3.10",
+        "lodash": "4.17.5",
+        "pretty-bytes": "4.0.2",
+        "stream-buffers": "2.2.0"
+      }
+    },
+    "grunt-contrib-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz",
+      "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "source-map": "0.5.7"
+      }
+    },
+    "grunt-contrib-connect": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-1.0.2.tgz",
+      "integrity": "sha1-XPkzuRpnOGBEJzwLJERgPNmIebo=",
+      "dev": true,
+      "requires": {
+        "async": "1.5.2",
+        "connect": "3.6.6",
+        "connect-livereload": "0.5.4",
+        "http2": "3.3.7",
+        "morgan": "1.9.0",
+        "opn": "4.0.2",
+        "portscanner": "1.2.0",
+        "serve-index": "1.9.1",
+        "serve-static": "1.13.2"
+      }
+    },
+    "grunt-contrib-copy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz",
+      "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "file-sync-cmp": "0.1.1"
+      }
+    },
+    "grunt-contrib-cssmin": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-2.2.1.tgz",
+      "integrity": "sha512-IXNomhQ5ekVZbDbj/ik5YccoD9khU6LT2fDXqO1+/Txjq8cp0tQKjVS8i8EAbHOrSDkL7/UD6A7b+xj98gqh9w==",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "clean-css": "4.1.11",
+        "maxmin": "2.1.0"
+      }
+    },
+    "grunt-contrib-jade": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-1.0.0.tgz",
+      "integrity": "sha1-tVe8uc0uczrU4gkOEpvrIBsLhFw=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "jade": "1.11.0"
+      }
+    },
+    "grunt-contrib-jshint": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz",
+      "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "hooker": "0.2.3",
+        "jshint": "2.9.5"
+      }
+    },
+    "grunt-contrib-uglify": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-3.3.0.tgz",
+      "integrity": "sha512-W9O7lJE3PlD8VCc5fyaf98QV7f5wEDiU4PBIh0+/6UBbk2LhgzEFS0/p+taH5UD3+PlEn7QPN0o06Z0To6SqXw==",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "maxmin": "1.1.0",
+        "uglify-js": "3.3.18",
+        "uri-path": "1.0.0"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.15.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
+          "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
+          "dev": true
+        },
+        "gzip-size": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz",
+          "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=",
+          "dev": true,
+          "requires": {
+            "browserify-zlib": "0.1.4",
+            "concat-stream": "1.6.2"
+          }
+        },
+        "maxmin": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz",
+          "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=",
+          "dev": true,
+          "requires": {
+            "chalk": "1.1.3",
+            "figures": "1.7.0",
+            "gzip-size": "1.0.0",
+            "pretty-bytes": "1.0.4"
+          }
+        },
+        "pretty-bytes": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
+          "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
+          "dev": true,
+          "requires": {
+            "get-stdin": "4.0.1",
+            "meow": "3.7.0"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "uglify-js": {
+          "version": "3.3.18",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.18.tgz",
+          "integrity": "sha512-VhjIFv93KnTx/ntNi9yTBbfrsWnQnqUy02MT32uqU/5i2oEJ8GAEJ0AwYV206JeOmIzSjm41Ba0iXVKv6j7y9g==",
+          "dev": true,
+          "requires": {
+            "commander": "2.15.1",
+            "source-map": "0.6.1"
+          }
+        }
+      }
+    },
+    "grunt-contrib-watch": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz",
+      "integrity": "sha1-hKGnodar0m7VaEE0lscxM+mQAY8=",
+      "dev": true,
+      "requires": {
+        "async": "1.5.2",
+        "gaze": "1.1.2",
+        "lodash": "3.10.1",
+        "tiny-lr": "0.2.1"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "3.10.1",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+          "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-jsdoc": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/grunt-jsdoc/-/grunt-jsdoc-2.2.1.tgz",
+      "integrity": "sha512-33QZYBYjv2Ph3H2ygqXHn/o0ttfptw1f9QciOTgvzhzUeiPrnvzMNUApTPtw22T6zgReE5FZ1RR58U2wnK/l+w==",
+      "dev": true,
+      "requires": {
+        "cross-spawn": "3.0.1",
+        "jsdoc": "3.5.5",
+        "marked": "0.3.19"
+      }
+    },
+    "grunt-known-options": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz",
+      "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=",
+      "dev": true
+    },
+    "grunt-legacy-log": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.1.tgz",
+      "integrity": "sha512-rwuyqNKlI0IPz0DvxzJjcEiQEBaBNVeb1LFoZKxSmHLETFUwhwUrqOsPIxURTKSwNZHZ4ht1YLBYmVU0YZAzHQ==",
+      "dev": true,
+      "requires": {
+        "colors": "1.1.2",
+        "grunt-legacy-log-utils": "1.0.0",
+        "hooker": "0.2.3",
+        "lodash": "4.17.5",
+        "underscore.string": "3.3.4"
+      }
+    },
+    "grunt-legacy-log-utils": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz",
+      "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "lodash": "4.3.0"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz",
+          "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-legacy-util": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz",
+      "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=",
+      "dev": true,
+      "requires": {
+        "async": "1.5.2",
+        "exit": "0.1.2",
+        "getobject": "0.1.0",
+        "hooker": "0.2.3",
+        "lodash": "4.3.0",
+        "underscore.string": "3.2.3",
+        "which": "1.2.14"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz",
+          "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=",
+          "dev": true
+        },
+        "underscore.string": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz",
+          "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-replace": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/grunt-replace/-/grunt-replace-1.0.1.tgz",
+      "integrity": "sha1-kKeVMvuJBB/kJ8h9QlI4sPiGZRo=",
+      "dev": true,
+      "requires": {
+        "applause": "1.2.2",
+        "chalk": "1.1.3",
+        "file-sync-cmp": "0.1.1",
+        "lodash": "4.17.5"
+      }
+    },
+    "grunt-shell": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-2.1.0.tgz",
+      "integrity": "sha1-Q595FZ7RHmSmUaacyKPQK+v17MI=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "npm-run-path": "2.0.2"
+      }
+    },
+    "gzip-size": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
+      "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
+      "dev": true,
+      "requires": {
+        "duplexer": "0.1.1"
+      }
+    },
+    "har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+      "dev": true,
+      "optional": true
+    },
+    "har-validator": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
+      "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "ajv": "5.5.2",
+        "har-schema": "2.0.0"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+      "dev": true
+    },
+    "hawk": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
+      "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "boom": "4.3.1",
+        "cryptiles": "3.1.2",
+        "hoek": "4.2.1",
+        "sntp": "2.1.0"
+      }
+    },
+    "hoek": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
+      "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==",
+      "dev": true
+    },
+    "hooker": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+      "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+      "dev": true
+    },
+    "hosted-git-info": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz",
+      "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==",
+      "dev": true
+    },
+    "htmlparser2": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
+      "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1.3.0",
+        "domhandler": "2.3.0",
+        "domutils": "1.5.1",
+        "entities": "1.0.0",
+        "readable-stream": "1.1.14"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "1.1.14",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+          "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+          "dev": true,
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+          "dev": true
+        }
+      }
+    },
+    "http-errors": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+      "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+      "dev": true,
+      "requires": {
+        "depd": "1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.0",
+        "statuses": "1.5.0"
+      },
+      "dependencies": {
+        "statuses": {
+          "version": "1.5.0",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+          "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+          "dev": true
+        }
+      }
+    },
+    "http-parser-js": {
+      "version": "0.4.11",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.11.tgz",
+      "integrity": "sha512-QCR5O2AjjMW8Mo4HyI1ctFcv+O99j/0g367V3YoVnrNw5hkDvAWZD0lWGcc+F4yN3V55USPCVix4efb75HxFfA==",
+      "dev": true
+    },
+    "http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "1.0.0",
+        "jsprim": "1.4.1",
+        "sshpk": "1.14.1"
+      }
+    },
+    "http2": {
+      "version": "3.3.7",
+      "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz",
+      "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==",
+      "dev": true
+    },
+    "iconv-lite": {
+      "version": "0.4.19",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+      "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==",
+      "dev": true
+    },
+    "iltorb": {
+      "version": "1.3.10",
+      "resolved": "https://registry.npmjs.org/iltorb/-/iltorb-1.3.10.tgz",
+      "integrity": "sha512-nyB4+ru1u8CQqQ6w7YjasboKN3NQTN8GH/V/eEssNRKhW6UbdxdWhB9fJ5EEdjJfezKY0qPrcwLyIcgjL8hHxA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "detect-libc": "0.2.0",
+        "nan": "2.10.0",
+        "node-gyp": "3.6.2",
+        "prebuild-install": "2.5.1"
+      }
+    },
+    "indent-string": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+      "dev": true,
+      "requires": {
+        "repeating": "2.0.1"
+      }
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "1.4.0",
+        "wrappy": "1.0.2"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "dev": true,
+      "optional": true
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "dev": true
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-builtin-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+      "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+      "dev": true,
+      "requires": {
+        "builtin-modules": "1.1.1"
+      }
+    },
+    "is-finite": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "1.0.1"
+      }
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "1.0.1"
+      }
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true,
+      "optional": true
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true,
+      "optional": true
+    },
+    "jade": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz",
+      "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=",
+      "dev": true,
+      "requires": {
+        "character-parser": "1.2.1",
+        "clean-css": "3.4.28",
+        "commander": "2.6.0",
+        "constantinople": "3.0.2",
+        "jstransformer": "0.0.2",
+        "mkdirp": "0.5.1",
+        "transformers": "2.1.0",
+        "uglify-js": "2.8.29",
+        "void-elements": "2.0.1",
+        "with": "4.0.3"
+      },
+      "dependencies": {
+        "clean-css": {
+          "version": "3.4.28",
+          "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
+          "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
+          "dev": true,
+          "requires": {
+            "commander": "2.8.1",
+            "source-map": "0.4.4"
+          },
+          "dependencies": {
+            "commander": {
+              "version": "2.8.1",
+              "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+              "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+              "dev": true,
+              "requires": {
+                "graceful-readlink": "1.0.1"
+              }
+            }
+          }
+        },
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "dev": true,
+          "requires": {
+            "amdefine": "1.0.1"
+          }
+        }
+      }
+    },
+    "js-yaml": {
+      "version": "3.5.5",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz",
+      "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=",
+      "dev": true,
+      "requires": {
+        "argparse": "1.0.10",
+        "esprima": "2.7.3"
+      }
+    },
+    "js2xmlparser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz",
+      "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=",
+      "dev": true,
+      "requires": {
+        "xmlcreate": "1.0.2"
+      }
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "dev": true,
+      "optional": true
+    },
+    "jsdoc": {
+      "version": "3.5.5",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz",
+      "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==",
+      "dev": true,
+      "requires": {
+        "babylon": "7.0.0-beta.19",
+        "bluebird": "3.5.1",
+        "catharsis": "0.8.9",
+        "escape-string-regexp": "1.0.5",
+        "js2xmlparser": "3.0.0",
+        "klaw": "2.0.0",
+        "marked": "0.3.19",
+        "mkdirp": "0.5.1",
+        "requizzle": "0.2.1",
+        "strip-json-comments": "2.0.1",
+        "taffydb": "2.6.2",
+        "underscore": "1.8.3"
+      }
+    },
+    "jshint": {
+      "version": "2.9.5",
+      "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz",
+      "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=",
+      "dev": true,
+      "requires": {
+        "cli": "1.0.1",
+        "console-browserify": "1.1.0",
+        "exit": "0.1.2",
+        "htmlparser2": "3.8.3",
+        "lodash": "3.7.0",
+        "minimatch": "3.0.4",
+        "shelljs": "0.3.0",
+        "strip-json-comments": "1.0.4"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "3.7.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz",
+          "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=",
+          "dev": true
+        },
+        "strip-json-comments": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+          "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+          "dev": true
+        }
+      }
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "dev": true,
+      "optional": true
+    },
+    "json-schema-traverse": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+      "dev": true,
+      "optional": true
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true,
+      "optional": true
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      }
+    },
+    "jstransformer": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz",
+      "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=",
+      "dev": true,
+      "requires": {
+        "is-promise": "2.1.0",
+        "promise": "6.1.0"
+      }
+    },
+    "jstransformer-markdown": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/jstransformer-markdown/-/jstransformer-markdown-1.2.1.tgz",
+      "integrity": "sha512-rNLxNC3LIGAc26Qcro73eWoosKymqyNVDn909KIq2QHVHGWZ+d+JzOCrHsmUt3DNAKF+hkJQJ1JufAhFEdZ5gw==",
+      "dev": true,
+      "requires": {
+        "markdown": "0.5.0"
+      }
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "requires": {
+        "is-buffer": "1.1.6"
+      }
+    },
+    "klaw": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz",
+      "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "4.1.11"
+      }
+    },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+      "dev": true
+    },
+    "lazystream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+      "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "2.3.5"
+      }
+    },
+    "livereload-js": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.3.0.tgz",
+      "integrity": "sha512-j1R0/FeGa64Y+NmqfZhyoVRzcFlOZ8sNlKzHjh4VvLULFACZhn68XrX5DFg2FhMvSMJmROuFxRSa560ECWKBMg==",
+      "dev": true
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "parse-json": "2.2.0",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1",
+        "strip-bom": "2.0.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.5",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
+      "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==",
+      "dev": true
+    },
+    "longest": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+      "dev": true
+    },
+    "loud-rejection": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+      "dev": true,
+      "requires": {
+        "currently-unhandled": "0.4.1",
+        "signal-exit": "3.0.2"
+      }
+    },
+    "lru-cache": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
+      "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
+      "dev": true,
+      "requires": {
+        "pseudomap": "1.0.2",
+        "yallist": "2.1.2"
+      }
+    },
+    "map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+      "dev": true
+    },
+    "markdown": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/markdown/-/markdown-0.5.0.tgz",
+      "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=",
+      "dev": true,
+      "requires": {
+        "nopt": "2.1.2"
+      },
+      "dependencies": {
+        "nopt": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz",
+          "integrity": "sha1-bMzZd7gBMqB3MdbozljCyDA8+a8=",
+          "dev": true,
+          "requires": {
+            "abbrev": "1.1.1"
+          }
+        }
+      }
+    },
+    "marked": {
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
+      "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==",
+      "dev": true
+    },
+    "maxmin": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
+      "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "figures": "1.7.0",
+        "gzip-size": "3.0.0",
+        "pretty-bytes": "3.0.1"
+      },
+      "dependencies": {
+        "pretty-bytes": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
+          "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        }
+      }
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "dev": true
+    },
+    "meow": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+      "dev": true,
+      "requires": {
+        "camelcase-keys": "2.1.0",
+        "decamelize": "1.2.0",
+        "loud-rejection": "1.6.0",
+        "map-obj": "1.0.1",
+        "minimist": "1.2.0",
+        "normalize-package-data": "2.4.0",
+        "object-assign": "4.1.1",
+        "read-pkg-up": "1.0.1",
+        "redent": "1.0.0",
+        "trim-newlines": "1.0.0"
+      }
+    },
+    "mime": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+      "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
+      "dev": true
+    },
+    "mime-db": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+      "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "2.1.18",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+      "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+      "dev": true,
+      "requires": {
+        "mime-db": "1.33.0"
+      }
+    },
+    "mimic-response": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz",
+      "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=",
+      "dev": true,
+      "optional": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "1.1.11"
+      }
+    },
+    "minimist": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+      "dev": true
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
+      "requires": {
+        "minimist": "0.0.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "dev": true
+        }
+      }
+    },
+    "morgan": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
+      "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
+      "dev": true,
+      "requires": {
+        "basic-auth": "2.0.0",
+        "debug": "2.6.9",
+        "depd": "1.1.2",
+        "on-finished": "2.3.0",
+        "on-headers": "1.0.1"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
+      "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+      "dev": true,
+      "optional": true
+    },
+    "negotiator": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+      "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
+      "dev": true
+    },
+    "node-abi": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.3.0.tgz",
+      "integrity": "sha512-zwm6vU3SsVgw3e9fu48JBaRBCJGIvAgysDsqtf5+vEexFE71bEOtaMWb5zr/zODZNzTPtQlqUUpC79k68Hspow==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "semver": "5.5.0"
+      }
+    },
+    "node-gyp": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz",
+      "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "fstream": "1.0.11",
+        "glob": "7.0.6",
+        "graceful-fs": "4.1.11",
+        "minimatch": "3.0.4",
+        "mkdirp": "0.5.1",
+        "nopt": "3.0.6",
+        "npmlog": "4.1.2",
+        "osenv": "0.1.5",
+        "request": "2.85.0",
+        "rimraf": "2.2.8",
+        "semver": "5.3.0",
+        "tar": "2.2.1",
+        "which": "1.2.14"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "noop-logger": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
+      "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=",
+      "dev": true,
+      "optional": true
+    },
+    "nopt": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+      "dev": true,
+      "requires": {
+        "abbrev": "1.1.1"
+      }
+    },
+    "normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "2.6.0",
+        "is-builtin-module": "1.0.0",
+        "semver": "5.5.0",
+        "validate-npm-package-license": "3.0.3"
+      }
+    },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "requires": {
+        "remove-trailing-separator": "1.1.0"
+      }
+    },
+    "npm-run-path": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "dev": true,
+      "requires": {
+        "path-key": "2.0.1"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "dev": true,
+      "requires": {
+        "are-we-there-yet": "1.1.4",
+        "console-control-strings": "1.1.0",
+        "gauge": "2.7.4",
+        "set-blocking": "2.0.0"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+      "dev": true
+    },
+    "oauth-sign": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+      "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+      "dev": true,
+      "optional": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "dev": true,
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "on-headers": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
+      "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=",
+      "dev": true
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1.0.2"
+      }
+    },
+    "opn": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
+      "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
+      "dev": true,
+      "requires": {
+        "object-assign": "4.1.1",
+        "pinkie-promise": "2.0.1"
+      }
+    },
+    "optimist": {
+      "version": "0.3.7",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz",
+      "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=",
+      "dev": true,
+      "requires": {
+        "wordwrap": "0.0.3"
+      }
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true,
+      "optional": true
+    },
+    "osenv": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "os-homedir": "1.0.2",
+        "os-tmpdir": "1.0.2"
+      }
+    },
+    "pako": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+      "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
+      "dev": true
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "dev": true,
+      "requires": {
+        "error-ex": "1.3.1"
+      }
+    },
+    "parseurl": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+      "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+      "dev": true,
+      "requires": {
+        "pinkie-promise": "2.0.1"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
+    },
+    "path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "pify": "2.3.0",
+        "pinkie-promise": "2.0.1"
+      }
+    },
+    "performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+      "dev": true,
+      "optional": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "2.0.4"
+      }
+    },
+    "portscanner": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz",
+      "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=",
+      "dev": true,
+      "requires": {
+        "async": "1.5.2"
+      }
+    },
+    "prebuild-install": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.1.tgz",
+      "integrity": "sha512-3DX9L6pzwc1m1ksMkW3Ky2WLgPQUBiySOfXVl3WZyAeJSyJb4wtoH9OmeRGcubAWsMlLiL8BTHbwfm/jPQE9Ag==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "detect-libc": "1.0.3",
+        "expand-template": "1.1.0",
+        "github-from-package": "0.0.0",
+        "minimist": "1.2.0",
+        "mkdirp": "0.5.1",
+        "node-abi": "2.3.0",
+        "noop-logger": "0.1.1",
+        "npmlog": "4.1.2",
+        "os-homedir": "1.0.2",
+        "pump": "2.0.1",
+        "rc": "1.2.6",
+        "simple-get": "2.7.0",
+        "tar-fs": "1.16.0",
+        "tunnel-agent": "0.6.0",
+        "which-pm-runs": "1.0.0"
+      },
+      "dependencies": {
+        "detect-libc": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+          "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "pretty-bytes": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz",
+      "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+      "dev": true
+    },
+    "promise": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz",
+      "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=",
+      "dev": true,
+      "requires": {
+        "asap": "1.0.0"
+      }
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "dev": true
+    },
+    "pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "end-of-stream": "1.4.1",
+        "once": "1.4.0"
+      }
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+      "dev": true,
+      "optional": true
+    },
+    "qs": {
+      "version": "6.5.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+      "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
+      "dev": true,
+      "optional": true
+    },
+    "range-parser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+      "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
+      "dev": true
+    },
+    "raw-body": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
+      "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=",
+      "dev": true,
+      "requires": {
+        "bytes": "2.4.0",
+        "iconv-lite": "0.4.13",
+        "unpipe": "1.0.0"
+      },
+      "dependencies": {
+        "bytes": {
+          "version": "2.4.0",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
+          "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=",
+          "dev": true
+        },
+        "iconv-lite": {
+          "version": "0.4.13",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+          "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=",
+          "dev": true
+        }
+      }
+    },
+    "rc": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz",
+      "integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "deep-extend": "0.4.2",
+        "ini": "1.3.5",
+        "minimist": "1.2.0",
+        "strip-json-comments": "2.0.1"
+      }
+    },
+    "read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+      "dev": true,
+      "requires": {
+        "load-json-file": "1.1.0",
+        "normalize-package-data": "2.4.0",
+        "path-type": "1.1.0"
+      }
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+      "dev": true,
+      "requires": {
+        "find-up": "1.1.2",
+        "read-pkg": "1.1.0"
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
+      "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "1.0.2",
+        "inherits": "2.0.3",
+        "isarray": "1.0.0",
+        "process-nextick-args": "2.0.0",
+        "safe-buffer": "5.1.1",
+        "string_decoder": "1.0.3",
+        "util-deprecate": "1.0.2"
+      }
+    },
+    "redent": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+      "dev": true,
+      "requires": {
+        "indent-string": "2.1.0",
+        "strip-indent": "1.0.1"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+      "dev": true,
+      "requires": {
+        "is-finite": "1.0.2"
+      }
+    },
+    "request": {
+      "version": "2.85.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz",
+      "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "aws-sign2": "0.7.0",
+        "aws4": "1.6.0",
+        "caseless": "0.12.0",
+        "combined-stream": "1.0.6",
+        "extend": "3.0.1",
+        "forever-agent": "0.6.1",
+        "form-data": "2.3.2",
+        "har-validator": "5.0.3",
+        "hawk": "6.0.2",
+        "http-signature": "1.2.0",
+        "is-typedarray": "1.0.0",
+        "isstream": "0.1.2",
+        "json-stringify-safe": "5.0.1",
+        "mime-types": "2.1.18",
+        "oauth-sign": "0.8.2",
+        "performance-now": "2.1.0",
+        "qs": "6.5.1",
+        "safe-buffer": "5.1.1",
+        "stringstream": "0.0.5",
+        "tough-cookie": "2.3.4",
+        "tunnel-agent": "0.6.0",
+        "uuid": "3.2.1"
+      }
+    },
+    "requizzle": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz",
+      "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=",
+      "dev": true,
+      "requires": {
+        "underscore": "1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+          "dev": true
+        }
+      }
+    },
+    "resolve": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+      "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+      "dev": true
+    },
+    "right-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+      "dev": true,
+      "requires": {
+        "align-text": "0.1.4"
+      }
+    },
+    "rimraf": {
+      "version": "2.2.8",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
+      "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
+      "dev": true
+    },
+    "safe-buffer": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+      "dev": true
+    },
+    "send": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
+      "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "1.1.2",
+        "destroy": "1.0.4",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "etag": "1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "1.6.3",
+        "mime": "1.4.1",
+        "ms": "2.0.0",
+        "on-finished": "2.3.0",
+        "range-parser": "1.2.0",
+        "statuses": "1.4.0"
+      },
+      "dependencies": {
+        "statuses": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
+          "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==",
+          "dev": true
+        }
+      }
+    },
+    "serve-index": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+      "dev": true,
+      "requires": {
+        "accepts": "1.3.5",
+        "batch": "0.6.1",
+        "debug": "2.6.9",
+        "escape-html": "1.0.3",
+        "http-errors": "1.6.3",
+        "mime-types": "2.1.18",
+        "parseurl": "1.3.2"
+      }
+    },
+    "serve-static": {
+      "version": "1.13.2",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
+      "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
+      "dev": true,
+      "requires": {
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "parseurl": "1.3.2",
+        "send": "0.16.2"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "setprototypeof": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+      "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+      "dev": true
+    },
+    "shelljs": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
+      "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
+    "simple-concat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+      "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
+      "dev": true,
+      "optional": true
+    },
+    "simple-get": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.7.0.tgz",
+      "integrity": "sha512-RkE9rGPHcxYZ/baYmgJtOSM63vH0Vyq+ma5TijBcLla41SWlh8t6XYIGMR/oeZcmr+/G8k+zrClkkVrtnQ0esg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "decompress-response": "3.3.0",
+        "once": "1.4.0",
+        "simple-concat": "1.0.0"
+      }
+    },
+    "sntp": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
+      "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "hoek": "4.2.1"
+      }
+    },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
+      "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "3.0.0",
+        "spdx-license-ids": "3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
+      "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "2.1.0",
+        "spdx-license-ids": "3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
+      "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==",
+      "dev": true
+    },
+    "sprintf-js": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
+      "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=",
+      "dev": true
+    },
+    "sshpk": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz",
+      "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "asn1": "0.2.3",
+        "assert-plus": "1.0.0",
+        "bcrypt-pbkdf": "1.0.1",
+        "dashdash": "1.14.1",
+        "ecc-jsbn": "0.1.1",
+        "getpass": "0.1.7",
+        "jsbn": "0.1.1",
+        "tweetnacl": "0.14.5"
+      }
+    },
+    "statuses": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+      "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=",
+      "dev": true
+    },
+    "stream-buffers": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
+      "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=",
+      "dev": true
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "dev": true,
+      "requires": {
+        "code-point-at": "1.1.0",
+        "is-fullwidth-code-point": "1.0.0",
+        "strip-ansi": "3.0.1"
+      }
+    },
+    "string_decoder": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+      "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "stringstream": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+      "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
+      "dev": true,
+      "optional": true
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "dev": true,
+      "requires": {
+        "is-utf8": "0.2.1"
+      }
+    },
+    "strip-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "4.0.1"
+      }
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true
+    },
+    "taffydb": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
+      "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=",
+      "dev": true
+    },
+    "tar": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
+      "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "block-stream": "0.0.9",
+        "fstream": "1.0.11",
+        "inherits": "2.0.3"
+      }
+    },
+    "tar-fs": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz",
+      "integrity": "sha512-I9rb6v7mjWLtOfCau9eH5L7sLJyU2BnxtEZRQ5Mt+eRKmf1F0ohXmT/Jc3fr52kDvjJ/HV5MH3soQfPL5bQ0Yg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "chownr": "1.0.1",
+        "mkdirp": "0.5.1",
+        "pump": "1.0.3",
+        "tar-stream": "1.5.5"
+      },
+      "dependencies": {
+        "pump": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
+          "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "end-of-stream": "1.4.1",
+            "once": "1.4.0"
+          }
+        }
+      }
+    },
+    "tar-stream": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
+      "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
+      "dev": true,
+      "requires": {
+        "bl": "1.2.2",
+        "end-of-stream": "1.4.1",
+        "readable-stream": "2.3.5",
+        "xtend": "4.0.1"
+      }
+    },
+    "tiny-lr": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz",
+      "integrity": "sha1-s/26gC5dVqM8L28QeUsy5Hescp0=",
+      "dev": true,
+      "requires": {
+        "body-parser": "1.14.2",
+        "debug": "2.2.0",
+        "faye-websocket": "0.10.0",
+        "livereload-js": "2.3.0",
+        "parseurl": "1.3.2",
+        "qs": "5.1.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+          "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+          "dev": true,
+          "requires": {
+            "ms": "0.7.1"
+          }
+        },
+        "ms": {
+          "version": "0.7.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+          "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
+          "dev": true
+        },
+        "qs": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz",
+          "integrity": "sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=",
+          "dev": true
+        }
+      }
+    },
+    "tough-cookie": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
+      "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "punycode": "1.4.1"
+      }
+    },
+    "transformers": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz",
+      "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=",
+      "dev": true,
+      "requires": {
+        "css": "1.0.8",
+        "promise": "2.0.0",
+        "uglify-js": "2.2.5"
+      },
+      "dependencies": {
+        "is-promise": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz",
+          "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=",
+          "dev": true
+        },
+        "promise": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz",
+          "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=",
+          "dev": true,
+          "requires": {
+            "is-promise": "1.0.1"
+          }
+        },
+        "source-map": {
+          "version": "0.1.43",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
+          "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
+          "dev": true,
+          "requires": {
+            "amdefine": "1.0.1"
+          }
+        },
+        "uglify-js": {
+          "version": "2.2.5",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz",
+          "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=",
+          "dev": true,
+          "requires": {
+            "optimist": "0.3.7",
+            "source-map": "0.1.43"
+          }
+        }
+      }
+    },
+    "trim-newlines": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+      "dev": true
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true,
+      "optional": true
+    },
+    "type-is": {
+      "version": "1.6.16",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
+      "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
+      "dev": true,
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "2.1.18"
+      }
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "uglify-js": {
+      "version": "2.8.29",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+      "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+      "dev": true,
+      "requires": {
+        "source-map": "0.5.7",
+        "uglify-to-browserify": "1.0.2",
+        "yargs": "3.10.0"
+      }
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+      "dev": true,
+      "optional": true
+    },
+    "underscore": {
+      "version": "1.8.3",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
+      "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
+      "dev": true
+    },
+    "underscore-contrib": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz",
+      "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=",
+      "dev": true,
+      "requires": {
+        "underscore": "1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+          "dev": true
+        }
+      }
+    },
+    "underscore.string": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz",
+      "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "1.1.1",
+        "util-deprecate": "1.0.2"
+      }
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "dev": true
+    },
+    "uri-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz",
+      "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
+      "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
+      "dev": true,
+      "optional": true
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
+      "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "3.0.0",
+        "spdx-expression-parse": "3.0.0"
+      }
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "1.3.0"
+      }
+    },
+    "void-elements": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+      "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
+      "dev": true
+    },
+    "walkdir": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz",
+      "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=",
+      "dev": true
+    },
+    "websocket-driver": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
+      "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=",
+      "dev": true,
+      "requires": {
+        "http-parser-js": "0.4.11",
+        "websocket-extensions": "0.1.3"
+      }
+    },
+    "websocket-extensions": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
+      "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
+      "dev": true
+    },
+    "which": {
+      "version": "1.2.14",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz",
+      "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=",
+      "dev": true,
+      "requires": {
+        "isexe": "2.0.0"
+      }
+    },
+    "which-pm-runs": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+      "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
+      "dev": true,
+      "optional": true
+    },
+    "wide-align": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
+      "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+      "dev": true,
+      "requires": {
+        "string-width": "1.0.2"
+      }
+    },
+    "window-size": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+      "dev": true
+    },
+    "with": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz",
+      "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=",
+      "dev": true,
+      "requires": {
+        "acorn": "1.2.2",
+        "acorn-globals": "1.0.9"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "1.2.2",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz",
+          "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=",
+          "dev": true
+        }
+      }
+    },
+    "wordwrap": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+      "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+      "dev": true
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "xmlcreate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
+      "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=",
+      "dev": true
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+      "dev": true
+    },
+    "yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+      "dev": true
+    },
+    "yargs": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+      "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+      "dev": true,
+      "requires": {
+        "camelcase": "1.2.1",
+        "cliui": "2.1.0",
+        "decamelize": "1.2.0",
+        "window-size": "0.1.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "1.2.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+          "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+          "dev": true
+        }
+      }
+    },
+    "zip-stream": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz",
+      "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=",
+      "dev": true,
+      "requires": {
+        "archiver-utils": "1.3.0",
+        "compress-commons": "1.2.2",
+        "lodash": "4.17.5",
+        "readable-stream": "2.3.5"
+      }
+    }
+  }
+}
diff --git a/civicrm/bower_components/checklist-model/readme.md b/civicrm/bower_components/checklist-model/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..4e43ee5f8125cc87f38e1800feeb714bcac54695
--- /dev/null
+++ b/civicrm/bower_components/checklist-model/readme.md
@@ -0,0 +1,85 @@
+![Bower](https://img.shields.io/bower/v/checklist-model.svg) [![NPM](https://img.shields.io/npm/v/checklist-model.svg)](https://www.npmjs.com/package/checklist-model) ![License](https://img.shields.io/npm/l/checklist-model.svg)
+
+[![NPM](https://nodei.co/npm/checklist-model.png)](https://nodei.co/npm/checklist-model/)
+
+# checklist-model
+AngularJS directive for list of checkboxes
+
+## Why this is needed?  
+In Angular one checkbox `<input type="checkbox" ng-model="...">` is linked
+with one model.  
+But in practice we usually want one model to store array of checked values
+from several checkboxes.  
+**Checklist-model** solves that task without additional code in controller.   
+
+## Live demo
+http://vitalets.github.io/checklist-model
+
+## Installation
+> Note: since version `1.0.0` you *must* install the `angular` library yourself as it is now a [`peerDependency`](https://nodejs.org/en/blog/npm/peer-dependencies/)
+
+1. Download package:
+    * From npm `npm install checklist-model`
+    * From bower `bower install checklist-model`
+    * From [latest release](https://github.com/vitalets/checklist-model/releases)
+2. Include script to the HTML:
+    ```html
+    <script src='checklist-model.js'></script>
+    ```
+3. Add to app dependencies:
+    ```js
+    var app = angular.module("app", ["checklist-model"]);
+    ```
+
+## Usage
+You should play with attributes of `<input>` tag:
+
+| Attribute                 | Mandatory | Description                                   |
+| :-----------------------: | :-------: | --------------------------------------------- |
+| `checklist-model`         | Yes       | Use instead of `ng-model`                     |
+| `checklist-value`         | No        | What should be picked as array item           |
+| `value`                   | No        | What should be picked as item, but unlike `checklist-value`, this does not evaluate as an angular expression, but rather a static value |
+| `ng-model`                | No        | Every checkbok will span a new scope and define a variable named `checked` to hold its state. You can modify this name by using this attribute. |
+| `checklist-comparator`    | No   | A custom comparator. If it starts with dot(`.`) then it will be an expression applied to the array item. Otherwise it should evaluate to a function as an angular expression. The function return true if the first two arguments are equal and false otherwise. |
+| `checklist-before-change` | No       | An angular expression evaluated each time before the `checklist-model` has changed. If it evaluates to 'false' then the model will not change anymore. |
+| `checklist-change`        | No       | An angular expression evaluated each time the `checklist-model` has changed. |
+
+* If you modify directly the value of the `checklist-model`, it is possible that the UI won't be updated. This is because this directive looks for the model in the parent, not in the current scope. Instead of doing `checklistModelList = []` you should do `checklistModelList.splice(0, checklistModelList.length)` or wrap it in another object. Consequently, instead of doing `checklistModelList = angular.copy(allValues)` you should do `checklistModelList.push.apply(checklistModelList, allValues)`. The idea is to use the same array and not replace it with a new one.
+* If you're using `track by` you must specify the same thing for `checklist-value` too. See [#46](https://github.com/vitalets/checklist-model/issues/46).
+* If you're also using `ngModel`, please keep in mind that the state of the checkbok is initialized with the value from `checklistModel`, not with the one from `ngModel`. Afterwards the two will be kept in sync, but initially, these two can be conflicting, so only `checklistModel` is used. See the entire discussion at [#104](https://github.com/vitalets/checklist-model/issues/104).
+
+## Examples
+* JsFiddle basic example (use this to report any issue): http://jsfiddle.net/beradrian/fjoLy5sq/
+* JSFiddle required example: http://jsfiddle.net/beradrian/7wt9q1ev/  
+* Plunkr example: http://plnkr.co/edit/0UrMwtiNQxJJbVWnYgSt?p=preview
+* Plunkr example for [tree list](http://plnkr.co/edit/QPLk98pCljp8dFtptSYz?p=preview)
+
+## How to get support
+* Ask a question on StackOverflow and tag it with [checklist-model](http://stackoverflow.com/questions/tagged/checklist-model).
+* [Fill in](https://github.com/vitalets/checklist-model/issues/new) an issue.
+
+Please keep in mind to also add a Plunkr or JSFiddle example. This will greatly help us in assisting you and you can use one of the existing examples and fork it.
+
+## Development
+### How to run tests
+1. Generate live demo *index.html* via `grunt jade` 
+2. Run local http server `grunt server` 
+3. Open in browser http://localhost:8000 to check that demo is accessible
+4. Open in browser http://localhost:8000/test and wait until all tests pass
+
+### How to add a new test case
+1. Create a new folder under `docs/blocks` named `your-test`.
+2. Create under that folder `ctrl.js` to describe the test Angular controller, `view.html` to describe the view part in HTML and `test.js` for the Angular scenario test. You can use an existing test as an example.
+3. Add a line like `- items.push({id: 'your-test', text: 'Your test, ctrlName: 'CtrlTestName', testValue: 'selectedItems'})` to `docs/index.jade`
+4. Add a line like `<script src="../docs/blocks/your-test/test.js"></script>` to `test\index.html`
+5. Run `grunt jade` to generate `index.html` from `docs/index.jade`
+6. Run `grunt server`
+7. Access `http://localhost:8000` for samples and `http://localhost:8000/test` for running the tests.
+
+### How to make a new release
+1. Change the version number in `package.json`, `bower.json` and `checklist-model.nuspec` (if not already changed - check the version number against the latest release in Github)
+2. Create a new [release](https://github.com/vitalets/checklist-model/releases) in github with the same name for tag and title as the version number (e.g. `1.0.0`). Do not forget to include the changelog in the release description.
+3. Run `npm publish` to publish the new version to npm
+
+## License
+MIT
diff --git a/civicrm/bower_components/css-color-names/.bower.json b/civicrm/bower_components/css-color-names/.bower.json
new file mode 100644
index 0000000000000000000000000000000000000000..db9d473fd805af2ce95834b39a855c08bd932d26
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/.bower.json
@@ -0,0 +1,14 @@
+{
+  "name": "css-color-names",
+  "homepage": "https://github.com/bahamas10/css-color-names",
+  "version": "1.0.1",
+  "_release": "1.0.1",
+  "_resolution": {
+    "type": "version",
+    "tag": "v1.0.1",
+    "commit": "c41f2d98d6b018226f3505d6e0238bd7e2d7e611"
+  },
+  "_source": "https://github.com/bahamas10/css-color-names.git",
+  "_target": "~1",
+  "_originalSource": "css-color-names"
+}
\ No newline at end of file
diff --git a/civicrm/bower_components/css-color-names/LICENSE b/civicrm/bower_components/css-color-names/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..6c5fea91fc1c54965795d26bbd9860bde5fbbb6d
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/LICENSE
@@ -0,0 +1,7 @@
+Copyright 2018 Dave Eddy <dave@daveeddy.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/civicrm/bower_components/css-color-names/Makefile b/civicrm/bower_components/css-color-names/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ebbcf1d1b14cf28fcfa9b6d9a6c824ffe2b30bc0
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/Makefile
@@ -0,0 +1,8 @@
+FILE = css-color-names.json
+
+all:
+	./getcolors.sh | ./stringify.js > $(FILE)
+clean:
+	rm -f $(FILE)
+
+.PHONY: all clean
diff --git a/civicrm/bower_components/css-color-names/README.md b/civicrm/bower_components/css-color-names/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bfe6263b7911f0bb6b9cbab5dcbc90459c037e5e
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/README.md
@@ -0,0 +1,48 @@
+css-color-names
+===============
+
+A JSON Object of css color names mapped to their hex value
+
+Usage
+-----
+
+``` js
+var csscolors = require('css-color-names');
+console.dir(csscolors);
+```
+
+yields
+
+``` json
+{
+  "aqua": "#00ffff",
+  "aliceblue": "#f0f8ff",
+  "antiquewhite": "#faebd7",
+  "black": "#000000",
+  "blue": "#0000ff",
+  ...
+}
+```
+
+How was this list generated?
+----------------------------
+
+In the Makefile you'll see a line like this:
+
+	./getcolors.sh | ./stringify.js > $(FILE)
+
+The first command scrapes a site for the list,
+and outputs the results separated by newlines.  The
+second command creates the JSON object and outputs
+it to stdout, which then gets redirected into
+`css-color-names.json`
+
+Installation
+------------
+
+    npm install css-color-names
+
+License
+-------
+
+MIT
diff --git a/civicrm/bower_components/css-color-names/css-color-names.json b/civicrm/bower_components/css-color-names/css-color-names.json
new file mode 100644
index 0000000000000000000000000000000000000000..7a1480dceaac8467ca7ce1e544dff234fa208a74
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/css-color-names.json
@@ -0,0 +1,150 @@
+{
+  "aliceblue": "#f0f8ff",
+  "antiquewhite": "#faebd7",
+  "aqua": "#00ffff",
+  "aquamarine": "#7fffd4",
+  "azure": "#f0ffff",
+  "beige": "#f5f5dc",
+  "bisque": "#ffe4c4",
+  "black": "#000000",
+  "blanchedalmond": "#ffebcd",
+  "blue": "#0000ff",
+  "blueviolet": "#8a2be2",
+  "brown": "#a52a2a",
+  "burlywood": "#deb887",
+  "cadetblue": "#5f9ea0",
+  "chartreuse": "#7fff00",
+  "chocolate": "#d2691e",
+  "coral": "#ff7f50",
+  "cornflowerblue": "#6495ed",
+  "cornsilk": "#fff8dc",
+  "crimson": "#dc143c",
+  "cyan": "#00ffff",
+  "darkblue": "#00008b",
+  "darkcyan": "#008b8b",
+  "darkgoldenrod": "#b8860b",
+  "darkgray": "#a9a9a9",
+  "darkgreen": "#006400",
+  "darkgrey": "#a9a9a9",
+  "darkkhaki": "#bdb76b",
+  "darkmagenta": "#8b008b",
+  "darkolivegreen": "#556b2f",
+  "darkorange": "#ff8c00",
+  "darkorchid": "#9932cc",
+  "darkred": "#8b0000",
+  "darksalmon": "#e9967a",
+  "darkseagreen": "#8fbc8f",
+  "darkslateblue": "#483d8b",
+  "darkslategray": "#2f4f4f",
+  "darkslategrey": "#2f4f4f",
+  "darkturquoise": "#00ced1",
+  "darkviolet": "#9400d3",
+  "deeppink": "#ff1493",
+  "deepskyblue": "#00bfff",
+  "dimgray": "#696969",
+  "dimgrey": "#696969",
+  "dodgerblue": "#1e90ff",
+  "firebrick": "#b22222",
+  "floralwhite": "#fffaf0",
+  "forestgreen": "#228b22",
+  "fuchsia": "#ff00ff",
+  "gainsboro": "#dcdcdc",
+  "ghostwhite": "#f8f8ff",
+  "goldenrod": "#daa520",
+  "gold": "#ffd700",
+  "gray": "#808080",
+  "green": "#008000",
+  "greenyellow": "#adff2f",
+  "grey": "#808080",
+  "honeydew": "#f0fff0",
+  "hotpink": "#ff69b4",
+  "indianred": "#cd5c5c",
+  "indigo": "#4b0082",
+  "ivory": "#fffff0",
+  "khaki": "#f0e68c",
+  "lavenderblush": "#fff0f5",
+  "lavender": "#e6e6fa",
+  "lawngreen": "#7cfc00",
+  "lemonchiffon": "#fffacd",
+  "lightblue": "#add8e6",
+  "lightcoral": "#f08080",
+  "lightcyan": "#e0ffff",
+  "lightgoldenrodyellow": "#fafad2",
+  "lightgray": "#d3d3d3",
+  "lightgreen": "#90ee90",
+  "lightgrey": "#d3d3d3",
+  "lightpink": "#ffb6c1",
+  "lightsalmon": "#ffa07a",
+  "lightseagreen": "#20b2aa",
+  "lightskyblue": "#87cefa",
+  "lightslategray": "#778899",
+  "lightslategrey": "#778899",
+  "lightsteelblue": "#b0c4de",
+  "lightyellow": "#ffffe0",
+  "lime": "#00ff00",
+  "limegreen": "#32cd32",
+  "linen": "#faf0e6",
+  "magenta": "#ff00ff",
+  "maroon": "#800000",
+  "mediumaquamarine": "#66cdaa",
+  "mediumblue": "#0000cd",
+  "mediumorchid": "#ba55d3",
+  "mediumpurple": "#9370db",
+  "mediumseagreen": "#3cb371",
+  "mediumslateblue": "#7b68ee",
+  "mediumspringgreen": "#00fa9a",
+  "mediumturquoise": "#48d1cc",
+  "mediumvioletred": "#c71585",
+  "midnightblue": "#191970",
+  "mintcream": "#f5fffa",
+  "mistyrose": "#ffe4e1",
+  "moccasin": "#ffe4b5",
+  "navajowhite": "#ffdead",
+  "navy": "#000080",
+  "oldlace": "#fdf5e6",
+  "olive": "#808000",
+  "olivedrab": "#6b8e23",
+  "orange": "#ffa500",
+  "orangered": "#ff4500",
+  "orchid": "#da70d6",
+  "palegoldenrod": "#eee8aa",
+  "palegreen": "#98fb98",
+  "paleturquoise": "#afeeee",
+  "palevioletred": "#db7093",
+  "papayawhip": "#ffefd5",
+  "peachpuff": "#ffdab9",
+  "peru": "#cd853f",
+  "pink": "#ffc0cb",
+  "plum": "#dda0dd",
+  "powderblue": "#b0e0e6",
+  "purple": "#800080",
+  "rebeccapurple": "#663399",
+  "red": "#ff0000",
+  "rosybrown": "#bc8f8f",
+  "royalblue": "#4169e1",
+  "saddlebrown": "#8b4513",
+  "salmon": "#fa8072",
+  "sandybrown": "#f4a460",
+  "seagreen": "#2e8b57",
+  "seashell": "#fff5ee",
+  "sienna": "#a0522d",
+  "silver": "#c0c0c0",
+  "skyblue": "#87ceeb",
+  "slateblue": "#6a5acd",
+  "slategray": "#708090",
+  "slategrey": "#708090",
+  "snow": "#fffafa",
+  "springgreen": "#00ff7f",
+  "steelblue": "#4682b4",
+  "tan": "#d2b48c",
+  "teal": "#008080",
+  "thistle": "#d8bfd8",
+  "tomato": "#ff6347",
+  "turquoise": "#40e0d0",
+  "violet": "#ee82ee",
+  "wheat": "#f5deb3",
+  "white": "#ffffff",
+  "whitesmoke": "#f5f5f5",
+  "yellow": "#ffff00",
+  "yellowgreen": "#9acd32"
+}
diff --git a/civicrm/bower_components/css-color-names/getcolors.sh b/civicrm/bower_components/css-color-names/getcolors.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2c8ba0503bca1ac6f22e9c326c039c64d652de0b
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/getcolors.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+curl -sS 'https://www.w3schools.com/colors/colors_names.asp' \
+	| tr -cd '\11\12\15\40-\176' \
+	| egrep '\?(color|hex)=' \
+	| sed -e 's/\r//g' -e 's/<[^>]*>//g' -e 's/\&nbsp;.*$//g' \
+	| awk 'NR%2 {color=$1} !(NR%2) {print color, $1}' \
+	| tr '[:upper:]' '[:lower:]' \
+	| sort
diff --git a/civicrm/bower_components/css-color-names/package.json b/civicrm/bower_components/css-color-names/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d8711cd600441b36e4083075751f96d265a0aefa
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "css-color-names",
+  "description": "A JSON Object of css color names mapped to their hex value",
+  "version": "1.0.1",
+  "author": "Dave Eddy <dave@daveeddy.com> (http://www.daveeddy.com)",
+  "contributors": [],
+  "main": "./css-color-names.json",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/bahamas10/css-color-names.git"
+  },
+  "scripts": {
+    "test": "for f in tests/*.js; do echo \"$f\"; node \"$f\" || exit 1; done; echo 'Passed!'"
+  },
+  "dependencies": {},
+  "devDependencies": {},
+  "optionalDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "license": "MIT",
+  "keywords": [
+    "css", "colors", "names"
+  ],
+  "files": [
+    "css-color-names.json"
+  ]
+}
diff --git a/civicrm/bower_components/css-color-names/stringify.js b/civicrm/bower_components/css-color-names/stringify.js
new file mode 100755
index 0000000000000000000000000000000000000000..cc119fb7c89737b3f3eb27ae9f1e212e3461a2da
--- /dev/null
+++ b/civicrm/bower_components/css-color-names/stringify.js
@@ -0,0 +1,17 @@
+#!/usr/bin/env node
+/**
+ * given a file, or data over stdin,
+ * split it on newlines and emit a json object kv
+ */
+var fs = require('fs');
+var file = process.argv[2] || '/dev/stdin';
+
+var arr = fs.readFileSync(file, 'utf-8').trim().split('\n');
+var ret = {};
+
+arr.forEach(function(line) {
+  var s = line.split(' ');
+  ret[s[0]] = s[1];
+});
+
+console.log(JSON.stringify(ret, null, 2));
diff --git a/civicrm/civicrm-version.php b/civicrm/civicrm-version.php
index f8ed285b55675184632a73f0dbcdc5e7f8f9a46e..ed175082df2c14961e614ee3b5180bd011dc8ae9 100644
--- a/civicrm/civicrm-version.php
+++ b/civicrm/civicrm-version.php
@@ -1,7 +1,7 @@
 <?php
 /** @deprecated */
 function civicrmVersion( ) {
-  return array( 'version'  => '5.15.2',
+  return array( 'version'  => '5.16.0',
                 'cms'      => 'Wordpress',
                 'revision' => '' );
 }
diff --git a/civicrm/composer.json b/civicrm/composer.json
index 271f33cf59a0bc2c9dd87c7af35b463709869405..1cfa14b776df4f5c31ba31a76b4a4d66f8aad564 100644
--- a/civicrm/composer.json
+++ b/civicrm/composer.json
@@ -61,7 +61,8 @@
     "psr/simple-cache": "~1.0.1",
     "cweagans/composer-patches": "~1.0",
     "pear/log": "1.13.1",
-    "katzien/php-mime-type": "2.1.0"
+    "katzien/php-mime-type": "2.1.0",
+    "league/csv": "^9.2"
   },
   "require-dev": {
     "cache/integration-tests": "dev-master"
diff --git a/civicrm/composer.lock b/civicrm/composer.lock
index 7fe362a0ac3f8d57c747351dcb97678c96e59718..3ca2b51fe243493db3f3774497548ca735ade787 100644
--- a/civicrm/composer.lock
+++ b/civicrm/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "a337d7adf0d57f28a1aff44917fe1b92",
+    "content-hash": "027475804731d7ef0bd3e0feb2139d3c",
     "packages": [
         {
             "name": "civicrm/civicrm-cxn-rpc",
@@ -451,6 +451,73 @@
             ],
             "time": "2017-03-23T02:05:33+00:00"
         },
+        {
+            "name": "league/csv",
+            "version": "9.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/csv.git",
+                "reference": "b574a7d8b28f1528e011d8652fb7d2e83410d4c9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/csv/zipball/b574a7d8b28f1528e011d8652fb7d2e83410d4c9",
+                "reference": "b574a7d8b28f1528e011d8652fb7d2e83410d4c9",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": ">=7.0.10"
+            },
+            "require-dev": {
+                "ext-curl": "*",
+                "friendsofphp/php-cs-fixer": "^2.12",
+                "phpstan/phpstan": "^0.9.2",
+                "phpstan/phpstan-phpunit": "^0.9.4",
+                "phpstan/phpstan-strict-rules": "^0.9.0",
+                "phpunit/phpunit": "^6.0"
+            },
+            "suggest": {
+                "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "9.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Csv\\": "src"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ignace Nyamagana Butera",
+                    "email": "nyamsprod@gmail.com",
+                    "homepage": "https://github.com/nyamsprod/",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Csv data manipulation made easy in PHP",
+            "homepage": "http://csv.thephpleague.com",
+            "keywords": [
+                "csv",
+                "export",
+                "filter",
+                "import",
+                "read",
+                "write"
+            ],
+            "time": "2019-06-07T06:24:33+00:00"
+        },
         {
             "name": "marcj/topsort",
             "version": "1.1.0",
diff --git a/civicrm/css/civicrm.css b/civicrm/css/civicrm.css
index ad42f00566e244dd92b941bf07ec627a396de89d..c1c75403f444ef7ec02e6b2040ad8bf499b44b84 100644
--- a/civicrm/css/civicrm.css
+++ b/civicrm/css/civicrm.css
@@ -887,6 +887,12 @@ input.crm-form-entityref {
   font-weight: bold;
 }
 
+/* dev/core#1039 Make contact details in popup on merge screen non bold */
+#crm-container tr.columnheader td [class*="crm-summary-col-"] {
+  font-size: 13px;
+  font-weight: normal;
+}
+
 #crm-container tr.columnheader-dark th span.extra {
   font-size: .95em;
   font-weight: normal;
diff --git a/civicrm/css/crm-menubar.css b/civicrm/css/crm-menubar.css
index c3d0ffd22f1269c6f1d221125a09509880450c66..5b584524f4676dc20ffd93394ceee3f219d29662 100644
--- a/civicrm/css/crm-menubar.css
+++ b/civicrm/css/crm-menubar.css
@@ -143,16 +143,16 @@ a.highlighted #crm-qsearch-input,
   width: 130px;
 }
 input#crm-qsearch-input:-ms-input-placeholder {
-  font-family: 'FontAwesome';
+  font-family: 'FontAwesome', sans-serif;
 }
 input#crm-qsearch-input::-webkit-input-placeholder {
-  font-family: 'FontAwesome';
+  font-family: 'FontAwesome', sans-serif;
 }
 input#crm-qsearch-input::-moz-placeholder {
-  font-family: 'FontAwesome';
+  font-family: 'FontAwesome', sans-serif;
 }
 input#crm-qsearch-input::placeholder {
-  font-family: 'FontAwesome';
+  font-family: 'FontAwesome', sans-serif;
 }
 
 ul.crm-quickSearch-results {
@@ -203,7 +203,7 @@ body.crm-menubar-over-cms-menu #crm-menubar-toggle-position a i {
   /* hide the button in desktop view */
   #civicrm-menu-nav .crm-menubar-toggle-btn {
     position: absolute;
-    top: -99999px;
+    top: -99999px; /* do not edit this without updating the isMobile() function in crm.menubar.js */
   }
 
   #civicrm-menu {
diff --git a/civicrm/js/Common.js b/civicrm/js/Common.js
index 9b5f835ed37921d563d4b7e401cd07fe3bc55600..25e228b594c3d41cda2825aa5d98fef43099e178 100644
--- a/civicrm/js/Common.js
+++ b/civicrm/js/Common.js
@@ -144,17 +144,11 @@ function showHideByValue(trigger_field_id, trigger_value, target_element_id, tar
   }
 }
 
+var submitcount = 0;
 /**
- * Function to change button text and disable one it is clicked
+ * Old submit-once function. Will be removed soon.
  * @deprecated
- * @param obj object - the button clicked
- * @param formID string - the id of the form being submitted
- * @param string procText - button text after user clicks it
- * @return bool
  */
-var submitcount = 0;
-/* Changes button label on submit, and disables button after submit for newer browsers.
- Puts up alert for older browsers. */
 function submitOnce(obj, formId, procText) {
   // if named button clicked, change text
   if (obj.value != null) {
@@ -860,6 +854,41 @@ if (!CRM.vars) CRM.vars = {};
     });
   };
 
+  // Submit-once
+  var submitted = [],
+    submitButton;
+  function submitOnceForm(e) {
+    if (e.isDefaultPrevented()) {
+      return;
+    }
+    if (_.contains(submitted, e.target)) {
+      return false;
+    }
+    submitted.push(e.target);
+    // Spin submit button icon
+    if (submitButton && $(submitButton, e.target).length) {
+      // Dialog button
+      if ($(e.target).closest('.ui-dialog .crm-ajax-container')) {
+        var identifier = $(submitButton).attr('name') || $(submitButton).attr('href');
+        if (identifier) {
+          submitButton = $(e.target).closest('.ui-dialog').find('button[data-identifier="' + identifier + '"]')[0] || submitButton;
+        }
+      }
+      var $icon = $(submitButton).siblings('.crm-i').add('.crm-i, .ui-icon', submitButton);
+      $icon.data('origClass', $icon.attr('class')).removeClass().addClass('crm-i crm-submit-icon fa-spinner fa-pulse');
+    }
+  }
+
+  // If form fails validation, restore button icon and reset the submitted array
+  function submitFormInvalid(form) {
+    submitted = [];
+    $('.crm-i.crm-submit-icon').each(function() {
+      if ($(this).data('origClass')) {
+        $(this).removeClass().addClass($(this).data('origClass'));
+      }
+    });
+  }
+
   // Initialize widgets
   $(document)
     .on('crmLoad', function(e) {
@@ -925,6 +954,13 @@ if (!CRM.vars) CRM.vars = {};
           CRM.wysiwyg.create(this);
         }
       });
+      // Submit once handlers
+      $('form[data-submit-once]', e.target)
+        .submit(submitOnceForm)
+        .on('invalid-form', submitFormInvalid);
+      $('form[data-submit-once] input[type=submit]', e.target).click(function(e) {
+        submitButton = e.target;
+      });
     })
     .on('dialogopen', function(e) {
       var $el = $(e.target);
diff --git a/civicrm/js/crm.ajax.js b/civicrm/js/crm.ajax.js
index 23be078e8b5af74a548cd9f2f87501d07fdeacaf..b64f33eec2c2e34beff9ac375974c9b74016de59 100644
--- a/civicrm/js/crm.ajax.js
+++ b/civicrm/js/crm.ajax.js
@@ -23,13 +23,13 @@
     }
     query = query || '';
     var frag = path.split('?');
-    var url = tplURL[mode].replace("*path*", frag[0]);
+    var url = tplURL[mode].replace("civicrm-placeholder-url-path", frag[0]);
 
     if (!query) {
-      url = url.replace(/[?&]\*query\*/, '');
+      url = url.replace(/[?&]civicrm-placeholder-url-query=1/, '');
     }
     else {
-      url = url.replace("*query*", typeof query === 'string' ? query : $.param(query));
+      url = url.replace("civicrm-placeholder-url-query=1", typeof query === 'string' ? query : $.param(query));
     }
     if (frag[1]) {
       url += (url.indexOf('?') < 0 ? '?' : '&') + frag[1];
@@ -456,7 +456,7 @@
         var buttonContainers = '.crm-submit-buttons, .action-link',
           buttons = [],
           added = [];
-        $(buttonContainers, $el).find('input.crm-form-submit, a.button').each(function() {
+        $(buttonContainers, $el).find('input.crm-form-submit, a.button, button').each(function() {
           var $el = $(this),
             label = $el.is('input') ? $el.attr('value') : $el.text(),
             identifier = $el.attr('name') || $el.attr('href');
diff --git a/civicrm/js/crm.datepicker.js b/civicrm/js/crm.datepicker.js
index ccb64c6aee28250a350a81765e628f03fb4eddb7..cf0719f78d11b2a1c71bdb25549627f2c0e55bea 100644
--- a/civicrm/js/crm.datepicker.js
+++ b/civicrm/js/crm.datepicker.js
@@ -49,6 +49,12 @@
         $dateField = $('<input type="' + type + '">').insertAfter($dataField);
         CRM.utils.copyAttributes($dataField, $dateField, ['placeholder', 'style', 'class', 'disabled', 'aria-label']);
         $dateField.addClass('crm-form-' + type);
+        if (!settings.minDate && !_.isUndefined(settings.start_date_years)) {
+          settings.minDate = '' + (new Date().getFullYear() - settings.start_date_years) + '-01-01';
+        }
+        if (!settings.maxDate && !_.isUndefined(settings.end_date_years)) {
+          settings.maxDate = '' + (new Date().getFullYear() + settings.end_date_years) + '-12-31';
+        }
         if (hasDatepicker) {
           settings.minDate = settings.minDate ? CRM.utils.makeDate(settings.minDate) : null;
           settings.maxDate = settings.maxDate ? CRM.utils.makeDate(settings.maxDate) : null;
diff --git a/civicrm/js/crm.menubar.js b/civicrm/js/crm.menubar.js
index ed5eb920ee600ff5fea5c225bf2c26016f2a4d05..bd42b8992f381d4619d80026fb1919fb7fd6331e 100644
--- a/civicrm/js/crm.menubar.js
+++ b/civicrm/js/crm.menubar.js
@@ -27,13 +27,13 @@
 
       // Wait for crm-container present on the page as it's faster than document.ready
       function insert(markup) {
-        if ($('#crm-container').length) {
+        if ($('.crm-container').length) {
           render(markup);
         } else {
           new MutationObserver(function(mutations, observer) {
             _.each(mutations, function(mutant) {
               _.each(mutant.addedNodes, function(node) {
-                if ($(node).is('#crm-container')) {
+                if ($(node).is('.crm-container')) {
                   render(markup);
                   observer.disconnect();
                 }
@@ -244,7 +244,7 @@
         }
       })
         .on('resize', function() {
-          if ($(window).width() >= 768 && $mainMenuState[0].checked) {
+          if (!isMobile() && $mainMenuState[0].checked) {
             $mainMenuState[0].click();
           }
           handleResize();
@@ -438,13 +438,18 @@
   }
 
   function handleResize() {
-    if ($(window).width() >= 768 && $('#civicrm-menu').height() > 50) {
+    if (!isMobile() && ($('#civicrm-menu').height() >= (2 * $('#civicrm-menu > li').height()))) {
       $('body').addClass('crm-menubar-wrapped');
     } else {
       $('body').removeClass('crm-menubar-wrapped');
     }
   }
 
+  // Figure out if we've hit the mobile breakpoint, based on the rule in crm-menubar.css
+  function isMobile() {
+    return $('.crm-menubar-toggle-btn', '#civicrm-menu-nav').css('top') !== '-99999px';
+  }
+
   function traverse(items, itemName, op) {
     var found;
     _.each(items, function(item, index) {
diff --git a/civicrm/js/crm.multilingual.js b/civicrm/js/crm.multilingual.js
index ced31483b764ea3c3219ec6ae201d5f9ebc7c31b..f3af7145d4046aded1ced7c9759da94eff61df24 100644
--- a/civicrm/js/crm.multilingual.js
+++ b/civicrm/js/crm.multilingual.js
@@ -7,18 +7,21 @@ CRM.$(function($) {
   $('body').on('click', 'a.crm-multilingual-edit-button', function(e) {
     var $el = $(this),
       $form = $el.closest('form'),
-      $field = $('#' + $el.data('field'), $form);
+      $field = $('#' + $el.data('field'), $form),
+      wysiwyg = $field.hasClass('crm-form-wysiwyg');
 
     CRM.loadForm($el.attr('href'), {
       dialog: {width: '50%', height: '50%'}
     })
       // Sync the primary language field with what the user has entered on the main form
       .on('crmFormLoad', function() {
-        $('.default-lang', this).val($field.val());
+        CRM.wysiwyg.setVal($('.default-lang', this), CRM.wysiwyg.getVal($field));
+        $('.default-lang', this).triggerHandler('change');
       })
       .on('crmFormSubmit', function() {
         // Sync the primary language field with what the user has entered in the popup
-        $field.val($('.default-lang', this).val());
+        CRM.wysiwyg.setVal($field, CRM.wysiwyg.getVal($('.default-lang', this)));
+        $field.triggerHandler('change');
         $el.trigger('crmPopupFormSuccess');
       });
     e.preventDefault();
diff --git a/civicrm/js/wysiwyg/crm.wysiwyg.js b/civicrm/js/wysiwyg/crm.wysiwyg.js
index f80b6e3388d68acaef420dbb4994a9d324c554ca..41adc35d4e74bf73899113780554858ed807951d 100644
--- a/civicrm/js/wysiwyg/crm.wysiwyg.js
+++ b/civicrm/js/wysiwyg/crm.wysiwyg.js
@@ -54,6 +54,9 @@
           CRM.wysiwyg.destroy(item);
           $(item).hide().next('.replace-plain').show().html($(item).val());
         })
+        .on('change', function() {
+          $(this).next('.replace-plain').html($(this).val());
+        })
         .after('<div class="replace-plain" tabindex="0"></div>');
       $(item).next('.replace-plain')
         .attr('title', ts('Click to edit'))
diff --git a/civicrm/release-notes.md b/civicrm/release-notes.md
index 1da908cf81a6a14255b5c4b88b86715995325d90..e5614b4ee11285e73c1131107dcb051c5aa7f188 100644
--- a/civicrm/release-notes.md
+++ b/civicrm/release-notes.md
@@ -15,6 +15,17 @@ Other resources for identifying changes are:
     * https://github.com/civicrm/civicrm-joomla
     * https://github.com/civicrm/civicrm-wordpress
 
+## CiviCRM 5.16.0
+
+Released August 7, 2019
+
+- **[Synopsis](release-notes/5.16.0.md#synopsis)**
+- **[Features](release-notes/5.16.0.md#features)**
+- **[Bugs resolved](release-notes/5.16.0.md#bugs)**
+- **[Miscellany](release-notes/5.16.0.md#misc)**
+- **[Credits](release-notes/5.16.0.md#credits)**
+- **[Feedback](release-notes/5.16.0.md#feedback)**
+
 ## CiviCRM 5.15.2
 
 Released July 30, 2019
diff --git a/civicrm/release-notes/5.15.2.md b/civicrm/release-notes/5.15.2.md
index c1b5ff17d1f38032408dcbe30e4e2e82847f2a74..4fd65f379c902e88144d0a81a3e58d2c71c6a00a 100644
--- a/civicrm/release-notes/5.15.2.md
+++ b/civicrm/release-notes/5.15.2.md
@@ -1,6 +1,6 @@
 # CiviCRM 5.15.2
 
-Released July 30, 2019
+Released July 31, 2019
 
 - **[Synopsis](#synopsis)**
 - **[Bugs resolved](#bugs)**
@@ -25,6 +25,7 @@ Released July 30, 2019
 - **CiviContribute: Fix translation of message ([dev/core#1084](https://lab.civicrm.org/dev/core/issues/1084), [#14935](https://github.com/civicrm/civicrm-core/pull/14935))**
 - **Search: Fix cross-page record selection ([#14929](https://github.com/civicrm/civicrm-core/pull/14929))**
 - **Status Check: Fix compatibility in new utf8mb4 check ([dev/core#1136](https://lab.civicrm.org/dev/core/issues/1136), [#14935](https://github.com/civicrm/civicrm-core/pull/14935))**
+- **Regression: Can't use operators to filter contact subtypes other than "Is One Of" ([dev/report#15](https://lab.civicrm.org/dev/report/issues/15): [14814](https://github.com/civicrm/civicrm-core/pull/14814))**
 
 ## <a name="credits"></a>Credits
 
diff --git a/civicrm/release-notes/5.16.0.md b/civicrm/release-notes/5.16.0.md
new file mode 100644
index 0000000000000000000000000000000000000000..c67f1743287067b91339ddc5e6fc3b711f80c59d
--- /dev/null
+++ b/civicrm/release-notes/5.16.0.md
@@ -0,0 +1,793 @@
+# CiviCRM 5.16.0
+
+Released August 7, 2019
+
+- **[Synopsis](#synopsis)**
+- **[Features](#features)**
+- **[Bugs resolved](#bugs)**
+- **[Miscellany](#misc)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| Change the database schema?                                     |   no    |
+| Alter the API?                                                  | **yes** |
+| Require attention to configuration options?                     | **yes** |
+| Fix problems installing or upgrading to a previous version?     | **yes** |
+| Introduce features?                                             | **yes** |
+| Fix bugs?                                                       | **yes** |
+
+## <a name="features"></a>Features
+
+### Core CiviCRM
+
+- **Allow extensions to define CSS themes / Add a configuration setting for when
+  to load custom CSS
+  ([CRM-18792](https://issues.civicrm.org/jira/browse/CRM-18792) /
+  [dev/core#378](https://lab.civicrm.org/dev/core/issues/378):
+  [14551](https://github.com/civicrm/civicrm-core/pull/14551) and
+  [12929](https://github.com/civicrm/civicrm-core/pull/12929))**
+
+  Adds an option to the "Display Preferences" settings form to allow users to
+  more finely tune when CiviCRM's css is loaded. On WordPress and Joomla two
+  options are available the "Backend Theme" and "Frontend Theme", on Drupal and
+  Backdrop, the administration screen "Display Preferences" presents a singular
+  "Theme" option.
+
+- **Clean up use of DAO::nullArray
+  ([dev/core#1047](https://lab.civicrm.org/dev/core/issues/1047):
+  [14556](https://github.com/civicrm/civicrm-core/pull/14556),
+  [14555](https://github.com/civicrm/civicrm-core/pull/14555) and
+  [14550](https://github.com/civicrm/civicrm-core/pull/14550))**
+
+  Improves code stability by removing the unnecessary function
+  `CRM_Core_DAO::_nullArray`.
+
+- **Consolidate handling of conflicts between the batch job and get_conflicts
+  api ([14685](https://github.com/civicrm/civicrm-core/pull/14685))**
+
+  Improves code consistency by ensuring that merge conflicts are stored during
+  batch_merge to the prev_next cache with the same format as when the api calls
+  get_conflicts, the code doing this wrangling is moved from the api to the BAO
+  layer.
+
+- **Better support for hookable menubar colors
+  ([14944](https://github.com/civicrm/civicrm-core/pull/14944))**
+
+  More colors in the menu, including the base color, highlight color, and text
+  color, can be modified with hooks.
+
+- **Add csv reader package
+  ([14524](https://github.com/civicrm/civicrm-core/pull/14524))**
+
+  Adds the CSV processing utility, league/csv ^9.2 which will help with future
+  PRs which introduce more test-coverage for CSV outputs and help cleanup some
+  of the csv code down the way.
+
+- **Improve protected field metadata
+  ([14679](https://github.com/civicrm/civicrm-core/pull/14679))**
+
+  Adds more robust metadata to fields protected by permissions in a format that
+  can be directly passed into `CRM_Core_Permissions::check()`.
+
+- **Move api_key read/write permission checks from api to BAO
+  ([14660](https://github.com/civicrm/civicrm-core/pull/14660))**
+
+  Moves the logic for checking the api_key field permissions from the api layer
+  to the BAO layer so it can be reused by api4 and other things.
+
+- **Add a configuration setting for when to load custom CSS (initial work for
+  [dev/core#378](https://lab.civicrm.org/dev/core/issues/378):
+  [14876](https://github.com/civicrm/civicrm-core/pull/14876))**
+
+  A new function, `CRM_Utils_System::isFrontEndPage()`, indicates whether a page
+  is considered "front-end".
+
+- **Permit sort_name as a url parameter on advanced search
+  ([14475](https://github.com/civicrm/civicrm-core/pull/14475) and
+  [14920](https://github.com/civicrm/civicrm-core/pull/14920))**
+
+  You can now set `sort_name=x` in the URL on the advanced search form.  In
+  doing this, the sort name field is now defined through metadata rather than
+  *ad hoc*.
+
+- **Menubar - Improve flexibility & remove hardcoded values
+  ([14924](https://github.com/civicrm/civicrm-core/pull/14924))**
+
+  The menu no longer relies on hardcoded pixel dimensions to determine mobile
+  appearance, and it replaces references to the ID selector `crm-container` with
+  the class selector of the same name (which is used more broadly).
+
+  This also resolves
+  [dev/core#1127](https://lab.civicrm.org/dev/core/issues/1127).
+
+- **Handle relative start & end dates passed to datepicker widget
+  ([14632](https://github.com/civicrm/civicrm-core/pull/14632))**
+
+  Adds some client-side logic to the datepicker widget that was previously done
+  server-side. Paves the way for afform.
+
+- **Improve utilities & tests for working with js notation
+  ([14588](https://github.com/civicrm/civicrm-core/pull/14588),
+  [14537](https://github.com/civicrm/civicrm-core/pull/14537) and
+  [14586](https://github.com/civicrm/civicrm-core/pull/14586))**
+
+  Removes dependence on an external library & improves robustness & accuracy of
+  reading/writing js notation. Adds a utility function for getting properties of
+  a Javascript option without parsing them. Adds a utility function  and a
+  test for dealing with data in js notation.
+
+- **i18n - Improve multilingual popup for text and wysiwyg fields
+  ([14578](https://github.com/civicrm/civicrm-core/pull/14578))**
+
+  Fixes copying of values between multilingual popup and main form for wysiwyg
+  fields and makes text fields larger in multilingual pop-up.
+
+- **Buttons inconsistencies
+  ([dev/core#347](https://lab.civicrm.org/dev/core/issues/347):
+  [14136](https://github.com/civicrm/civicrm-core/pull/14136) and
+  [14509](https://github.com/civicrm/civicrm-core/pull/14509))**
+
+  Adds support for "button" elements in CiviCRM ajax popup forms in addition to
+  the input type=button/submit and the "a class=button". This is a first step
+  towards cleaning up button handling from a theming perspective. Adds
+  buttons to 'Cleanup caches and update paths' in standard way
+
+- **Display description next to 'paperclip' file icon - usually the filename
+  ([14501](https://github.com/civicrm/civicrm-core/pull/14501))**
+
+  When viewing custom files displays the description (usually the filename) next
+  to the paperclip.
+
+- **Address BAO - Handle standard 'custom' param as well as individual fields
+  ([14535](https://github.com/civicrm/civicrm-core/pull/14535))**
+
+  Ensures that the Address BAO can handle both raw unformatted custom field
+  input and processed custom field inputs.
+
+- **Update PSR16 handling for multisite extension legacy caching group
+  ([14505](https://github.com/civicrm/civicrm-core/pull/14505))**
+
+  Only use a Legacy group if using a version of org.civicrm.multisite 2.6 or
+  below.
+
+- **Improve I18n schema by including comments and default and NOT NULL or NULL
+  statements to be more consistent with non lingual schema
+  ([14484](https://github.com/civicrm/civicrm-core/pull/14484))**
+
+  Adds more information to the I18n schema structure so that when the
+  translated schema is created it is more similar to the non multilingual schema.
+
+- **Add a couple customField pseudoconstants
+  ([14494](https://github.com/civicrm/civicrm-core/pull/14494))**
+
+  Adds a couple missing option lists to the schema so that they show up in the
+  api explorer for the CustomField entity.
+
+- **Deprecate ARCHIVE format for CiviCRM Database Logging (continues work for
+  [dev/core#663](https://lab.civicrm.org/dev/core/issues/663):
+  [14256](https://github.com/civicrm/civicrm-core/pull/14256))**
+
+  Switches to using InnoDB for extended log tables instead of the ARCHIVE
+  format.
+
+- **ActivityForm - Redirect to contact page or activity view in standalone mode
+  ([14522](https://github.com/civicrm/civicrm-core/pull/14522))**
+
+  When using the "standalone" New Activity form, moves from always redirecting
+  to the dashboard after saving to redirecting to the contact page (if 1
+  contact) and the activity view screen (if multiple).
+
+### CiviEvent
+
+- **URL support for some params in event search
+  ([14477](https://github.com/civicrm/civicrm-core/pull/14477))**
+
+  Adds Event Search URL support for the params: sort_name, participant_status_id,
+  participant_register_date_low, participant_register_date_high, and
+  participant_register_date_relative. Date format is a string of numbers YmdHIS
+  (ex: 20180101).
+
+- **Add checklist-model angular module
+  ([14634](https://github.com/civicrm/civicrm-core/pull/14634))**
+
+  Adds the angular `checklist-model` library required by form builder.
+
+### CiviContribute
+
+- **Reduce deadlocks on inserting custom data by only using 'ON DUPLICATE' when
+  it is not a new row
+  ([14605](https://github.com/civicrm/civicrm-core/pull/14605))**
+
+  Reduce deadlocks when processing contributions with custom data. This
+  specifically makes the custom data insert SQL more efficient.
+
+- **Fix url support for receive_date_high & receive_date_low
+  ([14594](https://github.com/civicrm/civicrm-core/pull/14594) and
+  [14611](https://github.com/civicrm/civicrm-core/pull/14611))**
+
+  As a part of a general standardization movement, adds Url support on the
+  contribution search form for the following fields: receive_date_high,
+  receive_date_low, contribution_cancel_date_high, contribution_cancel_date_low
+  and invoice_number=9. Deprecates and continues to support the start date being
+  passed to contribution search as "start=2018-01-01".
+
+- **Deprecate contribution_date as a parameter
+  ([14533](https://github.com/civicrm/civicrm-core/pull/14533))**
+
+  Add deprecation notice for accessing old field name for receive_date in query
+  object.
+
+- **Create payment activity when creating a payment via the api, test
+  ([14452](https://github.com/civicrm/civicrm-core/pull/14452))**
+
+  Ensures when creating a payment via the api a payment activity is created.
+
+### CiviMembership
+
+- **Expose Primary member only/Non primary member only filter in membership
+  reports. ([14530](https://github.com/civicrm/civicrm-core/pull/14530) and
+  [14507](https://github.com/civicrm/civicrm-core/pull/14507))**
+
+  On Membership Reports filters tabs, cleans up Membership Owner ID options.
+
+- **Update Owner Membership ID label in reports to be Primary Membership to be
+  more consistent with rest of system
+  ([14585](https://github.com/civicrm/civicrm-core/pull/14585))**
+
+  Changes the label of the Owner Membership ID in reports from "Membership Owner
+  ID" to "Primary Membership".
+
+## <a name="bugs"></a>Bugs resolved
+
+### Core CiviCRM
+
+- **submitOnce revisited
+  ([dev/core#914](https://lab.civicrm.org/dev/core/issues/914):
+  [14519](https://github.com/civicrm/civicrm-core/pull/14519))**
+
+  Ensures "SubmitOnce" functionality works with forms with multiple buttons.
+
+- **[regression] `cv` fails on CiviCRM 5.15.0
+  ([dev/drupal#75](https://lab.civicrm.org/dev/drupal/issues/75):
+  [14775](https://github.com/civicrm/civicrm-core/pull/14775))**
+
+  This fixes the return value of `CRM_Utils_System_Drupal8::languageNegotiationURL()`
+
+- **Errors exporting contributions on 5.13.2 (continues work for
+  [dev/core#1015](https://lab.civicrm.org/dev/core/issues/1015):
+  [14513](https://github.com/civicrm/civicrm-core/pull/14513))**
+
+  Applies a more robust fix to a bug exporting soft credits in 5.13.2.
+
+- **Email created without location when syncing from CMS account
+  ([dev/core#1026](https://lab.civicrm.org/dev/core/issues/1026):
+  [14489](https://github.com/civicrm/civicrm-core/pull/14489))**
+
+  Adds a default for `location_type_id` in the API Email.create in order to
+  address a bug where Emails were being created without a location type when
+  syncing from a CMS account.
+
+- **$this->_selectedTables is not populated incase of boleen filters
+  ([14503](https://github.com/civicrm/civicrm-core/pull/14503))**
+
+  Fixes a bug where when a report was filtered on a boolean field with option No
+  then `$this->_selectedTables` was not being populated so that it is populated.
+
+- **Block classes in unserialize field for IDE cheer
+  ([14683](https://github.com/civicrm/civicrm-core/pull/14683))**
+
+  Ensures unserialize does not permit class unserialization.
+
+- **Support api3 & 4 language syntax & improve test
+  ([14590](https://github.com/civicrm/civicrm-core/pull/14590))**
+
+   Fixes support for api3 "language" option and extends test coverage to the new
+   syntax as well as api v4.
+
+- **Reset language at end of localized api call
+  ([14597](https://github.com/civicrm/civicrm-core/pull/14597))**
+
+  Restore the original language after changing it for an api call using
+  `options['language']`.
+
+- **Activity formRule status check cleanup
+  ([14630](https://github.com/civicrm/civicrm-core/pull/14630))**
+
+  Fixes a bug where under some circumstances, the activity_type_id from fields
+  and from the getKey call can both return NULL, causing the formRule to raise
+  an error that one cannot record a scheduled SMS activity.
+
+- **Add query object support for receive_date_high & receive_date_low and
+  generically date fields
+  ([14623](https://github.com/civicrm/civicrm-core/pull/14623))**
+
+  Ensures choosing from receive date in advanced search filters appropriately.
+
+- **Fix setup.sh crash when using the -a flag
+  ([14595](https://github.com/civicrm/civicrm-core/pull/14595))**
+
+  Fixes an error where the command setup.sh -a dies with an error because it
+  doesn't know what database to load.
+
+- **Fix duplicate households on 'Merge same household' exports
+  ([14443](https://github.com/civicrm/civicrm-core/pull/14443))**
+
+  Ensures "Merge same household" does not create duplicate rows for each
+  household, one for the "merged individuals" and one being the explicit
+  household directly exported.
+
+- **Fix placeholder font in Quicksearch
+  ([14154](https://github.com/civicrm/civicrm-core/pull/14154))**
+
+  Make the Quicksearch font be the CiviCRM font instead of the "FontAwesome"
+  font.
+
+- **CRM_Utils_SQL_ - Properly interpolate NULL values
+  ([14250](https://github.com/civicrm/civicrm-core/pull/14250))**
+
+  Ensures the classes `CRM_Utils_SQL_Select`, `CRM_Utils_SQL_Delete`, and
+  `CRM_Utils_SQL_Insert` properly handle NULL values.
+
+- **Fix deletion of contact sub_type in api4
+  ([14492](https://github.com/civicrm/civicrm-core/pull/14492))**
+
+   Cleans up the contact BAO to not arbitrarily delete a contact's sub-type when
+   saving a contact using Api4.
+
+- **Add in uniqueness to cache keys to mitigate clashes on multisite installs
+  ([14485](https://github.com/civicrm/civicrm-core/pull/14485))**
+
+  Ensures cache keys are unique to the specific domain.
+
+- **Object id is always NULL in ore hook in update activity mode
+  ([14491](https://github.com/civicrm/civicrm-core/pull/14491))**
+
+  Ensures when using the pre hook with the Activity entity, the Activity id (i.e
+  the object id) is NOT NULL.
+
+- **Scheduled jobs: replace outdated wiki link
+  ([14641](https://github.com/civicrm/civicrm-core/pull/14641))**
+
+- **Make the contact summary details popup on merge screen non bold a la contact
+  summary screen ([dev/core#1039](https://lab.civicrm.org/dev/core/issues/1039):
+  [14506](https://github.com/civicrm/civicrm-core/pull/14506))**
+
+- **When using custom fields for smart group criteria with relative dates the
+  group does not respect the relative date over time
+  ([dev/core#389](https://lab.civicrm.org/dev/core/issues/389):
+  [14625](https://github.com/civicrm/civicrm-core/pull/14625))**  
+
+- **Improper character encoding breaks xml processor
+  ([dev-core#1079](https://lab.civicrm.org/dev/core/issues/1079):
+  [14654](https://github.com/civicrm/civicrm-core/pull/14654))**
+
+- **Php 7.2 notices fix on import
+  ([14531](https://github.com/civicrm/civicrm-core/pull/14531))**
+
+- **Fix use of cached schema information in SchemaHandler
+  ([14568](https://github.com/civicrm/civicrm-core/pull/14568))**
+
+- **Ensure that contact groups caches are cleared if memory backed
+  ([14607](https://github.com/civicrm/civicrm-core/pull/14607))**
+
+- **Ensure recently converted groups cache matches previous behaviour by setting
+  `withArray` as fast for it
+  ([14789](https://github.com/civicrm/civicrm-core/pull/14789))**
+
+- **Does CiviCRM make it possible to specify which directories are private and
+  which are public-accessible? (continues work for
+  [dev/cloud-native#3](https://lab.civicrm.org/dev/cloud-native/issues/3):
+  [14717](https://github.com/civicrm/civicrm-core/pull/14717))**
+
+  Removes an unused cache-driver for storing cache records in the file system
+  (under CIVICRM_TEMPLATE_COMPILEDIR, using PHP serialize() format).
+
+### CiviCampaign
+
+- **CiviCRM Campaign, the Revenue Goal field stores 0 if $5,000 or any other
+  non-numeric value is entered
+  ([dev/core#1067](https://lab.civicrm.org/dev/core/issues/1067):
+  [14601](https://github.com/civicrm/civicrm-core/pull/14601))**
+
+### CiviCase
+
+- **Make a_b relationships available as case roles
+  ([dev/core#530](https://lab.civicrm.org/dev/core/issues/530):
+  [13916](https://github.com/civicrm/civicrm-core/pull/13916))**
+
+  This change makes it so users can select b_a relationships AND a_b
+  relationships when creating case roles, before this change only b_a
+  relationships were available when creating case roles.
+
+- **Too many divs in caseTypeDetails.html
+  ([dev/core#1086](https://lab.civicrm.org/dev/core/issues/1086):
+  [14682](https://github.com/civicrm/civicrm-core/pull/14682))**
+
+- **Send copy of case activity is using the contribution receipt template -
+  actually all message templates seem to be mixed up (Test for
+  [dev/core#1082](https://lab.civicrm.org/dev/core/issues/1082):
+  [14666](https://github.com/civicrm/civicrm-core/pull/14666))**
+
+### CiviContribute
+
+- **Add default receive_date for contributions at BAO level
+  ([14460](https://github.com/civicrm/civicrm-core/pull/14460))**
+
+  This change ensures one cannot create contributions with no receive date using
+  the API.
+
+- **Fix A.net to resolve time when using default
+  ([14540](https://github.com/civicrm/civicrm-core/pull/14540))**
+
+  Fixes failure to resolve date in authorize.net - this is likely a test-only
+  bug.
+
+- **Fixed visibility logic on Price field options.
+  ([13966](https://github.com/civicrm/civicrm-core/pull/13966))**
+
+  Ensure that when adding price options to a price field with some public
+  options and some private options the new options are considered when
+  validating that there is an admin option.
+
+- **Support storing IPNs in `civicrm_system_log` for processors that send JSON
+  data ([dev/financial#55](https://lab.civicrm.org/dev/financial/issues/55):
+  [14290](https://github.com/civicrm/civicrm-core/pull/14290))**
+
+  Ensures Stripe can log to the `civicrm_system_log`.
+
+- **Grab contribution status id from database
+  ([14713](https://github.com/civicrm/civicrm-core/pull/14713) and
+  [14704](https://github.com/civicrm/civicrm-core/pull/14704))**
+
+  Replaces hard coded Contribution Status Id with a pseudoconstant.
+
+- **Error in civicrm/payment/edit "Expected one FinancialTrxn but found 25
+  ([dev/core#965](https://lab.civicrm.org/dev/core/issues/965):
+  [14518](https://github.com/civicrm/civicrm-core/pull/14518))**
+
+  Fixes a bug where when ajax popup forms are disabled submitting the payment
+  edit form results in a fatal error "Expected one FinancialTrxn but found 25".
+
+- **New contribution may overwrite other contribution if it's opened in other
+  tab ([dev/financial#50](https://lab.civicrm.org/dev/financial/issues/50):
+  [14244](https://github.com/civicrm/civicrm-core/pull/14244))**
+
+- **Refund throws a fatal error if the main contribution amount is
+  0. ([dev/core#889](https://lab.civicrm.org/dev/core/issues/889):
+  [14488](https://github.com/civicrm/civicrm-core/pull/14488) and
+  [14103](https://github.com/civicrm/civicrm-core/pull/14103))**
+
+- **Event Confirmation and ThankYou forms show tax rate with ALL the decimal
+  places. ([dev/core#1049](https://lab.civicrm.org/dev/core/issues/1049):
+  [14562](https://github.com/civicrm/civicrm-core/pull/14562))**
+
+- **Deprecation notice on Find Contributions when get there from Manage
+  Contribution Pages
+  ([dev/core#1059](https://lab.civicrm.org/dev/core/issues/1059):
+  [14624](https://github.com/civicrm/civicrm-core/pull/14624) and
+  [14613](https://github.com/civicrm/civicrm-core/pull/14613))**
+
+- **Fix refund payment not recording from additional payment form
+  ([14733](https://github.com/civicrm/civicrm-core/pull/14733))**
+
+- **contribution detail report: error when sorting by custom contrib field (DB
+  Error: no such field)
+  ([dev/core#1081](https://lab.civicrm.org/dev/core/issues/1081):
+  [14746](https://github.com/civicrm/civicrm-core/pull/14746))**
+
+- **Fix notice on editing contribution
+  ([14626](https://github.com/civicrm/civicrm-core/pull/14626))**
+
+- **Ensure that completed status is selected by default on search contribution
+  form ([14612](https://github.com/civicrm/civicrm-core/pull/14612))**
+
+- **Fix unreleased regression - fatal on financial account screen
+  ([14900](https://github.com/civicrm/civicrm-core/pull/14900))**
+
+### CiviEvent
+
+- **When creating a new event using a template the new event screen is taking
+  the default values directly from the custom fields, and not from what's saved
+  in the event template.
+  ([dev/core#553](https://lab.civicrm.org/dev/core/issues/553) /
+  [CRM-18570](https://issues.civicrm.org/jira/browse/CRM-18570):
+  [14480](https://github.com/civicrm/civicrm-core/pull/14480))**
+
+- **Display bug for Checkboxes Custom field on Event Confirm / Thank you pages
+  ([dev/core#1058](https://lab.civicrm.org/dev/core/issues/1058):
+  [14587](https://github.com/civicrm/civicrm-core/pull/14587))**
+
+- **Fix incorrect display of Line Items created via API when printing invoice
+  (for Participants)
+  ([13477](https://github.com/civicrm/civicrm-core/pull/13477))**
+
+- **Add a helper function to ensure we always set the correct tab for manage
+  events ([14602](https://github.com/civicrm/civicrm-core/pull/14602))**
+
+- **Removed hardcoded value for registered participant status
+  ([14569](https://github.com/civicrm/civicrm-core/pull/14569))**
+
+### CiviMail
+
+- **Hashed mailing URLs do not work with view mailing links
+  ([dev/core#1037](https://lab.civicrm.org/dev/core/issues/1037):
+  [14508](https://github.com/civicrm/civicrm-core/pull/14508) and
+  [14722](https://github.com/civicrm/civicrm-core/pull/14722))**
+
+### Drupal Integration
+
+- **Drupal8: CiviCRM menu does not use the correct locale (continues work for
+  [dev/drupal#21](https://lab.civicrm.org/dev/drupal/issues/21):
+  [14474](https://github.com/civicrm/civicrm-core/pull/14474))**
+
+  Ensures CiviCRM menu is translated appropriately on Drupal 8 sites using the
+  locale module and CiviCRM in multilingual mode.
+
+- **Drupal8: drupal_set_message is deprecated (or: Event Cart messages display
+  HTML) ([dev/drupal#63](https://lab.civicrm.org/dev/drupal/issues/63):
+  [13959](https://github.com/civicrm/civicrm-core/pull/13959))**
+
+  Fixes a bug where when using CiviCRM Event Cart in Drupal8, some status
+  messages were being displayed as HTML to the user.
+
+### Joomla Integration
+
+- **Upgrade to 5.14 fails on updating case views
+  ([dev/joomla#13](https://lab.civicrm.org/dev/joomla/issues/13):
+  [14707](https://github.com/civicrm/civicrm-core/pull/14707),
+  [14708](https://github.com/civicrm/civicrm-core/pull/14708),
+  [14709](https://github.com/civicrm/civicrm-core/pull/14709),
+  [14710](https://github.com/civicrm/civicrm-core/pull/14710) and
+  [14702](https://github.com/civicrm/civicrm-core/pull/14702))**
+
+- **CiviDist fails on BSD flavor of 'cp' with '-r -p' switch to '-R -p'
+  ([14523](https://github.com/civicrm/civicrm-core/pull/14523))**
+
+  Ensures cividist does not fail for joomla-alt on MacOSX.
+
+### Wordpress Integration
+
+- **Recreate rewrite rules when basepage setting is updated
+  ([157](https://github.com/civicrm/civicrm-wordpress/pull/157))**
+
+  Ensures rewrite rules are flushed when saving the WordPress Base Page setting
+  in CiviCRM.
+
+- **Implement "document_title_parts" filter to apply CiviCRM title on basepage
+  ([158](https://github.com/civicrm/civicrm-wordpress/pull/158))**
+
+  Ensures when Clean URLs are not implemented, the `<title>` element is
+  correctly set on the civicrm base page.
+
+## <a name="misc"></a>Miscellany
+
+- **Revert "[REF] use generic loadStandardSearchOptionsFromUrl". Fix search
+  selections. ([14918](https://github.com/civicrm/civicrm-core/pull/14918))**
+
+- **Remove duplicated code in contribution recur search build function
+  ([14504](https://github.com/civicrm/civicrm-core/pull/14504))**
+
+- **Civi\Angular\ChangeSet - Relax debug-mode consistency check
+  ([14510](https://github.com/civicrm/civicrm-core/pull/14510))**
+
+- **Alter PSR16 code to take into account of new entitysetting release with
+  upgraded caching
+  ([14559](https://github.com/civicrm/civicrm-core/pull/14559))**
+
+- **Remove handling for legacy PrevNextCache group as it has now been converted
+  ([14584](https://github.com/civicrm/civicrm-core/pull/14584),
+  [14631](https://github.com/civicrm/civicrm-core/pull/14631) and
+  [14580](https://github.com/civicrm/civicrm-core/pull/14580))**
+
+- **[Form cleanup] remove form classes & tpls for Event Component settings &
+  Multisite ([14425](https://github.com/civicrm/civicrm-core/pull/14425))**
+
+- **Add WP-oriented E2E test suite, with HookTest as an example
+  ([159](https://github.com/civicrm/civicrm-wordpress/pull/159))**
+
+- **Decommission recordPartialPayment function
+  ([14599](https://github.com/civicrm/civicrm-core/pull/14599))**
+
+- **Fix erroneous variable passed to callAPISuccessGetValue
+  ([14688](https://github.com/civicrm/civicrm-core/pull/14688))**
+
+- **Deprecate some deprecated address functions: defaultCurrencySymbol
+  ([14687](https://github.com/civicrm/civicrm-core/pull/14687))**
+
+- **Extract code converting a date object to local timezone object to own
+  function ([14723](https://github.com/civicrm/civicrm-core/pull/14723))**
+
+- **Replace jcalendar instances with datepicker (continues work for
+  [dev/core#561](https://lab.civicrm.org/dev/core/issues/561):
+  [14593](https://github.com/civicrm/civicrm-core/pull/14593),
+  [14431](https://github.com/civicrm/civicrm-core/pull/14431) and
+  [14627](https://github.com/civicrm/civicrm-core/pull/14627))**
+
+- **[REF] Remove more instances of _nullArray
+  ([14558](https://github.com/civicrm/civicrm-core/pull/14558))**
+
+- **[REF] transform the setting of defaults in CustomField::create to be like
+  (some) other entities
+  ([14671](https://github.com/civicrm/civicrm-core/pull/14671))**
+
+- **[NFC] Fix Test function delcaration to match change in CiviUnitTestCa…
+  ([14548](https://github.com/civicrm/civicrm-core/pull/14548))**
+
+- **[NFC] Fix indenting in Misc Setting Template
+  ([14526](https://github.com/civicrm/civicrm-core/pull/14526))**
+
+- **[NFC] code formatting
+  ([14606](https://github.com/civicrm/civicrm-core/pull/14606))**
+
+- **[NFC][test] reformat jobTest class
+  ([14681](https://github.com/civicrm/civicrm-core/pull/14681))**
+
+- **[NFC] test cleanup. Uses CRM_Core_Exceptions, properly outputs unfiltered
+  results ([14471](https://github.com/civicrm/civicrm-core/pull/14471))**
+
+- **[NFC][test] reformat activity search test
+  ([14699](https://github.com/civicrm/civicrm-core/pull/14699))**
+
+- **[NFC][test] code formatting only
+  ([14700](https://github.com/civicrm/civicrm-core/pull/14700))**
+
+- **[NFC] formatting on test class cleanup
+  ([14649](https://github.com/civicrm/civicrm-core/pull/14649))**
+
+- **NFC These pseudoconstant functions return array or string
+  ([14619](https://github.com/civicrm/civicrm-core/pull/14619))**
+
+- **NFC Comments and formatting only
+  ([14497](https://github.com/civicrm/civicrm-core/pull/14497))**
+
+- **NFC Cleanup comments on BAO event
+  ([14603](https://github.com/civicrm/civicrm-core/pull/14603))**
+
+- **[TEST] add assert to ensure nullArray & nullObject are not contaminated
+  ([14543](https://github.com/civicrm/civicrm-core/pull/14543))**
+
+- **[TEST] Update Email Common Test to incorporate testing for the fix fo…
+  ([14629](https://github.com/civicrm/civicrm-core/pull/14629))**
+
+- **[TEST] Fix intermittent test fail on NULL array getting contaminated
+  ([14542](https://github.com/civicrm/civicrm-core/pull/14542))**
+
+- **[Test] Add in unit test attempting to demonstrate issue caused by dev…
+  ([14637](https://github.com/civicrm/civicrm-core/pull/14637))**
+
+- **[test] Call parent tearDown more consistently
+  ([14552](https://github.com/civicrm/civicrm-core/pull/14552))**
+
+- **[test] convert export test to handle exception rather than early return
+  ([14608](https://github.com/civicrm/civicrm-core/pull/14608))**
+
+- **[test] truncate pledge block when cleaning up financial entities
+  ([14538](https://github.com/civicrm/civicrm-core/pull/14538))**
+
+- **Fix failing test by changing expected date format
+  ([14686](https://github.com/civicrm/civicrm-core/pull/14686))**
+
+- **Fix proportional test to test Payment.create & for the test to make more
+  sense ([14436](https://github.com/civicrm/civicrm-core/pull/14436))**
+
+- **Fix test which fails when run in isolation.
+  ([14517](https://github.com/civicrm/civicrm-core/pull/14517))**
+
+- **[REF] do not receive  by reference in CustomField::create
+  ([14670](https://github.com/civicrm/civicrm-core/pull/14670))**
+
+- **[REF] extract createOptionValue function in CustomField::create
+  ([14652](https://github.com/civicrm/civicrm-core/pull/14652))**
+
+- **[REF] remove instances of pass-by-reference where no change takes place
+  ([14693](https://github.com/civicrm/civicrm-core/pull/14693))**
+
+- **[REF] extract prepareCreate from CustomField.create
+  ([14689](https://github.com/civicrm/civicrm-core/pull/14689))**
+
+- **[REF] Minor code cleanup on string concatenation
+  ([14444](https://github.com/civicrm/civicrm-core/pull/14444))**
+
+- **[REF] Move sort_name definition to searchFieldMetadata
+  ([14478](https://github.com/civicrm/civicrm-core/pull/14478))**
+
+- **[REF] Copy assignProportional Line items back into Payment.create function
+  ([14622](https://github.com/civicrm/civicrm-core/pull/14622))**
+
+- **[REF] minor code cleanup - move indexExist calculation to the only place in
+  the code that needs it
+  ([14650](https://github.com/civicrm/civicrm-core/pull/14650))**
+
+- **[REF] Remove columnName field
+  ([14651](https://github.com/civicrm/civicrm-core/pull/14651))**
+
+- **[REF + test] extract buildFieldChangeSql and add unit test
+  ([14653](https://github.com/civicrm/civicrm-core/pull/14653))**
+
+- **[REF] CRM_Case_BAO_Case::addcaseActivityLinks to CRM_Case_Selector_Search
+  ([14512](https://github.com/civicrm/civicrm-core/pull/14512))**
+
+- **[REF] dev/core#561 Convert Contribution Date field to use date picker…
+  ([14486](https://github.com/civicrm/civicrm-core/pull/14486))**
+
+- **[REF] do not pass  by reference to store & create functions
+  ([14598](https://github.com/civicrm/civicrm-core/pull/14598))**
+
+- **[REF] Add in utility function for resetting ACL and System Level Caches
+  ([14600](https://github.com/civicrm/civicrm-core/pull/14600))**
+
+- **REF Extract getDefaultRoleID for add participant
+  ([14499](https://github.com/civicrm/civicrm-core/pull/14499))**
+
+- **REF Deduplicate recaptcha handling code
+  ([14500](https://github.com/civicrm/civicrm-core/pull/14500))**
+
+- **REF Extract override default currency function
+  ([14496](https://github.com/civicrm/civicrm-core/pull/14496))**
+
+- **REF: Extract preProcess paypalexpress
+  ([14498](https://github.com/civicrm/civicrm-core/pull/14498))**
+
+- **Remove more uses of CRM_Core_DAO::$_nullArray that are unncessary
+  ([14564](https://github.com/civicrm/civicrm-core/pull/14564))**
+
+- **Remove unncessary $_nullArray usage when calling createProfileContact
+  function ([14560](https://github.com/civicrm/civicrm-core/pull/14560))**
+
+- **Remove unneeded use of CRM_Core_DAO::$_nullArray in executeQuery or s…
+  ([14561](https://github.com/civicrm/civicrm-core/pull/14561))**
+
+- **Remove more free calls
+  ([14493](https://github.com/civicrm/civicrm-core/pull/14493))**
+
+- **Remove a few places where pass by reference is used but does not need to be
+  ([14643](https://github.com/civicrm/civicrm-core/pull/14643))**
+
+- **Remove failing assertion
+  ([14695](https://github.com/civicrm/civicrm-core/pull/14695))**
+
+- **Removing unused spec function
+  ([14646](https://github.com/civicrm/civicrm-core/pull/14646))**
+
+- **Remove superfluous pass-by-ref in api3
+  ([14645](https://github.com/civicrm/civicrm-core/pull/14645))**
+
+- **Add in Andrei Mondoc(mecachisenros) to contributor key
+  ([14665](https://github.com/civicrm/civicrm-core/pull/14665))**
+
+- **Adding myself to the contributors file
+  ([14532](https://github.com/civicrm/civicrm-core/pull/14532))**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following code authors:
+
+AGH Strategies - Alice Frumin, Andrew Hunt, Eli Lisseck; Agileware - Alok Patel,
+Francis Whittle; Andrei Mondoc; Australian Greens - Seamus Lee; Christian Wach;
+CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Yashodha Chaku; Coop SymbioTIC -
+Mathieu Lutfy, Samuel Vanhove; Dave D; Electronic Frontier Foundation - Mark
+Burdett; Fuzion - Jitendra Purohit; Greenpeace CEE - Patrick Figel; iXiam -
+César Ramos; JMA Consulting - Monish Deb; John Kingsnorth; Megaphone Technology
+Consulting - Jon Goldberg; MJW Consulting - Matthew Wire; Nicol Wistreich;
+Pradeep Nayak; Squiffle Consulting - Aidan Saunders; Tadpole Collective - Kevin
+Cristiano; Wikimedia Foundation - Eileen McNaughton
+
+Most authors also reviewed code for this release; in addition, the following
+reviewers contributed their comments:
+
+Agileware - Justin Freeman; CiviCoop - Jaap Jansma; CiviDesk - Sunil Pawar;
+Fuzion - Luke Stewart; JMA Consulting - Joe Murray; Korlon - Stuart Gaston;
+Lighthouse Design and Consulting - Brian Shaughnessy; National Urban League -
+Lisa Taliano; Palante Technology Cooperative - Morgan Robinson; Semper IT -
+Karin Gerritsen; Tech To The People - Xavier Dutoit
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Alice Frumin and Andrew Hunt.  If you'd like
+to provide feedback on them, please log in to https://chat.civicrm.org/civicrm
+and contact `@agh1`.
diff --git a/civicrm/settings/Campaign.setting.php b/civicrm/settings/Campaign.setting.php
index a17b25007c25a38420e312e87df643cd7e3f2b58..7f6aaf2c470d84c16a70c927d4ce96a087468605 100644
--- a/civicrm/settings/Campaign.setting.php
+++ b/civicrm/settings/Campaign.setting.php
@@ -49,6 +49,7 @@ return [
     'is_contact' => 0,
     'description' => ts('If set, new contacts that are created when signing a petition are assigned a tag of this name.'),
     'help_text' => '',
+    'settings_pages' => ['campaign' => ['weight' => 10]],
   ],
   'petition_contacts' => [
     'group_name' => 'Campaign Preferences',
@@ -63,6 +64,7 @@ return [
     'is_contact' => 0,
     'description' => ts('All contacts that have signed a CiviCampaign petition will be added to this group. The group will be created if it does not exist (it is required for email verification).'),
     'help_text' => '',
+    'settings_pages' => ['campaign' => ['weight' => 20]],
   ],
 
 ];
diff --git a/civicrm/settings/Core.setting.php b/civicrm/settings/Core.setting.php
index d75631387973484133473432244057cf083ce03e..68d82a2367aebaf3d5bf0ad766f9341a7b99ff0a 100644
--- a/civicrm/settings/Core.setting.php
+++ b/civicrm/settings/Core.setting.php
@@ -1046,7 +1046,7 @@ return [
     'is_contact' => 0,
     'description' => ts('Color of the CiviCRM main menu.'),
     'help_text' => NULL,
-    'validate_callback' => 'CRM_Utils_Rule::color',
+    'validate_callback' => 'CRM_Utils_Color::normalize',
   ],
   'requestableMimeTypes' => [
     'group_name' => 'CiviCRM Preferences',
@@ -1062,6 +1062,48 @@ return [
     'description' => ts('Acceptable Mime Types that can be used as part of file urls'),
     'help_text' => NULL,
   ],
+  'theme_frontend' => [
+    'group_name' => 'CiviCRM Preferences',
+    'group' => 'core',
+    'name' => 'theme_frontend',
+    'type' => 'String',
+    'quick_form_type' => 'Select',
+    'html_type' => 'Select',
+    'html_attributes' => array(
+      'class' => 'crm-select2',
+    ),
+    'pseudoconstant' => array(
+      'callback' => 'call://themes/getAvailable',
+    ),
+    'default' => 'default',
+    'add' => '5.16',
+    'title' => ts('Frontend Theme'),
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'description' => ts('Theme to use on frontend pages'),
+    'help_text' => NULL,
+  ],
+  'theme_backend' => [
+    'group_name' => 'CiviCRM Preferences',
+    'group' => 'core',
+    'name' => 'theme_backend',
+    'type' => 'String',
+    'quick_form_type' => 'Select',
+    'html_type' => 'Select',
+    'html_attributes' => array(
+      'class' => 'crm-select2',
+    ),
+    'pseudoconstant' => array(
+      'callback' => 'call://themes/getAvailable',
+    ),
+    'default' => 'default',
+    'add' => '5.16',
+    'title' => ts('Backend Theme'),
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'description' => ts('Theme to use on backend pages'),
+    'help_text' => NULL,
+  ],
   'http_timeout' => [
     'group_name' => 'CiviCRM Preferences',
     'group' => 'core',
diff --git a/civicrm/settings/Multisite.setting.php b/civicrm/settings/Multisite.setting.php
index f82304b9103960f36c1c2b5316f40c270baea797..669dede5a3301e6e20ffe461882dd038e5a38c28 100644
--- a/civicrm/settings/Multisite.setting.php
+++ b/civicrm/settings/Multisite.setting.php
@@ -50,6 +50,7 @@ return [
     'description' => ts('Make CiviCRM aware of multiple domains. You should configure a domain group if enabled'),
     'documentation_link' => ['page' => 'Multi Site Installation', 'resource' => 'wiki'],
     'help_text' => NULL,
+    'settings_pages' => ['multisite' => ['weight' => 10]],
   ],
   'domain_group_id' => [
     'group_name' => 'Multi Site Preferences',
@@ -65,6 +66,7 @@ return [
     'is_contact' => 0,
     'description' => ts('Contacts created on this site are added to this group'),
     'help_text' => NULL,
+    'settings_pages' => ['multisite' => ['weight' => 20]],
   ],
   'event_price_set_domain_id' => [
     'group_name' => 'Multi Site Preferences',
diff --git a/civicrm/sql/civicrm.mysql b/civicrm/sql/civicrm.mysql
index 27279138c606befa82eb71ad4d41adff2f4e6936..883250392d2f27fc88777ecd9b813e0dd2986f17 100644
--- a/civicrm/sql/civicrm.mysql
+++ b/civicrm/sql/civicrm.mysql
@@ -1860,8 +1860,8 @@ CREATE TABLE `civicrm_custom_field` (
      `end_date_years` int    COMMENT 'Date may be up to end_date_years years after the current date.',
      `date_format` varchar(64)    COMMENT 'date format for custom date',
      `time_format` int unsigned    COMMENT 'time format for custom date',
-     `note_columns` int unsigned    COMMENT ' Number of columns in Note Field ',
-     `note_rows` int unsigned    COMMENT ' Number of rows in Note Field ',
+     `note_columns` int unsigned    COMMENT 'Number of columns in Note Field',
+     `note_rows` int unsigned    COMMENT 'Number of rows in Note Field',
      `column_name` varchar(255)    COMMENT 'Name of the column that holds the values for this field.',
      `option_group_id` int unsigned    COMMENT 'For elements with options, the option group id that is used',
      `filter` varchar(255)    COMMENT 'Stores Contact Get API params contact reference custom fields. May be used for other filters in the future.',
diff --git a/civicrm/sql/civicrm_data.mysql b/civicrm/sql/civicrm_data.mysql
index f75e1f457b2c95da2f8e8a58421503ef0def4a46..d59c6fcd57b3870cfde1d3eef17474fe20e3b47c 100644
--- a/civicrm/sql/civicrm_data.mysql
+++ b/civicrm/sql/civicrm_data.mysql
@@ -24049,4 +24049,4 @@ INSERT INTO `civicrm_report_instance`
     ( `domain_id`, `title`, `report_id`, `description`, `permission`, `form_values`)
 VALUES
     (  @domainID, 'Survey Details', 'survey/detail', 'Detailed report for canvassing, phone-banking, walk lists or other surveys.', 'access CiviReport', 'a:39:{s:6:"fields";a:2:{s:9:"sort_name";s:1:"1";s:6:"result";s:1:"1";}s:22:"assignee_contact_id_op";s:2:"eq";s:25:"assignee_contact_id_value";s:0:"";s:12:"sort_name_op";s:3:"has";s:15:"sort_name_value";s:0:"";s:17:"street_number_min";s:0:"";s:17:"street_number_max";s:0:"";s:16:"street_number_op";s:3:"lte";s:19:"street_number_value";s:0:"";s:14:"street_name_op";s:3:"has";s:17:"street_name_value";s:0:"";s:15:"postal_code_min";s:0:"";s:15:"postal_code_max";s:0:"";s:14:"postal_code_op";s:3:"lte";s:17:"postal_code_value";s:0:"";s:7:"city_op";s:3:"has";s:10:"city_value";s:0:"";s:20:"state_province_id_op";s:2:"in";s:23:"state_province_id_value";a:0:{}s:13:"country_id_op";s:2:"in";s:16:"country_id_value";a:0:{}s:12:"survey_id_op";s:2:"in";s:15:"survey_id_value";a:0:{}s:12:"status_id_op";s:2:"eq";s:15:"status_id_value";s:1:"1";s:11:"custom_1_op";s:2:"in";s:14:"custom_1_value";a:0:{}s:11:"custom_2_op";s:2:"in";s:14:"custom_2_value";a:0:{}s:17:"custom_3_relative";s:1:"0";s:13:"custom_3_from";s:0:"";s:11:"custom_3_to";s:0:"";s:11:"description";s:75:"Detailed report for canvassing, phone-banking, walk lists or other surveys.";s:13:"email_subject";s:0:"";s:8:"email_to";s:0:"";s:8:"email_cc";s:0:"";s:10:"permission";s:17:"access CiviReport";s:6:"groups";s:0:"";s:9:"domain_id";i:1;}');
-UPDATE civicrm_domain SET version = '5.15.2';
+UPDATE civicrm_domain SET version = '5.16.0';
diff --git a/civicrm/sql/civicrm_generated.mysql b/civicrm/sql/civicrm_generated.mysql
index 0791164493ac2815adf2be68393ac5ae078979ef..021ae6c8b1d5d25e6d88e9a03393b52e03b1f426 100644
--- a/civicrm/sql/civicrm_generated.mysql
+++ b/civicrm/sql/civicrm_generated.mysql
@@ -398,7 +398,7 @@ UNLOCK TABLES;
 
 LOCK TABLES `civicrm_domain` WRITE;
 /*!40000 ALTER TABLE `civicrm_domain` DISABLE KEYS */;
-INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.15.2',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
+INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.16.0',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
 /*!40000 ALTER TABLE `civicrm_domain` ENABLE KEYS */;
 UNLOCK TABLES;
 
diff --git a/civicrm/templates/CRM/Admin/Form/Preferences/Campaign.tpl b/civicrm/templates/CRM/Admin/Form/Preferences/Campaign.tpl
deleted file mode 100644
index def983c50a9b0dac5ae41afdb7fece533f1edd1e..0000000000000000000000000000000000000000
--- a/civicrm/templates/CRM/Admin/Form/Preferences/Campaign.tpl
+++ /dev/null
@@ -1,26 +0,0 @@
-{*
- +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
-*}
-{include file="CRM/Form/basicForm.tpl"}
diff --git a/civicrm/templates/CRM/Admin/Form/Preferences/Display.hlp b/civicrm/templates/CRM/Admin/Form/Preferences/Display.hlp
index ae1dde2df3475e5db3d63f68e238b28ea0f109a8..42e406c5f1c7cae52f4228f11975a172516bb900 100644
--- a/civicrm/templates/CRM/Admin/Form/Preferences/Display.hlp
+++ b/civicrm/templates/CRM/Admin/Form/Preferences/Display.hlp
@@ -44,3 +44,48 @@
   {capture assign=invoiceURL}{crmURL p='civicrm/admin/setting/preferences/contribute' q="reset=1"}{/capture} 
   {ts 1=$invoiceURL}In order to enable logged in users to download invoices and credit notes from the dashboard, please first enable CiviCRM invoicing functionality <a href='%1'>Administer > CiviContribute > CiviContribute Component Settings</a>{/ts}
 {/htxt}
+
+{* ***** Theme options ***** *}
+
+{capture assign=themeDefn}
+  <p>
+    {ts}The theme system allows you to change CiviCRM's appearance by replacing important CSS files.{/ts}
+  </p>
+{/capture}
+{capture assign=themeAdv}
+  {* TODO: Update when there is a page to link to:
+  <p>
+    {ts 1='http://fixme.example.com'}For more advanced theming options, consult the <a href="%1">theme documentation</a>.{/ts}
+  </p>
+  *}
+{/capture}
+
+{htxt id="theme-title"}
+  {ts}Theme{/ts}
+{/htxt}
+{htxt id="theme"}
+  {$themeDefn}
+  {$themeAdv}
+{/htxt}
+
+{htxt id="theme_backend-title"}
+  {ts}Backend Theme{/ts}
+{/htxt}
+{htxt id="theme_backend"}
+  {$themeDefn}
+  <p>
+    {ts}The backend theme determines the appearance on administrative screens, such as the "Manage Event" screen.{/ts}
+  </p>
+  {$themeAdv}
+{/htxt}
+
+{htxt id="theme_frontend-title"}
+  {ts}Frontend Theme{/ts}
+{/htxt}
+{htxt id="theme_frontend"}
+  {$themeDefn}
+  <p>
+    {ts}On WordPress, Joomla, or a similar CMS, the frontend theme determines the appearance on user-facing screens, such as the "Event Registration" screen.{/ts}
+  </p>
+  {$themeAdv}
+{/htxt}
diff --git a/civicrm/templates/CRM/Admin/Form/Preferences/Display.tpl b/civicrm/templates/CRM/Admin/Form/Preferences/Display.tpl
index 0aa794a4a46577a8f765ed4a4564e8d19fb85159..336ae914d1d199d151fb13d8b6053c0bfa6abd2e 100644
--- a/civicrm/templates/CRM/Admin/Form/Preferences/Display.tpl
+++ b/civicrm/templates/CRM/Admin/Form/Preferences/Display.tpl
@@ -222,6 +222,22 @@
         {$form.menubar_color.html}
       </td>
     </tr>
+
+    {if $config->userSystem->is_drupal EQ '1'}
+      <tr class="crm-preferences-display-form-block-theme">
+        <td class="label">{ts}Theme{/ts} {help id="theme"}</td>
+        <td>{$form.theme_backend.html}</td>
+      </tr>
+    {else}
+      <tr class="crm-preferences-display-form-block-theme_backend">
+        <td class="label">{$form.theme_backend.label} {help id="theme_backend"}</td>
+        <td>{$form.theme_backend.html}</td>
+      </tr>
+      <tr class="crm-preferences-display-form-block-theme_frontend">
+        <td class="label">{$form.theme_frontend.label} {help id="theme_frontend"}</td>
+        <td>{$form.theme_frontend.html}</td>
+      </tr>
+      {/if}
   </table>
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
 </div>
diff --git a/civicrm/templates/CRM/Admin/Form/Preferences/Multisite.tpl b/civicrm/templates/CRM/Admin/Form/Preferences/Multisite.tpl
deleted file mode 100644
index def983c50a9b0dac5ae41afdb7fece533f1edd1e..0000000000000000000000000000000000000000
--- a/civicrm/templates/CRM/Admin/Form/Preferences/Multisite.tpl
+++ /dev/null
@@ -1,26 +0,0 @@
-{*
- +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
-*}
-{include file="CRM/Form/basicForm.tpl"}
diff --git a/civicrm/templates/CRM/Admin/Form/Setting/Miscellaneous.tpl b/civicrm/templates/CRM/Admin/Form/Setting/Miscellaneous.tpl
index dd6f200e183628339d6cce1f93c996fad6e63c65..69a917f5cc522f28571b1da0373adb72ea01a67d 100644
--- a/civicrm/templates/CRM/Admin/Form/Setting/Miscellaneous.tpl
+++ b/civicrm/templates/CRM/Admin/Form/Setting/Miscellaneous.tpl
@@ -24,106 +24,106 @@
  +--------------------------------------------------------------------+
 *}
 <div class="crm-block crm-form-block crm-miscellaneous-form-block">
-  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
+   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 
     <table class="form-layout">
-        <tr class="crm-miscellaneous-form-block-checksum_timeout">
-            <td class="label">{$form.checksum_timeout.label}</td>
-            <td>{$form.checksum_timeout.html}<br />
-                <span class="description">{ts}The number of days before a personalized (hashed) link will expire.{/ts}</span></td>
-        </tr>
+      <tr class="crm-miscellaneous-form-block-checksum_timeout">
+        <td class="label">{$form.checksum_timeout.label}</td>
+        <td>{$form.checksum_timeout.html}<br />
+            <span class="description">{ts}The number of days before a personalized (hashed) link will expire.{/ts}</span></td>
+      </tr>
     </table>
 
     <table class="form-layout">
-        <tr class="crm-miscellaneous-form-block-contact_undelete">
-          <td class="label">{$form.contact_undelete.label}</td>
-          <td>
-            {$form.contact_undelete.html}<br />
-            <p class="description">{ts}{$contact_undelete_description}{/ts}</p>
-          </td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-logging">
-          <td class="label">{$form.logging.label}</td>
-          <td>
-            {$form.logging.html}<br />
-          {if $validTriggerPermission}
-            <p class="description">{ts}If enabled, all actions will be logged with a complete record of changes.{/ts}</p>
-          {else}
-            <p class="description">{ts}In order to use this functionality, the installation's database user must have privileges to create triggers (in MySQL 5.0 – and in MySQL 5.1 if binary logging is enabled – this means the SUPER privilege). This install either does not seem to have the required privilege enabled.{/ts}&nbsp;{ts}This functionality cannot be enabled on multilingual installations.{/ts}</p>
-           {/if}
-          </td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-doNotAttachPDFReceipt">
-            <td class="label">{$form.doNotAttachPDFReceipt.label}</td>
-            <td>{$form.doNotAttachPDFReceipt.html}<br />
-                <p class="description">{ts}If enabled, CiviCRM sends PDF receipt as an attachment during event signup or online contribution.{/ts}</p>
-            </td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-recordGeneratedLetters">
-            <td class="label">{$form.recordGeneratedLetters.label}</td>
-            <td>{$form.recordGeneratedLetters.html}<br />
-                <p class="description">{ts}When generating a letter (PDF/Word) via mail-merge, how should the letter be recorded?{/ts}</p>
-            </td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-wkhtmltopdfPath">
-            <td class="label">{$form.wkhtmltopdfPath.label}</td>
-            <td>{$form.wkhtmltopdfPath.html}<br />
-                <p class="description">{ts 1="http://wkhtmltopdf.org/"}<a href="%1">wkhtmltopdf is an alternative utility for generating PDF's</a> which may provide better performance especially if you are generating a large number of PDF letters or receipts. Your system administrator will need to download and install this utility, and enter the executable path here.{/ts}</p>
-            </td>
-        </tr>
-        {foreach from=$pure_config_settings item=setting_name}
-          <tr class="crm-miscellaneous-form-block-{$setting_name}">
-            <td class="label">{$form.$setting_name.label}</td>
-            <td>{$form.$setting_name.html}<br />
-              <span class="description">{$setting_descriptions.$setting_name}</span>
-            </td>
-          </tr>
-        {/foreach}
-        <tr class="crm-miscellaneous-form-block-remote_profile_submissions_allowed">
-          <td class="label">{$form.remote_profile_submissions.label}</td>
-          <td>{$form.remote_profile_submissions.html}<br />
-            <p class="description">{ts}If enabled, CiviCRM will allow users to submit profiles from external sites. This is disabled by default to limit abuse.{/ts}</p>
+      <tr class="crm-miscellaneous-form-block-contact_undelete">
+        <td class="label">{$form.contact_undelete.label}</td>
+        <td>
+          {$form.contact_undelete.html}<br />
+          <p class="description">{ts}{$contact_undelete_description}{/ts}</p>
+        </td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-logging">
+        <td class="label">{$form.logging.label}</td>
+        <td>
+          {$form.logging.html}<br />
+        {if $validTriggerPermission}
+          <p class="description">{ts}If enabled, all actions will be logged with a complete record of changes.{/ts}</p>
+        {else}
+          <p class="description">{ts}In order to use this functionality, the installation's database user must have privileges to create triggers (in MySQL 5.0 – and in MySQL 5.1 if binary logging is enabled – this means the SUPER privilege). This install either does not seem to have the required privilege enabled.{/ts}&nbsp;{ts}This functionality cannot be enabled on multilingual installations.{/ts}</p>
+         {/if}
+        </td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-doNotAttachPDFReceipt">
+        <td class="label">{$form.doNotAttachPDFReceipt.label}</td>
+        <td>{$form.doNotAttachPDFReceipt.html}<br />
+          <p class="description">{ts}If enabled, CiviCRM sends PDF receipt as an attachment during event signup or online contribution.{/ts}</p>
+        </td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-recordGeneratedLetters">
+        <td class="label">{$form.recordGeneratedLetters.label}</td>
+        <td>{$form.recordGeneratedLetters.html}<br />
+          <p class="description">{ts}When generating a letter (PDF/Word) via mail-merge, how should the letter be recorded?{/ts}</p>
+        </td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-wkhtmltopdfPath">
+        <td class="label">{$form.wkhtmltopdfPath.label}</td>
+        <td>{$form.wkhtmltopdfPath.html}<br />
+          <p class="description">{ts 1="http://wkhtmltopdf.org/"}<a href="%1">wkhtmltopdf is an alternative utility for generating PDF's</a> which may provide better performance especially if you are generating a large number of PDF letters or receipts. Your system administrator will need to download and install this utility, and enter the executable path here.{/ts}</p>
+        </td>
+      </tr>
+      {foreach from=$pure_config_settings item=setting_name}
+        <tr class="crm-miscellaneous-form-block-{$setting_name}">
+          <td class="label">{$form.$setting_name.label}</td>
+          <td>{$form.$setting_name.html}<br />
+            <span class="description">{$setting_descriptions.$setting_name}</span>
           </td>
         </tr>
-        <tr class="crm-miscellaneous-form-block-allow_alert_autodismissal">
-            <td class="label">{$form.allow_alert_autodismissal.label}</td>
-            <td>{$form.allow_alert_autodismissal.html}<br />
-                <p class="description">{ts}If disabled, CiviCRM will not automatically dismiss any alerts after 10 seconds.{/ts}</p>
-            </td>
-        </tr>
+      {/foreach}
+      <tr class="crm-miscellaneous-form-block-remote_profile_submissions_allowed">
+        <td class="label">{$form.remote_profile_submissions.label}</td>
+        <td>{$form.remote_profile_submissions.html}<br />
+          <p class="description">{ts}If enabled, CiviCRM will allow users to submit profiles from external sites. This is disabled by default to limit abuse.{/ts}</p>
+        </td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-allow_alert_autodismissal">
+        <td class="label">{$form.allow_alert_autodismissal.label}</td>
+        <td>{$form.allow_alert_autodismissal.html}<br />
+          <p class="description">{ts}If disabled, CiviCRM will not automatically dismiss any alerts after 10 seconds.{/ts}</p>
+        </td>
+      </tr>
     </table>
 
     <h3>{ts}reCAPTCHA Keys{/ts}</h3>
 
     <div class="description">
-        {ts 1="https://www.google.com/recaptcha"}reCAPTCHA is a free service that helps prevent automated abuse of your site. To use reCAPTCHA on public-facing CiviCRM forms: sign up at <a href="%1" "target=_blank">Google's reCaptcha site</a>; enter the provided public and private reCAPTCHA keys here; then enable reCAPTCHA under Advanced Settings in any Profile.{/ts}
+      {ts 1="https://www.google.com/recaptcha"}reCAPTCHA is a free service that helps prevent automated abuse of your site. To use reCAPTCHA on public-facing CiviCRM forms: sign up at <a href="%1" "target=_blank">Google's reCaptcha site</a>; enter the provided public and private reCAPTCHA keys here; then enable reCAPTCHA under Advanced Settings in any Profile.{/ts}
     </div>
     <table class="form-layout">
-        <tr class="crm-miscellaneous-form-block-recaptchaPublicKey">
-            <td class="label">{$form.recaptchaPublicKey.label}</td>
-            <td>{$form.recaptchaPublicKey.html}</td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-recaptchaPrivateKey">
-            <td class="label">{$form.recaptchaPrivateKey.label}</td>
-            <td>{$form.recaptchaPrivateKey.html}</td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-recaptchaOptions">
-            <td class="label">{$form.recaptchaOptions.label}</td>
-            <td>{$form.recaptchaOptions.html}<br />
-              <span class="description">
-                {ts}You can specify the reCAPTCHA theme options as comma separated data.(eg: theme:'blackglass', lang : 'fr' ).{/ts}
-                <br />
-                {ts 1='href="https://developers.google.com/recaptcha/docs/display#config" target="_blank"'}Check the available options at <a %1>Customizing the Look and Feel of reCAPTCHA</a>.{/ts}
-              </span>
-            </td>
-        </tr>
-        <tr class="crm-miscellaneous-form-block-recaptchaPrivateKey">
-            <td class="label">{$form.forceRecaptcha.label}</td>
-            <td>
-              {$form.forceRecaptcha.html}
-              <p class="description">{ts}If enabled, reCAPTCHA will show on all contribution pages.{/ts}</p>
-            </td>
-        </tr>
-        </table>
-           <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
+      <tr class="crm-miscellaneous-form-block-recaptchaPublicKey">
+        <td class="label">{$form.recaptchaPublicKey.label}</td>
+        <td>{$form.recaptchaPublicKey.html}</td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-recaptchaPrivateKey">
+        <td class="label">{$form.recaptchaPrivateKey.label}</td>
+        <td>{$form.recaptchaPrivateKey.html}</td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-recaptchaOptions">
+        <td class="label">{$form.recaptchaOptions.label}</td>
+        <td>{$form.recaptchaOptions.html}<br />
+          <span class="description">
+            {ts}You can specify the reCAPTCHA theme options as comma separated data.(eg: theme:'blackglass', lang : 'fr' ).{/ts}
+            <br />
+            {ts 1='href="https://developers.google.com/recaptcha/docs/display#config" target="_blank"'}Check the available options at <a %1>Customizing the Look and Feel of reCAPTCHA</a>.{/ts}
+          </span>
+        </td>
+      </tr>
+      <tr class="crm-miscellaneous-form-block-recaptchaPrivateKey">
+        <td class="label">{$form.forceRecaptcha.label}</td>
+        <td>
+          {$form.forceRecaptcha.html}
+          <p class="description">{ts}If enabled, reCAPTCHA will show on all contribution pages.{/ts}</p>
+        </td>
+      </tr>
+    </table>
+  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
 </div>
diff --git a/civicrm/templates/CRM/Admin/Form/Setting/UpdateConfigBackend.tpl b/civicrm/templates/CRM/Admin/Form/Setting/UpdateConfigBackend.tpl
index 9d7fe82c6883068424e1c2b507e4e55e395aad62..3d1a3e6a61e32ec8c6665369ec9087c564679b13 100644
--- a/civicrm/templates/CRM/Admin/Form/Setting/UpdateConfigBackend.tpl
+++ b/civicrm/templates/CRM/Admin/Form/Setting/UpdateConfigBackend.tpl
@@ -24,26 +24,15 @@
  +--------------------------------------------------------------------+
 *}
 <div class="help">
-    <p>
+  <p>
     {ts}When migrating a site to a new server, the paths and URLs of your CiviCRM installation may change. {/ts}
-    </p>
-    <p>
+  </p>
+  <p>
     {capture assign="pathsURL"}{crmURL p="civicrm/admin/setting/path" q="reset=1"}{/capture}
     {capture assign="urlsURL"}{crmURL p="civicrm/admin/setting/url" q="reset=1"}{/capture}
     {ts 1=$pathsURL 2=$urlsURL}The old paths and URLs may be retained in some database records. Use this form to clear caches or to reset paths to their defaults. If you need further customizations, then update the <a href="%1">Directories</a> and <a href="%2">Resource URLs</a>.{/ts}
-    </p>
+  </p>
 </div>
 <div class="crm-block crm-form-block crm-config-backend-form-block">
-        <div class="crm-submit-buttons">
-          <span class="crm-button crm-i-button">
-            <i class="crm-i fa-undo"></i>
-            {$form._qf_UpdateConfigBackend_next_cleanup.html}
-          </span>
-          <span class="crm-button crm-i-button">
-            <i class="crm-i fa-terminal"></i>
-            {$form._qf_UpdateConfigBackend_next_resetpaths.html}
-          </span>
-        </div>
-        <div>{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
-<div class="spacer"></div>
+  <div>{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
 </div>
diff --git a/civicrm/templates/CRM/Admin/Page/Job.tpl b/civicrm/templates/CRM/Admin/Page/Job.tpl
index 2001bfa815a4404bc1ada42227bddb7902f69a9c..678349897effdf6083b81adb0238599f2a5f88ab 100644
--- a/civicrm/templates/CRM/Admin/Page/Job.tpl
+++ b/civicrm/templates/CRM/Admin/Page/Job.tpl
@@ -25,7 +25,7 @@
 *}
 {capture assign=runAllURL}{crmURL p='civicrm/admin/runjobs' q="reset=1"}{/capture}
 <div class="help">
-    {ts 1=$runAllURL}You can configure scheduled jobs (cron tasks) for your CiviCRM installation. For most sites, your system administrator should set up one or more 'cron' tasks to run the enabled jobs. However, you can also <a href="%1">run all scheduled jobs manually</a>, or run specific jobs from this screen (click 'more' and then 'Execute Now').{/ts} {docURL page="Managing Scheduled Jobs" resource="wiki" text="(Job parameters and command line syntax documentation...)"}
+    {ts 1=$runAllURL}You can configure scheduled jobs (cron tasks) for your CiviCRM installation. For most sites, your system administrator should set up one or more 'cron' tasks to run the enabled jobs. However, you can also <a href="%1">run all scheduled jobs manually</a>, or run specific jobs from this screen (click 'more' and then 'Execute Now').{/ts} {docURL page="sysadmin/setup/jobs" text="(Job parameters and command line syntax documentation...)"}
 </div>
 
 {if $action eq 1 or $action eq 2 or $action eq 8}
diff --git a/civicrm/templates/CRM/Batch/Form/Entry.tpl b/civicrm/templates/CRM/Batch/Form/Entry.tpl
index 6233b3f9885b087e92637327f471b3c4eb622870..994f2448022d39ef1965ac99b3bdfd522ff44c82 100644
--- a/civicrm/templates/CRM/Batch/Form/Entry.tpl
+++ b/civicrm/templates/CRM/Batch/Form/Entry.tpl
@@ -54,7 +54,7 @@
       <td class="label">
         <label>{ts}Total amount entered{/ts}</label>
       </td>
-      <td class="right">{$config->defaultCurrencySymbol} <span class="batch-actual-total"></span></td>
+      <td class="right">{$defaultCurrencySymbol} <span class="batch-actual-total"></span></td>
     </tr>
   </table>
 
diff --git a/civicrm/templates/CRM/Case/XMLProcessor/Report.tpl b/civicrm/templates/CRM/Case/XMLProcessor/Report.tpl
index a3384c5c5e9d218e087771f5f5fe47353fcba250..99f8aa94819d790ea9bcab095a8e0d2d6862dd00 100644
--- a/civicrm/templates/CRM/Case/XMLProcessor/Report.tpl
+++ b/civicrm/templates/CRM/Case/XMLProcessor/Report.tpl
@@ -25,7 +25,7 @@
 *}
 <?xml version="1.0" encoding="UTF-8"?>
 <Case>
-  <Client>{$case.clientName}</Client>
+  <Client>{$case.clientName|escape}</Client>
   <CaseType>{$case.caseType}</CaseType>
   <CaseSubject>{$case.subject|escape}</CaseSubject>
   <CaseStatus>{$case.status}</CaseStatus>
@@ -70,4 +70,3 @@
 {/foreach}
   </ActivitySet>
 </Case>
-
diff --git a/civicrm/templates/CRM/Contact/Form/Search/Custom/ContributionAggregate.tpl b/civicrm/templates/CRM/Contact/Form/Search/Custom/ContributionAggregate.tpl
index 4f9da68e169dc404b5ae97674bf2628962e02024..0022ef836cfb47218c59401c479c2a54b0261d95 100644
--- a/civicrm/templates/CRM/Contact/Form/Search/Custom/ContributionAggregate.tpl
+++ b/civicrm/templates/CRM/Contact/Form/Search/Custom/ContributionAggregate.tpl
@@ -39,11 +39,15 @@
                 </tr>
             {/foreach}
             <tr class="crm-contact-custom-search-contributionDetails-form-block-receive_date">
-              <td class="label">{ts}Contribution Dates{/ts}</td>
-              {include file="CRM/Core/DateRange.tpl" fieldName="contribution_date" from='_low' to='_high'}
+              <td class="label" for="receive_date_relative">
+                <label>{ts}Contribution Dates{/ts}</label>
+              </td>
+              {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="receive_date" colspan="2"}
             </tr>
             <tr class="crm-contact-custom-search-contributionDetails-form-block-financial_type">
-                <td class="label">{ts}Financial Type{/ts}</td>
+                <td class="label" for="financial_type_id">
+                  <label>{ts}Financial Type{/ts}</label>
+                </td>
                 <td>{$form.financial_type_id.html|crmAddClass:twenty}</td>
             </tr>
         </table>
diff --git a/civicrm/templates/CRM/Contribute/Form/Search/Common.tpl b/civicrm/templates/CRM/Contribute/Form/Search/Common.tpl
index 368d31ecc4ccaad943a0335900fd856f99172f8e..e2ff246741f01f3d21815c0ed6da2318c4b43d31 100644
--- a/civicrm/templates/CRM/Contribute/Form/Search/Common.tpl
+++ b/civicrm/templates/CRM/Contribute/Form/Search/Common.tpl
@@ -24,9 +24,8 @@
  +--------------------------------------------------------------------+
 *}
 
-<tr><td><label>{ts}Date Received{/ts}</label></td></tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="contribution_date" from='_low' to='_high'}
+{include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="receive_date" colspan="2"}
 </tr>
 <tr>
   <td><label>{ts}Contribution Amounts{/ts}</label> <br />
@@ -157,27 +156,21 @@
     {$form.contribution_pcp_made_through_id.html}
     {include file="CRM/Contribute/Form/PCP.js.tpl"}
   </td>
-  <td>
-    {$form.cancel_reason.label}<br />
-    {$form.cancel_reason.html}
-  </td>
+  <td>&nbsp;</td>
 </tr>
 <tr>
   <td>
     {$form.contribution_pcp_display_in_roll.label}
     {$form.contribution_pcp_display_in_roll.html}
   </td>
+</tr>
+<tr>
+  {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="contribution_cancel_date" colspan="2"}
+</tr>
+<tr>
   <td>
-    <table style="width:auto">
-      <tr>
-        <td>
-          <label>{ts}Cancelled / Refunded Date{/ts}</label>
-        </td>
-      </tr>
-      <tr>
-        {include file="CRM/Core/DateRange.tpl" fieldName="contribution_cancel_date" from='_low' to='_high'}
-      </tr>
-    </table>
+    {$form.cancel_reason.label}<br />
+    {$form.cancel_reason.html}
   </td>
 </tr>
 
diff --git a/civicrm/templates/CRM/Event/Form/Participant.tpl b/civicrm/templates/CRM/Event/Form/Participant.tpl
index 6ffa6fb72588d54b042ad9bbe45f4ce62f18427f..e62dbf5ae7685feb24ebcffb82e2c59c5e257fcf 100644
--- a/civicrm/templates/CRM/Event/Form/Participant.tpl
+++ b/civicrm/templates/CRM/Event/Form/Participant.tpl
@@ -395,6 +395,9 @@
           {if $urlPathVar}
           dataUrl += '&' + '{$urlPathVar}';
           {/if}
+          {if $isBackOffice}
+            dataUrl += '&' + 'is_backoffice=1';
+          {/if}
 
           {literal}
           var eventId = $('[name=event_id], #event_id', $form).val();
diff --git a/civicrm/templates/CRM/common/jsortable.tpl b/civicrm/templates/CRM/common/jsortable.tpl
index 7beb21dae90e2a51ccb4728ce42f647610a6c015..a83957e16def220177e2cb29f1e2a9d24fc241cc 100644
--- a/civicrm/templates/CRM/common/jsortable.tpl
+++ b/civicrm/templates/CRM/common/jsortable.tpl
@@ -167,7 +167,7 @@
 
   //plugin to sort on currency
   cj.fn.dataTableExt.oSort['currency-asc']  = function(a,b) {
-    var symbol = "{/literal}{$config->defaultCurrencySymbol()}{literal}";
+    var symbol = "{/literal}{$defaultCurrencySymbol}{literal}";
     var x = (a == "-") ? 0 : a.replace( symbol, "" );
     var y = (b == "-") ? 0 : b.replace( symbol, "" );
     x = parseFloat( x );
@@ -176,7 +176,7 @@
   };
 
   cj.fn.dataTableExt.oSort['currency-desc'] = function(a,b) {
-    var symbol = "{/literal}{$config->defaultCurrencySymbol()}{literal}";
+    var symbol = "{/literal}{$defaultCurrencySymbol}{literal}";
     var x = (a == "-") ? 0 : a.replace( symbol, "" );
     var y = (b == "-") ? 0 : b.replace( symbol, "" );
     x = parseFloat( x );
diff --git a/civicrm/templates/CRM/common/l10n.js.tpl b/civicrm/templates/CRM/common/l10n.js.tpl
index f2047652cc8a939367b8e7e55c99b289546d726e..89e923e150de0539436ce11ea77533d1323e7499 100644
--- a/civicrm/templates/CRM/common/l10n.js.tpl
+++ b/civicrm/templates/CRM/common/l10n.js.tpl
@@ -42,7 +42,7 @@
   CRM.config.entityRef = $.extend({ldelim}{rdelim}, {$entityRef|@json_encode}, CRM.config.entityRef || {ldelim}{rdelim});
 
   // Initialize CRM.url and CRM.formatMoney
-  CRM.url({ldelim}back: '{crmURL p="*path*" q="*query*" h=0 fb=1}', front: '{crmURL p="*path*" q="*query*" h=0 fe=1}'{rdelim});
+  CRM.url({ldelim}back: '{crmURL p="civicrm-placeholder-url-path" q="civicrm-placeholder-url-query=1" h=0 fb=1}', front: '{crmURL p="civicrm-placeholder-url-path" q="civicrm-placeholder-url-query=1" h=0 fe=1}'{rdelim});
   CRM.formatMoney('init', false, {$moneyFormat});
 
   // Localize select2
diff --git a/civicrm/vendor/autoload.php b/civicrm/vendor/autoload.php
index 835a5840518040c7a026900bf29705b9b7f9c977..cd18aa12106d6a25919602a71d53fe7306c6b021 100644
--- a/civicrm/vendor/autoload.php
+++ b/civicrm/vendor/autoload.php
@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc::getLoader();
+return ComposerAutoloaderInitd5a4836e150dcf81a7364359449f0717::getLoader();
diff --git a/civicrm/vendor/composer/autoload_files.php b/civicrm/vendor/composer/autoload_files.php
index c044948f25a4b4e53c1a61f1012e5b104e894a8f..ee86ff3ce2234af69d9beeb07635f57a98c4521c 100644
--- a/civicrm/vendor/composer/autoload_files.php
+++ b/civicrm/vendor/composer/autoload_files.php
@@ -13,5 +13,6 @@ return array(
     'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
     '5636a0a89fc28f9cfa8624493b142015' => $vendorDir . '/civicrm/civicrm-setup/civicrm-setup-autoload.php',
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
+    '9e4824c5afbdc1482b6025ce3d4dfde8' => $vendorDir . '/league/csv/src/functions_include.php',
     'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
 );
diff --git a/civicrm/vendor/composer/autoload_psr4.php b/civicrm/vendor/composer/autoload_psr4.php
index 2b7efa49a3a50804bca1fc85952fef44276c649e..5da2a783b667a5533f18560827a0dcc68c913aff 100644
--- a/civicrm/vendor/composer/autoload_psr4.php
+++ b/civicrm/vendor/composer/autoload_psr4.php
@@ -27,6 +27,7 @@ return array(
     'MimeType\\' => array($vendorDir . '/katzien/php-mime-type/src'),
     'MJS\\TopSort\\Tests\\' => array($vendorDir . '/marcj/topsort/tests/Tests'),
     'MJS\\TopSort\\' => array($vendorDir . '/marcj/topsort/src'),
+    'League\\Csv\\' => array($vendorDir . '/league/csv/src'),
     'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
     'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
     'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
diff --git a/civicrm/vendor/composer/autoload_real.php b/civicrm/vendor/composer/autoload_real.php
index e5ae70a68ea307ad0b99094cab2a076ce243f7c5..7d70d1d1f12033c4b06d9d13ae9bf0d498e93ef3 100644
--- a/civicrm/vendor/composer/autoload_real.php
+++ b/civicrm/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc
+class ComposerAutoloaderInitd5a4836e150dcf81a7364359449f0717
 {
     private static $loader;
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInitd5a4836e150dcf81a7364359449f0717', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        spl_autoload_unregister(array('ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInitd5a4836e150dcf81a7364359449f0717', 'loadClassLoader'));
 
         $includePaths = require __DIR__ . '/include_paths.php';
         $includePaths[] = get_include_path();
@@ -31,7 +31,7 @@ class ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc
         if ($useStaticLoader) {
             require_once __DIR__ . '/autoload_static.php';
 
-            call_user_func(\Composer\Autoload\ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::getInitializer($loader));
+            call_user_func(\Composer\Autoload\ComposerStaticInitd5a4836e150dcf81a7364359449f0717::getInitializer($loader));
         } else {
             $map = require __DIR__ . '/autoload_namespaces.php';
             foreach ($map as $namespace => $path) {
@@ -52,19 +52,19 @@ class ComposerAutoloaderInit74c53cd33f5acb326b2e2d0c9fd7a2cc
         $loader->register(true);
 
         if ($useStaticLoader) {
-            $includeFiles = Composer\Autoload\ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::$files;
+            $includeFiles = Composer\Autoload\ComposerStaticInitd5a4836e150dcf81a7364359449f0717::$files;
         } else {
             $includeFiles = require __DIR__ . '/autoload_files.php';
         }
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire74c53cd33f5acb326b2e2d0c9fd7a2cc($fileIdentifier, $file);
+            composerRequired5a4836e150dcf81a7364359449f0717($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
 
-function composerRequire74c53cd33f5acb326b2e2d0c9fd7a2cc($fileIdentifier, $file)
+function composerRequired5a4836e150dcf81a7364359449f0717($fileIdentifier, $file)
 {
     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
         require $file;
diff --git a/civicrm/vendor/composer/autoload_static.php b/civicrm/vendor/composer/autoload_static.php
index 3c8c3002cb5faabc2832ff306485c60c689f51e8..86f3fc03d859739fcf833499f468429db7d974eb 100644
--- a/civicrm/vendor/composer/autoload_static.php
+++ b/civicrm/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc
+class ComposerStaticInitd5a4836e150dcf81a7364359449f0717
 {
     public static $files = array (
         '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
@@ -14,6 +14,7 @@ class ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc
         'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
         '5636a0a89fc28f9cfa8624493b142015' => __DIR__ . '/..' . '/civicrm/civicrm-setup/civicrm-setup-autoload.php',
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
+        '9e4824c5afbdc1482b6025ce3d4dfde8' => __DIR__ . '/..' . '/league/csv/src/functions_include.php',
         'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
     );
 
@@ -54,6 +55,10 @@ class ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc
             'MJS\\TopSort\\Tests\\' => 18,
             'MJS\\TopSort\\' => 12,
         ),
+        'L' => 
+        array (
+            'League\\Csv\\' => 11,
+        ),
         'G' => 
         array (
             'GuzzleHttp\\Psr7\\' => 16,
@@ -161,6 +166,10 @@ class ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc
         array (
             0 => __DIR__ . '/..' . '/marcj/topsort/src',
         ),
+        'League\\Csv\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/league/csv/src',
+        ),
         'GuzzleHttp\\Psr7\\' => 
         array (
             0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
@@ -447,11 +456,11 @@ class ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::$prefixDirsPsr4;
-            $loader->prefixesPsr0 = ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::$prefixesPsr0;
-            $loader->fallbackDirsPsr0 = ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::$fallbackDirsPsr0;
-            $loader->classMap = ComposerStaticInit74c53cd33f5acb326b2e2d0c9fd7a2cc::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInitd5a4836e150dcf81a7364359449f0717::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInitd5a4836e150dcf81a7364359449f0717::$prefixDirsPsr4;
+            $loader->prefixesPsr0 = ComposerStaticInitd5a4836e150dcf81a7364359449f0717::$prefixesPsr0;
+            $loader->fallbackDirsPsr0 = ComposerStaticInitd5a4836e150dcf81a7364359449f0717::$fallbackDirsPsr0;
+            $loader->classMap = ComposerStaticInitd5a4836e150dcf81a7364359449f0717::$classMap;
 
         }, null, ClassLoader::class);
     }
diff --git a/civicrm/vendor/composer/installed.json b/civicrm/vendor/composer/installed.json
index b0da1df71af44f8c6669f8d0be6ffdbd838d03a0..2114774cd482884e846409ee82e455c9513c5363 100644
--- a/civicrm/vendor/composer/installed.json
+++ b/civicrm/vendor/composer/installed.json
@@ -583,6 +583,75 @@
             "php"
         ]
     },
+    {
+        "name": "league/csv",
+        "version": "9.2.1",
+        "version_normalized": "9.2.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/thephpleague/csv.git",
+            "reference": "b574a7d8b28f1528e011d8652fb7d2e83410d4c9"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/thephpleague/csv/zipball/b574a7d8b28f1528e011d8652fb7d2e83410d4c9",
+            "reference": "b574a7d8b28f1528e011d8652fb7d2e83410d4c9",
+            "shasum": ""
+        },
+        "require": {
+            "ext-mbstring": "*",
+            "php": ">=7.0.10"
+        },
+        "require-dev": {
+            "ext-curl": "*",
+            "friendsofphp/php-cs-fixer": "^2.12",
+            "phpstan/phpstan": "^0.9.2",
+            "phpstan/phpstan-phpunit": "^0.9.4",
+            "phpstan/phpstan-strict-rules": "^0.9.0",
+            "phpunit/phpunit": "^6.0"
+        },
+        "suggest": {
+            "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
+        },
+        "time": "2019-06-07T06:24:33+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "9.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "League\\Csv\\": "src"
+            },
+            "files": [
+                "src/functions_include.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Ignace Nyamagana Butera",
+                "email": "nyamsprod@gmail.com",
+                "homepage": "https://github.com/nyamsprod/",
+                "role": "Developer"
+            }
+        ],
+        "description": "Csv data manipulation made easy in PHP",
+        "homepage": "http://csv.thephpleague.com",
+        "keywords": [
+            "csv",
+            "export",
+            "filter",
+            "import",
+            "read",
+            "write"
+        ]
+    },
     {
         "name": "marcj/topsort",
         "version": "1.1.0",
diff --git a/civicrm/vendor/league/csv/CHANGELOG.md b/civicrm/vendor/league/csv/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..e78a4b2fe2f964b2554621be775fd8cce9fe0078
--- /dev/null
+++ b/civicrm/vendor/league/csv/CHANGELOG.md
@@ -0,0 +1,960 @@
+# Changelog
+
+All Notable changes to `Csv` will be documented in this file
+
+## Next - TBD
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `AbstractCSV::chunk` see [#325](https://github.com/thephpleague/csv/pull/325) remove CSV flags from the Stream class to avoid infinite loop.
+- Internal improve `HTMLConverter`.
+
+### Removed
+
+- Nothing
+
+## 9.2.0 - 2019-03-08
+
+### Added
+
+- Supports for PHP7.4 empty string for the escape character
+- Supports for empty string for the escape character with a polyfill for PHP7.4- versions.
+- `AbstractCSV::getPathname` see [#321](https://github.com/thephpleague/csv/pull/321) thanks [@tomkyle](https://github.com/tomkyle)
+
+### Deprecated
+
+- `League\Csv\RFC4180Field` use `AbstractCSV::setEscape` method with an empty string instead.
+
+### Fixed
+
+- `AbstractCSV::__construct` correctly initializes properties
+- `AbstractCSV::createFromString` named constructor default argument is now the empty string
+- `AbstractCSV::setEscape` now accepts the empty string like `fputcsv` and `fgetcsv`
+- `Writer::insertOne` fixes throwing exception when record can not be inserted
+- `XMLConverter` convert to string the record value to avoid PHP warning on `null` value
+- Internal `Stream::createFromString` named constructor default argument is now the empty string
+- Internal `Stream::fwrite` improved
+- Internal `Stream::__destruct` no longer emit warning on invalid stream filter removal.
+- Internal `Stream::seek` returns `0` if the seeked position `0` is valid see [#321](https://github.com/thephpleague/csv/pull/332) thanks [@HaozhouChen](https://github.com/HaozhouChen) 
+
+- `Reader:getHeader` when the record is an empty line.
+
+### Removed
+
+- Nothing
+
+## 9.1.4 - 2018-05-01
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `Writer::setFlushThreshold` should accept 1 as an argument [#289](https://github.com/thephpleague/csv/issue/289)
+- `CharsetConverter::convert` should not try to convert numeric value [#287](https://github.com/thephpleague/csv/issue/287)
+
+### Removed
+
+- Nothing
+
+## 9.1.3 - 2018-03-12
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `Writer::insertOne` allow empty array to be added to the CSV (allow inserting empty row)
+- Removed all return type from named constructor see [#285](https://github.com/thephpleague/csv/pull/285)
+- Added PHPStan for static code analysis
+
+### Removed
+
+- Nothing
+
+## 9.1.2 - 2018-02-05
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `is_iterable` polyfill for PHP7.0
+- `Reader::getHeader` no longer throws exception because of a bug in PHP7.2+ [issue #279](https://github.com/thephpleague/csv/issues/279)
+
+### Removed
+
+- Nothing
+
+## 9.1.1 - 2017-11-28
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- issue with `error_get_last` usage when using a modified PHP error handler see [#254](https://github.com/thephpleague/csv/issues/254) - fixed by [@csiszarattila](https://github.com/csiszarattila)
+
+- Removed seekable word from Stream exception messages.
+
+### Removed
+
+- Nothing
+
+## 9.1.0 - 2017-10-20
+
+### Added
+
+- Support for non seekable stream. When seekable feature are required an exceptions will be thrown.
+- `League\Csv\EncloseField` to force enclosure insertion on every field. [#269](https://github.com/thephpleague/csv/pull/269)
+- `League\Csv\EscapeFormula` a League CSV formatter to prevent CSV Formula Injection in Spreadsheet programs.
+- `League\Csv\RFC4180Field::addTo` accept an option `$replace_whitespace` argument to improve RFC4180 compliance.
+- `League\Csv\Abstract::getContent` to replace `League\Csv\Abstract::__toString`. The `__toString` method may trigger a Fatal Error with non seekable stream, instead you are recommended to used the new `getContent` method which will trigger an exception instead.
+
+### Deprecated
+
+- `League\Csv\Abstract::__toString` use `League\Csv\Abstract::getContent` instead. the `__toString` triggers a Fatal Error when used on a non-seekable CSV document. use the `getContent` method instead which will trigger an exception instead.
+
+### Fixed
+
+- Bug fixes headers from AbstractCsv::output according to RFC6266 [#250](https://github.com/thephpleague/csv/issues/250)
+- Make sure the internal source still exists before closing it [#251](https://github.com/thephpleague/csv/issues/251)
+- Make sure the `Reader::createFromPath` default open mode is `r` see [#258](https://github.com/thephpleague/csv/pull/258) and [#266](https://github.com/thephpleague/csv/pull/266)
+
+### Removed
+
+- Nothing
+
+## 9.0.1 - 2017-08-21
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- CSV controls not applied when calling Writer::insertOne
+
+### Removed
+
+- Nothing
+
+## 9.0.0 - 2017-08-18
+
+### Added
+
+- Improved CSV Records selection
+    - `League\Csv\Reader::getRecords` to access all CSV records
+    - `League\Csv\Statement` provides a constraint builder to select CSV records.
+    - `League\Csv\ResultSet` represents the result set of the selected CSV records.
+    - `League\Csv\delimiter_detect` function to detect CSV delimiter character
+- Improved CSV document header selection.
+    - `League\Csv\Reader::getHeader`
+    - `League\Csv\Reader::getHeaderOffset`
+    - `League\Csv\Reader::setHeaderOffset`
+- Improved CSV Records conversion
+    - `League\Csv\CharsetConverter` converts CSV records charset.
+    - `League\Csv\XMLConverter` converts CSV records into DOMDocument
+    - `League\Csv\HTMLConverter` converts CSV records into HTML table.
+- Improved Exception handling
+    - `League\Csv\Exception` the default exception
+    - `League\Csv\CannotInsertRecord`
+- Improved CSV document output
+    - `League\Csv\AbstractCsv::chunk` method to output the CSV document in chunk
+    - `League\Csv\bom_match` function to detect BOM sequence in a given string
+    - `League\Csv\ByteSequence` interface to decoupled BOM sequence from CSV documents
+- Improved CSV records column count consistency on insertion
+    - `League\Csv\ColumnConsistency`
+- Improved CSV document flush mechanism on insertion
+    - `League\Csv\Writer::setFlushThreshold`
+    - `League\Csv\Writer::getFlushThreshold`
+- Improve RFC4180 compliance
+    - `League\Csv\RFC4180Field` to format field according to RFC4180 rules
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Improved CSV record insertion
+    - `League\Csv\Writer::insertOne` only accepts an array and returns a integer
+    - `League\Csv\Writer::insertAll` only accepts an iterable of array and returns an integer
+
+- Normalized CSV offset returned value
+    - `League\Csv\Reader::fetchColumn` always returns the CSV document original offset.
+
+### Removed
+
+- `examples` directory
+- `PHP5` support
+- The following method is removed because The BOM API is simplified:
+    - `League\Csv\AbstractCsv::stripBOM`
+- All conversion methods are removed in favor of the conversion classes:
+    - `League\Csv\Writer::jsonSerialize`
+    - `League\Csv\AbstractCsv::toHTML`
+    - `League\Csv\AbstractCsv::toXML`
+    - `League\Csv\AbstractCsv::setInputEncoding`
+    - `League\Csv\AbstractCsv::getInputEncoding`
+- The following methods are removed because the PHP stream filter API is simplified:
+    - `League\Csv\AbstractCsv::isActiveStreamFilter`
+    - `League\Csv\AbstractCsv::setStreamFilterMode`
+    - `League\Csv\AbstractCsv::appendStreamFilter`
+    - `League\Csv\AbstractCsv::prependStreamFilter`
+    - `League\Csv\AbstractCsv::removeStreamFilter`
+    - `League\Csv\AbstractCsv::clearStreamFilters`
+- The following methods are removed because switching between connections is no longer possible:
+    - `League\Csv\AbstractCsv::newReader`
+    - `League\Csv\AbstractCsv::newWriter`
+    - `League\Csv\Reader::getNewline`
+    - `League\Csv\Reader::setNewline`
+- The Exception mechanism is improved thus the following class is removed:
+    - `League\Csv\Exception\InvalidRowException`;
+- The CSV records filtering methods are removed in favor of the `League\Csv\Statement` class:
+    - `League\Csv\AbstractCsv::addFilter`,
+    - `League\Csv\AbstractCsv::addSortBy`,
+    - `League\Csv\AbstractCsv::setOffset`,
+    - `League\Csv\AbstractCsv::setLimit`;
+- CSV records selecting API methods is simplified:
+    - `League\Csv\Reader::each`
+    - `League\Csv\Reader::fetch`
+    - `League\Csv\Reader::fetchAll`
+    - `League\Csv\Reader::fetchAssoc`
+    - `League\Csv\Reader::fetchPairsWithoutDuplicates`
+- Formatting and validating CSV records on insertion is simplified, the following methods are removed:
+    - `League\Csv\Writer::hasFormatter`
+    - `League\Csv\Writer::removeFormatter`
+    - `League\Csv\Writer::clearFormatters`
+    - `League\Csv\Writer::hasValidator`
+    - `League\Csv\Writer::removeValidator`
+    - `League\Csv\Writer::clearValidators`
+    - `League\Csv\Writer::getIterator`
+- The following Formatters and Validators classes are removed from the package:
+    - `League\Csv\Plugin\SkipNullValuesFormatter`
+    - `League\Csv\Plugin\ForbiddenNullValuesValidator`
+    - `League\Csv\Plugin\ColumnConsistencyValidator` *replace by `League\Csv\ColumnConsistency`*
+- `League\Csv\Writer` no longers implements the `IteratorAggregate` interface
+- `League\Csv\AbstractCsv::fetchDelimitersOccurrence` is removed *replace by `League\Csv\delimiter_detect` function*
+
+## 8.2.2 - 2017-07-12
+
+### Added
+
+- None
+
+### Deprecated
+
+- None
+
+### Fixed
+
+- `Writer::insertOne` was silently failing when inserting record in a CSV document in non-writing mode.
+- bug fix docblock
+
+### Removed
+
+- None
+
+## 8.2.1 - 2017-02-22
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- internal `Reader::getRow` when using a `StreamIterator` [issue #213](https://github.com/thephpleague/csv/issues/213)
+- Removed `@deprecated` from selected methods [issue #208](https://github.com/thephpleague/csv/issues/213)
+
+### Removed
+
+- Nothing
+
+## 8.2.0 - 2017-01-25
+
+### Added
+
+- `AbstractCsv::createFromStream` to enable working with resource stream [issue #202](https://github.com/thephpleague/csv/issues/202)
+
+### Deprecated
+
+- `League\Csv\AbstractCsv::stripBom`
+- `League\Csv\Reader::getOffset`
+- `League\Csv\Reader::getLimit`
+- `League\Csv\Reader::getSortBy`
+- `League\Csv\Reader::getFilter`
+- `League\Csv\Reader::setOffset`
+- `League\Csv\Reader::setLimit`
+- `League\Csv\Reader::addSortBy`
+- `League\Csv\Reader::addFilter`
+- `League\Csv\Reader::fetch`
+- `League\Csv\Reader::each`
+- `League\Csv\Reader::fetchPairsWithoutDuplicates`
+- `League\Csv\Reader::fetchAssoc`
+- `League\Csv\Writer::removeFormatter`
+- `League\Csv\Writer::hasFormatter`
+- `League\Csv\Writer::clearFormatters`
+- `League\Csv\Writer::removeValidator`
+- `League\Csv\Writer::hasValidator`
+- `League\Csv\Writer::clearValidators`
+- `League\Csv\Writer::jsonSerialize`
+- `League\Csv\Writer::toHTML`
+- `League\Csv\Writer::toXML`
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 8.1.2 - 2016-10-27
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- BOM filtering fix [issue #184](https://github.com/thephpleague/csv/issues/184)
+- `AbstractCsv::BOM_UTF32_LE` value fixed
+
+### Removed
+
+- Nothing
+
+## 8.1.1 - 2016-09-05
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `getInputBOM` method name is now consistent everywhere in the API [PR #171](https://github.com/thephpleague/csv/pull/171)
+- preserve fileObject CSV controls [commit #8a20c56](https://github.com/thephpleague/csv/commit/8a20c56144effa552a8cba5d8c626063222975b7)
+- Change `output` method header content-type value to `text/csv` [PR #175](https://github.com/thephpleague/csv/pull/175)
+
+### Removed
+
+- Nothing
+
+## 8.1.0 - 2016-05-31
+
+### Added
+
+- The package now includes its own autoloader.
+- `Ouput::getInputEncoding`
+- `Ouput::setInputEncoding`
+
+### Deprecated
+
+- `Ouput::getEncodingFrom` replaced by `Ouput::getInputEncoding`
+- `Ouput::setEncodingFrom` replaced by `Ouput::setInputEncoding`
+
+### Fixed
+
+- Stream Filters are now url encoded before usage [issue #72](https://github.com/thephpleague/csv/issues/72)
+- All internal parameters are now using the snake case format
+
+### Removed
+
+- Nothing
+
+## 8.0.0 - 2015-12-11
+
+### Added
+
+- `Reader::fetchPairs`
+- `Reader::fetchPairsWithoutDuplicates`
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `Reader::fetchColumn` and `Reader::fetchAssoc` now return `Iterator`
+- `Reader::fetchAssoc` callable argument expects an indexed row using the submitted keys as its first argument
+- `Reader::fetchColumn` callable argument expects the selected column value as its first argument
+-  Default value on `setOutputBOM` is removed
+- `AbstractCsv::getOutputBOM` always return a string
+- `AbstractCsv::getInputBOM` always return a string
+
+### Removed
+
+- `Controls::setFlags`
+- `Controls::getFlags`
+- `Controls::detectDelimiterList`
+- `QueryFilter::removeFilter`
+- `QueryFilter::removeSortBy`
+- `QueryFilter::hasFilter`
+- `QueryFilter::hasSortBy`
+- `QueryFilter::clearFilter`
+- `QueryFilter::clearSortBy`
+- `Reader::query`
+- The `$newline` argument from `AbstractCsv::createFromString`
+
+## 7.2.0 - 2015-11-02
+
+### Added
+
+- `Reader::fetch` replaces `League\Csv\Reader::query` for naming consistency
+- `Controls::fetchDelimitersOccurrence` to replace `Controls::detectDelimiterList` the latter gives erronous results
+
+### Deprecated
+
+- `Controls::detectDelimiterList`
+- `Reader::query`
+- The `$newline` argument from `AbstractCsv::createFromString`
+
+### Fixed
+
+- Streamming feature no longer trim filter name argument [issue #122](https://github.com/thephpleague/csv/issues/122)
+- Fix default `SplFileObject` flags usage [PR #130](https://github.com/thephpleague/csv/pull/130)
+- `AbstractCsv::createFromString` no longer trim the submitted string [issue #132](https://github.com/thephpleague/csv/issues/132)
+
+### Removed
+
+- Nothing
+
+## 7.1.2 - 2015-06-10
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Enclosures should be removed when a BOM sequence is stripped [issue #102](http://github.com/thephpleague/csv/issues/99)
+
+### Removed
+
+- Nothing
+
+## 7.1.1 - 2015-05-20
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `SplFileObject` flags were not always applied using query filter [issue #99](http://github.com/thephpleague/csv/issues/99)
+
+### Removed
+
+- Nothing
+
+## 7.1.0 - 2015-05-06
+
+### Added
+
+- `stripBOM` query filtering method to ease removing the BOM sequence when querying the CSV document.
+- All query filters are now accessible in the `Writer` class for conversion methods.
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Internal code has been updated to take into account [issue #68479](http://bugs.php.net/68479)
+- `setFlags` on conversion methods SplFileObject default flags are `SplFileObject::READ_AHEAD|SplFileObject::SKIP_EMPTY`
+- `insertOne` now takes into account the escape character when modified after the first insert.
+
+### Removed
+
+- Nothing
+
+## 7.0.1 - 2015-03-23
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `setFlags`: `SplFileObject::DROP_NEW_LINE` can be remove using `setFlags` method.
+
+### Removed
+
+- Nothing
+
+## 7.0.0 - 2015-02-19
+
+### Added
+
+- A new flexible mechanism to format and validate a row before its insertion by adding
+    - `Writer::addFormatter` to add a formatter to the `Writer` object
+    - `Writer::removeFormatter` to remove an already registered formatter
+    - `Writer::hasFormatter` to detect the presence of a formatter
+    - `Writer::clearFormatters` to clear all registered formatter
+    - `Writer::addValidator` to add a validator to the `Writer` object
+    - `Writer::removeValidator` to remove an already registered validator
+    - `Writer::hasValidator` to detect the presence of a validator
+    - `Writer::clearValidators` to clear all registered validator
+    - `League\Csv\Exception\InvalidRowException` exception thrown when row validation failed
+- Classes to maintain removed features from the `Writer` class
+    - `League\Csv\Plugin\ColumnConsistencyValidator` to validate column consistency on insertion
+    - `League\Csv\Plugin\ForbiddenNullValuesValidator` to validate `null` value on insertion
+    - `League\Csv\Plugin\SkipNullValuesFormatter` to format `null` value on insertion
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `jsonSerialize`, `toXML` and `toHTML` output can be modified using `Reader` query options methods.
+- `AbstractCSV::detectDelimiterList` index keys now represents the occurrence of the found delimiter.
+- `getNewline` and `setNewline` are accessible on the `Reader` class too.
+- the named constructor `createFromString` now accepts the `$newline` sequence as a second argument to specify the last added new line character to better work with interoperability.
+- Default value on CSV controls setter methods `setDelimiter`, `setEnclosure` and `setEscape` are removed
+- Default `SplFileObject` flags value is now `SplFileObject::READ_CSV|SplFileObject::DROP_NEW_LINE`
+- All CSV properties are now copied when using `newReader` and `newWriter` methods
+- BOM addition on output improved by removing if found the existing BOM character
+- the `AbstractCSV::output` method now returns the number of bytes send to the output buffer
+- `Reader::fetchColumn` will automatically filter out non existing values from the return array
+
+### Removed
+
+- Setting `ini_set("auto_detect_line_endings", true);` is no longer set in the class constructor. Mac OS X users must explicitly set this ini options in their script.
+- `Writer` and `Reader` default constructor are removed from public API in favor of the named constructors.
+- All `Writer` methods and constant related to CSV data validation and formatting before insertion
+    - `Writer::getNullHandlingMode`
+    - `Writer::setNullHandlingMode`
+    - `Writer::setColumnsCount`
+    - `Writer::getColumnsCount`
+    - `Writer::autodetectColumnsCount`
+    - `Writer::NULL_AS_EXCEPTION`
+    - `Writer::NULL_AS_EMPTY`
+    - `Writer::NULL_AS_SKIP_CELL`
+
+## 6.3.0 - 2015-01-21
+
+### Added
+
+- `AbstractCSV::setOutputBOM`
+- `AbstractCSV::getOutputBOM`
+- `AbstractCSV::getInputBOM`
+
+to manage BOM character with CSV.
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 6.2.0 - 2014-12-12
+
+### Added
+
+- `Writer::setNewline` , `Writer::getNewline`  to control the newline sequence character added at the end of each CSV row.
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 6.1.0 - 2014-12-08
+
+### Added
+
+- `Reader::fetchAssoc` now also accepts an integer as first argument representing a row index.
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 6.0.1 - 2014-11-12
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Bug Fixed `detectDelimiterList`
+
+### Removed
+
+- Nothing
+
+## 6.0.0 - 2014-08-28
+
+### Added
+
+- Stream Filter API in `League\Csv\AbstractCsv`
+- named constructors `createFromPath` and `createFromFileObject` in `League\Csv\AbstractCsv` to ease CSV object instantiation
+- `detectDelimiterList` in `League\Csv\AbstractCsv` to replace and remove the use of `RuntimeException` in `detectDelimiter`
+- `setEncodingFrom` and `setDecodingFrom` in `League\Csv\AbstractCsv` to replace `setEncoding` and `getEncoding` for naming consistency
+- `newWriter` and `newReader` methods in `League\Csv\AbstractCsv` to replace `Writer::getReader` and `Reader::getWriter`
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `League\Csv\Reader::each` more strict `$callable` MUST returns `true`
+
+### Remove
+
+- `League\Csv\AbstractCsv::detectDelimiter`
+- `League\Csv\AbstractCsv::setEncoding` and `League\Csv\AbstractCsv::getEncoding`
+- `League\Csv\Reader::setSortBy`
+- `League\Csv\Reader::setFilter`
+- `League\Csv\Reader::getWriter`
+- `League\Csv\Writer::getReader`
+- `League\Csv\Reader::fetchCol`
+
+## 5.4.0 - 2014-04-17
+
+### Added
+
+- `League\Csv\Writer::setColumnsCount`, `League\Csv\Writer::getColumnsCount`, `League\Csv\Writer::autodetectColumnsCount` to enable column consistency in writer mode
+- `League\Csv\Reader::fetchColumn` replaces `League\Csv\Reader::fetchCol` for naming consistency
+
+### Deprecated
+
+- `League\Csv\Reader::fetchCol`
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 5.3.1 - 2014-04-09
+
+### Added
+
+- Nothing
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `$open_mode` default to `r+` in `League\Csv\AbstractCsv` constructors
+
+### Removed
+
+- Nothing
+
+## 5.3.0 - 2014-03-24
+
+### Added
+
+- `League\Csv\Writer::setNullHandlingMode` and `League\Csv\Writer::getNullHandlingMode` to handle `null` value
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `setting ini_set("auto_detect_line_endings", true);` no longer needed for Mac OS
+
+### Removed
+
+- Nothing
+
+## 5.2.0 - 2014-03-13
+
+### Added
+
+- `League\Csv\Reader::addSortBy`, `League\Csv\Reader::removeSortBy`, `League\Csv\Reader::hasSortBy`, `League\Csv\Reader::clearSortBy` to improve sorting
+- `League\Csv\Reader::clearFilter` to align extract filter capabilities to sorting capabilities
+
+### Deprecated
+
+- `League\Csv\Reader::setSortBy` replaced by a better implementation
+
+### Fixed
+
+- `League\Csv\Reader::setOffset` now default to 0;
+- `League\Csv\Reader::setLimit` now default to -1;
+- `detectDelimiter` bug fixes
+
+### Removed
+
+- Nothing
+
+## 5.1.0 - 2014-03-11
+
+### Added
+
+- `League\Csv\Reader::each` to ease CSV import data
+- `League\Csv\Reader::addFilter`, `League\Csv\Reader::removeFilter`, `League\Csv\Reader::hasFilter` to improve extract filter capabilities
+- `detectDelimiter` method to `League\Csv\AbstractCsv` to sniff CSV delimiter character.
+
+### Deprecated
+
+- `League\Csv\Reader::setFilter` replaced by a better implementation
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 5.0.0 - 2014-02-28
+
+### Added
+
+- Change namespace from `Bakame\Csv` to `League\Csv`
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- Nothing
+
+## 4.2.1 - 2014-02-22
+
+### Fixed
+
+- `$open_mode` validation is done by PHP internals directly
+
+### Removed
+
+- Nothing
+
+## 4.2.0 - 2014-02-17
+
+### Added
+
+- `toXML` method to transcode the CSV into a XML in `Bakame\Csv\AbstractCsv`
+
+### Fixed
+
+- `toHTML` method bug in `Bakame\Csv\AbstractCsv`
+- `output` method accepts an optional `$filename` argument
+- `Bakame\Csv\Reader::fetchCol` default to `$columnIndex = 0`
+- `Bakame\Csv\Reader::fetchOne` default to `$offset = 0`
+
+## 4.1.2 - 2014-02-14
+
+### Added
+
+- Move from `PSR-0` to `PSR-4` to autoload the library
+
+## 4.1.1 - 2014-02-14
+
+### Fixed
+
+- `Bakame\Csv\Reader` methods fixed
+- `jsonSerialize` bug fixed
+
+## 4.1.0 - 2014-02-07
+
+### Added
+
+- `getEncoding` and `setEncoding` methods to `Bakame\Csv\AbstractCsv`
+
+### Fixed
+
+- `Bakame\Csv\Writer::insertOne` takes into account CSV controls
+- `toHTML` method takes into account encoding
+
+## 4.0.0 - 2014-02-05
+
+### Added
+
+- `Bakame\Csv\Writer`
+- `Bakame\Csv\Writer` and `Bakame\Csv\Reader` extend `Bakame\Csv\AbstractCsv`
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- `Bakame\Csv\Reader::fetchOne` is no longer deprecated
+- `Bakame\Csv\Reader::fetchCol` no longer accepts a third parameter `$strict`
+
+### Removed
+
+- `Bakame\Csv\Codec` now the library is composer of 2 main classes
+- `Bakame\Csv\Reader::getFile`
+- `Bakame\Csv\Reader::fetchValue`
+- `Bakame\Csv\Reader` no longer implements the `ArrayAccess` interface
+
+## 3.3.0 - 2014-01-28
+
+### Added
+
+- `Bakame\Csv\Reader` implements `IteratorAggregate` Interface
+- `Bakame\Csv\Reader::createFromString` to create a CSV object from a raw string
+- `Bakame\Csv\Reader::query` accept an optional `$callable` parameter
+
+### Deprecated
+
+- `Bakame\Csv\Reader::getFile` in favor of `Bakame\Csv\Reader::getIterator`
+
+### Removed
+
+- `Bakame\Csv\ReaderInterface` useless interface
+
+### Fixed
+
+- `Bakame\Csv\Reader::fetch*` `$callable` parameter is normalized to accept an array
+- `Bakame\Csv\Reader::fetchCol` accepts a third parameter `$strict`
+
+## 3.2.0 - 2014-01-16
+
+### Added
+
+- `Bakame\Csv\Reader` implements the following interfaces `JsonSerializable` and `ArrayAccess`
+- `Bakame\Csv\Reader::toHTML` to output the CSV as a HTML table
+- `Bakame\Csv\Reader::setFilter`, `Bakame\Csv\Reader::setSortBy`, `Bakame\Csv\Reader::setOffset`, `Bakame\Csv\Reader::setLimit`, `Bakame\Csv\Reader::query` to perform SQL like queries on the CSV content.
+- `Bakame\Csv\Codec::setFlags`, `Bakame\Csv\Codec::getFlags`, Bakame\Csv\Codec::__construct : add an optional `$flags` parameter to enable the use of `SplFileObject` constants flags
+
+### Deprecated
+
+- `Bakame\Csv\Reader::fetchOne` replaced by `Bakame\Csv\Reader::offsetGet`
+- `Bakame\Csv\Reader::fetchValue` useless method
+
+## 3.1.0 - 2014-01-13
+
+### Added
+
+- `Bakame\Csv\Reader::output` output the CSV data directly in the output buffer
+- `Bakame\Csv\Reader::__toString` can be use to echo the raw CSV
+
+## 3.0.1 - 2014-01-10
+
+### Fixed
+
+- `Bakame\Csv\Reader::fetchAssoc` when users keys and CSV row data don't have the same length
+
+## 3.0.0 - 2014-01-10
+
+### Added
+
+- `Bakame\Csv\ReaderInterface`
+- `Bakame\Csv\Reader` class
+
+### Fixed
+
+- `Bakame\Csv\Codec::loadString`returns a `Bakame\Csv\Reader` object
+- `Bakame\Csv\Codec::loadFile` returns a `Bakame\Csv\Reader` object
+- `Bakame\Csv\Codec::save` returns a `Bakame\Csv\Reader` object
+
+## 2.0.0 - 2014-01-09
+
+### Added
+
+- `Bakame\Csv\CsvCodec` class renamed `Bakame\Csv\Codec`
+
+### Deprecated
+
+- Nothing
+
+### Fixed
+
+- Nothing
+
+### Removed
+
+- `Bakame\Csv\Codec::create` from public API
+
+## 1.0.0 - 2013-12-03
+
+Initial Release of `Bakame\Csv`
diff --git a/civicrm/vendor/league/csv/LICENSE b/civicrm/vendor/league/csv/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..baa67a6fc5c81e386b474afb9b87ad74c96e20b0
--- /dev/null
+++ b/civicrm/vendor/league/csv/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2017 ignace nyamagana butera
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/civicrm/vendor/league/csv/autoload.php b/civicrm/vendor/league/csv/autoload.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5af4a02c34d15979df00815225ba944b889b803
--- /dev/null
+++ b/civicrm/vendor/league/csv/autoload.php
@@ -0,0 +1,18 @@
+<?php
+
+require __DIR__.'/src/functions_include.php';
+
+spl_autoload_register(function ($class) {
+
+    $prefix = 'League\Csv\\';
+    if (0 !== strpos($class, $prefix)) {
+        return;
+    }
+
+    $file = __DIR__.'/src/'.str_replace('\\', '/', substr($class, strlen($prefix))).'.php';
+    if (!is_readable($file)) {
+        return;
+    }
+
+    require $file;
+});
diff --git a/civicrm/vendor/league/csv/composer.json b/civicrm/vendor/league/csv/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..ab75fd2b2d27084569f9e624db81a57bd30cb175
--- /dev/null
+++ b/civicrm/vendor/league/csv/composer.json
@@ -0,0 +1,72 @@
+{
+    "name": "league/csv",
+    "type": "library",
+    "description" : "Csv data manipulation made easy in PHP",
+    "keywords": ["csv", "import", "export", "read", "write", "filter"],
+    "license": "MIT",
+    "homepage" : "http://csv.thephpleague.com",
+    "authors": [
+        {
+            "name" : "Ignace Nyamagana Butera",
+            "email" : "nyamsprod@gmail.com",
+            "homepage" : "https://github.com/nyamsprod/",
+            "role" : "Developer"
+        }
+    ],
+    "support": {
+        "docs": "https://csv.thephpleague.com",
+        "forum": "https://groups.google.com/forum/#!forum/thephpleague",
+        "issues": "https://github.com/thephpleague/csv/issues",
+        "rss": "https://github.com/thephpleague/csv/releases.atom",
+        "source": "https://github.com/thephpleague/csv"
+    },
+    "require": {
+        "php" : ">=7.0.10",
+        "ext-mbstring" : "*"
+    },
+    "require-dev": {
+        "ext-curl" : "*",
+        "friendsofphp/php-cs-fixer": "^2.12",
+        "phpunit/phpunit" : "^6.0",
+        "phpstan/phpstan": "^0.9.2",
+        "phpstan/phpstan-strict-rules": "^0.9.0",
+        "phpstan/phpstan-phpunit": "^0.9.4"
+    },
+    "autoload": {
+        "psr-4": {
+            "League\\Csv\\": "src"
+        },
+        "files": ["src/functions_include.php"]
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "LeagueTest\\Csv\\": "tests"
+        }
+    },
+    "scripts": {
+        "phpcs": "php-cs-fixer fix -v --diff --dry-run --allow-risky=yes;",
+        "phpstan-src": "phpstan analyse -l max -c phpstan.src.neon src",
+        "phpstan-tests": "phpstan analyse -l max -c phpstan.tests.neon tests",
+        "phpstan": [
+            "@phpstan-src",
+            "@phpstan-tests"
+        ],
+        "phpunit": "phpunit --coverage-text",
+        "test": [
+            "@phpcs",
+            "@phpstan",
+            "@phpunit"
+        ]
+    },
+    "suggest": {
+        "ext-iconv" : "Needed to ease transcoding CSV using iconv stream filters"
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "9.x-dev"
+        }
+    },
+    "config": {
+        "sort-packages": true
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/AbstractCsv.php b/civicrm/vendor/league/csv/src/AbstractCsv.php
new file mode 100644
index 0000000000000000000000000000000000000000..e7e335205cb0739bbbbd0f4ba548e86f32f67a09
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/AbstractCsv.php
@@ -0,0 +1,457 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use Generator;
+use SplFileObject;
+use function filter_var;
+use function mb_strlen;
+use function rawurlencode;
+use function sprintf;
+use function str_replace;
+use function str_split;
+use function strcspn;
+use function strlen;
+use const FILTER_FLAG_STRIP_HIGH;
+use const FILTER_FLAG_STRIP_LOW;
+use const FILTER_SANITIZE_STRING;
+
+/**
+ * An abstract class to enable CSV document loading.
+ */
+abstract class AbstractCsv implements ByteSequence
+{
+    /**
+     * The stream filter mode (read or write).
+     *
+     * @var int
+     */
+    protected $stream_filter_mode;
+
+    /**
+     * collection of stream filters.
+     *
+     * @var bool[]
+     */
+    protected $stream_filters = [];
+
+    /**
+     * The CSV document BOM sequence.
+     *
+     * @var string|null
+     */
+    protected $input_bom = null;
+
+    /**
+     * The Output file BOM character.
+     *
+     * @var string
+     */
+    protected $output_bom = '';
+
+    /**
+     * the field delimiter (one character only).
+     *
+     * @var string
+     */
+    protected $delimiter = ',';
+
+    /**
+     * the field enclosure character (one character only).
+     *
+     * @var string
+     */
+    protected $enclosure = '"';
+
+    /**
+     * the field escape character (one character only).
+     *
+     * @var string
+     */
+    protected $escape = '\\';
+
+    /**
+     * The CSV document.
+     *
+     * @var SplFileObject|Stream
+     */
+    protected $document;
+
+    /**
+     * New instance.
+     *
+     * @param SplFileObject|Stream $document The CSV Object instance
+     */
+    protected function __construct($document)
+    {
+        $this->document = $document;
+        list($this->delimiter, $this->enclosure, $this->escape) = $this->document->getCsvControl();
+        $this->resetProperties();
+    }
+
+    /**
+     * Reset dynamic object properties to improve performance.
+     */
+    protected function resetProperties()
+    {
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __destruct()
+    {
+        unset($this->document);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __clone()
+    {
+        throw new Exception(sprintf('An object of class %s cannot be cloned', static::class));
+    }
+
+    /**
+     * Return a new instance from a SplFileObject.
+     *
+     * @return static
+     */
+    public static function createFromFileObject(SplFileObject $file)
+    {
+        return new static($file);
+    }
+
+    /**
+     * Return a new instance from a PHP resource stream.
+     *
+     * @param resource $stream
+     *
+     * @return static
+     */
+    public static function createFromStream($stream)
+    {
+        return new static(new Stream($stream));
+    }
+
+    /**
+     * Return a new instance from a string.
+     *
+     * @return static
+     */
+    public static function createFromString(string $content = '')
+    {
+        return new static(Stream::createFromString($content));
+    }
+
+    /**
+     * Return a new instance from a file path.
+     *
+     * @param resource|null $context the resource context
+     *
+     * @return static
+     */
+    public static function createFromPath(string $path, string $open_mode = 'r+', $context = null)
+    {
+        return new static(Stream::createFromPath($path, $open_mode, $context));
+    }
+
+    /**
+     * Returns the current field delimiter.
+     */
+    public function getDelimiter(): string
+    {
+        return $this->delimiter;
+    }
+
+    /**
+     * Returns the current field enclosure.
+     */
+    public function getEnclosure(): string
+    {
+        return $this->enclosure;
+    }
+
+    /**
+     * Returns the pathname of the underlying document.
+     */
+    public function getPathname(): string
+    {
+        return $this->document->getPathname();
+    }
+
+    /**
+     * Returns the current field escape character.
+     */
+    public function getEscape(): string
+    {
+        return $this->escape;
+    }
+
+    /**
+     * Returns the BOM sequence in use on Output methods.
+     */
+    public function getOutputBOM(): string
+    {
+        return $this->output_bom;
+    }
+
+    /**
+     * Returns the BOM sequence of the given CSV.
+     */
+    public function getInputBOM(): string
+    {
+        if (null !== $this->input_bom) {
+            return $this->input_bom;
+        }
+
+        $this->document->setFlags(SplFileObject::READ_CSV);
+        $this->document->rewind();
+        $this->input_bom = bom_match((string) $this->document->fread(4));
+
+        return $this->input_bom;
+    }
+
+    /**
+     * Returns the stream filter mode.
+     */
+    public function getStreamFilterMode(): int
+    {
+        return $this->stream_filter_mode;
+    }
+
+    /**
+     * Tells whether the stream filter capabilities can be used.
+     */
+    public function supportsStreamFilter(): bool
+    {
+        return $this->document instanceof Stream;
+    }
+
+    /**
+     * Tell whether the specify stream filter is attach to the current stream.
+     */
+    public function hasStreamFilter(string $filtername): bool
+    {
+        return $this->stream_filters[$filtername] ?? false;
+    }
+
+    /**
+     * Retuns the CSV document as a Generator of string chunk.
+     *
+     * @param int $length number of bytes read
+     *
+     * @throws Exception if the number of bytes is lesser than 1
+     */
+    public function chunk(int $length): Generator
+    {
+        if ($length < 1) {
+            throw new Exception(sprintf('%s() expects the length to be a positive integer %d given', __METHOD__, $length));
+        }
+
+        $input_bom = $this->getInputBOM();
+        $this->document->rewind();
+        $this->document->setFlags(0);
+        $this->document->fseek(strlen($input_bom));
+        foreach (str_split($this->output_bom.$this->document->fread($length), $length) as $chunk) {
+            yield $chunk;
+        }
+
+        while ($this->document->valid()) {
+            yield $this->document->fread($length);
+        }
+    }
+
+    /**
+     * DEPRECATION WARNING! This method will be removed in the next major point release.
+     *
+     * @deprecated deprecated since version 9.1.0
+     * @see AbstractCsv::getContent
+     *
+     * Retrieves the CSV content
+     */
+    public function __toString(): string
+    {
+        return $this->getContent();
+    }
+
+    /**
+     * Retrieves the CSV content.
+     */
+    public function getContent(): string
+    {
+        $raw = '';
+        foreach ($this->chunk(8192) as $chunk) {
+            $raw .= $chunk;
+        }
+
+        return $raw;
+    }
+
+    /**
+     * Outputs all data on the CSV file.
+     *
+     * @return int Returns the number of characters read from the handle
+     *             and passed through to the output.
+     */
+    public function output(string $filename = null): int
+    {
+        if (null !== $filename) {
+            $this->sendHeaders($filename);
+        }
+        $input_bom = $this->getInputBOM();
+        $this->document->rewind();
+        $this->document->fseek(strlen($input_bom));
+        echo $this->output_bom;
+
+        return strlen($this->output_bom) + $this->document->fpassthru();
+    }
+
+    /**
+     * Send the CSV headers.
+     *
+     * Adapted from Symfony\Component\HttpFoundation\ResponseHeaderBag::makeDisposition
+     *
+     * @throws Exception if the submitted header is invalid according to RFC 6266
+     *
+     * @see https://tools.ietf.org/html/rfc6266#section-4.3
+     */
+    protected function sendHeaders(string $filename)
+    {
+        if (strlen($filename) != strcspn($filename, '\\/')) {
+            throw new Exception('The filename cannot contain the "/" and "\\" characters.');
+        }
+
+        $flag = FILTER_FLAG_STRIP_LOW;
+        if (strlen($filename) !== mb_strlen($filename)) {
+            $flag |= FILTER_FLAG_STRIP_HIGH;
+        }
+
+        $filenameFallback = str_replace('%', '', filter_var($filename, FILTER_SANITIZE_STRING, $flag));
+
+        $disposition = sprintf('attachment; filename="%s"', str_replace('"', '\\"', $filenameFallback));
+        if ($filename !== $filenameFallback) {
+            $disposition .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
+        }
+
+        header('Content-Type: text/csv');
+        header('Content-Transfer-Encoding: binary');
+        header('Content-Description: File Transfer');
+        header('Content-Disposition: '.$disposition);
+    }
+
+    /**
+     * Sets the field delimiter.
+     *
+     * @throws Exception If the Csv control character is not one character only.
+     *
+     * @return static
+     */
+    public function setDelimiter(string $delimiter): self
+    {
+        if ($delimiter === $this->delimiter) {
+            return $this;
+        }
+
+        if (1 === strlen($delimiter)) {
+            $this->delimiter = $delimiter;
+            $this->resetProperties();
+
+            return $this;
+        }
+
+        throw new Exception(sprintf('%s() expects delimiter to be a single character %s given', __METHOD__, $delimiter));
+    }
+
+    /**
+     * Sets the field enclosure.
+     *
+     * @throws Exception If the Csv control character is not one character only.
+     *
+     * @return static
+     */
+    public function setEnclosure(string $enclosure): self
+    {
+        if ($enclosure === $this->enclosure) {
+            return $this;
+        }
+
+        if (1 === strlen($enclosure)) {
+            $this->enclosure = $enclosure;
+            $this->resetProperties();
+
+            return $this;
+        }
+
+        throw new Exception(sprintf('%s() expects enclosure to be a single character %s given', __METHOD__, $enclosure));
+    }
+
+    /**
+     * Sets the field escape character.
+     *
+     * @throws Exception If the Csv control character is not one character only.
+     *
+     * @return static
+     */
+    public function setEscape(string $escape): self
+    {
+        if ($escape === $this->escape) {
+            return $this;
+        }
+
+        if ('' === $escape || 1 === strlen($escape)) {
+            $this->escape = $escape;
+            $this->resetProperties();
+
+            return $this;
+        }
+
+        throw new Exception(sprintf('%s() expects escape to be a single character or the empty string %s given', __METHOD__, $escape));
+    }
+
+    /**
+     * Sets the BOM sequence to prepend the CSV on output.
+     *
+     * @return static
+     */
+    public function setOutputBOM(string $str): self
+    {
+        $this->output_bom = $str;
+
+        return $this;
+    }
+
+    /**
+     * append a stream filter.
+     *
+     * @param null|mixed $params
+     *
+     * @throws Exception If the stream filter API can not be used
+     *
+     * @return static
+     */
+    public function addStreamFilter(string $filtername, $params = null): self
+    {
+        if (!$this->document instanceof Stream) {
+            throw new Exception('The stream filter API can not be used');
+        }
+
+        $this->document->appendFilter($filtername, $this->stream_filter_mode, $params);
+        $this->stream_filters[$filtername] = true;
+        $this->resetProperties();
+        $this->input_bom = null;
+
+        return $this;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/ByteSequence.php b/civicrm/vendor/league/csv/src/ByteSequence.php
new file mode 100644
index 0000000000000000000000000000000000000000..deb01863ffd2f7227100c43b831c5f303d9503b4
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/ByteSequence.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace League\Csv;
+
+/**
+ * Defines constants for common BOM sequences.
+ */
+interface ByteSequence
+{
+    /**
+     *  UTF-8 BOM sequence.
+     */
+    const BOM_UTF8 = "\xEF\xBB\xBF";
+
+    /**
+     * UTF-16 BE BOM sequence.
+     */
+    const BOM_UTF16_BE = "\xFE\xFF";
+
+    /**
+     * UTF-16 LE BOM sequence.
+     */
+    const BOM_UTF16_LE = "\xFF\xFE";
+
+    /**
+     * UTF-32 BE BOM sequence.
+     */
+    const BOM_UTF32_BE = "\x00\x00\xFE\xFF";
+
+    /**
+     * UTF-32 LE BOM sequence.
+     */
+    const BOM_UTF32_LE = "\xFF\xFE\x00\x00";
+}
diff --git a/civicrm/vendor/league/csv/src/CannotInsertRecord.php b/civicrm/vendor/league/csv/src/CannotInsertRecord.php
new file mode 100644
index 0000000000000000000000000000000000000000..da26e5fd2970bf8018b7078b152c108aaa136744
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/CannotInsertRecord.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+/**
+ * Thrown when a data is not added to the Csv Document.
+ */
+class CannotInsertRecord extends Exception
+{
+    /**
+     * The record submitted for insertion.
+     *
+     * @var array
+     */
+    protected $record;
+
+    /**
+     * Validator which did not validated the data.
+     *
+     * @var string
+     */
+    protected $name = '';
+
+    /**
+     * Create an Exception from a record insertion into a stream.
+     */
+    public static function triggerOnInsertion(array $record): self
+    {
+        $exception = new static('Unable to write record to the CSV document');
+        $exception->record = $record;
+
+        return $exception;
+    }
+
+    /**
+     * Create an Exception from a Record Validation.
+     */
+    public static function triggerOnValidation(string $name, array $record): self
+    {
+        $exception = new static('Record validation failed');
+        $exception->name = $name;
+        $exception->record = $record;
+
+        return $exception;
+    }
+
+    /**
+     * return the validator name.
+     *
+     */
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    /**
+     * return the invalid data submitted.
+     *
+     */
+    public function getRecord(): array
+    {
+        return $this->record;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/CharsetConverter.php b/civicrm/vendor/league/csv/src/CharsetConverter.php
new file mode 100644
index 0000000000000000000000000000000000000000..a3a72b97a7f341561afa8aa1888227ba9757c8e0
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/CharsetConverter.php
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use OutOfRangeException;
+use php_user_filter;
+use Traversable;
+use TypeError;
+use function array_combine;
+use function array_map;
+use function array_walk;
+use function gettype;
+use function in_array;
+use function is_iterable;
+use function is_numeric;
+use function mb_convert_encoding;
+use function mb_list_encodings;
+use function preg_match;
+use function sprintf;
+use function stream_bucket_append;
+use function stream_bucket_make_writeable;
+use function stream_filter_register;
+use function stream_get_filters;
+use function strpos;
+use function strtolower;
+use function substr;
+
+/**
+ * Converts resource stream or tabular data content charset.
+ */
+class CharsetConverter extends php_user_filter
+{
+    const FILTERNAME = 'convert.league.csv';
+
+    /**
+     * the filter name used to instantiate the class with.
+     *
+     * @var string
+     */
+    public $filtername;
+
+    /**
+     * Contents of the params parameter passed to stream_filter_append
+     * or stream_filter_prepend functions.
+     *
+     * @var mixed
+     */
+    public $params;
+
+    /**
+     * The records input encoding charset.
+     *
+     * @var string
+     */
+    protected $input_encoding = 'UTF-8';
+
+    /**
+     * The records output encoding charset.
+     *
+     * @var string
+     */
+    protected $output_encoding = 'UTF-8';
+
+    /**
+     * Static method to add the stream filter to a {@link AbstractCsv} object.
+     */
+    public static function addTo(AbstractCsv $csv, string $input_encoding, string $output_encoding): AbstractCsv
+    {
+        self::register();
+
+        return $csv->addStreamFilter(self::getFiltername($input_encoding, $output_encoding));
+    }
+
+    /**
+     * Static method to register the class as a stream filter.
+     */
+    public static function register()
+    {
+        $filtername = self::FILTERNAME.'.*';
+        if (!in_array($filtername, stream_get_filters(), true)) {
+            stream_filter_register($filtername, self::class);
+        }
+    }
+
+    /**
+     * Static method to return the stream filter filtername.
+     */
+    public static function getFiltername(string $input_encoding, string $output_encoding): string
+    {
+        return sprintf(
+            '%s.%s/%s',
+            self::FILTERNAME,
+            self::filterEncoding($input_encoding),
+            self::filterEncoding($output_encoding)
+        );
+    }
+
+    /**
+     * Filter encoding charset.
+     *
+     * @throws OutOfRangeException if the charset is malformed or unsupported
+     */
+    protected static function filterEncoding(string $encoding): string
+    {
+        static $encoding_list;
+        if (null === $encoding_list) {
+            $list = mb_list_encodings();
+            $encoding_list = array_combine(array_map('strtolower', $list), $list);
+        }
+
+        $key = strtolower($encoding);
+        if (isset($encoding_list[$key])) {
+            return $encoding_list[$key];
+        }
+
+        throw new OutOfRangeException(sprintf('The submitted charset %s is not supported by the mbstring extension', $encoding));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onCreate()
+    {
+        $prefix = self::FILTERNAME.'.';
+        if (0 !== strpos($this->filtername, $prefix)) {
+            return false;
+        }
+
+        $encodings = substr($this->filtername, strlen($prefix));
+        if (!preg_match(',^(?<input>[-\w]+)\/(?<output>[-\w]+)$,', $encodings, $matches)) {
+            return false;
+        }
+
+        try {
+            $this->input_encoding = $this->filterEncoding($matches['input']);
+            $this->output_encoding = $this->filterEncoding($matches['output']);
+            return true;
+        } catch (OutOfRangeException $e) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function filter($in, $out, &$consumed, $closing)
+    {
+        while ($res = stream_bucket_make_writeable($in)) {
+            $res->data = @mb_convert_encoding($res->data, $this->output_encoding, $this->input_encoding);
+            $consumed += $res->datalen;
+            stream_bucket_append($out, $res);
+        }
+
+        return PSFS_PASS_ON;
+    }
+
+    /**
+     * Convert Csv records collection into UTF-8.
+     *
+     * @param array|Traversable $records
+     *
+     * @return array|Traversable
+     */
+    public function convert($records)
+    {
+        if (!is_iterable($records)) {
+            throw new TypeError(sprintf('%s() expects argument passed to be iterable, %s given', __METHOD__, gettype($records)));
+        }
+
+        if ($this->output_encoding === $this->input_encoding) {
+            return $records;
+        }
+
+        if (is_array($records)) {
+            return array_map($this, $records);
+        }
+
+        return new MapIterator($records, $this);
+    }
+
+    /**
+     * Enable using the class as a formatter for the {@link Writer}.
+     */
+    public function __invoke(array $record): array
+    {
+        array_walk($record, [$this, 'encodeField']);
+
+        return $record;
+    }
+
+    /**
+     * Walker method to convert the offset and the value of a CSV record field.
+     *
+     * @param mixed $value
+     * @param mixed $offset
+     */
+    protected function encodeField(&$value, &$offset)
+    {
+        if (null !== $value && !is_numeric($value)) {
+            $value = mb_convert_encoding((string) $value, $this->output_encoding, $this->input_encoding);
+        }
+
+        if (!is_numeric($offset)) {
+            $offset = mb_convert_encoding((string) $offset, $this->output_encoding, $this->input_encoding);
+        }
+    }
+
+    /**
+     * Sets the records input encoding charset.
+     */
+    public function inputEncoding(string $encoding): self
+    {
+        $encoding = $this->filterEncoding($encoding);
+        if ($encoding === $this->input_encoding) {
+            return $this;
+        }
+
+        $clone = clone $this;
+        $clone->input_encoding = $encoding;
+
+        return $clone;
+    }
+
+    /**
+     * Sets the records output encoding charset.
+     */
+    public function outputEncoding(string $encoding): self
+    {
+        $encoding = $this->filterEncoding($encoding);
+        if ($encoding === $this->output_encoding) {
+            return $this;
+        }
+
+        $clone = clone $this;
+        $clone->output_encoding = $encoding;
+
+        return $clone;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/ColumnConsistency.php b/civicrm/vendor/league/csv/src/ColumnConsistency.php
new file mode 100644
index 0000000000000000000000000000000000000000..7b2cd689ce53ec8aa98fb31f2812eb50206c6e87
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/ColumnConsistency.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use function count;
+use function sprintf;
+
+/**
+ * Validates column consistency when inserting records into a CSV document.
+ */
+class ColumnConsistency
+{
+    /**
+     * The number of column per record.
+     *
+     * @var int
+     */
+    protected $columns_count;
+
+    /**
+     * New Instance.
+     *
+     * @throws OutOfRangeException if the column count is lesser than -1
+     */
+    public function __construct(int $columns_count = -1)
+    {
+        if ($columns_count < -1) {
+            throw new Exception(sprintf('%s() expects the column count to be greater or equal to -1 %s given', __METHOD__, $columns_count));
+        }
+
+        $this->columns_count = $columns_count;
+    }
+
+    /**
+     * Returns the column count.
+     */
+    public function getColumnCount(): int
+    {
+        return $this->columns_count;
+    }
+
+    /**
+     * Tell whether the submitted record is valid.
+     */
+    public function __invoke(array $record): bool
+    {
+        $count = count($record);
+        if (-1 === $this->columns_count) {
+            $this->columns_count = $count;
+
+            return true;
+        }
+
+        return $count === $this->columns_count;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/EncloseField.php b/civicrm/vendor/league/csv/src/EncloseField.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0cb65bd5336061f84a9292b3c1d653a90acd8e7
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/EncloseField.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use InvalidArgumentException;
+use php_user_filter;
+use function in_array;
+use function str_replace;
+use function strcspn;
+use function stream_bucket_append;
+use function stream_bucket_make_writeable;
+use function stream_filter_register;
+use function stream_get_filters;
+use function strlen;
+
+/**
+ * A stream filter to improve enclosure character usage.
+ *
+ * @see https://tools.ietf.org/html/rfc4180#section-2
+ * @see https://bugs.php.net/bug.php?id=38301
+ */
+class EncloseField extends php_user_filter
+{
+    const FILTERNAME = 'convert.league.csv.enclosure';
+
+    /**
+     * the filter name used to instantiate the class with.
+     *
+     * @var string
+     */
+    public $filtername;
+
+    /**
+     * Contents of the params parameter passed to stream_filter_append
+     * or stream_filter_prepend functions.
+     *
+     * @var mixed
+     */
+    public $params;
+
+    /**
+     * Default sequence.
+     *
+     * @var string
+     */
+    protected $sequence;
+
+    /**
+     * Characters that triggers enclosure in PHP.
+     *
+     * @var string
+     */
+    protected static $force_enclosure = "\n\r\t ";
+
+    /**
+     * Static method to return the stream filter filtername.
+     */
+    public static function getFiltername(): string
+    {
+        return self::FILTERNAME;
+    }
+
+    /**
+     * Static method to register the class as a stream filter.
+     */
+    public static function register()
+    {
+        if (!in_array(self::FILTERNAME, stream_get_filters(), true)) {
+            stream_filter_register(self::FILTERNAME, self::class);
+        }
+    }
+
+    /**
+     * Static method to add the stream filter to a {@link Writer} object.
+     *
+     * @throws InvalidArgumentException if the sequence is malformed
+     */
+    public static function addTo(Writer $csv, string $sequence): Writer
+    {
+        self::register();
+
+        if (!self::isValidSequence($sequence)) {
+            throw new InvalidArgumentException('The sequence must contain at least one character to force enclosure');
+        }
+
+        $formatter = static function (array $record) use ($sequence) {
+            foreach ($record as &$value) {
+                $value = $sequence.$value;
+            }
+            unset($value);
+
+            return $record;
+        };
+
+        return $csv
+            ->addFormatter($formatter)
+            ->addStreamFilter(self::FILTERNAME, ['sequence' => $sequence]);
+    }
+
+    /**
+     * Filter type and sequence parameters.
+     *
+     * The sequence to force enclosure MUST contains one of the following character ("\n\r\t ")
+     */
+    protected static function isValidSequence(string $sequence): bool
+    {
+        return strlen($sequence) != strcspn($sequence, self::$force_enclosure);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onCreate()
+    {
+        return isset($this->params['sequence'])
+            && $this->isValidSequence($this->params['sequence']);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function filter($in, $out, &$consumed, $closing)
+    {
+        while ($res = stream_bucket_make_writeable($in)) {
+            $res->data = str_replace($this->params['sequence'], '', $res->data);
+            $consumed += $res->datalen;
+            stream_bucket_append($out, $res);
+        }
+
+        return PSFS_PASS_ON;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/EscapeFormula.php b/civicrm/vendor/league/csv/src/EscapeFormula.php
new file mode 100644
index 0000000000000000000000000000000000000000..5b8065113ad5123778a8d15e25cd91d245de5ac7
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/EscapeFormula.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use InvalidArgumentException;
+use function array_fill_keys;
+use function array_keys;
+use function array_map;
+use function array_merge;
+use function array_unique;
+use function is_object;
+use function is_string;
+use function method_exists;
+use function sprintf;
+
+/**
+ * A Formatter to tackle CSV Formula Injection.
+ *
+ * @see http://georgemauer.net/2017/10/07/csv-injection.html
+ */
+class EscapeFormula
+{
+    /**
+     * Spreadsheet formula starting character.
+     */
+    const FORMULA_STARTING_CHARS = ['=', '-', '+', '@'];
+
+    /**
+     * Effective Spreadsheet formula starting characters.
+     *
+     * @var array
+     */
+    protected $special_chars = [];
+
+    /**
+     * Escape character to escape each CSV formula field.
+     *
+     * @var string
+     */
+    protected $escape;
+
+    /**
+     * New instance.
+     *
+     * @param string   $escape        escape character to escape each CSV formula field
+     * @param string[] $special_chars additional spreadsheet formula starting characters
+     *
+     */
+    public function __construct(string $escape = "\t", array $special_chars = [])
+    {
+        $this->escape = $escape;
+        if ([] !== $special_chars) {
+            $special_chars = $this->filterSpecialCharacters(...$special_chars);
+        }
+
+        $chars = array_merge(self::FORMULA_STARTING_CHARS, $special_chars);
+        $chars = array_unique($chars);
+        $this->special_chars = array_fill_keys($chars, 1);
+    }
+
+    /**
+     * Filter submitted special characters.
+     *
+     * @param string ...$characters
+     *
+     * @throws InvalidArgumentException if the string is not a single character
+     *
+     * @return string[]
+     */
+    protected function filterSpecialCharacters(string ...$characters): array
+    {
+        foreach ($characters as $str) {
+            if (1 != strlen($str)) {
+                throw new InvalidArgumentException(sprintf('The submitted string %s must be a single character', $str));
+            }
+        }
+
+        return $characters;
+    }
+
+    /**
+     * Returns the list of character the instance will escape.
+     *
+     * @return string[]
+     */
+    public function getSpecialCharacters(): array
+    {
+        return array_keys($this->special_chars);
+    }
+
+    /**
+     * Returns the escape character.
+     */
+    public function getEscape(): string
+    {
+        return $this->escape;
+    }
+
+    /**
+     * League CSV formatter hook.
+     *
+     * @see escapeRecord
+     */
+    public function __invoke(array $record): array
+    {
+        return $this->escapeRecord($record);
+    }
+
+    /**
+     * Escape a CSV record.
+     */
+    public function escapeRecord(array $record): array
+    {
+        return array_map([$this, 'escapeField'], $record);
+    }
+
+    /**
+     * Escape a CSV cell.
+     */
+    protected function escapeField($cell)
+    {
+        if (!$this->isStringable($cell)) {
+            return $cell;
+        }
+
+        $str_cell = (string) $cell;
+        if (isset($str_cell[0], $this->special_chars[$str_cell[0]])) {
+            return $this->escape.$str_cell;
+        }
+
+        return $cell;
+    }
+
+    /**
+     * Tell whether the submitted value is stringable.
+     */
+    protected function isStringable($value): bool
+    {
+        return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/Exception.php b/civicrm/vendor/league/csv/src/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..90facb03e00f8f7acdba0d7efefb113e748d7a7a
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/Exception.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+/**
+ * League Csv Base Exception.
+ */
+class Exception extends \Exception
+{
+}
diff --git a/civicrm/vendor/league/csv/src/HTMLConverter.php b/civicrm/vendor/league/csv/src/HTMLConverter.php
new file mode 100644
index 0000000000000000000000000000000000000000..27b7c644b1d71f1f4c71939179ce606b1e289617
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/HTMLConverter.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use DOMDocument;
+use DOMElement;
+use DOMException;
+use Traversable;
+use function preg_match;
+
+/**
+ * Converts tabular data into an HTML Table string.
+ */
+class HTMLConverter
+{
+    /**
+     * table class attribute value.
+     *
+     * @var string
+     */
+    protected $class_name = 'table-csv-data';
+
+    /**
+     * table id attribute value.
+     *
+     * @var string
+     */
+    protected $id_value = '';
+
+    /**
+     * @var XMLConverter
+     */
+    protected $xml_converter;
+
+    /**
+     * New Instance.
+     */
+    public function __construct()
+    {
+        $this->xml_converter = (new XMLConverter())
+            ->rootElement('table')
+            ->recordElement('tr')
+            ->fieldElement('td')
+        ;
+    }
+
+    /**
+     * Convert an Record collection into a DOMDocument.
+     *
+     * @param array|Traversable $records the tabular data collection
+     */
+    public function convert($records): string
+    {
+        /** @var DOMDocument $doc */
+        $doc = $this->xml_converter->convert($records);
+
+        /** @var DOMElement $table */
+        $table = $doc->getElementsByTagName('table')->item(0);
+        $table->setAttribute('class', $this->class_name);
+        $table->setAttribute('id', $this->id_value);
+
+        return $doc->saveHTML($table);
+    }
+
+    /**
+     * HTML table class name setter.
+     *
+     * @throws DOMException if the id_value contains any type of whitespace
+     */
+    public function table(string $class_name, string $id_value = ''): self
+    {
+        if (preg_match(",\s,", $id_value)) {
+            throw new DOMException("the id attribute's value must not contain whitespace (spaces, tabs etc.)");
+        }
+        $clone = clone $this;
+        $clone->class_name = $class_name;
+        $clone->id_value = $id_value;
+
+        return $clone;
+    }
+
+    /**
+     * HTML tr record offset attribute setter.
+     */
+    public function tr(string $record_offset_attribute_name): self
+    {
+        $clone = clone $this;
+        $clone->xml_converter = $this->xml_converter->recordElement('tr', $record_offset_attribute_name);
+
+        return $clone;
+    }
+
+    /**
+     * HTML td field name attribute setter.
+     */
+    public function td(string $fieldname_attribute_name): self
+    {
+        $clone = clone $this;
+        $clone->xml_converter = $this->xml_converter->fieldElement('td', $fieldname_attribute_name);
+
+        return $clone;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/MapIterator.php b/civicrm/vendor/league/csv/src/MapIterator.php
new file mode 100644
index 0000000000000000000000000000000000000000..3c96733af0644e8e349f5a736a34e333346ae5d0
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/MapIterator.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use IteratorIterator;
+use Traversable;
+
+/**
+ * Map value from an iterator before yielding.
+ *
+ * @internal used internally to modify CSV content
+ */
+class MapIterator extends IteratorIterator
+{
+    /**
+     * The callback to apply on all InnerIterator current value.
+     *
+     * @var callable
+     */
+    protected $callable;
+
+    /**
+     * New instance.
+     */
+    public function __construct(Traversable $iterator, callable $callable)
+    {
+        parent::__construct($iterator);
+        $this->callable = $callable;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function current()
+    {
+        return ($this->callable)(parent::current(), $this->key());
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/Polyfill/EmptyEscapeParser.php b/civicrm/vendor/league/csv/src/Polyfill/EmptyEscapeParser.php
new file mode 100644
index 0000000000000000000000000000000000000000..6d445aa8d961eb874dd08e1c4f8e02549d490b34
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/Polyfill/EmptyEscapeParser.php
@@ -0,0 +1,251 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv\Polyfill;
+
+use Generator;
+use League\Csv\Stream;
+use SplFileObject;
+use TypeError;
+use function explode;
+use function get_class;
+use function gettype;
+use function in_array;
+use function is_object;
+use function ltrim;
+use function rtrim;
+use function sprintf;
+use function str_replace;
+use function substr;
+
+/**
+ * A Polyfill to PHP's SplFileObject to enable parsing the CSV document
+ * without taking into account the escape character.
+ *
+ * @see https://php.net/manual/en/function.fgetcsv.php
+ * @see https://php.net/manual/en/function.fgets.php
+ * @see https://tools.ietf.org/html/rfc4180
+ * @see http://edoceo.com/utilitas/csv-file-format
+ *
+ * @internal used internally to parse a CSV document without using the escape character
+ */
+final class EmptyEscapeParser
+{
+    /**
+     * @internal
+     */
+    const FIELD_BREAKS = [false, '', "\r\n", "\n", "\r"];
+
+    /**
+     * @var SplFileObject|Stream
+     */
+    private static $document;
+
+    /**
+     * @var string
+     */
+    private static $delimiter;
+
+    /**
+     * @var string
+     */
+    private static $enclosure;
+
+    /**
+     * @var string
+     */
+    private static $trim_mask;
+
+    /**
+     * @var string|bool
+     */
+    private static $line;
+
+    /**
+     * @codeCoverageIgnore
+     */
+    private function __construct()
+    {
+    }
+
+    /**
+     * Converts the document into a CSV record iterator.
+     *
+     * In PHP7.4+ you'll be able to do
+     *
+     * <code>
+     * $file = new SplFileObject('/path/to/file.csv', 'r');
+     * $file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
+     * $file->setCsvControl($delimiter, $enclosure, '');
+     * foreach ($file as $record) {
+     *    //$record escape mechanism is blocked by the empty string
+     * }
+     * </code>
+     *
+     * In PHP7.3- you can do
+     *
+     * <code>
+     * $file = new SplFileObject('/path/to/file.csv', 'r');
+     * $it = EmptyEscapeParser::parse($file); //parsing will be done while ignoring the escape character value.
+     * foreach ($it as $record) {
+     *    //fgetcsv is not directly use hence the escape char is not taken into account
+     * }
+     * </code>
+     *
+     * Each record array contains strings elements.
+     *
+     * @param SplFileObject|Stream $document
+     *
+     * @return Generator|array[]
+     */
+    public static function parse($document): Generator
+    {
+        self::$document = self::filterDocument($document);
+        list(self::$delimiter, self::$enclosure, ) = self::$document->getCsvControl();
+        self::$trim_mask = str_replace([self::$delimiter, self::$enclosure], '', " \t\0\x0B");
+        self::$document->setFlags(0);
+        self::$document->rewind();
+        while (self::$document->valid()) {
+            $record = self::extractRecord();
+            if (!in_array(null, $record, true)) {
+                yield $record;
+            }
+        }
+    }
+
+    /**
+     * Filters the submitted document.
+     *
+     * @param SplFileObject|Stream $document
+     *
+     * @return SplFileObject|Stream
+     */
+    private static function filterDocument($document)
+    {
+        if ($document instanceof Stream || $document instanceof SplFileObject) {
+            return $document;
+        }
+
+        throw new TypeError(sprintf(
+            '%s::parse expects parameter 1 to be a %s or a SplFileObject object, %s given',
+            self::class,
+            Stream::class,
+            is_object($document) ? get_class($document) : gettype($document)
+        ));
+    }
+
+    /**
+     * Extracts a record form the CSV document.
+     */
+    private static function extractRecord(): array
+    {
+        $record = [];
+        self::$line = self::$document->fgets();
+        do {
+            $method = 'extractFieldContent';
+            $buffer = ltrim(self::$line, self::$trim_mask);
+            if (($buffer[0] ?? '') === self::$enclosure) {
+                $method = 'extractEnclosedFieldContent';
+                self::$line = $buffer;
+            }
+
+            $record[] = self::$method();
+        } while (false !== self::$line);
+
+        return $record;
+    }
+
+    /**
+     * Extracts the content from a field without enclosure.
+     *
+     * - Field content can not spread on multiple document lines.
+     * - Content must be preserved.
+     * - Trailing line-breaks must be removed.
+     *
+     * @return string|null
+     */
+    private static function extractFieldContent()
+    {
+        if (in_array(self::$line, self::FIELD_BREAKS, true)) {
+            self::$line = false;
+
+            return null;
+        }
+
+        list($content, self::$line) = explode(self::$delimiter, self::$line, 2) + [1 => false];
+        if (false === self::$line) {
+            return rtrim($content, "\r\n");
+        }
+
+        return $content;
+    }
+
+    /**
+     * Extracts the content from a field with enclosure.
+     *
+     * - Field content can spread on multiple document lines.
+     * - Content between consecutive enclosure characters must be preserved.
+     * - Double enclosure sequence must be replaced by single enclosure character.
+     * - Trailing line break must be removed if they are not part of the field content.
+     * - Invalid field content is treated as per fgetcsv behavior.
+     *
+     * @return string|null
+     */
+    private static function extractEnclosedFieldContent()
+    {
+        if ((self::$line[0] ?? '') === self::$enclosure) {
+            self::$line = substr(self::$line, 1);
+        }
+
+        $content = '';
+        while (false !== self::$line) {
+            list($buffer, $remainder) = explode(self::$enclosure, self::$line, 2) + [1 => false];
+            $content .= $buffer;
+            self::$line = $remainder;
+            if (false !== self::$line) {
+                break;
+            }
+
+            if (self::$document->valid()) {
+                self::$line = self::$document->fgets();
+                continue;
+            }
+
+            if ($buffer === rtrim($content, "\r\n")) {
+                return null;
+            }
+        }
+
+        if (in_array(self::$line, self::FIELD_BREAKS, true)) {
+            self::$line = false;
+            if (!self::$document->valid()) {
+                return $content;
+            }
+
+            return rtrim($content, "\r\n");
+        }
+
+        $char = self::$line[0] ?? '';
+        if ($char === self::$delimiter) {
+            self::$line = substr(self::$line, 1);
+
+            return $content;
+        }
+
+        if ($char === self::$enclosure) {
+            return $content.self::$enclosure.self::extractEnclosedFieldContent();
+        }
+
+        return $content.self::extractFieldContent();
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/RFC4180Field.php b/civicrm/vendor/league/csv/src/RFC4180Field.php
new file mode 100644
index 0000000000000000000000000000000000000000..e054868e8998b6278e381689326dfadd5f4e3796
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/RFC4180Field.php
@@ -0,0 +1,206 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use InvalidArgumentException;
+use php_user_filter;
+use function array_map;
+use function in_array;
+use function is_string;
+use function str_replace;
+use function strcspn;
+use function stream_bucket_append;
+use function stream_bucket_make_writeable;
+use function stream_filter_register;
+use function stream_get_filters;
+use function strlen;
+use const STREAM_FILTER_READ;
+use const STREAM_FILTER_WRITE;
+
+/**
+ * A stream filter to conform the CSV field to RFC4180.
+ *
+ * DEPRECATION WARNING! This class will be removed in the next major point release
+ *
+ * @deprecated deprecated since version 9.2.0
+ * @see AbstractCsv::setEscape
+ *
+ * @see https://tools.ietf.org/html/rfc4180#section-2
+ */
+class RFC4180Field extends php_user_filter
+{
+    const FILTERNAME = 'convert.league.csv.rfc4180';
+
+    /**
+     * the filter name used to instantiate the class with.
+     *
+     * @var string
+     */
+    public $filtername;
+
+    /**
+     * Contents of the params parameter passed to stream_filter_append
+     * or stream_filter_prepend functions.
+     *
+     * @var mixed
+     */
+    public $params;
+
+    /**
+     * The value being search for.
+     *
+     * @var string[]
+     */
+    protected $search;
+
+    /**
+     * The replacement value that replace found $search values.
+     *
+     * @var string[]
+     */
+    protected $replace;
+
+    /**
+     * Characters that triggers enclosure with PHP fputcsv.
+     *
+     * @var string
+     */
+    protected static $force_enclosure = "\n\r\t ";
+
+    /**
+     * Static method to add the stream filter to a {@link AbstractCsv} object.
+     */
+    public static function addTo(AbstractCsv $csv, string $whitespace_replace = ''): AbstractCsv
+    {
+        self::register();
+
+        $params = [
+            'enclosure' => $csv->getEnclosure(),
+            'escape' => $csv->getEscape(),
+            'mode' => $csv->getStreamFilterMode(),
+        ];
+
+        if ($csv instanceof Writer && '' != $whitespace_replace) {
+            self::addFormatterTo($csv, $whitespace_replace);
+            $params['whitespace_replace'] = $whitespace_replace;
+        }
+
+        return $csv->addStreamFilter(self::FILTERNAME, $params);
+    }
+
+    /**
+     * Add a formatter to the {@link Writer} object to format the record
+     * field to avoid enclosure around a field with an empty space.
+     */
+    public static function addFormatterTo(Writer $csv, string $whitespace_replace): Writer
+    {
+        if ('' == $whitespace_replace || strlen($whitespace_replace) != strcspn($whitespace_replace, self::$force_enclosure)) {
+            throw new InvalidArgumentException('The sequence contains a character that enforces enclosure or is a CSV control character or is the empty string.');
+        }
+
+        $mapper = static function ($value) use ($whitespace_replace) {
+            if (is_string($value)) {
+                return str_replace(' ', $whitespace_replace, $value);
+            }
+
+            return $value;
+        };
+
+        $formatter = static function (array $record) use ($mapper): array {
+            return array_map($mapper, $record);
+        };
+
+        return $csv->addFormatter($formatter);
+    }
+
+    /**
+     * Static method to register the class as a stream filter.
+     */
+    public static function register()
+    {
+        if (!in_array(self::FILTERNAME, stream_get_filters(), true)) {
+            stream_filter_register(self::FILTERNAME, self::class);
+        }
+    }
+
+    /**
+     * Static method to return the stream filter filtername.
+     */
+    public static function getFiltername(): string
+    {
+        return self::FILTERNAME;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function filter($in, $out, &$consumed, $closing)
+    {
+        while ($bucket = stream_bucket_make_writeable($in)) {
+            $bucket->data = str_replace($this->search, $this->replace, $bucket->data);
+            $consumed += $bucket->datalen;
+            stream_bucket_append($out, $bucket);
+        }
+
+        return PSFS_PASS_ON;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function onCreate()
+    {
+        if (!$this->isValidParams($this->params)) {
+            return false;
+        }
+
+        $this->search = [$this->params['escape'].$this->params['enclosure']];
+        $this->replace = [$this->params['enclosure'].$this->params['enclosure']];
+        if (STREAM_FILTER_WRITE != $this->params['mode']) {
+            return true;
+        }
+
+        $this->search = [$this->params['escape'].$this->params['enclosure']];
+        $this->replace = [$this->params['escape'].$this->params['enclosure'].$this->params['enclosure']];
+        if ($this->isValidSequence($this->params)) {
+            $this->search[] = $this->params['whitespace_replace'];
+            $this->replace[] = ' ';
+        }
+
+        return true;
+    }
+
+    /**
+     * Validate params property.
+     */
+    protected function isValidParams(array $params): bool
+    {
+        static $mode_list = [STREAM_FILTER_READ => 1, STREAM_FILTER_WRITE => 1];
+
+        return isset($params['enclosure'], $params['escape'], $params['mode'], $mode_list[$params['mode']])
+            && 1 == strlen($params['enclosure'])
+            && 1 == strlen($params['escape']);
+    }
+
+    /**
+     * Is Valid White space replaced sequence.
+     *
+     * @return bool
+     */
+    protected function isValidSequence(array $params)
+    {
+        return isset($params['whitespace_replace'])
+            && strlen($params['whitespace_replace']) == strcspn($params['whitespace_replace'], self::$force_enclosure);
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/Reader.php b/civicrm/vendor/league/csv/src/Reader.php
new file mode 100644
index 0000000000000000000000000000000000000000..3256cd44676827400240b15d7e626fbf26d64462
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/Reader.php
@@ -0,0 +1,378 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use BadMethodCallException;
+use CallbackFilterIterator;
+use Countable;
+use Iterator;
+use IteratorAggregate;
+use JsonSerializable;
+use League\Csv\Polyfill\EmptyEscapeParser;
+use SplFileObject;
+use TypeError;
+use function array_combine;
+use function array_filter;
+use function array_pad;
+use function array_slice;
+use function array_unique;
+use function gettype;
+use function is_array;
+use function iterator_count;
+use function iterator_to_array;
+use function mb_strlen;
+use function mb_substr;
+use function sprintf;
+use function strlen;
+use function substr;
+use const PHP_VERSION_ID;
+use const STREAM_FILTER_READ;
+
+/**
+ * A class to parse and read records from a CSV document.
+ *
+ * @method array fetchOne(int $nth_record = 0) Returns a single record from the CSV
+ * @method Generator fetchColumn(string|int $column_index) Returns the next value from a single CSV record field
+ * @method Generator fetchPairs(string|int $offset_index = 0, string|int $value_index = 1) Fetches the next key-value pairs from the CSV document
+ */
+class Reader extends AbstractCsv implements Countable, IteratorAggregate, JsonSerializable
+{
+    /**
+     * header offset.
+     *
+     * @var int|null
+     */
+    protected $header_offset;
+
+    /**
+     * header record.
+     *
+     * @var string[]
+     */
+    protected $header = [];
+
+    /**
+     * records count.
+     *
+     * @var int
+     */
+    protected $nb_records = -1;
+
+    /**
+     * {@inheritdoc}
+     */
+    protected $stream_filter_mode = STREAM_FILTER_READ;
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function createFromPath(string $path, string $open_mode = 'r', $context = null)
+    {
+        return parent::createFromPath($path, $open_mode, $context);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function resetProperties()
+    {
+        parent::resetProperties();
+        $this->nb_records = -1;
+        $this->header = [];
+    }
+
+    /**
+     * Returns the header offset.
+     *
+     * If no CSV header offset is set this method MUST return null
+     *
+     * @return int|null
+     */
+    public function getHeaderOffset()
+    {
+        return $this->header_offset;
+    }
+
+    /**
+     * Returns the CSV record used as header.
+     *
+     * The returned header is represented as an array of string values
+     *
+     * @return string[]
+     */
+    public function getHeader(): array
+    {
+        if (null === $this->header_offset) {
+            return $this->header;
+        }
+
+        if ([] !== $this->header) {
+            return $this->header;
+        }
+
+        $this->header = $this->setHeader($this->header_offset);
+
+        return $this->header;
+    }
+
+    /**
+     * Determine the CSV record header.
+     *
+     * @throws Exception If the header offset is set and no record is found or is the empty array
+     *
+     * @return string[]
+     */
+    protected function setHeader(int $offset): array
+    {
+        $header = $this->seekRow($offset);
+        if (false === $header || [] === $header) {
+            throw new Exception(sprintf('The header record does not exist or is empty at offset: `%s`', $offset));
+        }
+
+        if (0 === $offset) {
+            return $this->removeBOM($header, mb_strlen($this->getInputBOM()), $this->enclosure);
+        }
+
+        return $header;
+    }
+
+    /**
+     * Returns the row at a given offset.
+     *
+     * @return array|false
+     */
+    protected function seekRow(int $offset)
+    {
+        foreach ($this->getDocument() as $index => $record) {
+            if ($offset === $index) {
+                return $record;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the document as an Iterator.
+     */
+    protected function getDocument(): Iterator
+    {
+        if (70400 > PHP_VERSION_ID && '' === $this->escape) {
+            $this->document->setCsvControl($this->delimiter, $this->enclosure);
+
+            return EmptyEscapeParser::parse($this->document);
+        }
+
+        $this->document->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
+        $this->document->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
+        $this->document->rewind();
+
+        return $this->document;
+    }
+
+    /**
+     * Strip the BOM sequence from a record.
+     *
+     * @param string[] $record
+     *
+     * @return string[]
+     */
+    protected function removeBOM(array $record, int $bom_length, string $enclosure): array
+    {
+        if (0 === $bom_length) {
+            return $record;
+        }
+
+        $record[0] = mb_substr($record[0], $bom_length);
+        if ($enclosure.$enclosure != substr($record[0].$record[0], strlen($record[0]) - 1, 2)) {
+            return $record;
+        }
+
+        $record[0] = substr($record[0], 1, -1);
+
+        return $record;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __call($method, array $arguments)
+    {
+        static $whitelisted = ['fetchColumn' => 1, 'fetchOne' => 1, 'fetchPairs' => 1];
+        if (isset($whitelisted[$method])) {
+            return (new ResultSet($this->getRecords(), $this->getHeader()))->$method(...$arguments);
+        }
+
+        throw new BadMethodCallException(sprintf('%s::%s() method does not exist', static::class, $method));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function count(): int
+    {
+        if (-1 === $this->nb_records) {
+            $this->nb_records = iterator_count($this->getRecords());
+        }
+
+        return $this->nb_records;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getIterator(): Iterator
+    {
+        return $this->getRecords();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function jsonSerialize(): array
+    {
+        return iterator_to_array($this->getRecords(), false);
+    }
+
+    /**
+     * Returns the CSV records as an iterator object.
+     *
+     * Each CSV record is represented as a simple array containing strings or null values.
+     *
+     * If the CSV document has a header record then each record is combined
+     * to the header record and the header record is removed from the iterator.
+     *
+     * If the CSV document is inconsistent. Missing record fields are
+     * filled with null values while extra record fields are strip from
+     * the returned object.
+     *
+     * @param string[] $header an optional header to use instead of the CSV document header
+     */
+    public function getRecords(array $header = []): Iterator
+    {
+        $header = $this->computeHeader($header);
+        $normalized = static function ($record): bool {
+            return is_array($record) && $record != [null];
+        };
+        $bom = $this->getInputBOM();
+        $document = $this->getDocument();
+
+        $records = $this->stripBOM(new CallbackFilterIterator($document, $normalized), $bom);
+        if (null !== $this->header_offset) {
+            $records = new CallbackFilterIterator($records, function (array $record, int $offset): bool {
+                return $offset !== $this->header_offset;
+            });
+        }
+
+        return $this->combineHeader($records, $header);
+    }
+
+    /**
+     * Returns the header to be used for iteration.
+     *
+     * @param string[] $header
+     *
+     * @throws Exception If the header contains non unique column name
+     *
+     * @return string[]
+     */
+    protected function computeHeader(array $header)
+    {
+        if ([] === $header) {
+            $header = $this->getHeader();
+        }
+
+        if ($header === array_unique(array_filter($header, 'is_string'))) {
+            return $header;
+        }
+
+        throw new Exception('The header record must be empty or a flat array with unique string values');
+    }
+
+    /**
+     * Combine the CSV header to each record if present.
+     *
+     * @param string[] $header
+     */
+    protected function combineHeader(Iterator $iterator, array $header): Iterator
+    {
+        if ([] === $header) {
+            return $iterator;
+        }
+
+        $field_count = count($header);
+        $mapper = static function (array $record) use ($header, $field_count): array {
+            if (count($record) != $field_count) {
+                $record = array_slice(array_pad($record, $field_count, null), 0, $field_count);
+            }
+
+            return array_combine($header, $record);
+        };
+
+        return new MapIterator($iterator, $mapper);
+    }
+
+    /**
+     * Strip the BOM sequence from the returned records if necessary.
+     */
+    protected function stripBOM(Iterator $iterator, string $bom): Iterator
+    {
+        if ('' === $bom) {
+            return $iterator;
+        }
+
+        $bom_length = mb_strlen($bom);
+        $mapper = function (array $record, int $index) use ($bom_length): array {
+            if (0 !== $index) {
+                return $record;
+            }
+
+            return $this->removeBOM($record, $bom_length, $this->enclosure);
+        };
+
+        return new MapIterator($iterator, $mapper);
+    }
+
+    /**
+     * Selects the record to be used as the CSV header.
+     *
+     * Because the header is represented as an array, to be valid
+     * a header MUST contain only unique string value.
+     *
+     * @param int|null $offset the header record offset
+     *
+     * @throws Exception if the offset is a negative integer
+     *
+     * @return static
+     */
+    public function setHeaderOffset($offset): self
+    {
+        if ($offset === $this->header_offset) {
+            return $this;
+        }
+
+        if (!is_nullable_int($offset)) {
+            throw new TypeError(sprintf(__METHOD__.'() expects 1 Argument to be null or an integer %s given', gettype($offset)));
+        }
+
+        if (null !== $offset && 0 > $offset) {
+            throw new Exception(__METHOD__.'() expects 1 Argument to be greater or equal to 0');
+        }
+
+        $this->header_offset = $offset;
+        $this->resetProperties();
+
+        return $this;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/ResultSet.php b/civicrm/vendor/league/csv/src/ResultSet.php
new file mode 100644
index 0000000000000000000000000000000000000000..20130249a4ac05e95ec37a41fdd81557d0f71292
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/ResultSet.php
@@ -0,0 +1,241 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use CallbackFilterIterator;
+use Countable;
+use Generator;
+use Iterator;
+use IteratorAggregate;
+use JsonSerializable;
+use LimitIterator;
+use function array_flip;
+use function array_search;
+use function is_string;
+use function iterator_count;
+use function iterator_to_array;
+use function sprintf;
+
+/**
+ * Represents the result set of a {@link Reader} processed by a {@link Statement}.
+ */
+class ResultSet implements Countable, IteratorAggregate, JsonSerializable
+{
+    /**
+     * The CSV records collection.
+     *
+     * @var Iterator
+     */
+    protected $records;
+
+    /**
+     * The CSV records collection header.
+     *
+     * @var array
+     */
+    protected $header = [];
+
+    /**
+     * New instance.
+     *
+     * @param Iterator $records a CSV records collection iterator
+     * @param array    $header  the associated collection column names
+     */
+    public function __construct(Iterator $records, array $header)
+    {
+        $this->records = $records;
+        $this->header = $header;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __destruct()
+    {
+        unset($this->records);
+    }
+
+    /**
+     * Returns the header associated with the result set.
+     *
+     * @return string[]
+     */
+    public function getHeader(): array
+    {
+        return $this->header;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRecords(): Generator
+    {
+        foreach ($this->records as $offset => $value) {
+            yield $offset => $value;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getIterator(): Generator
+    {
+        return $this->getRecords();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function count(): int
+    {
+        return iterator_count($this->records);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function jsonSerialize(): array
+    {
+        return iterator_to_array($this->records, false);
+    }
+
+    /**
+     * Returns the nth record from the result set.
+     *
+     * By default if no index is provided the first record of the resultet is returned
+     *
+     * @param int $nth_record the CSV record offset
+     *
+     * @throws Exception if argument is lesser than 0
+     */
+    public function fetchOne(int $nth_record = 0): array
+    {
+        if ($nth_record < 0) {
+            throw new Exception(sprintf('%s() expects the submitted offset to be a positive integer or 0, %s given', __METHOD__, $nth_record));
+        }
+
+        $iterator = new LimitIterator($this->records, $nth_record, 1);
+        $iterator->rewind();
+
+        return (array) $iterator->current();
+    }
+
+    /**
+     * Returns a single column from the next record of the result set.
+     *
+     * By default if no value is supplied the first column is fetch
+     *
+     * @param string|int $index CSV column index
+     */
+    public function fetchColumn($index = 0): Generator
+    {
+        $offset = $this->getColumnIndex($index, __METHOD__.'() expects the column index to be a valid string or integer, `%s` given');
+        $filter = static function (array $record) use ($offset): bool {
+            return isset($record[$offset]);
+        };
+
+        $select = static function (array $record) use ($offset): string {
+            return $record[$offset];
+        };
+
+        $iterator = new MapIterator(new CallbackFilterIterator($this->records, $filter), $select);
+        foreach ($iterator as $offset => $value) {
+            yield $offset => $value;
+        }
+    }
+
+    /**
+     * Filter a column name against the header if any.
+     *
+     * @param string|int $field         the field name or the field index
+     * @param string     $error_message the associated error message
+     *
+     * @return string|int
+     */
+    protected function getColumnIndex($field, string $error_message)
+    {
+        $method = is_string($field) ? 'getColumnIndexByValue' : 'getColumnIndexByKey';
+
+        return $this->$method($field, $error_message);
+    }
+
+    /**
+     * Returns the selected column name.
+     *
+     * @throws Exception if the column is not found
+     */
+    protected function getColumnIndexByValue(string $value, string $error_message): string
+    {
+        if (false !== array_search($value, $this->header, true)) {
+            return $value;
+        }
+
+        throw new Exception(sprintf($error_message, $value));
+    }
+
+    /**
+     * Returns the selected column name according to its offset.
+     *
+     * @throws Exception if the field is invalid or not found
+     *
+     * @return int|string
+     */
+    protected function getColumnIndexByKey(int $index, string $error_message)
+    {
+        if ($index < 0) {
+            throw new Exception($error_message);
+        }
+
+        if ([] === $this->header) {
+            return $index;
+        }
+
+        $value = array_search($index, array_flip($this->header), true);
+        if (false !== $value) {
+            return $value;
+        }
+
+        throw new Exception(sprintf($error_message, $index));
+    }
+
+    /**
+     * Returns the next key-value pairs from a result set (first
+     * column is the key, second column is the value).
+     *
+     * By default if no column index is provided:
+     * - the first column is used to provide the keys
+     * - the second column is used to provide the value
+     *
+     * @param string|int $offset_index The column index to serve as offset
+     * @param string|int $value_index  The column index to serve as value
+     */
+    public function fetchPairs($offset_index = 0, $value_index = 1): Generator
+    {
+        $offset = $this->getColumnIndex($offset_index, __METHOD__.'() expects the offset index value to be a valid string or integer, `%s` given');
+        $value = $this->getColumnIndex($value_index, __METHOD__.'() expects the value index value to be a valid string or integer, `%s` given');
+
+        $filter = static function (array $record) use ($offset): bool {
+            return isset($record[$offset]);
+        };
+
+        $select = static function (array $record) use ($offset, $value): array {
+            return [$record[$offset], $record[$value] ?? null];
+        };
+
+        $iterator = new MapIterator(new CallbackFilterIterator($this->records, $filter), $select);
+        foreach ($iterator as $pair) {
+            yield $pair[0] => $pair[1];
+        }
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/Statement.php b/civicrm/vendor/league/csv/src/Statement.php
new file mode 100644
index 0000000000000000000000000000000000000000..31015adeab5f1f2fb9c203d2d2eb7c0059481cd1
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/Statement.php
@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use ArrayIterator;
+use CallbackFilterIterator;
+use Iterator;
+use LimitIterator;
+use function array_reduce;
+use function iterator_to_array;
+
+/**
+ * Criteria to filter a {@link Reader} object.
+ */
+class Statement
+{
+    /**
+     * Callables to filter the iterator.
+     *
+     * @var callable[]
+     */
+    protected $where = [];
+
+    /**
+     * Callables to sort the iterator.
+     *
+     * @var callable[]
+     */
+    protected $order_by = [];
+
+    /**
+     * iterator Offset.
+     *
+     * @var int
+     */
+    protected $offset = 0;
+
+    /**
+     * iterator maximum length.
+     *
+     * @var int
+     */
+    protected $limit = -1;
+
+    /**
+     * Set the Iterator filter method.
+     */
+    public function where(callable $callable): self
+    {
+        $clone = clone $this;
+        $clone->where[] = $callable;
+
+        return $clone;
+    }
+
+    /**
+     * Set an Iterator sorting callable function.
+     */
+    public function orderBy(callable $callable): self
+    {
+        $clone = clone $this;
+        $clone->order_by[] = $callable;
+
+        return $clone;
+    }
+
+    /**
+     * Set LimitIterator Offset.
+     *
+     * @throws Exception if the offset is lesser than 0
+     */
+    public function offset(int $offset): self
+    {
+        if (0 > $offset) {
+            throw new Exception(sprintf('%s() expects the offset to be a positive integer or 0, %s given', __METHOD__, $offset));
+        }
+
+        if ($offset === $this->offset) {
+            return $this;
+        }
+
+        $clone = clone $this;
+        $clone->offset = $offset;
+
+        return $clone;
+    }
+
+    /**
+     * Set LimitIterator Count.
+     *
+     * @throws Exception if the limit is lesser than -1
+     */
+    public function limit(int $limit): self
+    {
+        if (-1 > $limit) {
+            throw new Exception(sprintf('%s() expects the limit to be greater or equal to -1, %s given', __METHOD__, $limit));
+        }
+
+        if ($limit === $this->limit) {
+            return $this;
+        }
+
+        $clone = clone $this;
+        $clone->limit = $limit;
+
+        return $clone;
+    }
+
+    /**
+     * Execute the prepared Statement on the {@link Reader} object.
+     *
+     * @param string[] $header an optional header to use instead of the CSV document header
+     */
+    public function process(Reader $csv, array $header = []): ResultSet
+    {
+        if ([] === $header) {
+            $header = $csv->getHeader();
+        }
+
+        $iterator = array_reduce($this->where, [$this, 'filter'], $csv->getRecords($header));
+        $iterator = $this->buildOrderBy($iterator);
+
+        return new ResultSet(new LimitIterator($iterator, $this->offset, $this->limit), $header);
+    }
+
+    /**
+     * Filters elements of an Iterator using a callback function.
+     */
+    protected function filter(Iterator $iterator, callable $callable): CallbackFilterIterator
+    {
+        return new CallbackFilterIterator($iterator, $callable);
+    }
+
+    /**
+     * Sort the Iterator.
+     */
+    protected function buildOrderBy(Iterator $iterator): Iterator
+    {
+        if ([] === $this->order_by) {
+            return $iterator;
+        }
+
+        $compare = function (array $record_a, array $record_b): int {
+            foreach ($this->order_by as $callable) {
+                if (0 !== ($cmp = $callable($record_a, $record_b))) {
+                    return $cmp;
+                }
+            }
+
+            return $cmp ?? 0;
+        };
+
+        $iterator = new ArrayIterator(iterator_to_array($iterator));
+        $iterator->uasort($compare);
+
+        return $iterator;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/Stream.php b/civicrm/vendor/league/csv/src/Stream.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc5d296288abc14e5e2eb37f5714fc921f21e2a6
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/Stream.php
@@ -0,0 +1,518 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use SeekableIterator;
+use SplFileObject;
+use TypeError;
+use function array_keys;
+use function array_values;
+use function array_walk_recursive;
+use function fclose;
+use function feof;
+use function fflush;
+use function fgetcsv;
+use function fgets;
+use function fopen;
+use function fpassthru;
+use function fputcsv;
+use function fread;
+use function fseek;
+use function fwrite;
+use function get_resource_type;
+use function gettype;
+use function is_resource;
+use function rewind;
+use function sprintf;
+use function stream_filter_append;
+use function stream_filter_remove;
+use function stream_get_meta_data;
+use function strlen;
+use const PHP_VERSION_ID;
+use const SEEK_SET;
+
+/**
+ * An object oriented API to handle a PHP stream resource.
+ *
+ * @internal used internally to iterate over a stream resource
+ */
+class Stream implements SeekableIterator
+{
+    /**
+     * Attached filters.
+     *
+     * @var resource[]
+     */
+    protected $filters = [];
+
+    /**
+     * stream resource.
+     *
+     * @var resource
+     */
+    protected $stream;
+
+    /**
+     * Tell whether the stream should be closed on object destruction.
+     *
+     * @var bool
+     */
+    protected $should_close_stream = false;
+
+    /**
+     * Current iterator value.
+     *
+     * @var mixed
+     */
+    protected $value;
+
+    /**
+     * Current iterator key.
+     *
+     * @var int
+     */
+    protected $offset;
+
+    /**
+     * Flags for the Document.
+     *
+     * @var int
+     */
+    protected $flags = 0;
+
+    /**
+     * the field delimiter (one character only).
+     *
+     * @var string
+     */
+    protected $delimiter = ',';
+
+    /**
+     * the field enclosure character (one character only).
+     *
+     * @var string
+     */
+    protected $enclosure = '"';
+
+    /**
+     * the field escape character (one character only).
+     *
+     * @var string
+     */
+    protected $escape = '\\';
+
+    /**
+     * Tell whether the current stream is seekable;.
+     *
+     * @var bool
+     */
+    protected $is_seekable = false;
+
+    /**
+     * New instance.
+     *
+     * @param resource $resource stream type resource
+     */
+    public function __construct($resource)
+    {
+        if (!is_resource($resource)) {
+            throw new TypeError(sprintf('Argument passed must be a stream resource, %s given', gettype($resource)));
+        }
+
+        if ('stream' !== ($type = get_resource_type($resource))) {
+            throw new TypeError(sprintf('Argument passed must be a stream resource, %s resource given', $type));
+        }
+
+        $this->is_seekable = stream_get_meta_data($resource)['seekable'];
+        $this->stream = $resource;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __destruct()
+    {
+        $walker = static function ($filter): bool {
+            return @stream_filter_remove($filter);
+        };
+
+        array_walk_recursive($this->filters, $walker);
+
+        if ($this->should_close_stream && is_resource($this->stream)) {
+            fclose($this->stream);
+        }
+
+        unset($this->stream);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __clone()
+    {
+        throw new Exception(sprintf('An object of class %s cannot be cloned', static::class));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __debugInfo()
+    {
+        return stream_get_meta_data($this->stream) + [
+            'delimiter' => $this->delimiter,
+            'enclosure' => $this->enclosure,
+            'escape' => $this->escape,
+            'stream_filters' => array_keys($this->filters),
+        ];
+    }
+
+    /**
+     * Return a new instance from a file path.
+     *
+     * @param resource|null $context
+     *
+     * @throws Exception if the stream resource can not be created
+     *
+     * @return static
+     */
+    public static function createFromPath(string $path, string $open_mode = 'r', $context = null)
+    {
+        $args = [$path, $open_mode];
+        if (null !== $context) {
+            $args[] = false;
+            $args[] = $context;
+        }
+
+        if (!$resource = @fopen(...$args)) {
+            throw new Exception(sprintf('`%s`: failed to open stream: No such file or directory', $path));
+        }
+
+        $instance = new static($resource);
+        $instance->should_close_stream = true;
+
+        return $instance;
+    }
+
+    /**
+     * Return a new instance from a string.
+     *
+     * @return static
+     */
+    public static function createFromString(string $content = '')
+    {
+        $resource = fopen('php://temp', 'r+');
+        fwrite($resource, $content);
+
+        $instance = new static($resource);
+        $instance->should_close_stream = true;
+
+        return $instance;
+    }
+
+    /**
+     * Return the URI of the underlying stream.
+     */
+    public function getPathname(): string
+    {
+        return stream_get_meta_data($this->stream)['uri'];
+    }
+
+    /**
+     * append a filter.
+     *
+     * @see http://php.net/manual/en/function.stream-filter-append.php
+     *
+     * @param  null|mixed $params
+     * @throws Exception  if the filter can not be appended
+     */
+    public function appendFilter(string $filtername, int $read_write, $params = null)
+    {
+        $res = @stream_filter_append($this->stream, $filtername, $read_write, $params);
+        if (is_resource($res)) {
+            $this->filters[$filtername][] = $res;
+            return;
+        }
+
+        throw new Exception(sprintf('unable to locate filter `%s`', $filtername));
+    }
+
+    /**
+     * Set CSV control.
+     *
+     * @see http://php.net/manual/en/splfileobject.setcsvcontrol.php
+     */
+    public function setCsvControl(string $delimiter = ',', string $enclosure = '"', string $escape = '\\')
+    {
+        list($this->delimiter, $this->enclosure, $this->escape) = $this->filterControl($delimiter, $enclosure, $escape, __METHOD__);
+    }
+
+    /**
+     * Filter Csv control characters.
+     *
+     * @throws Exception If the Csv control character is not one character only.
+     */
+    protected function filterControl(string $delimiter, string $enclosure, string $escape, string $caller): array
+    {
+        $controls = ['delimiter' => $delimiter, 'enclosure' => $enclosure, 'escape' => $escape];
+        foreach ($controls as $type => $control) {
+            if ('escape' === $type && '' === $control && 70400 <= PHP_VERSION_ID) {
+                continue;
+            }
+
+            if (1 !== strlen($control)) {
+                throw new Exception(sprintf('%s() expects %s to be a single character', $caller, $type));
+            }
+        }
+
+        return array_values($controls);
+    }
+
+    /**
+     * Set CSV control.
+     *
+     * @see http://php.net/manual/en/splfileobject.getcsvcontrol.php
+     *
+     * @return string[]
+     */
+    public function getCsvControl()
+    {
+        return [$this->delimiter, $this->enclosure, $this->escape];
+    }
+
+    /**
+     * Set CSV stream flags.
+     *
+     * @see http://php.net/manual/en/splfileobject.setflags.php
+     */
+    public function setFlags(int $flags)
+    {
+        $this->flags = $flags;
+    }
+
+    /**
+     * Write a field array as a CSV line.
+     *
+     * @see http://php.net/manual/en/splfileobject.fputcsv.php
+     *
+     * @return int|bool
+     */
+    public function fputcsv(array $fields, string $delimiter = ',', string $enclosure = '"', string $escape = '\\')
+    {
+        $controls = $this->filterControl($delimiter, $enclosure, $escape, __METHOD__);
+
+        return fputcsv($this->stream, $fields, ...$controls);
+    }
+
+    /**
+     * Get line number.
+     *
+     * @see http://php.net/manual/en/splfileobject.key.php
+     *
+     * @return int
+     */
+    public function key()
+    {
+        return $this->offset;
+    }
+
+    /**
+     * Read next line.
+     *
+     * @see http://php.net/manual/en/splfileobject.next.php
+     */
+    public function next()
+    {
+        $this->value = false;
+        $this->offset++;
+    }
+
+    /**
+     * Rewind the file to the first line.
+     *
+     * @see http://php.net/manual/en/splfileobject.rewind.php
+     *
+     * @throws Exception if the stream resource is not seekable
+     */
+    public function rewind()
+    {
+        if (!$this->is_seekable) {
+            throw new Exception('stream does not support seeking');
+        }
+
+        rewind($this->stream);
+        $this->offset = 0;
+        $this->value = false;
+        if ($this->flags & SplFileObject::READ_AHEAD) {
+            $this->current();
+        }
+    }
+
+    /**
+     * Not at EOF.
+     *
+     * @see http://php.net/manual/en/splfileobject.valid.php
+     *
+     * @return bool
+     */
+    public function valid()
+    {
+        if ($this->flags & SplFileObject::READ_AHEAD) {
+            return $this->current() !== false;
+        }
+
+        return !feof($this->stream);
+    }
+
+    /**
+     * Retrieves the current line of the file.
+     *
+     * @see http://php.net/manual/en/splfileobject.current.php
+     */
+    public function current()
+    {
+        if (false !== $this->value) {
+            return $this->value;
+        }
+
+        $this->value = $this->getCurrentRecord();
+
+        return $this->value;
+    }
+
+    /**
+     * Retrieves the current line as a CSV Record.
+     *
+     * @return array|bool
+     */
+    protected function getCurrentRecord()
+    {
+        do {
+            $ret = fgetcsv($this->stream, 0, $this->delimiter, $this->enclosure, $this->escape);
+        } while ($this->flags & SplFileObject::SKIP_EMPTY && $ret !== false && $ret[0] === null);
+
+        return $ret;
+    }
+
+    /**
+     * Seek to specified line.
+     *
+     * @see http://php.net/manual/en/splfileobject.seek.php
+     *
+     * @param  int       $position
+     * @throws Exception if the position is negative
+     */
+    public function seek($position)
+    {
+        if ($position < 0) {
+            throw new Exception(sprintf('%s() can\'t seek stream to negative line %d', __METHOD__, $position));
+        }
+
+        $this->rewind();
+        while ($this->key() !== $position && $this->valid()) {
+            $this->current();
+            $this->next();
+        }
+        
+        if (0 !== $position) {
+            $this->offset--;
+        }
+        
+        $this->current();
+    }
+
+    /**
+     * Output all remaining data on a file pointer.
+     *
+     * @see http://php.net/manual/en/splfileobject.fpatssthru.php
+     *
+     * @return int
+     */
+    public function fpassthru()
+    {
+        return fpassthru($this->stream);
+    }
+
+    /**
+     * Read from file.
+     *
+     * @see http://php.net/manual/en/splfileobject.fread.php
+     *
+     * @param int $length The number of bytes to read
+     *
+     * @return string|false
+     */
+    public function fread($length)
+    {
+        return fread($this->stream, $length);
+    }
+
+    /**
+     * Gets a line from file.
+     *
+     * @see http://php.net/manual/en/splfileobject.fgets.php
+     *
+     * @return string|false
+     */
+    public function fgets()
+    {
+        return fgets($this->stream);
+    }
+
+    /**
+     * Seek to a position.
+     *
+     * @see http://php.net/manual/en/splfileobject.fseek.php
+     *
+     * @throws Exception if the stream resource is not seekable
+     *
+     * @return int
+     */
+    public function fseek(int $offset, int $whence = SEEK_SET)
+    {
+        if (!$this->is_seekable) {
+            throw new Exception('stream does not support seeking');
+        }
+
+        return fseek($this->stream, $offset, $whence);
+    }
+
+    /**
+     * Write to stream.
+     *
+     * @see http://php.net/manual/en/splfileobject.fwrite.php
+     *
+     * @return int|bool
+     */
+    public function fwrite(string $str, int $length = null)
+    {
+        $args = [$this->stream, $str];
+        if (null !== $length) {
+            $args[] = $length;
+        }
+
+        return fwrite(...$args);
+    }
+
+    /**
+     * Flushes the output to a file.
+     *
+     * @see http://php.net/manual/en/splfileobject.fwrite.php
+     *
+     * @return bool
+     */
+    public function fflush()
+    {
+        return fflush($this->stream);
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/Writer.php b/civicrm/vendor/league/csv/src/Writer.php
new file mode 100644
index 0000000000000000000000000000000000000000..0a23c7c41078889916785387466129b1a26eabcc
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/Writer.php
@@ -0,0 +1,330 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use Traversable;
+use TypeError;
+use function array_reduce;
+use function gettype;
+use function implode;
+use function is_iterable;
+use function preg_match;
+use function preg_quote;
+use function sprintf;
+use function str_replace;
+use function strlen;
+use const PHP_VERSION_ID;
+use const SEEK_CUR;
+use const STREAM_FILTER_WRITE;
+
+/**
+ * A class to insert records into a CSV Document.
+ */
+class Writer extends AbstractCsv
+{
+    /**
+     * callable collection to format the record before insertion.
+     *
+     * @var callable[]
+     */
+    protected $formatters = [];
+
+    /**
+     * callable collection to validate the record before insertion.
+     *
+     * @var callable[]
+     */
+    protected $validators = [];
+
+    /**
+     * newline character.
+     *
+     * @var string
+     */
+    protected $newline = "\n";
+
+    /**
+     * Insert records count for flushing.
+     *
+     * @var int
+     */
+    protected $flush_counter = 0;
+
+    /**
+     * Buffer flush threshold.
+     *
+     * @var int|null
+     */
+    protected $flush_threshold;
+
+    /**
+     * {@inheritdoc}
+     */
+    protected $stream_filter_mode = STREAM_FILTER_WRITE;
+
+    /**
+     * Regular expression used to detect if RFC4180 formatting is necessary.
+     *
+     * @var string
+     */
+    protected $rfc4180_regexp;
+
+    /**
+     * double enclosure for RFC4180 compliance.
+     *
+     * @var string
+     */
+    protected $rfc4180_enclosure;
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function resetProperties()
+    {
+        parent::resetProperties();
+        $characters = preg_quote($this->delimiter, '/').'|'.preg_quote($this->enclosure, '/');
+        $this->rfc4180_regexp = '/[\s|'.$characters.']/x';
+        $this->rfc4180_enclosure = $this->enclosure.$this->enclosure;
+    }
+
+    /**
+     * Returns the current newline sequence characters.
+     */
+    public function getNewline(): string
+    {
+        return $this->newline;
+    }
+
+    /**
+     * Get the flush threshold.
+     *
+     * @return int|null
+     */
+    public function getFlushThreshold()
+    {
+        return $this->flush_threshold;
+    }
+
+    /**
+     * Adds multiple records to the CSV document.
+     *
+     * @see Writer::insertOne
+     *
+     * @param Traversable|array $records
+     */
+    public function insertAll($records): int
+    {
+        if (!is_iterable($records)) {
+            throw new TypeError(sprintf('%s() expects argument passed to be iterable, %s given', __METHOD__, gettype($records)));
+        }
+
+        $bytes = 0;
+        foreach ($records as $record) {
+            $bytes += $this->insertOne($record);
+        }
+
+        $this->flush_counter = 0;
+        $this->document->fflush();
+
+        return $bytes;
+    }
+
+    /**
+     * Adds a single record to a CSV document.
+     *
+     * A record is an array that can contains scalar types values, NULL values
+     * or objects implementing the __toString method.
+     *
+     * @throws CannotInsertRecord If the record can not be inserted
+     */
+    public function insertOne(array $record): int
+    {
+        $method = 'addRecord';
+        if (70400 > PHP_VERSION_ID && '' === $this->escape) {
+            $method = 'addRFC4180CompliantRecord';
+        }
+
+        $record = array_reduce($this->formatters, [$this, 'formatRecord'], $record);
+        $this->validateRecord($record);
+        $bytes = $this->$method($record);
+        if (false !== $bytes && 0 !== $bytes) {
+            return $bytes + $this->consolidate();
+        }
+
+        throw CannotInsertRecord::triggerOnInsertion($record);
+    }
+
+    /**
+     * Adds a single record to a CSV Document using PHP algorithm.
+     *
+     * @see https://php.net/manual/en/function.fputcsv.php
+     *
+     * @return int|bool
+     */
+    protected function addRecord(array $record)
+    {
+        return $this->document->fputcsv($record, $this->delimiter, $this->enclosure, $this->escape);
+    }
+
+    /**
+     * Adds a single record to a CSV Document using RFC4180 algorithm.
+     *
+     * @see https://php.net/manual/en/function.fputcsv.php
+     * @see https://php.net/manual/en/function.fwrite.php
+     * @see https://tools.ietf.org/html/rfc4180
+     * @see http://edoceo.com/utilitas/csv-file-format
+     *
+     * String conversion is done without any check like fputcsv.
+     *
+     *     - Emits E_NOTICE on Array conversion (returns the 'Array' string)
+     *     - Throws catchable fatal error on objects that can not be converted
+     *     - Returns resource id without notice or error (returns 'Resource id #2')
+     *     - Converts boolean true to '1', boolean false to the empty string
+     *     - Converts null value to the empty string
+     *
+     * Fields must be delimited with enclosures if they contains :
+     *
+     *     - Embedded whitespaces
+     *     - Embedded delimiters
+     *     - Embedded line-breaks
+     *     - Embedded enclosures.
+     *
+     * Embedded enclosures must be doubled.
+     *
+     * The LF character is added at the end of each record to mimic fputcsv behavior
+     *
+     * @return int|bool
+     */
+    protected function addRFC4180CompliantRecord(array $record)
+    {
+        foreach ($record as &$field) {
+            $field = (string) $field;
+            if (preg_match($this->rfc4180_regexp, $field)) {
+                $field = $this->enclosure.str_replace($this->enclosure, $this->rfc4180_enclosure, $field).$this->enclosure;
+            }
+        }
+        unset($field);
+
+        return $this->document->fwrite(implode($this->delimiter, $record)."\n");
+    }
+
+    /**
+     * Format a record.
+     *
+     * The returned array must contain
+     *   - scalar types values,
+     *   - NULL values,
+     *   - or objects implementing the __toString() method.
+     */
+    protected function formatRecord(array $record, callable $formatter): array
+    {
+        return $formatter($record);
+    }
+
+    /**
+     * Validate a record.
+     *
+     * @throws CannotInsertRecord If the validation failed
+     */
+    protected function validateRecord(array $record)
+    {
+        foreach ($this->validators as $name => $validator) {
+            if (true !== $validator($record)) {
+                throw CannotInsertRecord::triggerOnValidation($name, $record);
+            }
+        }
+    }
+
+    /**
+     * Apply post insertion actions.
+     */
+    protected function consolidate(): int
+    {
+        $bytes = 0;
+        if ("\n" !== $this->newline) {
+            $this->document->fseek(-1, SEEK_CUR);
+            $bytes = $this->document->fwrite($this->newline, strlen($this->newline)) - 1;
+        }
+
+        if (null === $this->flush_threshold) {
+            return $bytes;
+        }
+
+        ++$this->flush_counter;
+        if (0 === $this->flush_counter % $this->flush_threshold) {
+            $this->flush_counter = 0;
+            $this->document->fflush();
+        }
+
+        return $bytes;
+    }
+
+    /**
+     * Adds a record formatter.
+     */
+    public function addFormatter(callable $formatter): self
+    {
+        $this->formatters[] = $formatter;
+
+        return $this;
+    }
+
+    /**
+     * Adds a record validator.
+     */
+    public function addValidator(callable $validator, string $validator_name): self
+    {
+        $this->validators[$validator_name] = $validator;
+
+        return $this;
+    }
+
+    /**
+     * Sets the newline sequence.
+     */
+    public function setNewline(string $newline): self
+    {
+        $this->newline = $newline;
+
+        return $this;
+    }
+
+    /**
+     * Set the flush threshold.
+     *
+     * @param int|null $threshold
+     *
+     * @throws Exception if the threshold is a integer lesser than 1
+     */
+    public function setFlushThreshold($threshold): self
+    {
+        if ($threshold === $this->flush_threshold) {
+            return $this;
+        }
+
+        if (!is_nullable_int($threshold)) {
+            throw new TypeError(sprintf(__METHOD__.'() expects 1 Argument to be null or an integer %s given', gettype($threshold)));
+        }
+
+        if (null !== $threshold && 1 > $threshold) {
+            throw new Exception(__METHOD__.'() expects 1 Argument to be null or a valid integer greater or equal to 1');
+        }
+
+        $this->flush_threshold = $threshold;
+        $this->flush_counter = 0;
+        $this->document->fflush();
+
+        return $this;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/XMLConverter.php b/civicrm/vendor/league/csv/src/XMLConverter.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7b2fdecc8eccac6049a03f7d4f543583a1a83a1
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/XMLConverter.php
@@ -0,0 +1,225 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv;
+
+use DOMAttr;
+use DOMDocument;
+use DOMElement;
+use DOMException;
+use Traversable;
+use TypeError;
+use function gettype;
+use function is_iterable;
+use function sprintf;
+
+/**
+ * Converts tabular data into a DOMDOcument object.
+ */
+class XMLConverter
+{
+    /**
+     * XML Root name.
+     *
+     * @var string
+     */
+    protected $root_name = 'csv';
+
+    /**
+     * XML Node name.
+     *
+     * @var string
+     */
+    protected $record_name = 'row';
+
+    /**
+     * XML Item name.
+     *
+     * @var string
+     */
+    protected $field_name = 'cell';
+
+    /**
+     * XML column attribute name.
+     *
+     * @var string
+     */
+    protected $column_attr = '';
+
+    /**
+     * XML offset attribute name.
+     *
+     * @var string
+     */
+    protected $offset_attr = '';
+
+    /**
+     * Conversion method list.
+     *
+     * @var array
+     */
+    protected $encoder = [
+        'field' => [
+            true => 'fieldToElementWithAttribute',
+            false => 'fieldToElement',
+        ],
+        'record' => [
+            true => 'recordToElementWithAttribute',
+            false => 'recordToElement',
+        ],
+    ];
+
+    /**
+     * Convert an Record collection into a DOMDocument.
+     *
+     * @param array|Traversable $records the CSV records collection
+     */
+    public function convert($records): DOMDocument
+    {
+        if (!is_iterable($records)) {
+            throw new TypeError(sprintf('%s() expects argument passed to be iterable, %s given', __METHOD__, gettype($records)));
+        }
+
+        $field_encoder = $this->encoder['field']['' !== $this->column_attr];
+        $record_encoder = $this->encoder['record']['' !== $this->offset_attr];
+        $doc = new DOMDocument('1.0');
+        $root = $doc->createElement($this->root_name);
+        foreach ($records as $offset => $record) {
+            $node = $this->$record_encoder($doc, $record, $field_encoder, $offset);
+            $root->appendChild($node);
+        }
+        $doc->appendChild($root);
+
+        return $doc;
+    }
+
+    /**
+     * Convert a CSV record into a DOMElement and
+     * adds its offset as DOMElement attribute.
+     */
+    protected function recordToElementWithAttribute(
+        DOMDocument $doc,
+        array $record,
+        string $field_encoder,
+        int $offset
+    ): DOMElement {
+        $node = $this->recordToElement($doc, $record, $field_encoder);
+        $node->setAttribute($this->offset_attr, (string) $offset);
+
+        return $node;
+    }
+
+    /**
+     * Convert a CSV record into a DOMElement.
+     */
+    protected function recordToElement(DOMDocument $doc, array $record, string $field_encoder): DOMElement
+    {
+        $node = $doc->createElement($this->record_name);
+        foreach ($record as $node_name => $value) {
+            $item = $this->$field_encoder($doc, (string) $value, $node_name);
+            $node->appendChild($item);
+        }
+
+        return $node;
+    }
+
+    /**
+     * Convert Cell to Item.
+     *
+     * Convert the CSV item into a DOMElement and adds the item offset
+     * as attribute to the returned DOMElement
+     *
+     * @param int|string $node_name
+     */
+    protected function fieldToElementWithAttribute(DOMDocument $doc, string $value, $node_name): DOMElement
+    {
+        $item = $this->fieldToElement($doc, $value);
+        $item->setAttribute($this->column_attr, (string) $node_name);
+
+        return $item;
+    }
+
+    /**
+     * Convert Cell to Item.
+     *
+     * @param string $value Record item value
+     */
+    protected function fieldToElement(DOMDocument $doc, string $value): DOMElement
+    {
+        $item = $doc->createElement($this->field_name);
+        $item->appendChild($doc->createTextNode($value));
+
+        return $item;
+    }
+
+    /**
+     * XML root element setter.
+     */
+    public function rootElement(string $node_name): self
+    {
+        $clone = clone $this;
+        $clone->root_name = $this->filterElementName($node_name);
+
+        return $clone;
+    }
+
+    /**
+     * Filter XML element name.
+     *
+     * @throws DOMException If the Element name is invalid
+     */
+    protected function filterElementName(string $value): string
+    {
+        return (new DOMElement($value))->tagName;
+    }
+
+    /**
+     * XML Record element setter.
+     */
+    public function recordElement(string $node_name, string $record_offset_attribute_name = ''): self
+    {
+        $clone = clone $this;
+        $clone->record_name = $this->filterElementName($node_name);
+        $clone->offset_attr = $this->filterAttributeName($record_offset_attribute_name);
+
+        return $clone;
+    }
+
+    /**
+     * Filter XML attribute name.
+     *
+     * @param string $value Element name
+     *
+     * @throws DOMException If the Element attribute name is invalid
+     */
+    protected function filterAttributeName(string $value): string
+    {
+        if ('' === $value) {
+            return $value;
+        }
+
+        return (new DOMAttr($value))->name;
+    }
+
+    /**
+     * XML Field element setter.
+     */
+    public function fieldElement(string $node_name, string $fieldname_attribute_name = ''): self
+    {
+        $clone = clone $this;
+        $clone->field_name = $this->filterElementName($node_name);
+        $clone->column_attr = $this->filterAttributeName($fieldname_attribute_name);
+
+        return $clone;
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/functions.php b/civicrm/vendor/league/csv/src/functions.php
new file mode 100644
index 0000000000000000000000000000000000000000..bf7537a84eba5cc21a387ea69026330c9194b54f
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/functions.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace League\Csv {
+
+    use ReflectionClass;
+    use Traversable;
+    use function array_fill_keys;
+    use function array_filter;
+    use function array_reduce;
+    use function array_unique;
+    use function count;
+    use function is_array;
+    use function iterator_to_array;
+    use function strpos;
+    use const COUNT_RECURSIVE;
+
+    /**
+     * Returns the BOM sequence found at the start of the string.
+     *
+     * If no valid BOM sequence is found an empty string is returned
+     */
+    function bom_match(string $str): string
+    {
+        static $list;
+
+        $list = $list ?? (new ReflectionClass(ByteSequence::class))->getConstants();
+
+        foreach ($list as $sequence) {
+            if (0 === strpos($str, $sequence)) {
+                return $sequence;
+            }
+        }
+
+        return '';
+    }
+
+    /**
+     * Detect Delimiters usage in a {@link Reader} object.
+     *
+     * Returns a associative array where each key represents
+     * a submitted delimiter and each value the number CSV fields found
+     * when processing at most $limit CSV records with the given delimiter
+     *
+     * @param string[] $delimiters
+     *
+     * @return int[]
+     */
+    function delimiter_detect(Reader $csv, array $delimiters, int $limit = 1): array
+    {
+        $found = array_unique(array_filter($delimiters, static function (string $value): bool {
+            return 1 == strlen($value);
+        }));
+        $stmt = (new Statement())->limit($limit)->where(static function (array $record): bool {
+            return count($record) > 1;
+        });
+        $reducer = static function (array $result, string $delimiter) use ($csv, $stmt): array {
+            $result[$delimiter] = count(iterator_to_array($stmt->process($csv->setDelimiter($delimiter)), false), COUNT_RECURSIVE);
+
+            return $result;
+        };
+        $delimiter = $csv->getDelimiter();
+        $header_offset = $csv->getHeaderOffset();
+        $csv->setHeaderOffset(null);
+        $stats = array_reduce($found, $reducer, array_fill_keys($delimiters, 0));
+        $csv->setHeaderOffset($header_offset)->setDelimiter($delimiter);
+
+        return $stats;
+    }
+
+    /**
+     * Tell whether the content of the variable is iterable.
+     *
+     * @see http://php.net/manual/en/function.is-iterable.php
+     */
+    function is_iterable($iterable): bool
+    {
+        return is_array($iterable) || $iterable instanceof Traversable;
+    }
+
+    /**
+     * Tell whether the content of the variable is an int or null.
+     *
+     * @see https://wiki.php.net/rfc/nullable_types
+     */
+    function is_nullable_int($value): bool
+    {
+        return null === $value || is_int($value);
+    }
+}
+
+namespace {
+
+    use League\Csv;
+
+    if (PHP_VERSION_ID < 70100 && !function_exists('\is_iterable')) {
+        /**
+         * @codeCoverageIgnore
+         */
+        function is_iterable($iterable)
+        {
+            return Csv\is_iterable($iterable);
+        }
+    }
+}
diff --git a/civicrm/vendor/league/csv/src/functions_include.php b/civicrm/vendor/league/csv/src/functions_include.php
new file mode 100644
index 0000000000000000000000000000000000000000..9ac9deb2a2a61df77a83eefe54106b1c0cf85477
--- /dev/null
+++ b/civicrm/vendor/league/csv/src/functions_include.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * League.Csv (https://csv.thephpleague.com)
+ *
+ * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (!function_exists('League\Csv\bom_match')) {
+    require __DIR__.'/functions.php';
+}
diff --git a/civicrm/xml/schema/Contact/Contact.xml b/civicrm/xml/schema/Contact/Contact.xml
index d197f6bf0838f304d8b1cc48bd2cc43af2ef44e1..1539d0c6e8b3289e7d950b61c57a87bf3d9f312d 100644
--- a/civicrm/xml/schema/Contact/Contact.xml
+++ b/civicrm/xml/schema/Contact/Contact.xml
@@ -351,7 +351,9 @@
     <length>32</length>
     <comment>API Key for validating requests related to this contact.</comment>
     <add>2.2</add>
-    <protected>true</protected>
+    <permission>
+      <or>administer CiviCRM, edit api keys</or>
+    </permission>
   </field>
   <index>
     <name>index_api_key</name>
diff --git a/civicrm/xml/schema/Contribute/Contribution.xml b/civicrm/xml/schema/Contribute/Contribution.xml
index 63b8d1302313f167e71165ed7d46b4abe7ec56eb..376f5675be623a2fe4ec4ec6bf77cdca2404a26c 100644
--- a/civicrm/xml/schema/Contribute/Contribution.xml
+++ b/civicrm/xml/schema/Contribute/Contribution.xml
@@ -272,6 +272,7 @@
   </field>
   <field>
     <name>cancel_date</name>
+    <title>Cancelled / Refunded Date</title>
     <type>datetime</type>
     <import>true</import>
     <headerPattern>/cancel(.?date)?/i</headerPattern>
@@ -282,6 +283,7 @@
       <type>Select Date</type>
       <formatType>activityDateTime</formatType>
     </html>
+    <uniqueName>contribution_cancel_date</uniqueName>
   </field>
   <field>
     <name>cancel_reason</name>
diff --git a/civicrm/xml/schema/Core/CustomField.xml b/civicrm/xml/schema/Core/CustomField.xml
index 919ec7588276e05e5e2bd0e1c8291fd64cfef893..0db65072278a4ceee2e3ebe86aba76c2326fa530 100644
--- a/civicrm/xml/schema/Core/CustomField.xml
+++ b/civicrm/xml/schema/Core/CustomField.xml
@@ -226,6 +226,9 @@
     <length>64</length>
     <comment>date format for custom date</comment>
     <add>3.1</add>
+    <pseudoconstant>
+      <callback>CRM_Core_SelectValues::getDatePluginInputFormats</callback>
+    </pseudoconstant>
   </field>
   <field>
     <name>time_format</name>
@@ -233,19 +236,22 @@
     <title>Field Time Format</title>
     <comment>time format for custom date</comment>
     <add>3.1</add>
+    <pseudoconstant>
+      <callback>CRM_Core_SelectValues::getTimeFormats</callback>
+    </pseudoconstant>
   </field>
   <field>
     <name>note_columns</name>
     <type>int unsigned</type>
     <title>Field Note Columns</title>
-    <comment> Number of columns in Note Field </comment>
+    <comment>Number of columns in Note Field</comment>
     <add>1.4</add>
   </field>
   <field>
     <name>note_rows</name>
     <type>int unsigned</type>
     <title>Field Note Rows</title>
-    <comment> Number of rows in Note Field </comment>
+    <comment>Number of rows in Note Field</comment>
     <add>1.4</add>
   </field>
   <field>
diff --git a/civicrm/xml/schema/Pledge/Pledge.xml b/civicrm/xml/schema/Pledge/Pledge.xml
index 6d4e15e519fcd3dde1efc909bd8cae26255241e5..22f672ea9258611aa76aa227bdcca9e1fd3e7d84 100644
--- a/civicrm/xml/schema/Pledge/Pledge.xml
+++ b/civicrm/xml/schema/Pledge/Pledge.xml
@@ -291,6 +291,9 @@
     <import>true</import>
     <export>false</export>
     <type>int unsigned</type>
+    <html>
+      <type>Select</type>
+    </html>
     <pseudoconstant>
       <optionGroupName>pledge_status</optionGroupName>
     </pseudoconstant>
diff --git a/civicrm/xml/templates/dao.tpl b/civicrm/xml/templates/dao.tpl
index 14f15735dea13545474f6512dfc7366050aa39ed..e9d6f36eca7ede02f9d80ea0c21175cb19de0261 100644
--- a/civicrm/xml/templates/dao.tpl
+++ b/civicrm/xml/templates/dao.tpl
@@ -128,8 +128,8 @@ class {$table.className} extends CRM_Core_DAO {ldelim}
 {if $field.rule}
                       'rule'      => '{$field.rule}',
 {/if} {* field.rule *}
-{if $field.protected}
-                      'protected'      => '{$field.protected}',
+{if !empty($field.permission)}
+                      'permission'      => {$field.permission|@print_array},
 {/if}
 {if $field.default || $field.default === '0'}
                          'default'   => '{if ($field.default[0]=="'" or $field.default[0]=='"')}{$field.default|substring:1:-1}{else}{$field.default}{/if}',
diff --git a/civicrm/xml/version.xml b/civicrm/xml/version.xml
index b3aead70e2a7714a6624024cd76a69c1e37ad6d0..fb21c80299def9bb0c64642cf51957b9a2e689da 100644
--- a/civicrm/xml/version.xml
+++ b/civicrm/xml/version.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="iso-8859-1" ?>
 <version>
-  <version_no>5.15.2</version_no>
+  <version_no>5.16.0</version_no>
 </version>
diff --git a/includes/civicrm.basepage.php b/includes/civicrm.basepage.php
index 19132170860914a203279904731980473b4ef6da..a808c5150ddff5641b7377665b5d4af05efccff9 100644
--- a/includes/civicrm.basepage.php
+++ b/includes/civicrm.basepage.php
@@ -398,6 +398,7 @@ class CiviCRM_For_WordPress_Basepage {
 
     // Override page title with high priority
     add_filter( 'wp_title', array( $this, 'wp_page_title' ), 100, 3 );
+    add_filter( 'document_title_parts', array( $this, 'wp_page_title_parts' ), 100, 1 );
 
     // Add compatibility with WordPress SEO plugin's Open Graph title
     add_filter( 'wpseo_opengraph_title', array( $this, 'wpseo_page_title' ), 100, 1 );
@@ -470,6 +471,31 @@ class CiviCRM_For_WordPress_Basepage {
   }
 
 
+  /**
+   * Get CiviCRM basepage title for <title> element.
+   *
+   * Callback method for 'document_title_parts' hook. This filter was introduced
+   * in WordPress 3.8 but it depends on whether the theme has implemented that
+   * method for generating the title or not.
+   *
+   * @since 5.14
+   *
+   * @param array $parts The existing title parts.
+   * @return array $parts The modified title parts.
+   */
+  public function wp_page_title_parts( $parts ) {
+
+    // Override with CiviCRM's title
+    if ( isset( $parts['title'] ) ) {
+      $parts['title'] = $this->basepage_title;
+    }
+
+    // Return modified title parts
+    return $parts;
+
+  }
+
+
   /**
    * Get CiviCRM base page title for Open Graph elements.
    *
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000000000000000000000000000000000000..ae5a224392df84905e21c04a21f8c84a7fc0f429
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,24 @@
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false"
+         syntaxCheck="false"
+         beStrictAboutTestsThatDoNotTestAnything="false"
+         bootstrap="tests/phpunit/bootstrap.php"
+>
+  <testsuites>
+    <testsuite name="CiviCRM-WordPress Test Suite">
+      <directory>./tests/phpunit</directory>
+    </testsuite>
+  </testsuites>
+
+  <filter>
+    <whitelist>
+      <directory suffix=".php">./CiviWP</directory>
+    </whitelist>
+  </filter>
+</phpunit>
diff --git a/tests/phpunit/CiviWP/HookTest.php b/tests/phpunit/CiviWP/HookTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..77817acc63ac88467b2bc3acdb9f7db44b32df49
--- /dev/null
+++ b/tests/phpunit/CiviWP/HookTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace CiviWP {
+
+  use Civi\Test\EndToEndInterface;
+
+  /**
+   * Class HookTest
+   * @package CiviWP
+   * @group e2e
+   */
+  class HookTest extends \PHPUnit_Framework_TestCase implements EndToEndInterface {
+
+    public function testFoo() {
+      add_action('civicrm_fakeAlterableHook', 'onFakeAlterableHook', 10, 2);
+
+      $arg1 = 'hello';
+      $arg2 = array(
+        'foo' => 123,
+      );
+      $this->assertNotEquals($arg2['foo'], 456);
+      $this->assertNotEquals($arg2['hook_was_called'], 1);
+      \CRM_Utils_Hook::singleton()
+        ->invoke(
+          2,
+          $arg1,
+          $arg2,
+          \CRM_Utils_Hook::$_nullObject,
+          \CRM_Utils_Hook::$_nullObject,
+          \CRM_Utils_Hook::$_nullObject,
+          \CRM_Utils_Hook::$_nullObject,
+          'civicrm_fakeAlterableHook'
+        );
+
+      $this->assertEquals($arg2['foo'], 456);
+      $this->assertEquals($arg2['hook_was_called'], 1);
+    }
+
+  }
+
+}
+
+namespace {
+
+  function onFakeAlterableHook($arg1, &$arg2) {
+    if ($arg1 != 'hello') {
+      throw new \Exception("Failed to receive arg1");
+    }
+    if ($arg2['foo'] != 123) {
+      throw new \Exception("Failed to receive arg2[foo]");
+    }
+    $arg2['foo'] = 456;
+    $arg2['hook_was_called'] = 1;
+  }
+
+}
diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php
new file mode 100644
index 0000000000000000000000000000000000000000..111952c00ebf27ea821cd86daff7e7d48a2c18ce
--- /dev/null
+++ b/tests/phpunit/bootstrap.php
@@ -0,0 +1,55 @@
+<?php
+
+// We switch between a few different container configurations during testing.
+define('CIVICRM_CONTAINER_CACHE', 'never');
+
+ini_set('memory_limit', '2G');
+ini_set('safe_mode', 0);
+// phpcs:disable
+eval(cv('php:boot', 'phpcode'));
+// phpcs:enable
+assert("CIVICRM_UF === 'WordPress'");
+
+/**
+ * Call the "cv" command.
+ *
+ * @param string $cmd
+ *   The rest of the command to send.
+ * @param string $decode
+ *   Ex: 'json' or 'phpcode'.
+ * @return string
+ *   Response output (if the command executed normally).
+ * @throws \RuntimeException
+ *   If the command terminates abnormally.
+ */
+function cv($cmd, $decode = 'json') {
+  $cmd = 'cv ' . $cmd;
+  $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR);
+  $oldOutput = getenv('CV_OUTPUT');
+  putenv("CV_OUTPUT=json");
+  $process = proc_open($cmd, $descriptorSpec, $pipes, __DIR__);
+  putenv("CV_OUTPUT=$oldOutput");
+  fclose($pipes[0]);
+  $result = stream_get_contents($pipes[1]);
+  fclose($pipes[1]);
+  if (proc_close($process) !== 0) {
+    throw new RuntimeException("Command failed ($cmd):\n$result");
+  }
+  switch ($decode) {
+    case 'raw':
+      return $result;
+
+    case 'phpcode':
+      // If the last output is /*PHPCODE*/, then we managed to complete execution.
+      if (substr(trim($result), 0, 12) !== "/*BEGINPHP*/" || substr(trim($result), -10) !== "/*ENDPHP*/") {
+        throw new \RuntimeException("Command failed ($cmd):\n$result");
+      }
+      return $result;
+
+    case 'json':
+      return json_decode($result, 1);
+
+    default:
+      throw new RuntimeException("Bad decoder format ($decode)");
+  }
+}