From ed595f2d3508aeca5cd9cec9196bbecd8869fac1 Mon Sep 17 00:00:00 2001
From: Kevin Cristiano <kcristiano@kcristiano.com>
Date: Thu, 8 Aug 2019 16:57:43 -0400
Subject: [PATCH] civicrm 5.16.0 release

---
 civicrm.php                                   |   28 +-
 civicrm/CRM/ACL/DAO/ACL.php                   |    2 +-
 civicrm/CRM/ACL/DAO/Cache.php                 |    2 +-
 civicrm/CRM/ACL/DAO/EntityRole.php            |    2 +-
 .../CRM/ACL/Form/WordPress/Permissions.php    |    2 +-
 civicrm/CRM/Activity/BAO/Activity.php         |    2 +-
 civicrm/CRM/Activity/BAO/Query.php            |    2 +-
 civicrm/CRM/Activity/DAO/Activity.php         |    2 +-
 civicrm/CRM/Activity/DAO/ActivityContact.php  |    2 +-
 civicrm/CRM/Activity/Form/Activity.php        |   32 +-
 civicrm/CRM/Activity/Page/AJAX.php            |    4 +-
 .../CRM/Admin/Form/Preferences/Campaign.php   |   44 -
 .../CRM/Admin/Form/Preferences/Contribute.php |   10 +-
 .../CRM/Admin/Form/Preferences/Display.php    |    2 +
 .../CRM/Admin/Form/Preferences/Multisite.php  |   44 -
 .../Form/Setting/UpdateConfigBackend.php      |   34 +-
 civicrm/CRM/Admin/Page/CKEditorConfig.php     |    2 +-
 civicrm/CRM/Batch/BAO/Batch.php               |   13 +-
 civicrm/CRM/Batch/DAO/Batch.php               |    2 +-
 civicrm/CRM/Batch/DAO/EntityBatch.php         |    2 +-
 civicrm/CRM/Batch/Form/Entry.php              |    1 +
 civicrm/CRM/Campaign/DAO/Campaign.php         |    2 +-
 civicrm/CRM/Campaign/DAO/CampaignGroup.php    |    2 +-
 civicrm/CRM/Campaign/DAO/Survey.php           |    2 +-
 civicrm/CRM/Campaign/Form/Campaign.php        |   52 +-
 .../CRM/Campaign/Form/Petition/Signature.php  |    4 +-
 civicrm/CRM/Campaign/Selector/Search.php      |    2 +-
 civicrm/CRM/Campaign/xml/Menu/Campaign.xml    |    2 +-
 civicrm/CRM/Case/BAO/Case.php                 |  261 +-
 civicrm/CRM/Case/BAO/Query.php                |    7 +-
 civicrm/CRM/Case/DAO/Case.php                 |    2 +-
 civicrm/CRM/Case/DAO/CaseActivity.php         |    2 +-
 civicrm/CRM/Case/DAO/CaseContact.php          |    2 +-
 civicrm/CRM/Case/DAO/CaseType.php             |    2 +-
 civicrm/CRM/Case/Form/Activity/OpenCase.php   |    1 -
 civicrm/CRM/Case/Form/AddToCaseAsRole.php     |   14 +-
 civicrm/CRM/Case/Form/Case.php                |    2 +
 civicrm/CRM/Case/Form/CaseView.php            |    2 +-
 civicrm/CRM/Case/Info.php                     |   10 +-
 civicrm/CRM/Case/ManagedEntities.php          |   17 +-
 civicrm/CRM/Case/Selector/Search.php          |   73 +
 civicrm/CRM/Case/XMLProcessor.php             |   46 +-
 civicrm/CRM/Case/XMLProcessor/Process.php     |   33 +-
 civicrm/CRM/Case/XMLProcessor/Report.php      |    4 +-
 civicrm/CRM/Case/XMLRepository.php            |    2 +
 civicrm/CRM/Contact/BAO/Contact.php           |   58 +-
 civicrm/CRM/Contact/BAO/Contact/Utils.php     |    4 +-
 civicrm/CRM/Contact/BAO/GroupNestingCache.php |   10 +-
 civicrm/CRM/Contact/BAO/Query.php             |   20 +-
 civicrm/CRM/Contact/BAO/Relationship.php      |    2 +-
 civicrm/CRM/Contact/BAO/SavedSearch.php       |    4 +-
 civicrm/CRM/Contact/DAO/ACLContactCache.php   |    2 +-
 civicrm/CRM/Contact/DAO/Contact.php           |    9 +-
 civicrm/CRM/Contact/DAO/ContactType.php       |    2 +-
 civicrm/CRM/Contact/DAO/DashboardContact.php  |    2 +-
 civicrm/CRM/Contact/DAO/Group.php             |    2 +-
 civicrm/CRM/Contact/DAO/GroupContact.php      |    2 +-
 civicrm/CRM/Contact/DAO/GroupContactCache.php |    2 +-
 civicrm/CRM/Contact/DAO/GroupNesting.php      |    2 +-
 civicrm/CRM/Contact/DAO/GroupOrganization.php |    2 +-
 civicrm/CRM/Contact/DAO/Relationship.php      |    2 +-
 civicrm/CRM/Contact/DAO/RelationshipType.php  |    2 +-
 civicrm/CRM/Contact/DAO/SavedSearch.php       |    2 +-
 .../CRM/Contact/DAO/SubscriptionHistory.php   |    2 +-
 civicrm/CRM/Contact/Form/Search/Criteria.php  |   11 +-
 .../Form/Search/Custom/ActivitySearch.php     |    4 +-
 .../CRM/Contact/Form/Search/Custom/Base.php   |    2 +-
 .../Search/Custom/ContributionAggregate.php   |   37 +-
 .../Contact/Form/Search/Custom/DateAdded.php  |   20 +-
 .../Form/Search/Custom/EventAggregate.php     |    8 +-
 .../Form/Search/Custom/TagContributions.php   |    4 +-
 civicrm/CRM/Contact/Form/Task/AddToGroup.php  |    2 +-
 civicrm/CRM/Contact/Page/CustomSearch.php     |    4 +-
 civicrm/CRM/Contact/Page/Inline/Website.php   |    2 +-
 civicrm/CRM/Contact/Selector.php              |    2 +-
 civicrm/CRM/Contribute/BAO/Contribution.php   |   33 +-
 .../CRM/Contribute/BAO/Contribution/Utils.php |   12 +
 .../CRM/Contribute/BAO/ContributionPage.php   |    2 +-
 .../CRM/Contribute/BAO/ContributionRecur.php  |    6 -
 .../CRM/Contribute/BAO/ContributionSoft.php   |    3 +-
 civicrm/CRM/Contribute/BAO/Query.php          |   37 +-
 civicrm/CRM/Contribute/BAO/Widget.php         |    2 +-
 civicrm/CRM/Contribute/DAO/Contribution.php   |    6 +-
 .../CRM/Contribute/DAO/ContributionPage.php   |    2 +-
 .../Contribute/DAO/ContributionProduct.php    |    2 +-
 .../CRM/Contribute/DAO/ContributionRecur.php  |    2 +-
 .../CRM/Contribute/DAO/ContributionSoft.php   |    2 +-
 civicrm/CRM/Contribute/DAO/Premium.php        |    2 +-
 .../CRM/Contribute/DAO/PremiumsProduct.php    |    2 +-
 civicrm/CRM/Contribute/DAO/Product.php        |    2 +-
 civicrm/CRM/Contribute/DAO/Widget.php         |    2 +-
 .../Contribute/Form/AbstractEditPayment.php   |    4 +-
 civicrm/CRM/Contribute/Form/Contribution.php  |    6 +-
 .../Contribute/Form/Contribution/Confirm.php  |    3 +-
 .../CRM/Contribute/Form/Contribution/Main.php |    2 +-
 .../CRM/Contribute/Form/ContributionBase.php  |   21 +-
 civicrm/CRM/Contribute/Form/Search.php        |   48 +-
 .../Form/Task/SearchTaskHookSample.php        |    4 +-
 civicrm/CRM/Contribute/Form/Task/Status.php   |   12 +-
 .../Contribute/Import/Parser/Contribution.php |   13 +-
 .../CRM/Contribute/Page/ContributionPage.php  |    6 +-
 civicrm/CRM/Contribute/Tokens.php             |    3 +-
 civicrm/CRM/Core/BAO/ActionSchedule.php       |    1 -
 civicrm/CRM/Core/BAO/Address.php              |   23 +-
 civicrm/CRM/Core/BAO/Cache.php                |   18 +-
 civicrm/CRM/Core/BAO/Cache/Psr16.php          |   34 +-
 civicrm/CRM/Core/BAO/Country.php              |    3 +-
 civicrm/CRM/Core/BAO/CustomField.php          |  354 +-
 civicrm/CRM/Core/BAO/CustomQuery.php          |   26 +-
 civicrm/CRM/Core/BAO/CustomValueTable.php     |   18 +-
 civicrm/CRM/Core/BAO/File.php                 |    1 -
 civicrm/CRM/Core/BAO/FinancialTrxn.php        |    2 +-
 civicrm/CRM/Core/BAO/Mapping.php              |    1 -
 civicrm/CRM/Core/BAO/MessageTemplate.php      |    4 -
 civicrm/CRM/Core/BAO/Navigation.php           |    2 +-
 civicrm/CRM/Core/BAO/PrevNextCache.php        |   31 +-
 civicrm/CRM/Core/BAO/SchemaHandler.php        |   96 +-
 civicrm/CRM/Core/BAO/UFGroup.php              |    1 -
 civicrm/CRM/Core/BAO/UFMatch.php              |   31 +-
 civicrm/CRM/Core/BAO/Website.php              |    3 +-
 civicrm/CRM/Core/CodeGen/BaseTask.php         |    1 +
 civicrm/CRM/Core/CodeGen/I18n.php             |    5 +-
 civicrm/CRM/Core/CodeGen/Specification.php    |    8 +-
 civicrm/CRM/Core/CodeGen/Util/Template.php    |    4 +-
 civicrm/CRM/Core/Config.php                   |    1 +
 civicrm/CRM/Core/DAO.php                      |   16 +-
 civicrm/CRM/Core/DAO/ActionLog.php            |    2 +-
 civicrm/CRM/Core/DAO/ActionMapping.php        |    2 +-
 civicrm/CRM/Core/DAO/ActionSchedule.php       |    2 +-
 civicrm/CRM/Core/DAO/Address.php              |    2 +-
 civicrm/CRM/Core/DAO/AddressFormat.php        |    2 +-
 civicrm/CRM/Core/DAO/Cache.php                |    2 +-
 civicrm/CRM/Core/DAO/Component.php            |    2 +-
 civicrm/CRM/Core/DAO/Country.php              |    2 +-
 civicrm/CRM/Core/DAO/County.php               |    2 +-
 civicrm/CRM/Core/DAO/CustomField.php          |   12 +-
 civicrm/CRM/Core/DAO/CustomGroup.php          |    2 +-
 civicrm/CRM/Core/DAO/Dashboard.php            |    2 +-
 civicrm/CRM/Core/DAO/Discount.php             |    2 +-
 civicrm/CRM/Core/DAO/Domain.php               |    2 +-
 civicrm/CRM/Core/DAO/Email.php                |    2 +-
 civicrm/CRM/Core/DAO/EntityFile.php           |    2 +-
 civicrm/CRM/Core/DAO/EntityTag.php            |    2 +-
 civicrm/CRM/Core/DAO/Extension.php            |    2 +-
 civicrm/CRM/Core/DAO/File.php                 |    2 +-
 civicrm/CRM/Core/DAO/IM.php                   |    2 +-
 civicrm/CRM/Core/DAO/Job.php                  |    2 +-
 civicrm/CRM/Core/DAO/JobLog.php               |    2 +-
 civicrm/CRM/Core/DAO/LocBlock.php             |    2 +-
 civicrm/CRM/Core/DAO/LocationType.php         |    2 +-
 civicrm/CRM/Core/DAO/Log.php                  |    2 +-
 civicrm/CRM/Core/DAO/MailSettings.php         |    2 +-
 civicrm/CRM/Core/DAO/Managed.php              |    2 +-
 civicrm/CRM/Core/DAO/Mapping.php              |    2 +-
 civicrm/CRM/Core/DAO/MappingField.php         |    2 +-
 civicrm/CRM/Core/DAO/Menu.php                 |    2 +-
 civicrm/CRM/Core/DAO/MessageTemplate.php      |    2 +-
 civicrm/CRM/Core/DAO/Navigation.php           |    2 +-
 civicrm/CRM/Core/DAO/Note.php                 |    2 +-
 civicrm/CRM/Core/DAO/OpenID.php               |    2 +-
 civicrm/CRM/Core/DAO/OptionGroup.php          |    2 +-
 civicrm/CRM/Core/DAO/OptionValue.php          |    2 +-
 civicrm/CRM/Core/DAO/Persistent.php           |    2 +-
 civicrm/CRM/Core/DAO/Phone.php                |    2 +-
 civicrm/CRM/Core/DAO/PreferencesDate.php      |    2 +-
 civicrm/CRM/Core/DAO/PrevNextCache.php        |    2 +-
 civicrm/CRM/Core/DAO/PrintLabel.php           |    2 +-
 civicrm/CRM/Core/DAO/RecurringEntity.php      |    2 +-
 civicrm/CRM/Core/DAO/Setting.php              |    2 +-
 civicrm/CRM/Core/DAO/StateProvince.php        |    2 +-
 civicrm/CRM/Core/DAO/StatusPreference.php     |    2 +-
 civicrm/CRM/Core/DAO/SystemLog.php            |    2 +-
 civicrm/CRM/Core/DAO/Tag.php                  |    2 +-
 civicrm/CRM/Core/DAO/Timezone.php             |    2 +-
 civicrm/CRM/Core/DAO/UFField.php              |    2 +-
 civicrm/CRM/Core/DAO/UFGroup.php              |    2 +-
 civicrm/CRM/Core/DAO/UFJoin.php               |    2 +-
 civicrm/CRM/Core/DAO/UFMatch.php              |    2 +-
 civicrm/CRM/Core/DAO/Website.php              |    2 +-
 civicrm/CRM/Core/DAO/WordReplacement.php      |    2 +-
 civicrm/CRM/Core/DAO/Worldregion.php          |    2 +-
 .../Core/Exception/PrematureExitException.php |   15 +
 civicrm/CRM/Core/Form.php                     |   17 +-
 civicrm/CRM/Core/Form/Search.php              |   32 +-
 civicrm/CRM/Core/I18n/Form.php                |    5 +-
 civicrm/CRM/Core/I18n/SchemaStructure.php     |  198 +-
 civicrm/CRM/Core/OptionGroup.php              |    2 -
 civicrm/CRM/Core/Page.php                     |    4 +
 civicrm/CRM/Core/Payment.php                  |    9 +-
 civicrm/CRM/Core/Payment/AuthorizeNetIPN.php  |    3 +-
 civicrm/CRM/Core/Payment/Dummy.php            |    4 +-
 civicrm/CRM/Core/Payment/Elavon.php           |    2 +-
 civicrm/CRM/Core/Payment/PayPalIPN.php        |    4 +-
 civicrm/CRM/Core/PseudoConstant.php           |    2 +-
 civicrm/CRM/Core/Resources.php                |   72 +-
 civicrm/CRM/Core/SelectValues.php             |   17 +-
 civicrm/CRM/Core/xml/Menu/Admin.xml           |    4 +-
 civicrm/CRM/Cxn/DAO/Cxn.php                   |    2 +-
 civicrm/CRM/Dedupe/DAO/Exception.php          |    2 +-
 civicrm/CRM/Dedupe/DAO/Rule.php               |    2 +-
 civicrm/CRM/Dedupe/DAO/RuleGroup.php          |    2 +-
 civicrm/CRM/Dedupe/Merger.php                 |  115 +-
 civicrm/CRM/Event/BAO/Event.php               |   18 +-
 civicrm/CRM/Event/BAO/Participant.php         |    2 +-
 civicrm/CRM/Event/BAO/Query.php               |    2 +-
 civicrm/CRM/Event/Cart/DAO/Cart.php           |    2 +-
 civicrm/CRM/Event/Cart/DAO/EventInCart.php    |    2 +-
 civicrm/CRM/Event/DAO/Event.php               |    2 +-
 civicrm/CRM/Event/DAO/Participant.php         |    2 +-
 civicrm/CRM/Event/DAO/ParticipantPayment.php  |    2 +-
 .../CRM/Event/DAO/ParticipantStatusType.php   |    2 +-
 civicrm/CRM/Event/Form/EventFees.php          |    2 +-
 civicrm/CRM/Event/Form/ManageEvent.php        |   15 +
 .../CRM/Event/Form/ManageEvent/EventInfo.php  |   32 +-
 civicrm/CRM/Event/Form/ManageEvent/Fee.php    |    2 +-
 .../CRM/Event/Form/ManageEvent/Location.php   |    2 +-
 .../Event/Form/ManageEvent/Registration.php   |    2 +-
 civicrm/CRM/Event/Form/ManageEvent/Repeat.php |    2 +-
 .../Form/ManageEvent/ScheduleReminders.php    |    2 +-
 .../CRM/Event/Form/ManageEvent/TabHeader.php  |    2 -
 civicrm/CRM/Event/Form/Participant.php        |    1 +
 .../Event/Form/ParticipantFeeSelection.php    |    5 +-
 civicrm/CRM/Event/Form/Registration.php       |   51 +-
 .../Registration/AdditionalParticipant.php    |    3 +-
 .../CRM/Event/Form/Registration/Confirm.php   |  135 +-
 .../CRM/Event/Form/Registration/Register.php  |    5 +-
 .../CRM/Event/Form/Registration/ThankYou.php  |    7 +-
 civicrm/CRM/Event/Form/Search.php             |   13 -
 civicrm/CRM/Event/Form/SelfSvcTransfer.php    |    6 +-
 civicrm/CRM/Event/Page/EventInfo.php          |    7 +-
 civicrm/CRM/Event/PseudoConstant.php          |    6 +-
 civicrm/CRM/Export/BAO/Export.php             |   56 +-
 civicrm/CRM/Export/BAO/ExportProcessor.php    |   49 +
 .../CRM/Financial/BAO/FinancialAccount.php    |    2 +-
 .../Financial/BAO/FinancialTypeAccount.php    |    2 +-
 civicrm/CRM/Financial/BAO/Payment.php         |   47 +-
 civicrm/CRM/Financial/DAO/Currency.php        |    2 +-
 .../Financial/DAO/EntityFinancialAccount.php  |    2 +-
 .../CRM/Financial/DAO/EntityFinancialTrxn.php |    2 +-
 .../CRM/Financial/DAO/FinancialAccount.php    |    2 +-
 civicrm/CRM/Financial/DAO/FinancialItem.php   |    2 +-
 civicrm/CRM/Financial/DAO/FinancialTrxn.php   |    2 +-
 civicrm/CRM/Financial/DAO/FinancialType.php   |    2 +-
 .../CRM/Financial/DAO/PaymentProcessor.php    |    2 +-
 .../Financial/DAO/PaymentProcessorType.php    |    2 +-
 civicrm/CRM/Financial/DAO/PaymentToken.php    |    2 +-
 .../CRM/Financial/Form/FinancialAccount.php   |    2 +-
 civicrm/CRM/Financial/Form/PaymentEdit.php    |    7 +-
 civicrm/CRM/Financial/Page/FinancialType.php  |    3 +-
 civicrm/CRM/Friend/BAO/Friend.php             |    2 +-
 civicrm/CRM/Friend/DAO/Friend.php             |    2 +-
 civicrm/CRM/Friend/Form.php                   |    1 -
 civicrm/CRM/Friend/Form/Event.php             |    2 +-
 civicrm/CRM/Grant/DAO/Grant.php               |    2 +-
 civicrm/CRM/Grant/Page/Tab.php                |    2 +-
 civicrm/CRM/Logging/Schema.php                |   47 +-
 civicrm/CRM/Mailing/BAO/Mailing.php           |   10 +-
 civicrm/CRM/Mailing/BAO/MailingJob.php        |    5 -
 civicrm/CRM/Mailing/BAO/Query.php             |    2 +-
 civicrm/CRM/Mailing/DAO/BouncePattern.php     |    2 +-
 civicrm/CRM/Mailing/DAO/BounceType.php        |    2 +-
 civicrm/CRM/Mailing/DAO/Mailing.php           |    2 +-
 civicrm/CRM/Mailing/DAO/MailingAB.php         |    2 +-
 civicrm/CRM/Mailing/DAO/MailingComponent.php  |    2 +-
 civicrm/CRM/Mailing/DAO/MailingGroup.php      |    2 +-
 civicrm/CRM/Mailing/DAO/MailingJob.php        |    2 +-
 civicrm/CRM/Mailing/DAO/Recipients.php        |    2 +-
 civicrm/CRM/Mailing/DAO/Spool.php             |    2 +-
 civicrm/CRM/Mailing/DAO/TrackableURL.php      |    2 +-
 civicrm/CRM/Mailing/Event/BAO/Bounce.php      |    2 +-
 civicrm/CRM/Mailing/Event/BAO/Delivered.php   |    4 +-
 civicrm/CRM/Mailing/Event/BAO/Forward.php     |    4 +-
 civicrm/CRM/Mailing/Event/BAO/Opened.php      |    2 +-
 civicrm/CRM/Mailing/Event/BAO/Queue.php       |    2 +-
 civicrm/CRM/Mailing/Event/BAO/Reply.php       |    2 +-
 .../Mailing/Event/BAO/TrackableURLOpen.php    |    2 +-
 civicrm/CRM/Mailing/Event/BAO/Unsubscribe.php |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Bounce.php      |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Confirm.php     |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Delivered.php   |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Forward.php     |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Opened.php      |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Queue.php       |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Reply.php       |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Subscribe.php   |    2 +-
 .../Mailing/Event/DAO/TrackableURLOpen.php    |    2 +-
 civicrm/CRM/Mailing/Event/DAO/Unsubscribe.php |    2 +-
 civicrm/CRM/Mailing/Form/Subscribe.php        |    5 +-
 civicrm/CRM/Mailing/Page/View.php             |    7 +
 civicrm/CRM/Mailing/Selector/Browse.php       |    8 +-
 civicrm/CRM/Member/BAO/Membership.php         |    6 +-
 civicrm/CRM/Member/BAO/MembershipStatus.php   |    4 +-
 civicrm/CRM/Member/BAO/Query.php              |    2 +-
 civicrm/CRM/Member/DAO/Membership.php         |    2 +-
 civicrm/CRM/Member/DAO/MembershipBlock.php    |    2 +-
 civicrm/CRM/Member/DAO/MembershipLog.php      |    2 +-
 civicrm/CRM/Member/DAO/MembershipPayment.php  |    2 +-
 civicrm/CRM/Member/DAO/MembershipStatus.php   |    2 +-
 civicrm/CRM/Member/DAO/MembershipType.php     |    2 +-
 civicrm/CRM/Member/Form/Membership.php        |    2 +-
 civicrm/CRM/PCP/BAO/PCP.php                   |   27 +-
 civicrm/CRM/PCP/DAO/PCP.php                   |    2 +-
 civicrm/CRM/PCP/DAO/PCPBlock.php              |    2 +-
 civicrm/CRM/PCP/Form/Event.php                |    2 +-
 civicrm/CRM/Pledge/BAO/PledgePayment.php      |    1 -
 civicrm/CRM/Pledge/BAO/Query.php              |   29 +-
 civicrm/CRM/Pledge/DAO/Pledge.php             |    5 +-
 civicrm/CRM/Pledge/DAO/PledgeBlock.php        |    2 +-
 civicrm/CRM/Pledge/DAO/PledgePayment.php      |    2 +-
 civicrm/CRM/Pledge/Form/Search.php            |    7 +
 civicrm/CRM/Price/BAO/LineItem.php            |   10 +-
 civicrm/CRM/Price/DAO/LineItem.php            |    2 +-
 civicrm/CRM/Price/DAO/PriceField.php          |    2 +-
 civicrm/CRM/Price/DAO/PriceFieldValue.php     |    2 +-
 civicrm/CRM/Price/DAO/PriceSet.php            |    2 +-
 civicrm/CRM/Price/DAO/PriceSetEntity.php      |    2 +-
 civicrm/CRM/Price/Form/Option.php             |    4 +-
 civicrm/CRM/Profile/Form.php                  |    5 +-
 civicrm/CRM/Queue/DAO/QueueItem.php           |    2 +-
 civicrm/CRM/Queue/Queue/Sql.php               |    2 -
 civicrm/CRM/Report/BAO/ReportInstance.php     |    1 -
 civicrm/CRM/Report/DAO/ReportInstance.php     |    2 +-
 civicrm/CRM/Report/Form.php                   |   14 +-
 civicrm/CRM/Report/Form/Case/Summary.php      |    8 +-
 .../Form/Contribute/DeferredRevenue.php       |    2 +
 civicrm/CRM/Report/Form/Contribute/Detail.php |    2 +
 .../Report/Form/Member/ContributionDetail.php |   21 +-
 civicrm/CRM/Report/Form/Member/Detail.php     |   21 +-
 civicrm/CRM/Report/Form/Member/Summary.php    |   21 +-
 civicrm/CRM/SMS/DAO/Provider.php              |    2 +-
 civicrm/CRM/SMS/Form/Schedule.php             |    3 +-
 civicrm/CRM/Upgrade/Form.php                  |    4 +-
 .../CRM/Upgrade/Incremental/SmartGroups.php   |   11 +-
 .../Upgrade/Incremental/php/FiveSixteen.php   |  110 +
 .../CRM/Upgrade/Incremental/php/FourFive.php  |    2 +-
 .../CRM/Upgrade/Incremental/php/FourThree.php |    2 +-
 .../Upgrade/Incremental/sql/5.15.1.mysql.tpl  |    1 -
 .../Upgrade/Incremental/sql/5.15.2.mysql.tpl  |    1 -
 .../Upgrade/Incremental/sql/5.16.0.mysql.tpl  |    1 +
 .../Incremental/sql/5.16.alpha1.mysql.tpl     |    5 +
 .../Incremental/sql/5.16.beta1.mysql.tpl      |    1 +
 civicrm/CRM/Utils/Address/BatchUpdate.php     |    1 -
 civicrm/CRM/Utils/Cache.php                   |    2 +-
 civicrm/CRM/Utils/Cache/ArrayCache.php        |    6 +-
 civicrm/CRM/Utils/Cache/SerializeCache.php    |  151 -
 civicrm/CRM/Utils/Cache/SqlGroup.php          |   18 +-
 .../CRM/Utils/Check/Component/Timestamps.php  |    1 -
 civicrm/CRM/Utils/Color.php                   |   95 +-
 civicrm/CRM/Utils/Date.php                    |   13 +
 civicrm/CRM/Utils/Hook.php                    |   57 +
 civicrm/CRM/Utils/JS.php                      |  147 +
 civicrm/CRM/Utils/JSON.php                    |   10 +
 civicrm/CRM/Utils/Mail/Incoming.php           |    4 +-
 civicrm/CRM/Utils/Migrate/ExportJSON.php      |    3 -
 civicrm/CRM/Utils/OpenFlashChart.php          |    9 +-
 civicrm/CRM/Utils/ReCAPTCHA.php               |   13 +
 civicrm/CRM/Utils/SQL/BaseParamQuery.php      |    4 +-
 civicrm/CRM/Utils/String.php                  |    2 +-
 civicrm/CRM/Utils/System.php                  |    9 +-
 civicrm/CRM/Utils/System/Base.php             |   13 +
 civicrm/CRM/Utils/System/Drupal8.php          |   18 +-
 civicrm/CRM/Utils/System/DrupalBase.php       |   22 +
 civicrm/CRM/Utils/System/WordPress.php        |   16 +-
 civicrm/CRM/Utils/VersionCheck.php            |    2 +-
 .../API/Subscriber/APIv3SchemaAdapter.php     |    3 +
 .../Civi/API/Subscriber/I18nSubscriber.php    |   61 +-
 civicrm/Civi/Angular/ChangeSet.php            |    3 -
 civicrm/Civi/Angular/Manager.php              |    3 +-
 civicrm/Civi/Core/Container.php               |   36 +-
 civicrm/Civi/Core/Themes.php                  |  283 ++
 civicrm/Civi/Core/Themes/Resolvers.php        |   97 +
 civicrm/Civi/Test/Api3TestTrait.php           |   27 +-
 civicrm/Civi/Test/ContactTestTrait.php        |    7 +-
 civicrm/Civi/Test/DbTestTrait.php             |    3 +
 civicrm/ang/checklist-model.ang.php           |   10 +
 civicrm/ang/crmCaseType.ang.php               |    6 -
 civicrm/ang/crmCaseType.js                    |   99 +-
 civicrm/ang/crmCaseType/caseTypeDetails.html  |    1 -
 civicrm/ang/crmCaseType/rolesTable.html       |    3 +-
 civicrm/api/v3/Address.php                    |    4 +-
 civicrm/api/v3/Contact.php                    |  131 +-
 civicrm/api/v3/Contribution.php               |    9 +-
 civicrm/api/v3/Dedupe.php                     |    2 +-
 civicrm/api/v3/Email.php                      |    4 +
 civicrm/api/v3/Order.php                      |    2 +-
 civicrm/api/v3/Payment.php                    |    6 +-
 civicrm/api/v3/PledgePayment.php              |   14 -
 civicrm/api/v3/Setting.php                    |    6 +-
 civicrm/api/v3/SurveyRespondant.php           |    2 +-
 civicrm/api/v3/System.php                     |    7 +
 civicrm/api/v3/utils.php                      |    4 +
 civicrm/bower.json                            |    4 +-
 .../checklist-model/.bower.json               |   30 +
 .../checklist-model/LICENSE.txt               |   23 +
 .../checklist-model/bower.json                |   22 +
 .../checklist-model/checklist-model.js        |  175 +
 .../checklist-model/checklist-model.nuspec    |   25 +
 .../checklist-model/package-lock.json         | 3511 +++++++++++++++++
 .../checklist-model/readme.md                 |   85 +
 .../css-color-names/.bower.json               |   14 +
 .../bower_components/css-color-names/LICENSE  |    7 +
 .../bower_components/css-color-names/Makefile |    8 +
 .../css-color-names/README.md                 |   48 +
 .../css-color-names/css-color-names.json      |  150 +
 .../css-color-names/getcolors.sh              |    8 +
 .../css-color-names/package.json              |   28 +
 .../css-color-names/stringify.js              |   17 +
 civicrm/civicrm-version.php                   |    2 +-
 civicrm/composer.json                         |    3 +-
 civicrm/composer.lock                         |   69 +-
 civicrm/css/civicrm.css                       |    6 +
 civicrm/css/crm-menubar.css                   |   10 +-
 civicrm/js/Common.js                          |   52 +-
 civicrm/js/crm.ajax.js                        |    8 +-
 civicrm/js/crm.datepicker.js                  |    6 +
 civicrm/js/crm.menubar.js                     |   13 +-
 civicrm/js/crm.multilingual.js                |    9 +-
 civicrm/js/wysiwyg/crm.wysiwyg.js             |    3 +
 civicrm/release-notes.md                      |   11 +
 civicrm/release-notes/5.15.2.md               |    3 +-
 civicrm/release-notes/5.16.0.md               |  793 ++++
 civicrm/settings/Campaign.setting.php         |    2 +
 civicrm/settings/Core.setting.php             |   44 +-
 civicrm/settings/Multisite.setting.php        |    2 +
 civicrm/sql/civicrm.mysql                     |    4 +-
 civicrm/sql/civicrm_data.mysql                |    2 +-
 civicrm/sql/civicrm_generated.mysql           |    2 +-
 .../CRM/Admin/Form/Preferences/Campaign.tpl   |   26 -
 .../CRM/Admin/Form/Preferences/Display.hlp    |   45 +
 .../CRM/Admin/Form/Preferences/Display.tpl    |   16 +
 .../CRM/Admin/Form/Preferences/Multisite.tpl  |   26 -
 .../CRM/Admin/Form/Setting/Miscellaneous.tpl  |  176 +-
 .../Form/Setting/UpdateConfigBackend.tpl      |   21 +-
 civicrm/templates/CRM/Admin/Page/Job.tpl      |    2 +-
 civicrm/templates/CRM/Batch/Form/Entry.tpl    |    2 +-
 .../CRM/Case/XMLProcessor/Report.tpl          |    3 +-
 .../Search/Custom/ContributionAggregate.tpl   |   10 +-
 .../CRM/Contribute/Form/Search/Common.tpl     |   25 +-
 .../templates/CRM/Event/Form/Participant.tpl  |    3 +
 civicrm/templates/CRM/common/jsortable.tpl    |    4 +-
 civicrm/templates/CRM/common/l10n.js.tpl      |    2 +-
 civicrm/vendor/autoload.php                   |    2 +-
 civicrm/vendor/composer/autoload_files.php    |    1 +
 civicrm/vendor/composer/autoload_psr4.php     |    1 +
 civicrm/vendor/composer/autoload_real.php     |   14 +-
 civicrm/vendor/composer/autoload_static.php   |   21 +-
 civicrm/vendor/composer/installed.json        |   69 +
 civicrm/vendor/league/csv/CHANGELOG.md        |  960 +++++
 civicrm/vendor/league/csv/LICENSE             |   20 +
 civicrm/vendor/league/csv/autoload.php        |   18 +
 civicrm/vendor/league/csv/composer.json       |   72 +
 civicrm/vendor/league/csv/src/AbstractCsv.php |  457 +++
 .../vendor/league/csv/src/ByteSequence.php    |   43 +
 .../league/csv/src/CannotInsertRecord.php     |   75 +
 .../league/csv/src/CharsetConverter.php       |  250 ++
 .../league/csv/src/ColumnConsistency.php      |   67 +
 .../vendor/league/csv/src/EncloseField.php    |  143 +
 .../vendor/league/csv/src/EscapeFormula.php   |  152 +
 civicrm/vendor/league/csv/src/Exception.php   |   21 +
 .../vendor/league/csv/src/HTMLConverter.php   |  114 +
 civicrm/vendor/league/csv/src/MapIterator.php |   49 +
 .../csv/src/Polyfill/EmptyEscapeParser.php    |  251 ++
 .../vendor/league/csv/src/RFC4180Field.php    |  206 +
 civicrm/vendor/league/csv/src/Reader.php      |  378 ++
 civicrm/vendor/league/csv/src/ResultSet.php   |  241 ++
 civicrm/vendor/league/csv/src/Statement.php   |  169 +
 civicrm/vendor/league/csv/src/Stream.php      |  518 +++
 civicrm/vendor/league/csv/src/Writer.php      |  330 ++
 .../vendor/league/csv/src/XMLConverter.php    |  225 ++
 civicrm/vendor/league/csv/src/functions.php   |  115 +
 .../league/csv/src/functions_include.php      |   14 +
 civicrm/xml/schema/Contact/Contact.xml        |    4 +-
 .../xml/schema/Contribute/Contribution.xml    |    2 +
 civicrm/xml/schema/Core/CustomField.xml       |   10 +-
 civicrm/xml/schema/Pledge/Pledge.xml          |    3 +
 civicrm/xml/templates/dao.tpl                 |    4 +-
 civicrm/xml/version.xml                       |    2 +-
 includes/civicrm.basepage.php                 |   26 +
 phpunit.xml.dist                              |   24 +
 tests/phpunit/CiviWP/HookTest.php             |   56 +
 tests/phpunit/bootstrap.php                   |   55 +
 481 files changed, 13663 insertions(+), 2141 deletions(-)
 delete mode 100644 civicrm/CRM/Admin/Form/Preferences/Campaign.php
 delete mode 100644 civicrm/CRM/Admin/Form/Preferences/Multisite.php
 create mode 100644 civicrm/CRM/Upgrade/Incremental/php/FiveSixteen.php
 delete mode 100644 civicrm/CRM/Upgrade/Incremental/sql/5.15.1.mysql.tpl
 delete mode 100644 civicrm/CRM/Upgrade/Incremental/sql/5.15.2.mysql.tpl
 create mode 100644 civicrm/CRM/Upgrade/Incremental/sql/5.16.0.mysql.tpl
 create mode 100644 civicrm/CRM/Upgrade/Incremental/sql/5.16.alpha1.mysql.tpl
 create mode 100644 civicrm/CRM/Upgrade/Incremental/sql/5.16.beta1.mysql.tpl
 delete mode 100644 civicrm/CRM/Utils/Cache/SerializeCache.php
 create mode 100644 civicrm/Civi/Core/Themes.php
 create mode 100644 civicrm/Civi/Core/Themes/Resolvers.php
 create mode 100644 civicrm/ang/checklist-model.ang.php
 create mode 100644 civicrm/bower_components/checklist-model/.bower.json
 create mode 100644 civicrm/bower_components/checklist-model/LICENSE.txt
 create mode 100644 civicrm/bower_components/checklist-model/bower.json
 create mode 100644 civicrm/bower_components/checklist-model/checklist-model.js
 create mode 100644 civicrm/bower_components/checklist-model/checklist-model.nuspec
 create mode 100644 civicrm/bower_components/checklist-model/package-lock.json
 create mode 100644 civicrm/bower_components/checklist-model/readme.md
 create mode 100644 civicrm/bower_components/css-color-names/.bower.json
 create mode 100644 civicrm/bower_components/css-color-names/LICENSE
 create mode 100644 civicrm/bower_components/css-color-names/Makefile
 create mode 100644 civicrm/bower_components/css-color-names/README.md
 create mode 100644 civicrm/bower_components/css-color-names/css-color-names.json
 create mode 100755 civicrm/bower_components/css-color-names/getcolors.sh
 create mode 100644 civicrm/bower_components/css-color-names/package.json
 create mode 100755 civicrm/bower_components/css-color-names/stringify.js
 create mode 100644 civicrm/release-notes/5.16.0.md
 delete mode 100644 civicrm/templates/CRM/Admin/Form/Preferences/Campaign.tpl
 delete mode 100644 civicrm/templates/CRM/Admin/Form/Preferences/Multisite.tpl
 create mode 100644 civicrm/vendor/league/csv/CHANGELOG.md
 create mode 100644 civicrm/vendor/league/csv/LICENSE
 create mode 100644 civicrm/vendor/league/csv/autoload.php
 create mode 100644 civicrm/vendor/league/csv/composer.json
 create mode 100644 civicrm/vendor/league/csv/src/AbstractCsv.php
 create mode 100644 civicrm/vendor/league/csv/src/ByteSequence.php
 create mode 100644 civicrm/vendor/league/csv/src/CannotInsertRecord.php
 create mode 100644 civicrm/vendor/league/csv/src/CharsetConverter.php
 create mode 100644 civicrm/vendor/league/csv/src/ColumnConsistency.php
 create mode 100644 civicrm/vendor/league/csv/src/EncloseField.php
 create mode 100644 civicrm/vendor/league/csv/src/EscapeFormula.php
 create mode 100644 civicrm/vendor/league/csv/src/Exception.php
 create mode 100644 civicrm/vendor/league/csv/src/HTMLConverter.php
 create mode 100644 civicrm/vendor/league/csv/src/MapIterator.php
 create mode 100644 civicrm/vendor/league/csv/src/Polyfill/EmptyEscapeParser.php
 create mode 100644 civicrm/vendor/league/csv/src/RFC4180Field.php
 create mode 100644 civicrm/vendor/league/csv/src/Reader.php
 create mode 100644 civicrm/vendor/league/csv/src/ResultSet.php
 create mode 100644 civicrm/vendor/league/csv/src/Statement.php
 create mode 100644 civicrm/vendor/league/csv/src/Stream.php
 create mode 100644 civicrm/vendor/league/csv/src/Writer.php
 create mode 100644 civicrm/vendor/league/csv/src/XMLConverter.php
 create mode 100644 civicrm/vendor/league/csv/src/functions.php
 create mode 100644 civicrm/vendor/league/csv/src/functions_include.php
 create mode 100644 phpunit.xml.dist
 create mode 100644 tests/phpunit/CiviWP/HookTest.php
 create mode 100644 tests/phpunit/bootstrap.php

diff --git a/civicrm.php b/civicrm.php
index 5b4cfb6519..26a1e3bf30 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 924a9eaf2a..d887be06bd 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 229f6f4c6e..52058d84a6 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 ea00194575..4fe8594781 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 bad293c934..65191fb979 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 fedf0b6d1b..313fa5c128 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 2c4a0440a7..db89d80422 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 8f4053dfed..21468db91b 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 aac6059d38..f82cd4c90f 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 38abfddd4c..c89b52f6c3 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 1da789c273..6c78fb59c5 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 3e372da4c9..0000000000
--- 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 7421754c72..2367796184 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 9ba36825cd..3e7b87a825 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 e561692268..0000000000
--- 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 d1a258738c..d4cf4ae094 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 22f6539913..02328983d7 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 fb2b2a3261..771c0cc412 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 26340d54ad..3ccd9c869e 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 5e0cb9ecb0..d07e6e1aab 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 b787b344a5..46555a290b 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 a3c496b315..f8f815a130 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 07f34d5fde..6f94488d13 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 d013622630..3bc1a8e71e 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 06a3c6130b..813d340055 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 f39166cebf..29e398ef18 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 7c22820e9b..1342053314 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 a5c673f24e..555eb1f284 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 4fcbe01cae..1b1340a9ef 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 e5bf54125e..321118bf96 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 717b2b1bf1..32f599953d 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 40b275fbf8..d19ca14a36 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 42a830d703..f1f5a9866b 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 533f0e03a3..84a3300b3a 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 ed571d76f3..c233fd321a 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 20be94a95a..f2809047e3 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 685ce79553..80b83d578c 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 fdf587ca58..2f9eb82a0e 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 413385c55d..ce5421fd1b 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 461b51f5da..15bc97354f 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 5a4ab88c8e..c1a4e68536 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 863ea68ff5..245e9ace1c 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 b83e11cce6..4cfb5c8d7e 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 98534dc95e..2915874f79 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 54011e77e3..243c74c5cc 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 cf540790ed..a6f660669d 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 a839ce5626..8850d9acc5 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 e48d988b90..49efecdcef 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 11aa9f4996..ab5e7f69d0 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 4898e7f204..1f10c64302 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 46886c6413..b3561a72fe 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 1134bf2a1c..b62b6e482e 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 139e0e71c0..3b662f4815 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 a999b9d402..78e7b6680c 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 edb5b3e352..1684bbefb6 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 3e2eddaf1f..20d066e94f 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 ba7352ccf1..5e651f25c6 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 c6697590c4..5157e2cf53 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 bbc3cf9936..ff40b3bd70 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 d35db86708..2b81492759 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 0eb497e53b..1f3778e22b 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 edb59a6b76..c5a9278a67 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 32eab98293..e9cf758ade 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 dd16bbcd64..bf79a94348 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 1a533342a0..0532894df3 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 afda78618c..30d95f1847 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 b4edd5986d..9baf5429b3 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 f776f8448e..5437e0d2a0 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 f3be4f2e2d..12b3a03e54 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 441688dab6..e3b36fc95d 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 df0e60488f..d6bd1b17d8 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 2958f6e98e..a25f920de3 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 15b313f231..0ee1969f91 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 929ec1e509..5e9ce5ea2c 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 a560a9adf3..ab894330c7 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 5ca5894dca..82a3e3d682 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 08c84098c3..ce18d470f3 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 fa6c55592e..164ab946ab 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 5f45d1868f..b87dba3494 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 8b7e1ec8c9..1ddfbedc56 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 e2ad53b260..1e88c66618 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 e4bff0b4ff..396fae5273 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 b628edef8c..2284edf547 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 e7d37109d3..3f731e4f95 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 5913150b44..b23eca995a 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 dfc0899bc5..ca9594294c 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 129b3a32ad..ec9594b5d8 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 48a7bfcd2d..282a55e2b0 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 cdc9f3e154..ed9ae18166 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 ad147b0646..a85ae650c3 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 aa2cbc3fab..a90456f891 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 196a0c348b..8da1c12557 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 0121cd1dbb..79a4db615d 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 9add6a4ec1..ffd9a524ce 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 601c8e08fd..7738e66017 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 18fcdc93be..1cd24557cf 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 847f64688b..d021b8157b 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 6c84b5315d..81a3f827df 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 bc291dc167..388362b05c 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 9aacd34fae..35b776de85 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 0f9f8df41a..826c4f0678 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 25d247c51f..6c97c765df 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 a85f4df852..abc90a1cfb 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 cbe0066dec..71ebf132db 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 fe41bd06cc..ef2bc60eee 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 03463d473e..ecf107831a 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 df195660c0..f6059a6deb 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 c0fb792829..d41a71e1a0 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 eb1b645c74..a3e2cf2736 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 759e83a719..c25baac556 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 c2c06bd279..a0a28476ed 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 742ad4aeb2..b02538e429 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 55e1ef9ae2..606c3d282c 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 6687dd0ee4..4b81879706 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 90cc56fb1c..bac09cd73c 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 bfb410d993..416709e59a 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 5fe0666b15..2dbe66fdff 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 3adba27015..98b6065688 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 18ce81f8aa..83713e6cf5 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 f947253594..f7fba2c6a2 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 c58a32ac15..caf7ff6611 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 ea648adaaa..3d3ecc1bcf 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 9593c45148..8e518894d2 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 ed2eac1cae..5183997b45 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 b9c632feb6..4e3679fb6d 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 e2adbc6f7e..5eb4713b8f 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 86a10b240d..6737bd08b9 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 841bc7d0e2..bfc83ced02 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 d6d17288fa..dba72de115 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 50841dbee5..8317a6a3ab 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 4aebbfb3c9..de8520b8ce 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 b9c0d73da3..5c68f255fa 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 77def7da10..d6b17a7f79 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 5087ed4138..adf66bb8d8 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 853be19f1b..6985316576 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 573ac27fa0..972923f326 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 363c13e419..0c57ff05fb 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 ea13f32203..c0239c4270 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 17250c3cb3..5bf27a0e0f 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 e3e5c13014..d816f99627 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 1d36308a30..b305a8eace 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 9ab75998b9..a31b7ae3da 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 e3ea7a3fe5..dd8ded639f 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 67f396493f..86d42298c9 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 508a449a0d..c893c81d1a 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 6d4583a6a1..dccac7b49b 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 3f4fe93d75..6625fa2574 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 6fd510f4fe..00531bbd4b 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 4c281a54c7..0a1a4be726 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 55f9e0c5fe..305e0763b0 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 9193116def..f114b8cc7f 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 a3aa181b9f..a6b6b834dd 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 68272f34cf..45009de133 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 d3b2da95e6..84e6234c70 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 afa1179d87..571f5941db 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 1aca8e4b08..45d6dab55e 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 5b4604881f..39c04a727f 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 2aa3fc3d0d..16e227b64e 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 4fe2a823cc..0c8e270cf1 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 542d774e9f..52014b7fa0 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 9908d873ae..a3d07c2bde 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 3f62e140d3..f98c38b2bf 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 41ffa70f1b..6b2661dcd0 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 f85772ce62..e204d3b3f5 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 2441d6c032..d0124645e5 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 190c889395..5e0d62a6dd 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 5591681252..6ba14b1e32 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 cd514f9b3d..9fad6c8240 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 bb9401d1a5..6f1be9bfd1 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 bf17bcd936..9cc7565717 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 94f5d59938..721b5e56b9 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 c1587e0bdd..b2e95c358d 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 826157f63c..3e365698db 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 0c33a2f11d..a688d9c820 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 7f06eb7a50..1773c9f32f 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 792c2abb1f..0a1c5b72e0 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 05bf4704f9..8f3589a09b 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 fc1d60dc1a..0066c7080e 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 31b4d03d4e..c73eb2040d 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 637bcceb5b..5407156400 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 05665f2303..9782972aed 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 3b0f574d16..854b233481 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 91d8cf8830..6d5e6e5a14 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 865cb9e694..2957645991 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 bc8b776af1..dd7aa9bd31 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 439e5ec58f..899d844231 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 1bf006722d..2a4324e6cd 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 145c91af53..b19388283f 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 eaa4cce0ee..502d332df3 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 a6beaf1231..d09276b9b2 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 d2f8c5c00d..7c260074a2 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 8d9df671c4..d0c4bbccfb 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 5e0a1034be..3ad4c74d27 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 9950cf10f5..5df5e7f275 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 3066d3331c..5a67b904c4 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 497e0904fa..65f7eb86bd 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 d23a10910b..34228dc51d 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 c75742e238..342a01222a 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 c68c5d0647..3d4743273a 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 5d513b1aaf..e9b3fd7cf9 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 bb54789c0b..3d1b6fc2d2 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 e6b07b9143..a57d64e100 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 2729d09693..cf52a5f32c 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 db4bf4f7c2..9819a2712f 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 77fa886ea1..45cfa1a226 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 92684931dc..8531b9ecc7 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 c0147b76dc..6f3812b365 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 598001578d..f28c91c2f1 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 cba5311348..66d2acf1a7 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 d9b126bb5c..cf4e80bc85 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 7a09e16739..ac353201e2 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 f5972943bf..dec7b6fd3c 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 9e065f4cc1..17c9b9e78d 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 31317c09aa..0bf756f151 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 ddc1c2da06..46420b809a 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 b33eafe0a4..7e2c8a8889 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 0c62605713..0c03c4f9f9 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 f02716591d..9aad1cd161 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 483f275de6..4129564e57 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 c966147e4f..d77440c1a0 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 d0426e4caa..02b6a75f2f 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 50511fba17..d79cc636e1 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 af19e44236..b29b6c7bc2 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 afaaf1a4d4..5e665f0175 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 1b35d29fe3..55e2e91e69 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 080ecb98c4..2fcd458f84 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 7c13ada6f6..00a1d89afa 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 412590c22a..e53572d90d 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 c3af950956..a0e629e0aa 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 6cdcab5bdd..b6f02a0688 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 23143f637d..8a8e556313 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 eb1e98a5c8..207fea2218 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 8e2489172a..8034f215a2 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 c8f3357370..42a97669b4 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 faa84e3f69..be81d888e1 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 1683e2e31b..d3f5dc3119 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 4192856b86..ae929e059d 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 13b31ce00c..b1e8b0ddb0 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 5387669daf..14724a83a2 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 5f0f5f1dc4..d5522bce08 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 d3fdc69d1d..b8a7537c23 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 fefd72cbdb..deb67cd909 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 636069efbe..3ffc40e40e 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 4a09521775..c103b7703f 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 3c3a7bb227..e870cc631f 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 17aa223d2c..3bea1c6e46 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 f304e7fcfa..227e6d0143 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 105b98641c..22a38b9be5 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 6bb3b325ff..f0e1f18232 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 b817cae909..2e8328255d 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 d072051971..0e1cc3af6c 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 70cd21086d..4509acd993 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 bf5b6cb518..2e68f80dc8 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 d889f2ad6f..b05255eca6 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 914879716c..c2134c06b5 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 9ce4883b18..0f7f3ac393 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 21d10f7c5f..9a24f8a9a8 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 6bbf839474..f14eb00c7e 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 ff1e5a8dd0..aadb018caf 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 e54fa43aa3..34bf17983b 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 db710ffeb9..073e78f4da 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 d6aef45f9e..83f0211943 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 9fb96960e1..89080d583e 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 8a5e52eb20..858090bb13 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 75bdc7f2b3..045b6cd524 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 ebec9368ab..40c9eca89e 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 8ca9fe6ec0..9b539a0f5b 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 20053007af..e2f960cf3f 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 751d21e744..faa50c5362 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 9a162c83de..1f3c8ba8c2 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 e8c9a4cc19..237f3a27fc 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 8d8532ea8d..4c79b03db4 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 a2a1e01b30..9188dadaa2 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 41cefaf8ee..59e979f080 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 03a54c9431..f02d1ffe60 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 29a907d29a..7237c7390f 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 415ae85350..f6c4771e28 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 8efd8fddb3..bcf3cf915a 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 b80f8fc319..7180aaf75f 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 5a3008d751..f10840e8f5 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 059c6b3a4a..f409781aec 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 69fb725731..e001bc82e2 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 efe1d0867d..69e1401c33 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 27ec175e90..f125bf1483 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 3162104cfc..f40c444a74 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 cce8241d1a..0a7ba546a2 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 8e7d40ddd7..c62df7d7e7 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 6a8feae66b..56e34f1e26 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 a6f03660f2..878434004e 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 1f4aa41c55..a0ae8f5b65 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 49e5181b8b..833b049fa2 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 c3508a7e17..e6310ae68e 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 3294569e6c..9edfe64693 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 696e8ad635..28dfaa8a02 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 117d8a7cc7..ea027ff216 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 ef491cc135..ff1f7611a1 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 d6369491b9..ab00757683 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 d238e87ac1..2f4b030144 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 fb3cddba56..e5d60dc87b 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 ec39152a44..cf5bf72ffc 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 367fa10429..c747805cbc 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 f6dc90a8d8..981687b04e 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 14e478a5b5..19b6dbc2cc 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 da7802382b..f242036b3e 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 ec637d58b7..7de77302e0 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 902872d1c1..1b3779060e 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 b18050474a..9a8cc6e54e 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 77e6525ca7..ff335a0cb2 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 a43fade054..2a46fab331 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 c101d33a6d..ecf8f503e4 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 6119f19478..08d4b2e032 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 ea4e67719a..9813a743db 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 e823c87c39..9df77e7cb4 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 0543497f1f..795230bb4a 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 1593408b04..1384fad77c 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 0e6750dc84..1824e53eb4 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 f159c37bdc..1ad15e8ddc 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 4c110de5d4..9052831d2b 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 f866a92be5..08e281d69d 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 6be0e23aa2..a77ba055fe 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 da56063bc7..1fd77605c8 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 45199eff78..8c79fd67b9 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 7c370c5cad..eff1db9aef 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 1db23629ce..286fe3b233 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 321c5378e3..75718bb137 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 82060fafdd..a4c6e0d31f 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 beabdbc122..3b92f9b633 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 4d816ee3db..cdb100c8f2 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 9ad2a41fb3..e4fb27ac9b 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 81a2b07603..3e9d2b1123 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 4a1fdefb4f..1f6e8f1451 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 47f71da3ea..008d42210a 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 a92aa9e649..feb9c6438a 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 0000000000..554d884b62
--- /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 f5b9aada41..cd9f0368a2 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 a444e4962b..a86316e1db 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 68abb9418a..0000000000
--- 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 8b49e8402d..0000000000
--- 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 0000000000..c553cb3545
--- /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 0000000000..be013c10a8
--- /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 0000000000..22be6dcfb8
--- /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 9b16c0d2f4..4e3a47331f 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 23975cae4d..26bdc6c3b7 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 92badc0cda..c83f3f1f4e 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 f17b459107..0000000000
--- 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 6c0b6960ff..fe34b5290c 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 932d33f070..8bf32c1204 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 2cceca9ff3..95872433f5 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 24b2f73880..fa96fca47f 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 e2abd5a79f..2595679938 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 95340e36a3..06331b5a2c 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 d771de94e4..7ec004714f 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 0c5e5300e1..eed6ec8075 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 ffaa63065b..24ba0aa764 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 26e34292eb..178f093bb0 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 3198043014..fab82510ce 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 f48d05556c..159f56a5fa 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 c740e72a1f..d0f295dd18 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 7508fe1573..602c88276b 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 2e675243c5..0dca55f657 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 4eb885592a..a8b8a0e947 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 75d04ca712..829b3870d1 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 c65c3a057b..bf35954360 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 eb72bd9451..9d2fe9f6f2 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 e6428711eb..3831cdf4d8 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 c430928202..02c4d7e797 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 f0eb38148c..27c92a5867 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 5d019a0318..c44b854aa6 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 9ce531d1bb..853299498b 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 0000000000..16968eb7a3
--- /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 0000000000..4671b92002
--- /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 aeb4247275..1c99c0490b 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 c98e457b05..8fee27bc2d 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 06b5e60b3c..3e97931cfe 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 0000000000..ffa8613bda
--- /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 21596810d4..c71e9c6678 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 ee2344ece8..a1ff51ae57 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 0f74ff9a9b..d11cc913c3 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 cc64a60a8e..e7edee076e 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 c480aee939..05586e2c37 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 e52a46093f..3c2fc5bed2 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 8366a44528..f59951194c 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 0a27dcffeb..0099206918 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 095e082e73..d1dd4ab669 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 e895e0fc11..6d3b4bad5e 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 7314311147..a2deaf562c 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 4301305a66..3f43f4e40c 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 a7ce04b76f..88e05cfad6 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 5fccf6bc6f..dd9b4fd7fd 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 3523877682..54faf069a1 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 f28c07aeed..5a8c0e54b7 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 80a5dbc3ad..75e67552ef 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 0000000000..94fdf460f4
--- /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 0000000000..60d185fe36
--- /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 0000000000..f6f7c9ea03
--- /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 0000000000..ab5b700555
--- /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 0000000000..e61c84a80b
--- /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 0000000000..9740754256
--- /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 0000000000..4e43ee5f81
--- /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 0000000000..db9d473fd8
--- /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 0000000000..6c5fea91fc
--- /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 0000000000..ebbcf1d1b1
--- /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 0000000000..bfe6263b79
--- /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 0000000000..7a1480dcea
--- /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 0000000000..2c8ba0503b
--- /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 0000000000..d8711cd600
--- /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 0000000000..cc119fb7c8
--- /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 f8ed285b55..ed175082df 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 271f33cf59..1cfa14b776 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 7fe362a0ac..3ca2b51fe2 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 ad42f00566..c1c75403f4 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 c3d0ffd22f..5b584524f4 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 9b5f835ed3..25e228b594 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 23be078e8b..b64f33eec2 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 ccb64c6aee..cf0719f78d 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 ed5eb920ee..bd42b8992f 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 ced31483b7..f3af7145d4 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 f80b6e3388..41adc35d4e 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 1da908cf81..e5614b4ee1 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 c1b5ff17d1..4fd65f379c 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 0000000000..c67f174328
--- /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 a17b25007c..7f6aaf2c47 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 d756313879..68d82a2367 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 f82304b910..669dede5a3 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 27279138c6..883250392d 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 f75e1f457b..d59c6fcd57 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 0791164493..021ae6c8b1 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 def983c50a..0000000000
--- 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 ae1dde2df3..42e406c5f1 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 0aa794a4a4..336ae914d1 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 def983c50a..0000000000
--- 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 dd6f200e18..69a917f5cc 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 9d7fe82c68..3d1a3e6a61 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 2001bfa815..678349897e 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 6233b3f988..994f244802 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 a3384c5c5e..99f8aa9481 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 4f9da68e16..0022ef836c 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 368d31ecc4..e2ff246741 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 6ffa6fb725..e62dbf5ae7 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 7beb21dae9..a83957e16d 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 f2047652cc..89e923e150 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 835a584051..cd18aa1210 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 c044948f25..ee86ff3ce2 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 2b7efa49a3..5da2a783b6 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 e5ae70a68e..7d70d1d1f1 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 3c8c3002cb..86f3fc03d8 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 b0da1df71a..2114774cd4 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 0000000000..e78a4b2fe2
--- /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 0000000000..baa67a6fc5
--- /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 0000000000..a5af4a02c3
--- /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 0000000000..ab75fd2b2d
--- /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 0000000000..e7e335205c
--- /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 0000000000..deb01863ff
--- /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 0000000000..da26e5fd29
--- /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 0000000000..a3a72b97a7
--- /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 0000000000..7b2cd689ce
--- /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 0000000000..e0cb65bd53
--- /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 0000000000..5b8065113a
--- /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 0000000000..90facb03e0
--- /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 0000000000..27b7c644b1
--- /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 0000000000..3c96733af0
--- /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 0000000000..6d445aa8d9
--- /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 0000000000..e054868e89
--- /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 0000000000..3256cd4467
--- /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 0000000000..20130249a4
--- /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 0000000000..31015adeab
--- /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 0000000000..cc5d296288
--- /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 0000000000..0a23c7c410
--- /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 0000000000..c7b2fdecc8
--- /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 0000000000..bf7537a84e
--- /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 0000000000..9ac9deb2a2
--- /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 d197f6bf08..1539d0c6e8 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 63b8d13023..376f5675be 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 919ec75882..0db6507227 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 6d4e15e519..22f672ea92 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 14f15735de..e9d6f36eca 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 b3aead70e2..fb21c80299 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 1913217086..a808c5150d 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 0000000000..ae5a224392
--- /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 0000000000..77817acc63
--- /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 0000000000..111952c00e
--- /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)");
+  }
+}
-- 
GitLab