[
  {
    "path": ".forceignore",
    "content": "# List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status\n# More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm\n#\n\npackage.xml\n\n# LWC configuration files\n**/jsconfig.json\n**/.eslintrc.json\n\n# LWC Jest\n**/__tests__/**\n\n# Profiles\n**/*.profile\n\n# Demo metadata not core to the project but may be deployed\n# in an org as I test the application in a browser.\n**DEMO_**"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "#\n# Code Owners File Format\n# https://help.github.com/articles/about-code-owners/\n#\n# A CODEOWNERS file uses a pattern that follows the same rules used in gitignore files.\n# The pattern is followed by one or more GitHub usernames or team names using the\n# standard @username or @org/team-name format. You can also refer to a user by an\n# email address that has been added to their GitHub account, for example user@example.com.\n#\n\n*       @douglascayers\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: https://www.paypal.me/douglascayers/ # Replace with a single custom sponsorship URL\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: \"discussion \\U0001F4AC\"\nassignees: douglascayers\n\n---\n\n<!--\nNOTICE: While GitHub is the preferred channel for reporting issues/feedback, please use the [Trailblazer community group](https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000LhvN) to ask questions about how to use Mass Action Scheduler or to share how you're using the app at your company.\n\nNOTICE: Your issue may already be reported. Before opening a new issue, please see our [Frequently Asked Questions](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Frequently-Asked-Questions) and search the [issue tracker](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues).\n-->\n\n## Summary\n<!-- Short summary of what is going on or to provide context. -->\n\n\n## Version of Mass Action Scheduler\n<!-- See https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler#packaged-release-history for latest version of the app. -->\n\n\n## Steps To Reproduce\n<!-- Help me, help you by telling me exactly how to reproduce the issue. -->\n\n1. List steps that cause the issue\n2. Screen shots are also helpful\n\n\n## Expected Behavior\n<!-- Describe what should have happened. -->\n\n\n## Actual Result\n<!-- Describe what actually happened instead. -->\n\n\n## Source Type\n<!-- If applicable, indicate which source type your configuration is using by placing an X in the brackets. -->\n\n- [ ] Reports\n- [ ] List Views\n- [ ] SOQL Queries\n\n\n## Action Type\n<!-- If applicable, indicate which action type your configuration is using by placing an X in the brackets. -->\n\n- [ ] Process Builder & Flows\n- [ ] Workflow Rules\n- [ ] Email Alerts\n- [ ] Quick Actions\n- [ ] Apex\n\n\n## Does your configuration use Named Credentials?\n\n<!--\nNOTICE: Since [Release 2.0](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Upgrading-to-Release-2.0#get-started-faster-with-optional-named-credentials), Named Credentials are optional. Please try your configuration without assigning a Named Credential and see if your issue still occurs.\n\nWhen using Named Credentials, make sure that you've enabled [My Domain](https://trailhead.salesforce.com/en/content/learn/modules/identity_login/identity_login_my_domain) and have followed [these setup instructions](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Specify-the-Context-User-via-Named-Credentials).\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/DOCUMENTATION_REQUEST.md",
    "content": "---\nname: Documentation request\nabout: Suggest a change to documentation\ntitle: ''\nlabels: documentation 📓\nassignees: ''\n\n---\n\n<!--\n  Documentation lives in the project wiki at\n  https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki\n-->\n\n## Is your documentation request related to an existing wiki page? If yes, which pages?\n<!-- Please paste the links to the wiki pages here -->\n\n\n## Describe the documentation change you're offering or requesting.\n<!-- A clear and concise description of what you want to happen. -->\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement ✨\nassignees: ''\n\n---\n\n## Is your feature request related to a problem? Please describe.\n<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->\n\n\n## Describe the solution you'd like.\n<!-- A clear and concise description of what you want to happen. -->\n\n\n## Describe alternatives you've considered.\n<!-- A clear and concise description of any alternative solutions or features you've considered. -->\n\n\n## Additional context.\n<!-- Add any other context or screenshots about the feature request here. -->\n\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "### What does this pull request do?\n\n\n### What issues does this pull request fix or reference?\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\n\non:\n  # Trigger the workflow on push or pull request,\n  # but only for the master branch.\n  push:\n    branches:\n      - main\n      - develop\n  pull_request:\n    branches:\n      - main\n      - develop\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: Create Auth URL to DevHub from secrets\n      run: echo ${{ secrets.SFDX_DEVHUB_URL }} > ./SFDX_DEVHUB_URL.txt\n\n    - name: Restore npm Cache\n      id: cache\n      uses: actions/cache@v3\n      with:\n        path: ~/.npm\n        key: ${{ runner.os }}-npm\n\n    - name: Install Salesforce CLI\n      if: steps.cache.outputs.cache-hit != 'true'\n      run: npm install sfdx-cli npx\n\n    - name: Update Dependencies\n      run: |\n        npm update sfdx-cli npx\n        npx sfdx-cli --version\n        npx sfdx-cli plugins --core\n\n    - name: Authorize DevHub\n      run: npx sfdx-cli force:auth:sfdxurl:store --sfdxurlfile ./SFDX_DEVHUB_URL.txt --setalias devhub --setdefaultdevhubusername\n\n    - name: Create Scratch Org\n      run: npx sfdx-cli force:org:create --targetdevhubusername devhub --setalias ciorg --setdefaultusername --definitionfile config/project-scratch-def.json --durationdays 1\n\n    - name: Push Source\n      run: npx sfdx-cli force:source:push --targetusername ciorg\n\n    - name: Assign Permission Set\n      run: npx sfdx-cli force:user:permset:assign --targetusername ciorg --permsetname Mass_Action_Admin\n\n    - name: Load Test Data\n      # The test account name, \"dca_mass_action: MA Test Account\", includes a colon \":\", which breaks the yaml parser.\n      # As workaround, I put the test name as a secret and bind that to the query instead.\n      run: npx sfdx-cli force:data:record:create --targetusername ciorg --sobjecttype Account --values \"Name='${{ secrets.TEST_ACCOUNT_NAME_FOR_APEX_TESTS }}'\"\n\n    - name: Run Apex Tests\n      run: npx sfdx-cli force:apex:test:run --targetusername ciorg --codecoverage --resultformat human --suitenames Mass_Action_Scheduler_Test_Suite --outputdir ./test-results/apex --wait 20\n\n    - name: Collect Flow Test Coverage\n      run: |\n        npx sfdx-cli force:data:soql:query --targetusername ciorg --usetoolingapi --query \"SELECT FlowVersionId, FlowVersion.Definition.DeveloperName, MAX(NumElementsCovered) ItemsCovered, MIN(NumElementsNotCovered) ItemsNotCovered FROM FlowTestCoverage WHERE FlowVersionId IN (SELECT ActiveVersionId FROM FlowDefinition) GROUP BY FlowVersionId, FlowVersion.Definition.DeveloperName\" --json | jq -r '[ .result.records[] | ( .ItemsCovered + .ItemsNotCovered ) as $totalLines | ( ( .ItemsCovered / $totalLines * 100 ) | floor ) as $coveredPercent | { id: .FlowVersionId, name: ( .DeveloperName + \".flow-meta.xml\" ), totalLines: $totalLines, totalCovered: .ItemsCovered, coveredPercent: $coveredPercent } ]' > ./test-results/apex/test-result-flowcoverage.json\n        npx sfdx-cli force:data:soql:query --targetusername ciorg --usetoolingapi --query \"SELECT ActiveVersionId, DeveloperName FROM FlowDefinition WHERE ActiveVersionId NOT IN ( SELECT FlowVersionId FROM FlowTestCoverage ) AND ActiveVersion.ProcessType IN ( 'AutoLaunchedFlow', 'CustomEvent', 'InvocableProcess', 'Workflow' )\" --json | jq -r '[ .result.records[] | { id: .ActiveVersionId, name: ( .DeveloperName + \".flow-meta.xml\" ), totalLines: 0, totalCovered: 0, coveredPercent: 0 } ]' > ./test-results/apex/test-result-noflowcoverage.json\n\n    - name: Upload Code Coverage\n      # Uploads code coverage results to Codecov.io.\n      # https://codecov.io/gh/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n      uses: codecov/codecov-action@v2\n      with:\n        token: ${{ secrets.CODECOV_TOKEN }}\n\n    - name: Delete Scratch Org\n      run: npx sfdx-cli force:org:delete --targetdevhubusername devhub --targetusername ciorg --noprompt\n"
  },
  {
    "path": ".gitignore",
    "content": "# Salesforce DX configuration files.\n.sfdx/\n.sf/\n\n# IlluminatedCloud configuration files.\n.idea/\nIlluminatedCloud/\n*.iml\n\n# Visual Studio Code configuration files.\n.vscode/\n\n# A temp directory where build scripts convert\n# source files to metadata format.\nmdapi/"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Salesforce Open Source Community Code of Conduct\n\n## About the Code of Conduct\n\nEquality is a core value at Salesforce. We believe a diverse and inclusive\ncommunity fosters innovation and creativity, and are committed to building a\nculture where everyone feels included.\n\nSalesforce open-source projects are committed to providing a friendly, safe, and\nwelcoming environment for all, regardless of gender identity and expression,\nsexual orientation, disability, physical appearance, body size, ethnicity, nationality, \nrace, age, religion, level of experience, education, socioeconomic status, or \nother similar personal characteristics.\n\nThe goal of this code of conduct is to specify a baseline standard of behavior so\nthat people with different social values and communication styles can work\ntogether effectively, productively, and respectfully in our open source community.\nIt also establishes a mechanism for reporting issues and resolving conflicts.\n\nAll questions and reports of abusive, harassing, or otherwise unacceptable behavior\nin a Salesforce open-source project may be reported by contacting the Salesforce\nOpen Source Conduct Committee at ossconduct@salesforce.com.\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of gender \nidentity and expression, sexual orientation, disability, physical appearance, \nbody size, ethnicity, nationality, race, age, religion, level of experience, education, \nsocioeconomic status, or other similar personal characteristics.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy toward other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Personal attacks, insulting/derogatory comments, or trolling\n* Public or private harassment\n* Publishing, or threatening to publish, others' private information—such as\na physical or electronic address—without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\nprofessional setting\n* Advocating for or encouraging any of the above behaviors\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned with this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project email\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the Salesforce Open Source Conduct Committee \nat ossconduct@salesforce.com. All complaints will be reviewed and investigated \nand will result in a response that is deemed necessary and appropriate to the \ncircumstances. The committee is obligated to maintain confidentiality with \nregard to the reporter of an incident. Further details of specific enforcement \npolicies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership and the Salesforce Open Source Conduct \nCommittee.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home],\nversion 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. \nIt includes adaptions and additions from [Go Community Code of Conduct][golang-coc], \n[CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc].\n\nThis Code of Conduct is licensed under the [Creative Commons Attribution 3.0 License][cc-by-3-us].\n\n[contributor-covenant-home]: https://www.contributor-covenant.org (https://www.contributor-covenant.org/)\n[golang-coc]: https://golang.org/conduct\n[cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md\n[microsoft-coc]: https://opensource.microsoft.com/codeofconduct/\n[cc-by-3-us]: https://creativecommons.org/licenses/by/3.0/us/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Mass Action Scheduler\n\n:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:\n\nThe following is a set of guidelines for contributing to Mass Action Scheduler and its packages,\nwhich are hosted in the [Salesforce Mass Action Scheduler](https://github.com/sfdx-mass-action-scheduler) organization on GitHub.\n\n## Table of Contents\n\n[Code of Conduct](#code-of-conduct)\n\n[How Can I Contribute?](#how-can-i-contribute)\n  * [Reporting Bugs](#reporting-bugs)\n  * [Suggesting Enhancements](#suggesting-enhancements)\n  * [Pull Requests](#pull-requests)\n\n[Styleguides](#styleguides)\n\n[Additional Notes](#additional-notes)\n\n\n## Code of Conduct\n\nThis project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).\nBy participating, you are expected to uphold this code.\n\n\n## How Can I Contribute?\n\n### Reporting Bugs\n\nThis section guides you through submitting a bug report for Mass Action Scheduler.\nFollowing these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:.\n\nBefore creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one.\n\nWhen you are creating a bug report, please include as many details as possible.\nFill out [the template](.github/ISSUE_TEMPLATE/BUG_REPORT.md), the information it asks for helps us resolve issues faster.\n\n> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.\n\n#### Before Submitting A Bug Report\n\n* Read the [wiki](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki) for documentation and usage.\n* Check the [FAQ](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Frequently-Asked-Questions). Your question might already be answered.\n* Review conversations in the [community group](https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000LhvN). Your issue might already have been discussed.\n* Perform a [cursory search](https://github.com/search?utf8=%E2%9C%93&q=repo%3Asfdx-mass-action-scheduler%2Fsfdx-mass-action-scheduler&type=issues) to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.\n\n#### How Do I Submit A (Good) Bug Report?\n\nBugs are tracked as [GitHub issues](https://guides.github.com/features/issues/).\n\n* **Use a clear and descriptive title** for the issue to identify the problem.\n* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, when listing steps, **don't just say what you did, but explain how you did it**.\n* **Provide specific examples to demonstrate the steps**.\n* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.\n* **Explain which behavior you expected to see instead and why.**\n* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.\n* **Include any error messages and information from Mass Action Logs.**\n\n### Suggesting Enhancements\n\nThis section guides you through submitting an enhancement suggestion for Mass Action Scheduler,\nincluding completely new features and minor improvements to existing functionality.\nFollowing these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.\n\nBefore creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one.\n\nWhen you are creating an enhancement suggestion, please include as many details as possible.\nFill out [the template](.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md), including how you imagine you would use the requested feature.\n\n#### Before Submitting An Enhancement Suggestion\n\n* Read the [wiki](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki) for documentation and usage. The feature might already exist.\n* Perform a [cursory search](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues?q=is%3Aopen+is%3Aissue+label%3A%22enhancement+%E2%9C%A8%22) to see if the enhancement has already been requested. If it has **and the request is still open**, add a comment to the existing request instead of opening a new one.\n\n#### How Do I Submit A (Good) Enhancement Suggestion?\n\nEnhancements are tracked as [GitHub issues](https://guides.github.com/features/issues/).\n\n* **Use a clear and descriptive title** for the issue to identify the suggestion.\n* **Provide a step-by-step description** of the suggested enhancement in as many details as possible.\n* **Describe the current behavior** and **explain which behavior you expected to see instead** and why.\n* **Explain why this enhancement would be useful.**\n* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of Mass Action Scheduler which the suggestion is related to.\n* **Specify which version of Mass Action Scheduler you're using.** Determine the version number by going to Setup, search for `Installed` in the Quick Find box, then click **Installed Packages**.\n\n### Pull Requests\n\nPlease follow these steps to have your contribution considered by the maintainers. We follow the [GitHub Flow](https://guides.github.com/introduction/flow/) to submit pull requests from feature branches from forks of this project.\n\n1. Fork the repo\n    * https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n2. Check out a new branch and name it to what you intend to do\n    * Use one branch per fix / feature\n3. Commit your changes\n    * Follow the [styleguides](#styleguides)\n    * Provide a git message that explains what you've done\n    * Commit to your forked repository\n4. Push to the branch of your forked repository\n5. Make a pull request to the main repository\n    * Follow all instructions in the [template](.github/PULL_REQUEST_TEMPLATE.md)\n\nWhile the prerequisites above must be satisfied prior to having your pull request reviewed,\nthe reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.\n\n\n## Styleguides\n\nFollow the coding convention and standards of the code in the project.\n\n\n## Additional Notes\n\n### Issue and Pull Request Labels\n\nLabels help us track and manage issues and pull requests.\nRefer to the full list of labels and their descriptions [here](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/labels).\n\n[GitHub search](https://help.github.com/articles/searching-issues/) makes it easy to use labels for finding groups of issues or pull requests you're interested in.\nWe encourage you to read about [other search filters](https://help.github.com/articles/searching-issues/) which will help you write more focused queries.\n\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "<!-- SHIELDS -->\n[![Latest Version][version-shield]][version-url]\n[![Salesforce Community Support][community-shield]][community-url]\n[![Sponsor][sponsor-shield]][sponsor-url]\n[![License][license-shield]][license-url]\n[![Build Status][cicd-shield]][cicd-url]\n[![Code Coverage][codecov-shield]][codecov-url]\n\n<!-- PROJECT LOGO -->\n<p align=\"center\">\n  <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/\">\n    <img src=\"images/mas-logo.png\" alt=\"Mass Action Scheduler Logo\" border=\"0\" />\n  </a>\n  <br />\n  Declaratively schedule process automation from reports and list views!\n  <br />\n  <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki\"><strong>Explore the docs »</strong></a>\n  <br />\n  <br />\n  <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Examples\">View Examples</a>\n  ·\n  <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues\">Report Bug</a>\n  ·\n  <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues\">Request Feature</a>\n</p>\n\n## 📝 Table of Contents\n\n* [About the Project](#-about-the-project)\n* [Features](#-features)\n* [Roadmap](#-roadmap)\n* [Documentation and Discussion](#-documentation-and--discussion)\n* [Getting Started](#-getting-started)\n  - [Prerequisites](#-prerequisites)\n  - [Install Package](#-install-package)\n* [Sponsoring](#-sponsoring)\n* [Contributing](#-contributing)\n* [Authors](#️-authors)\n* [Acknowledgements](#-acknowledgements)\n* [License](#-license)\n\n## 🧐 About the Project\n\n#### 🗣 Ethos\n\nMass Action Scheduler is a [free-as-in-speech](https://www.howtogeek.com/howto/31717/what-do-the-phrases-free-speech-vs.-free-beer-really-mean/) and [open source](https://opensource.com/resources/what-open-source) developed passion project of [Doug Ayers](https://douglascayers.com).\n\n#### 💪 Mission\n\nPut the power of [Batch Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch.htm) within reach of [declarative configuration](https://help.salesforce.com/articleView?id=extend_click_intro.htm&type=5).\n\n#### 🚀 Value Proposition\n\nDeclaratively schedule Process Builder, Flows, Quick Actions, Email Alerts, Workflow Rules, or Apex to process records from Reports, List Views, SOQL, or Apex.\n\nNo more waiting for records to be updated or creating clever workarounds to cause records to be updated to cause these actions to fire.\n\n##### Choose source data to process\n\n![image](https://raw.githubusercontent.com/wiki/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/images/sources-choose-source.png)\n\n##### Choose an action to automate\n\n![image](https://raw.githubusercontent.com/wiki/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/images/actions-choose-action.png)\n\n##### Map fields as inputs to selected action\n\n![image](https://raw.githubusercontent.com/wiki/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/images/field-mappings-choose-fields.png)\n\n##### Choose how often to automate action\n\n![image](https://raw.githubusercontent.com/wiki/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/images/schedule-choose-scheduled.png)\n\n##### Receive near real-time updates on batch job successes and failures\n\n![image](https://raw.githubusercontent.com/wiki/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/images/related-logs-of-parent-log-with-errors.png)\n\n#### 💡 Inspiration\n\nThis project is inspired by the following IdeaExchange ideas. Please vote them up to increase chances this functionality becomes standard on the Salesforce platform. Thank you!\n\nInspired by Marie Chandra's idea [Ability to Schedule when Process Builder Triggers](https://success.salesforce.com/ideaView?id=08730000000DjEmAAK).\n\nInspired by Narender Singh's idea [Ability to schedule flows, workflows and processes in process builder](https://success.salesforce.com/ideaView?id=0873A000000EA71QAG).\n\n## 🎈 Features\n\n**Declarative** - no code necessary, never write Batch Apex again for queries that can be expressed in a report or list view and actions that can be expressed with a declarative alternative.\n\n**On Platform** - everything happens in Salesforce so no exporting or uploading data necessary.\n\n**Timely** - run actions [manually](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/On-Demand-Scheduling) or [schedule](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Scheduling) hourly, daily, weekly, or any time in between.\n\n**Versatile** - explore the many [data sources](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Sources) and [actions](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Actions) that can be [scheduled](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Scheduling) with Mass Action Scheduler.\n\n## 🗺 Roadmap\n\nSee the [open issues](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues) for a list of proposed features (and known issues).\n\nSee the [open milestones](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/milestones?state=open) for a list of upcoming planned releases.\n\n## 📘 Documentation and 💬 Discussion\n\nRead the [wiki](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki) for documentation on Mass Action Scheduler.\n\nRead the [FAQ](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Frequently-Asked-Questions) to troubleshoot common technical issues.\n\nJoin our [community group](https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000LhvN) to discuss and solution with other Mass Action Scheduler users.\n\nRaise well defined issues and ideas via the [issue tracker](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues).\n\n## 👋 Getting Started\n\n### 🚨 Prerequisites\n\nThere are a few items you need to setup before installing and using this app.\n\n1. You will need to [Enable Lightning Experience](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Prerequisites#1-enable-lightning-experience) because we are using Lightning Components.\n2. You will need to [Enable My Domain](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Prerequisites#2-enable-my-domain) because we are using Lightning Components.\n3. You will need to [Allow IFraming of Visualforce Pages with Clickjack Protection](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Prerequisites#3-allow-iframing-of-visualforce-pages-with-clickjack-protection) because we iframe pages in Lightning Components.\n\nPlease see the [instructions in the wiki](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Prerequisites) for screen shots and step-by-steps.\n\n### 📦 Install Package\n\n1. See the [Release Notes](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Release-Notes) for install links to each package version.\n2. Assign the **Mass Action Admin** permission set to users who will configure mass actions.\n3. Finish reviewing the [Getting Started](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Getting-Started) instructions.\n\n## 💎 Sponsoring\n\nMass Action Scheduler is a [free-as-in-speech](https://www.howtogeek.com/howto/31717/what-do-the-phrases-free-speech-vs.-free-beer-really-mean/) and [open source](https://opensource.com/resources/what-open-source) developed passion project of [Doug Ayers](https://douglascayers.com).\n\nIf you've found value in my open source projects, please consider showing your support:\n  * ⭐️ [Star](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler) this project on GitHub\n  * 📣 [Tweet](https://twitter.com/intent/tweet/?url=https%3A%2F%2Fgithub.com%2Fsfdx-mass-action-scheduler%2Fsfdx-mass-action-scheduler&text=%F0%9F%9A%80%20Declaratively%20schedule%20Process%20Builder%2C%20Flows%2C%20Quick%20Actions%2C%20Email%20Alerts%2C%20Workflow%20Rules%2C%20or%20Apex%20to%20process%20records%20from%20Reports%2C%20List%20Views%2C%20SOQL%2C%20or%20Apex%20with%20%23MassActionScheduler%20by%20%40DouglasCAyers&related=douglascayers%2Csalesforcedevs&hashtags=salesforce) this project to your followers\n  * Contribute a ☕️ or 🌮 via my [virtual tip jar on PayPal](https://www.paypal.me/douglascayers/)\n\nThank you! ❤️\n\nhttps://douglascayers.com/thanks-for-your-support/\n\n## 🙏 Contributing\n\nContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\nPlease see the [guidelines for contributing](CONTRIBUTING.md) for more details.\n\nFor documentation contributions (the [wiki](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki)), please [open an issue](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues) with your suggested changes.\n\nFor code contributions, please follow the [GitHub flow](https://help.github.com/en/articles/github-flow):\n1. Fork this project and [install the source code](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Install-Source-Code).\n2. Create your feature branch (`git checkout -b feature/AmazingFeature`).\n3. Commit your changes (`git commit -m 'Add some AmazingFeature'`).\n4. Push to your feature branch (`git push origin feature/AmazingFeature`).\n5. Open a pull request to the `develop` branch.\n\n## ✍️ Authors\n\n[Doug Ayers](https://douglascayers.com) develops and maintains the project.\n\nSee also the list of [contributors](https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/contributors) who participated in this project.\n\n## 🎉 Acknowledgements\n\n[Appiphony](http://www.lightningstrike.io) for developing the Strike Wizard component based on Lightning Design System [Path blueprint](https://www.lightningdesignsystem.com/components/path/).\n\n[Salesforce Foundation](https://github.com/SalesforceFoundation/CampaignTools) for developing tools for querying Salesforce Reports API in Apex.\n\n[Shinichi Tomita](https://twitter.com/stomita) for developing [jsforce](https://jsforce.github.io/) and [soql-parse](https://github.com/stomita/soql-parse) libraries for easy use of Salesforce REST APIs in JavaScript.\n\n[jQuery](https://jquery.com/) for developing jQuery library.\n\n[Aaron Hardy](https://twitter.com/aaronius) for developing [Penpal](https://github.com/Aaronius/penpal), a promise-based library for securely communicating with iframes via postMessage.\n\n## 👀 License\n\nThe source code is licensed under the [BSD 3-Clause License](LICENSE).\n\n<!-- MARKDOWN LINKS & IMAGES -->\n\n[version-shield]: https://img.shields.io/github/tag/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler.svg?label=release&color=green\n[version-url]: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Release-Notes\n\n[license-shield]: https://img.shields.io/github/license/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler.svg?label=license&color=green\n[license-url]: LICENSE\n\n[community-shield]: https://img.shields.io/badge/-Join_our_Community-blue.svg?logo=salesforce&logoColor=white\n[community-url]: https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000LhvN\n\n[cicd-shield]: https://img.shields.io/github/workflow/status/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/CI?logo=github\n[cicd-url]: https://circleci.com/gh/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n\n[codecov-shield]: https://img.shields.io/codecov/c/github/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler.svg?logo=codecov\n[codecov-url]: https://codecov.io/gh/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n\n<!-- https://stackoverflow.com/questions/42679712/why-does-the-red-heart-emoji-require-two-code-points-but-the-other-colored-hear -->\n[sponsor-shield]: https://img.shields.io/badge/-💜_Sponsor_this_project-ff69b4.svg\n[sponsor-url]: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/blob/master/README.md#-sponsoring\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-cayman\ntitle: Mass Action Scheduler\n"
  },
  {
    "path": "_layouts/default.html",
    "content": "<!DOCTYPE html>\n<html lang=\"{{ site.lang | default: \"en-US\" }}\">\n\n<head>\n\n    <meta charset=\"UTF-8\">\n\n    {% seo %}\n\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"theme-color\" content=\"#157878\">\n\n    <link rel=\"stylesheet\" href=\"{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}\">\n\n</head>\n\n<body>\n\n    <section class=\"page-header\">\n\n        <h1 class=\"project-name\">{{ site.title | default: site.github.repository_name }}</h1>\n        <h2 class=\"project-tagline\">{{ site.description | default: site.github.project_tagline }}</h2>\n\n        {% if site.github.is_project_page %}\n            <a href=\"{{ site.github.repository_url }}\" class=\"btn\">View on GitHub</a>\n            <a href=\"#-getting-started\" class=\"btn\">Install Package</a>\n            <a href=\"{{ site.github.repository_url }}/wiki\" class=\"btn\">Documentation</a>\n            <a href=\"#-sponsoring\" class=\"btn\">❤️ Sponsor</a>\n        {% endif %}\n\n        {% if site.show_downloads %}\n            <a href=\"{{ site.github.zip_url }}\" class=\"btn\">Download .zip</a>\n            <a href=\"{{ site.github.tar_url }}\" class=\"btn\">Download .tar.gz</a>\n        {% endif %}\n\n    </section>\n\n    <section class=\"main-content\">\n\n        {{ content }}\n\n        <footer class=\"site-footer\">\n            {% if site.github.is_project_page %}\n                <span class=\"site-footer-owner\">\n                    <a href=\"{{ site.github.repository_url }}\">{{ site.github.repository_name }}</a>\n                    is maintained by <a href=\"{{ site.github.owner_url }}\">{{ site.github.owner_name }}</a>.\n                </span>\n            {% endif %}\n            <span class=\"site-footer-credits\">\n                This page was generated by <a href=\"https://pages.github.com\">GitHub Pages</a>.\n            </span>\n        </footer>\n\n    </section>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "config/project-scratch-def.json",
    "content": "{\n    \"orgName\": \"Mass Action Scheduler\",\n    \"edition\": \"Enterprise\",\n    \"hasSampleData\": false,\n    \"features\": [],\n    \"settings\": {\n        \"mobileSettings\": {\n            \"enableS1EncryptedStoragePref2\": false\n        },\n        \"securitySettings\": {\n            \"sessionSettings\": {\n                \"enableClickjackNonsetupUser\": false,\n                \"enableClickjackNonsetupUserHeaderless\": false\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "force-app/main/default/applications/Mass_Action_Scheduler.app-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomApplication xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <defaultLandingTab>Mass_Action_Configuration__c</defaultLandingTab>\n    <description>Declaratively schedule records from Reports or List Views to be processed by Workflow Rules, Process Builder, Flows, and Apex. https://douglascayers.com</description>\n    <isNavAutoTempTabsDisabled>false</isNavAutoTempTabsDisabled>\n    <isNavPersonalizationDisabled>false</isNavPersonalizationDisabled>\n    <label>Mass Action Scheduler</label>\n    <tabs>Mass_Action_Configuration__c</tabs>\n    <tabs>MA_SetupAuthWizardPageTab</tabs>\n    <tabs>Mass_Action_Log__c</tabs>\n    <tabs>standard-report</tabs>\n</CustomApplication>\n"
  },
  {
    "path": "force-app/main/default/applications/Mass_Action_Scheduler_Lightning.app-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomApplication xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionOverrides>\n        <actionName>View</actionName>\n        <comment>Action override created by Lightning App Builder during activation.</comment>\n        <content>Mass_Action_Configuration_Record_Page_One_Column</content>\n        <formFactor>Large</formFactor>\n        <skipRecordTypeSelect>false</skipRecordTypeSelect>\n        <type>Flexipage</type>\n        <pageOrSobjectType>Mass_Action_Configuration__c</pageOrSobjectType>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <comment>Action override created by Lightning App Builder during activation.</comment>\n        <content>Mass_Action_Log_Record_Page</content>\n        <formFactor>Large</formFactor>\n        <skipRecordTypeSelect>false</skipRecordTypeSelect>\n        <type>Flexipage</type>\n        <pageOrSobjectType>Mass_Action_Log__c</pageOrSobjectType>\n    </actionOverrides>\n    <brand>\n        <headerColor>#2C94BA</headerColor>\n        <logo>maslogominimal</logo>\n        <logoVersion>1</logoVersion>\n        <shouldOverrideOrgTheme>true</shouldOverrideOrgTheme>\n    </brand>\n    <description>Declaratively schedule process automation from reports and list views</description>\n    <formFactors>Large</formFactors>\n    <isNavAutoTempTabsDisabled>false</isNavAutoTempTabsDisabled>\n    <isNavPersonalizationDisabled>false</isNavPersonalizationDisabled>\n    <label>Mass Action Scheduler</label>\n    <navType>Standard</navType>\n    <setupExperience>all</setupExperience>\n    <tabs>Mass_Action_Configuration__c</tabs>\n    <tabs>MA_SetupAuthWizardPageTab</tabs>\n    <tabs>Mass_Action_Log__c</tabs>\n    <tabs>standard-report</tabs>\n    <uiType>Lightning</uiType>\n</CustomApplication>\n"
  },
  {
    "path": "force-app/main/default/aura/LC_API/LC_API.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n -->\n<aura:component controller=\"LC_VisualforceDomainController\">\n\n    <ltng:require scripts=\"{!$Resource.penpal}\"\n                  afterScriptsLoaded=\"{!c.onScriptsLoaded}\"/>\n\n    <aura:attribute name=\"iframeSrc\"\n                    type=\"String\"\n                    access=\"private\"\n                    description=\"Which visualforce page to load for bridging API calls.\"/>\n\n    <aura:attribute name=\"penpalFrameCreated\"\n                    type=\"Boolean\"\n                    access=\"private\"\n                    default=\"false\"\n                    description=\"Has the Penpal iframe been created?\"/>\n\n    <aura:attribute name=\"penpalFrameConnected\"\n                    type=\"Boolean\"\n                    access=\"private\"\n                    default=\"false\"\n                    description=\"Has the Penpal iframe been connected?\"/>\n\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.onInit}\"/>\n\n    <aura:handler name=\"render\" value=\"{!this}\" action=\"{!c.onRender}\"/>\n\n    <!--\n        Makes a Salesforce REST API request and returns a promise that resolves to the response.\n\n        @param request\n            JSON object with properties:\n            'url'     (String, required) The Salesforce REST endpoint to call.\n            'method'  (String, optional) The http method like 'get' or 'post'. Default is 'get'.\n            'body'    (String, optional) The request body, varies by the endpoint you're calling.\n            'headers' (Map, optional)    String key-value pairs of http headers to send.\n                                         Default is { 'Content-Type' : 'application/json' }.\n                                         Your headers are merged with the default headers,\n                                         overwriting any existing keys.\n\n        Example usage:\n            component.find( 'lcAPI' ).restRequest({\n                'url' : '/services/data/v54.0/sobjects/Account',\n                'method' : 'post',\n                'body' : JSON.stringify({\n                    'Name' : 'Salesforce',\n                    'BillingStreet' : '1 Market Street',\n                    'BillingCity' : 'San Francisco',\n                    'BillingState' : 'CA'\n                }),\n                'headers' : {\n                    'Sforce-Query-Options' : 'batchSize=200'\n                }\n            }).then( $A.getCallback( function( response ) {\n                // handle response\n            })).catch( $A.getCallback( function( err ) {\n                // handle error\n            }));\n     -->\n    <aura:method name=\"restRequest\" action=\"{!c.onRestRequest}\">\n        <aura:attribute name=\"request\"\n                        type=\"Map\"\n                        required=\"true\"\n                        description=\"Supports these keys: url (string), method (string), body (string), headers (map).\"/>\n    </aura:method>\n\n    <!--\n        Makes a JavaScript Fetch request and returns a promise that resolves to the response.\n        https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch\n\n        @param request\n            JSON object with properties:\n            'url'     (String, required) The url to fetch.\n            'options' (Map, optional)    The init options for the request.\n\n        Example usage:\n            component.find( 'lcAPI' ).fetchRequest({\n                'url' : 'https://example.com',\n                'options': {\n                    'method' : 'GET',\n                    'headers' : {\n                        'Accepts' : 'application/json'\n                    }\n                }\n            }).then( $A.getCallback( function( response ) {\n                // handle response\n            })).catch( $A.getCallback( function( err ) {\n                // handle error\n            }));\n     -->\n    <aura:method name=\"fetchRequest\" action=\"{!c.onFetchRequest}\">\n        <aura:attribute name=\"request\"\n                        type=\"Map\"\n                        required=\"true\"\n                        description=\"Supports these keys: url (string), options (map).\"/>\n    </aura:method>\n\n    <div aura:id=\"penpalFrameContainer\" class=\"slds-hide\">\n        {!v.body}\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/LC_API/LC_API.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>LC_API</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/LC_API/LC_APIController.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n */\n({\n    /**\n     * Called once during component initialization phase.\n     */\n    onInit: function( component, event, helper ) {\n        helper._penpal = {};\n        helper.makeApexRequest( component, 'c.getVisualforceDomainURL' ).then( $A.getCallback( function( vfDomainURL ) {\n            component.set( 'v.iframeSrc', `${vfDomainURL}/apex/LC_APIPage` );\n        })).catch( $A.getCallback( function( err ) {\n            console.error( 'LC_API: Error determining visualforce domain', err );\n        }));\n    },\n\n    /**\n     * Called once after ltng:require has loaded scripts.\n     */\n    onScriptsLoaded: function( component, event, helper ) {\n\n    },\n\n    /**\n     * Called each time the component renders itself.\n     */\n    onRender: function( component, event, helper ) {\n\n        const isPenpalFrameCreated = component.get( 'v.penpalFrameCreated' );\n\n        // For Penpal to operate correctly, you must ensure that `connectToChild`\n        // is called before the iframe has called `connectToParent`.\n        // Since the iframe source is calculated asynchronously,\n        // we listen to the component's render events and each time\n        // check if the iframe source is ready, and if so, then we initialize\n        // penpal to connect this component to the iframe.\n        // Since we only want to do this once, we also set the initialized flag.\n        if ( !isPenpalFrameCreated ) {\n\n            const container = component.find( 'penpalFrameContainer' );\n            const iframeSrc = component.get( 'v.iframeSrc' );\n\n            // Ensure the container element has rendered otherwise we can't\n            // append child elements to it. And wait for the iframe source to\n            // be available otherwise no reason to create the iframe element.\n            if ( !$A.util.isEmpty( container ) && !$A.util.isEmpty( iframeSrc ) ) {\n\n                $A.createComponent(\n                    \"aura:html\",\n                    {\n                        \"aura:id\": \"penpalFrame\",\n                        \"tag\": \"iframe\",\n                        \"HTMLAttributes\": {\n                            \"src\": iframeSrc\n                        }\n                    },\n                    function( iframeCmp, status, errorMessage ) {\n\n                        // This callback happened asynchronously, so make one\n                        // more check on whether the penpal frame has been initialized or not\n                        // in the off chance a separate render cycle got here before this one.\n                        const isPenpalFrameCreated = component.get( 'v.penpalFrameCreated' );\n\n                        if ( isPenpalFrameCreated ) {\n\n                            console.log( 'LC_API: iframe is already initialized' );\n\n                        } else if ( status === 'SUCCESS' ) {\n\n                            // At this point, the iframe component has been constructed\n                            // but not yet been rendered, so we don't have access to the\n                            // HTML iframe element yet. We need to wait for another render cycle,\n                            // that is, we need to wait for the render() method to be called again\n                            // after we append the new iframe component to the body of its container.\n                            // Once we're able to find the 'penpalFrame' on the page then\n                            // we can proceed with the rest of the penpal initialization.\n\n                            component.set( 'v.penpalFrameCreated', true );\n\n                            container.set( 'v.body', [ iframeCmp ] );\n\n                            console.info( 'LC_API: iframe initialized' );\n\n                        } else if ( status === 'INCOMPLETE' ) {\n\n                            console.warn( 'LC_API: No response from server or client is offline' );\n\n                        } else if ( status === 'ERROR' ) {\n\n                            console.error( 'LC_API: Error creating iframe: ' + errorMessage );\n\n                        }\n\n                    }\n                );\n\n            } // else, iframe source is empty, keep waiting\n\n        } else {\n\n            const isPenpalFrameConnected = component.get( 'v.penpalFrameConnected' );\n            const iframeCmp = component.find( 'penpalFrame' );\n\n            if ( !$A.util.isEmpty( iframeCmp ) && !isPenpalFrameConnected ) {\n\n                const connection = Penpal.connectToChild({\n                    // The iframe to which a connection should be made\n                    iframe: iframeCmp.getElement()\n                });\n\n                helper._penpal.connection = connection;\n\n                connection.promise.then( $A.getCallback( function( child ) {\n\n                    // Cache a reference to the child so that we can\n                    // use it in the restRequest/fetchRequest methods,\n                    // as well as be able to destroy it when this component unrenders.\n                    helper._penpal.child = child;\n                    console.info( 'LC_API: connected to iframe ' + iframeCmp.getGlobalId() );\n                    component.set( 'v.penpalFrameConnected', true );\n\n                })).catch( $A.getCallback( function( err ) {\n\n                    console.error( 'LC_API: Error establishing connection to iframe ' + iframeCmp.getGlobalId(), err );\n                    component.set( 'v.penpalFrameConnected', false );\n\n                }));\n\n            }\n\n        }\n\n    },\n\n    onRestRequest: function( component, event, helper ) {\n        const params = event.getParam( 'arguments' );\n        return helper.handleRestRequest( component, params.request );\n    },\n\n    onFetchRequest: function( component, event, helper ) {\n        const params = event.getParam( 'arguments' );\n        return helper.handleFetchRequest( component, params.request );\n    }\n})\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/LC_API/LC_APIHelper.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n */\n({\n    handleRestRequest: function( component, request ) {\n\n        const helper = this;\n\n        const defaultRequest = {\n            'method' : 'get'\n        };\n\n        const defaultHeaders = {\n            'Content-Type': 'application/json'\n        };\n\n        request = Object.assign( {}, defaultRequest, request );\n        request.headers = Object.assign( {}, defaultHeaders, request.headers );\n\n        return helper.getPenpalChild().then( $A.getCallback( function( child ) {\n            return helper.makePenpalRequest( 'rest', child, request );\n        }));\n\n    },\n\n    handleFetchRequest: function( component, request ) {\n\n        const helper = this;\n\n        return helper.getPenpalChild().then( $A.getCallback( function( child ) {\n            return helper.makePenpalRequest( 'fetch', child, request );\n        }));\n\n    },\n\n    // ------------------------------------------------------------\n\n    /**\n     * For internal use.\n     * Returns a promise waiting for the parent-child penpal handshake to complete\n     * then resolves with reference to the penpal child for making requests.\n     */\n    getPenpalChild: function() {\n\n        const helper = this;\n\n        return new Promise( $A.getCallback( function( resolve, reject ) {\n\n            let child = helper._penpal.child;\n\n            if ( child ) {\n\n                resolve( child );\n\n            } else {\n\n                // all time values in milliseconds\n                const timeout = 10000; // ten seconds\n                const pollFrequency = 500; // half a second\n                const startTime = new Date().getTime();\n                const endTime = startTime + timeout;\n\n                const timerId = setInterval( $A.getCallback( function() {\n\n                    child = helper._penpal.child;\n\n                    if ( child ) {\n\n                        // parent-child penpal handshake now complete\n                        clearInterval( timerId );\n                        resolve( child );\n\n                    } else {\n\n                        // check if we have exceeded our timeout\n                        const currentTime = new Date().getTime();\n                        if ( currentTime > endTime ) {\n                            clearInterval( timerId );\n                            reject( 'LC_API: Timeout trying to establish connection to iframe' );\n                        }\n                        // else, keep polling\n\n                    }\n\n                }), pollFrequency );\n\n            }\n\n        }));\n\n    },\n\n    /**\n     * For internal use.\n     * Returns a promise waiting for the parent-child penpal request to complete\n     * then resolves with response from the child iframe.\n     */\n    makePenpalRequest: function( requestType, child, request ) {\n\n        let p;\n\n        if ( requestType === 'rest' ) {\n            p = child.restRequest( request );\n        } else if ( requestType === 'fetch' ) {\n            p = child.fetchRequest( request );\n        } else {\n            p = Promise.resolve({\n                success: false,\n                data: 'LC_API: Invalid request type: ' + requestType\n            });\n        }\n\n        return p.then( $A.getCallback( function( response ) {\n            if ( response.success ) {\n                return response.data;\n            } else {\n                return Promise.reject( response.data );\n            }\n        }));\n\n    },\n\n    /**\n     * For internal use.\n     * Returns a promise waiting for the Apex request to complete\n     * then resolves with the JSON response, or rejects if any error.\n     *\n     * @param component\n     *      (required) Reference to the component who has access to the Aura Enabled method specified by `actionName`.\n     * @param actionName\n     *      (required) Name of the Aura Enabled Apex method in form `c.methodName`.\n     * @param params\n     *      (optional) JSON map of request parameters to pass to the Apex action.\n     * @param options\n     *      (optional) JSON map of options to customize the request.\n     *      `background` set to true will execute request in background thread.\n     *      `storable` set to true will cache the response.\n     */\n    makeApexRequest: function( component, actionName, params, options ) {\n\n        const helper = this;\n\n        return new Promise( $A.getCallback( function( resolve, reject ) {\n\n            const action = component.get( actionName );\n\n            if ( params ) {\n                action.setParams( params );\n            }\n\n            if ( options ) {\n                if ( options.background ) { action.setBackground(); }\n                if ( options.storable )   { action.setStorable(); }\n            }\n\n            action.setCallback( helper, function( response ) {\n                if ( component.isValid() && response.getState() === 'SUCCESS' ) {\n\n                    resolve( response.getReturnValue() );\n\n                } else {\n\n                    console.error( 'Error calling action \"' + actionName + '\" with state: ' + response.getState() );\n\n                    helper.logActionErrors( response.getError() );\n\n                    reject( response.getError() );\n\n                }\n            });\n\n            $A.enqueueAction( action );\n\n        }));\n\n    },\n\n    /**\n     * For internal use.\n     * Logs to console errors object.\n     * Errors may be a String or Array.\n     */\n    logActionErrors: function( errors ) {\n        if ( errors ) {\n            if ( errors.length > 0 ) {\n                for ( var i = 0; i < errors.length; i++ ) {\n                    console.error( 'Error: ' + errors[i].message );\n                }\n            } else {\n                console.error( 'Error: ' + errors );\n            }\n        } else {\n            console.error( 'Unknown error' );\n        }\n    }\n\n})\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n"
  },
  {
    "path": "force-app/main/default/aura/LC_API/LC_APIRenderer.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n */\n({\n    unrender: function( component, helper ) {\n        this.superUnrender();\n        // When component unrenders then cleanup penpal\n        // resources by destroying the connection and nulling out\n        // the helper's cached reference to the connection and child.\n        // This ensures that the helper.handleXyzRequest(..) methods\n        // wait appropriately for the new parent-child handshake to complete\n        // when this component is re-initialized and scripts are loaded.\n        if ( helper._penpal && helper._penpal.connection ) {\n            helper._penpal.connection.destroy();\n            helper._penpal = {};\n        }\n    }\n})\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/LC_URL/LC_URL.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n-->\n<aura:component controller=\"LC_URLController\">\n\n    <!--\n        Simple service component to obtain Salesforce URLs.\n        https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_url.htm\n     -->\n\n    <c:lax context=\"{!this}\"/>\n\n    <aura:method name=\"getUrlInfo\" action=\"{!c.onGetUrlInfo}\"/>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/LC_URL/LC_URL.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>LC_URL</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/LC_URL/LC_URLController.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n */\n({\n    onGetUrlInfo: function( component, event, helper ) {\n        return component.lax.enqueue( 'c.getUrlInfo' );\n    }\n})\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/MA_CheckForPackageUpdatesCmp/MA_CheckForPackageUpdatesCmp.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<aura:component implements=\"flexipage:availableForAllPageTypes\" access=\"global\">\n\n    <aura:attribute name=\"upgradeAvailable\" type=\"Boolean\" default=\"false\" access=\"private\"/>\n\n    <aura:attribute name=\"linkToInstalledVersion\" type=\"String\" access=\"private\"/>\n    <aura:attribute name=\"installedVersionNumber\" type=\"String\" access=\"private\"/>\n\n    <aura:attribute name=\"linkToLatestVersion\" type=\"String\" access=\"private\"/>\n    <aura:attribute name=\"latestVersionNumber\" type=\"String\" access=\"private\"/>\n\n    <c:LC_API aura:id=\"lc_api\"/>\n\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.onInit}\"/>\n\n    <aura:if isTrue=\"{!v.upgradeAvailable}\">\n        <div class=\"slds-var-p-around_xx-small slds-var-m-bottom_x-small slds-text-align_center slds-theme_success\">\n            A new version is available.\n            You're on version <a href=\"{!v.linkToInstalledVersion}\" target=\"_blank\" rel=\"noopener noreferrer\">{!v.installedVersionNumber}</a>.\n            Upgrade to version <a href=\"{!v.linkToLatestVersion}\" target=\"_blank\" rel=\"noopener noreferrer\">{!v.latestVersionNumber}</a>.\n        </div>\n    </aura:if>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_CheckForPackageUpdatesCmp/MA_CheckForPackageUpdatesCmp.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>MA_CheckForPackageUpdatesCmp</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/MA_CheckForPackageUpdatesCmp/MA_CheckForPackageUpdatesCmpController.js",
    "content": "({\n    onInit: function( component, event, helper ) {\n\n        let promises = [];\n        let lcApi = component.find( 'lc_api' );\n\n        // get the latest package version available\n        promises.push(\n            lcApi.fetchRequest({\n                'url' : 'https://gist.githubusercontent.com/douglascayers/e96c53304dc78dc83e59a85753f29111/raw/sfdx-mass-action-scheduler-version.js'\n            }).then( $A.getCallback( function( response ) {\n                return response;\n            }))\n        );\n\n        // get the currently installed package version\n        promises.push(\n            lcApi.restRequest({\n                'url' : '/services/data/v54.0/tooling/query?q=SELECT+Id,+SubscriberPackageId,+SubscriberPackage.Name,+SubscriberPackage.NamespacePrefix,+SubscriberPackageVersion.MajorVersion,+SubscriberPackageVersion.MinorVersion+FROM+InstalledSubscriberPackage'\n            }).then( $A.getCallback( function( response ) {\n                // The InstalledSubscriberPackage object doesn't support WHERE clause filtering on the package's namespace\n                // so we have to filter the results ourselves\n                return response.records.find( ( record ) => {\n                    return ( record.SubscriberPackage.NamespacePrefix === 'dca_mass_action' );\n                });\n            }))\n        );\n\n        // notify user if there's a newer package version to upgrade to\n        Promise.all( promises ).then( $A.getCallback( function( results ) {\n\n            let linkToLatest = ( results[0] && results[0].url );\n            let linkToInstalled = ( results[1] && `/${results[1].Id}` );\n\n            let latestVersion = ( results[0] && results[0].version );\n            let installedVersion = ( results[1] && `${results[1].SubscriberPackageVersion.MajorVersion}.${results[1].SubscriberPackageVersion.MinorVersion}` );\n\n            if ( latestVersion > installedVersion ) {\n\n                component.set( 'v.upgradeAvailable', true );\n\n                component.set( 'v.linkToInstalledVersion', linkToInstalled );\n                component.set( 'v.installedVersionNumber', installedVersion );\n\n                component.set( 'v.linkToLatestVersion', linkToLatest );\n                component.set( 'v.latestVersionNumber', latestVersion );\n\n            }\n\n        })).catch( $A.getCallback( function( error ) {\n\n            component.set( 'v.upgradeAvailable', false );\n            console.error( 'MA_CheckForPackageUpdatesCmp.onInit: error=' + JSON.stringify( error, null, 2 ) );\n\n        }));\n\n    }\n})"
  },
  {
    "path": "force-app/main/default/aura/MA_DevelopedByCmp/MA_DevelopedByCmp.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<aura:component implements=\"flexipage:availableForAllPageTypes\" access=\"global\">\n\n    <div class=\"slds-theme_shade slds-box slds-box_small slds-var-m-vertical_medium slds-text-align_center\">\n        <span><a href=\"https://sfdx-mass-action-scheduler.github.io/sfdx-mass-action-scheduler/\" target=\"_blank\" rel=\"noopener noreferrer\">Mass Action Scheduler</a></span>\n        <span class=\"slds-var-m-horizontal_xx-small\">️is developed with love by</span>\n        <span><a href=\"https://douglascayers.com\" target=\"_blank\" rel=\"noopener noreferrer\">Doug Ayers</a></span>\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_DevelopedByCmp/MA_DevelopedByCmp.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>MA_DevelopedByCmp</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/MA_EditConfigCmp/MA_EditConfigCmp.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<aura:component controller=\"MA_EditConfigCmpController\" implements=\"flexipage:availableForRecordHome,force:hasRecordId,lightning:actionOverride\" access=\"global\">\n\n    <aura:attribute name=\"didInitConfig\"\n                    type=\"Boolean\"\n                    description=\"Track if onInit has loaded the configuration record yet.\"\n                    default=\"false\"/>\n\n    <aura:attribute name=\"objectDescribe\"\n                    type=\"Object\"\n                    description=\"SObject and Field describe info\"/>\n\n    <aura:attribute name=\"recordId\"\n                    type=\"String\"\n                    description=\"The ID of the record to be displayed. Provided by force:hasRecordId interface.\"/>\n\n    <aura:attribute name=\"record\"\n                    type=\"Object\"\n                    description=\"The record object to be displayed. This is a wrapper object and not the sobject.\"/>\n\n    <aura:attribute name=\"spinnerTimerIds\"\n                    type=\"String[]\"\n                    description=\"To minimize flickering of the spinner, delay hiding spinner when another async action starts.\"/>\n\n    <c:LC_API aura:id=\"lc_api\"/>\n    <c:LC_URL aura:id=\"lc_url\"/>\n\n    <aura:attribute name=\"urlInfo\"\n                    type=\"Map\"\n                    description=\"Info from LC_URL component.\"/>\n\n    <!-- Lightning Data Service -->\n\n    <!--\n        This allows us to know when the record is changed outside this component,\n        such as when the user might click the standard 'Edit' button and save the record.\n        If we don't reload this component then upon saving the record via the component\n        we could overwrite, undoing, the outside changes.\n     -->\n\n    <aura:attribute name=\"ldsComplexRecord\"\n                    type=\"Object\"\n                    description=\"The complex record. Used only with Lightning Data Service to detect when record changes outside this component.\"/>\n\n    <aura:attribute name=\"ldsSimpleRecord\"\n                    type=\"Mass_Action_Configuration__c\"\n                    description=\"The simple record. Used only with Lightning Data Service to detect when record changes outside this component.\"/>\n\n    <force:recordData aura:id=\"lds\"\n        recordId=\"{!v.recordId}\"\n        fields=\"Id\"\n        mode=\"EDIT\"\n        targetRecord=\"{!v.ldsComplexRecord}\"\n        targetFields=\"{!v.ldsSimpleRecord}\"\n        recordUpdated=\"{!c.onInit}\"/>\n\n    <!-- Wizard Attributes -->\n\n    <aura:attribute name=\"wizardActiveStageIndex\"\n                    type=\"Integer\"\n                    description=\"In the Wizard, which stage is user actively on.\"\n                    default=\"0\"/>\n\n    <aura:attribute name=\"wizardStageNames\"\n                    type=\"String[]\"\n                    description=\"In the Wizard, the names of the stages.\"\n                    default=\"[ 'Details', 'Choose Source', 'Choose Action', 'Field Mappings', 'Schedule' ]\"/>\n\n    <!-- Source Attributes -->\n\n    <aura:attribute name=\"sourceType\"\n                    type=\"String\"\n                    description=\"For tracking changes to source type. If bind to property of sobject then change handler is called when any field on record changes.\"/>\n\n    <aura:attribute name=\"sourceTypeURL\"\n                    type=\"String\"\n                    description=\"URL to the selected report or list view so user can verify their selection.\"/>\n\n    <aura:attribute name=\"sourceFields\"\n                    type=\"Map[]\"\n                    description=\"During field mapping stage, these are the assignable source fields.\"/>\n\n    <aura:attribute name=\"sourceFieldsInputType\"\n                    type=\"String\"\n                    default=\"text\"\n                    description=\"Input field variant for user to specify source field mappings. Options: TEXT, COMBOBOX\"/>\n\n    <!-- Source Type : Reports -->\n\n    <aura:attribute name=\"sourceReportFolders\"\n                    type=\"Map[]\"\n                    description=\"Folder select options to narrow down search of a report. User must choose one to drive report filtering.\"/>\n\n    <aura:attribute name=\"sourceReportFolderId\"\n                    type=\"String\"\n                    description=\"Selected report folder id.\"/>\n\n    <aura:attribute name=\"sourceReports\"\n                    type=\"Map[]\"\n                    description=\"Report select options within the currently selected report.\"/>\n\n    <aura:attribute name=\"sourceReportId\"\n                    type=\"String\"\n                    description=\"Selected report id.\"/>\n\n    <aura:attribute name=\"sourceReport\"\n                    type=\"Object\"\n                    description=\"Details about the selected report, like name and folder.\"/>\n\n    <aura:attribute name=\"sourceReportColumns\"\n                    type=\"Map[]\"\n                    description=\"Column select options from the selected source report. User must choose one to drive sorting and pagination.\"/>\n\n    <aura:attribute name=\"sourceReportColumnName\"\n                    type=\"String\"\n                    description=\"Selected report column.\"/>\n\n    <!-- Source Type : List Views -->\n\n    <aura:attribute name=\"sourceListViewSobjectTypes\"\n                    type=\"Map[]\"\n                    description=\"SObject select options to narrow down search of a list view. User must choose one to drive list view filtering.\"/>\n\n    <aura:attribute name=\"sourceListViewSobjectType\"\n                    type=\"String\"\n                    description=\"Selected list view sobject type.\"/>\n\n    <aura:attribute name=\"sourceListViews\"\n                    type=\"Map[]\"\n                    description=\"List View select options within the currently selected sobject.\"/>\n\n    <aura:attribute name=\"sourceListViewId\"\n                    type=\"String\"\n                    description=\"Selected list view id.\"/>\n\n    <aura:attribute name=\"sourceListView\"\n                    type=\"Object\"\n                    description=\"Details about the selected list view, like name and sobject type.\"/>\n\n    <!-- Target Attributes -->\n\n    <aura:attribute name=\"targetType\"\n                    type=\"String\"\n                    description=\"For tracking changes to target type. If bind to property of sobject then change handler is called when any field on record changes.\"/>\n\n    <aura:attribute name=\"targetTypeRequiresSobject\"\n                    type=\"Boolean\"\n                    description=\"Indicates if selected target type requires user to select a specific object to know available actions. For example, Apex does not but Email Alerts do.\"/>\n\n    <aura:attribute name=\"targetTypeRequiresAction\"\n                    type=\"Boolean\"\n                    description=\"Indicates if selected target type requires user to select a specific action to invoke. For example, Workflows do not but Quick Actions do.\"/>\n\n    <aura:attribute name=\"targetSobjectTypes\"\n                    type=\"Map[]\"\n                    description=\"Object name select options of objects that have custom actions (e.g. objects with custom Email Alerts or Quick Actions).\"/>\n\n    <aura:attribute name=\"targetSobjectType\"\n                    type=\"String\"\n                    description=\"Selected sobject type.\"/>\n\n    <aura:attribute name=\"targetApexTypes\"\n                    type=\"Map[]\"\n                    default=\"[\n                        {\n                            'label': 'Invocable Method',\n                            'value': 'Invocable'\n                        },\n                        {\n                            'label': 'Anonymous Block',\n                            'value': 'Anonymous'\n                        }\n                    ]\"\n                    description=\"Apex Type select options.\"/>\n\n    <aura:attribute name=\"targetApexType\"\n                    type=\"String\"\n                    description=\"Selected apex type.\"/>\n\n    <aura:attribute name=\"isValidToRenderTargetInvocableActions\"\n                    type=\"Boolean\"\n                    description=\"Indicates conditions are met to fetch and show the target invocable action select options.\"/>\n\n    <aura:attribute name=\"targetNamedCredentials\"\n                    type=\"Map[]\"\n                    description=\"SObject select options of Named Credentials to choose for making API callout to REST API to execute target action.\"/>\n\n    <aura:attribute name=\"targetInvocableActions\"\n                    type=\"Map[]\"\n                    description=\"Action select options within the currently selected target type and target sobject.\"/>\n\n    <aura:attribute name=\"targetInvocableAction\"\n                    type=\"String\"\n                    description=\"The selected action name from the target invocable actions select options.\"/>\n\n    <aura:attribute name=\"targetFields\"\n                    type=\"Map[]\"\n                    description=\"During field mapping stage, these are the assignable target fields.\"/>\n\n    <aura:attribute name=\"targetFieldMappings\"\n                    type=\"Map[]\"\n                    description=\"Array of input arguments for target action to map source fields to.\"/>\n\n    <!-- Schedule Option Attributes -->\n\n    <aura:attribute name=\"scheduleOptionsHourOfDay\"\n                    type=\"Map[]\"\n                    description=\"Hour of Day in Cron schedule expression.\"/>\n\n    <aura:attribute name=\"scheduleOptionsDayOfMonth\"\n                    type=\"Map[]\"\n                    description=\"Day of Month in Cron schedule expression.\"/>\n\n    <aura:attribute name=\"scheduleOptionsDayOfWeek\"\n                    type=\"Map[]\"\n                    description=\"Weekday in Cron schedule expression.\"/>\n\n    <aura:attribute name=\"scheduleOptionsMonthOfYear\"\n                    type=\"Map[]\"\n                    description=\"Month of Year in Cron schedule expression.\"/>\n\n    <!-- Schedule Selection Attributes -->\n\n    <aura:attribute name=\"scheduleSelectionsFrequency\"\n                    type=\"String\"\n                    description=\"The selected values from the radioGroup. ODDITY: The type of this attribute must be String for initial value to be selected by lightning:radioGroup; but note that if user makes a selection then an array is bound to this attribute.\"/>\n\n    <aura:attribute name=\"scheduleSelectionsHourOfDay\"\n                    type=\"String[]\"\n                    description=\"The selected values from the checkboxGroup. When save record need to convert list to csv string.\"/>\n\n    <aura:attribute name=\"scheduleSelectionsDayOfMonth\"\n                    type=\"String[]\"\n                    description=\"The selected values from the dual listbox. When save record need to convert list to csv string.\"/>\n\n    <aura:attribute name=\"scheduleSelectionsDayOfWeek\"\n                    type=\"String[]\"\n                    description=\"The selected values from the checkboxGroup. When save record need to convert list to csv string.\"/>\n\n    <aura:attribute name=\"scheduleSelectionsMonthOfYear\"\n                    type=\"String[]\"\n                    description=\"The selected values from the checkboxGroup. When save record need to convert list to csv string.\"/>\n\n    <!-- Events -->\n\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.onInit}\"/>\n\n    <aura:handler name=\"change\" value=\"{!v.sourceType}\" action=\"{!c.handleSourceTypeChange}\"/>\n    <aura:handler name=\"change\" value=\"{!v.targetType}\" action=\"{!c.handleTargetTypeChange}\"/>\n\n    <aura:handler name=\"change\" value=\"{!v.sourceReportFolderId}\" action=\"{!c.handleSourceReportFolderChange}\"/>\n    <aura:handler name=\"change\" value=\"{!v.sourceReportId}\" action=\"{!c.handleSourceReportChange}\"/>\n\n    <aura:handler name=\"change\" value=\"{!v.sourceListViewSobjectType}\" action=\"{!c.handleSourceListViewSobjectTypeChange}\"/>\n    <aura:handler name=\"change\" value=\"{!v.sourceListViewId}\" action=\"{!c.handleSourceListViewChange}\"/>\n\n    <aura:handler name=\"change\" value=\"{!v.targetTypeRequiresSobject}\" action=\"{!c.handleTargetTypeRequiresSobjectChange}\"/>\n    <aura:handler name=\"change\" value=\"{!v.targetSobjectType}\" action=\"{!c.handleTargetSobjectTypeChange}\"/>\n\n    <aura:handler name=\"change\" value=\"{!v.targetApexType}\" action=\"{!c.handleTargetApexTypeChange}\"/>\n\n    <!-- Markup -->\n\n    <div class=\"slds-theme_default slds-box slds-box_xx-small\">\n\n        <lightning:spinner aura:id=\"spinner\" variant=\"brand\"/>\n\n        <div class=\"slds-grid slds-var-p-around_medium\">\n            <div class=\"slds-col\">\n\n                <c:strike_wizard aura:id=\"wizard\"\n                    stageNames=\"{!v.wizardStageNames}\"\n                    activeChevron=\"{!v.wizardActiveStageIndex}\"\n                    displayMode=\"wizard\"\n                    collapseExpandButton=\"true\"\n                    toggleBodyView=\"false\"\n                    disableForwardNavOnIncomplete=\"true\"\n                    processComplete=\"false\">\n\n                    <div class=\"slds-box\">\n\n                            <!-- Stage: Details -->\n\n                            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 0 )}\">\n\n                                <c:MA_WizardCoachingCmp>\n\n                                    <aura:set attribute=\"leftTitle\" value=\"About This Step\"/>\n                                    <aura:set attribute=\"leftContent\">\n                                        <p>\n                                            Describe the purpose of this Mass Action Configuration.\n                                            Your future self and those that come after you will appreciate it.\n                                        </p>\n                                        <p>\n                                            Pro Tip: After you've saved this record, use the <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/How-to-Customize-the-Quick-Edit-Page-Layout\" target=\"_blank\" rel=\"noopener noreferrer\">Quick Edit</a> button to edit details\n                                            without needing to step through the entire wizard each time.\n                                        </p>\n                                        <p>\n                                            Each step of this wizard includes tips and advice.\n                                            You can also find more documentation, examples, and support at these resources:\n                                        </p>\n                                        <p>\n                                            <ul>\n                                                <li>For discussion and feedback <a href=\"https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000LhvN\" target=\"_blank\" rel=\"noopener noreferrer\">post in the community group</a> or raise well defined issues and ideas via the <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues\" target=\"_blank\" rel=\"noopener noreferrer\">Issues feature</a>.</li>\n                                                <li>Read the <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki\" target=\"_blank\" rel=\"noopener noreferrer\">wiki page</a> for further documentation on Mass Action Scheduler.</li>\n                                                <li>Read the <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Frequently-Asked-Questions\" target=\"_blank\" rel=\"noopener noreferrer\">FAQ page</a> to help troubleshoot technical issues.</li>\n                                            </ul>\n                                        </p>\n                                    </aura:set>\n\n                                    <aura:set attribute=\"rightTitle\" value=\"Guidance\"/>\n                                    <aura:set attribute=\"rightContent\">\n                                        <p>\n                                            <b>Active</b> configurations can be run manually or on a schedule.\n                                        </p>\n                                        <p>\n                                            <b>Inactive</b> configurations do not run.\n                                            If a configuration is scheduled, it's Apex job is unscheduled for future runs until you re-activate it again.\n                                        </p>\n                                        <p>\n                                            <b>Batch Size</b> controls the number of times the target action from the Choose Action step is invoked per save transaction.\n                                            As when using Data Loader, you may need to reduce the batch size to stay within <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm\" target=\"_blank\" rel=\"noopener noreferrer\">governor limits</a>.\n                                        </p>\n                                        <p>\n                                            <b>Named Credential</b> is optional and is a way to <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Specify-the-Running-User-via-Named-Credentials\" target=\"_blank\" rel=\"noopener noreferrer\">specify the running user</a> performing the actions.\n                                            That is to say the user who has their name stamped as the \"Last Modified By\" on any updated records\n                                            by the target action from the Choose Action step.\n                                            If not specified, then the user who last activates the configuration, or who manually runs it, is the running user.\n                                        </p>\n                                    </aura:set>\n\n                                </c:MA_WizardCoachingCmp>\n\n                            </aura:if>\n\n                            <!-- Stage: Choose Source -->\n\n                            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 1 )}\">\n\n                                <c:MA_WizardCoachingCmp>\n\n                                    <aura:set attribute=\"leftTitle\" value=\"About This Step\"/>\n                                    <aura:set attribute=\"leftContent\">\n                                        <p>\n                                            Select the source of the records you want to process.\n                                        </p>\n                                        <p>\n                                            <b>List Views</b> are easy to create and support simple filter criteria.\n                                            Learn how to create list views with the <a href=\"https://trailhead.salesforce.com/content/learn/modules/lex_customization/lex_customization_list?trail_id=lex_admin_implementation\" target=\"_blank\" rel=\"noopener noreferrer\">Create and Customize List Views</a> unit on Trailhead.\n                                        </p>\n                                        <p>\n                                            <b>Reports</b> are powerful and support complex filter criteria\n                                            like <a href=\"https://help.salesforce.com/articleView?id=reports_cross_filters_create.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Cross Filters</a>.\n                                            Learn how to create reports with the <a href=\"https://trailhead.salesforce.com/content/learn/modules/lex_implementation_reports_dashboards?trail_id=lex_admin_implementation\" target=\"_blank\" rel=\"noopener noreferrer\">Reports &amp; Dashboards for Lightning Experience</a> module on Trailhead.\n                                        </p>\n                                        <p>\n                                            <b>SOQL</b> queries are an advanced technique to search for specific records. Simple queries can be helpful when you don't want to deal with the overhead of creating a list view or a report.\n                                            Learn how to write SOQL queries with the <a href=\"https://trailhead.salesforce.com/en/content/learn/modules/apex_database/apex_database_soql?trail_id=force_com_dev_beginner\" target=\"_blank\" rel=\"noopener noreferrer\">Write SOQL Queries</a> unit on Trailhead.\n                                        </p>\n                                        <p>\n                                            <b>Apex</b> classes that implement <code class=\"keyword\">Iterable&lt;Map&lt;String, Object&gt;&gt;</code> are an advanced technique that give you full control over what the source data is.\n                                            For example, if you need to make multiple SOQL queries, apply complex data filtering, or retrieve data from an external web service with http callouts.\n                                            Learn how to develop custom iterators with the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_iterable.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Apex Developer Guide</a>.\n                                        </p>\n                                    </aura:set>\n\n                                    <aura:set attribute=\"rightTitle\" value=\"Guidance\"/>\n                                    <aura:set attribute=\"rightContent\">\n\n                                        <p>\n                                            <p>\n                                                <b>Stay within limits</b>. If your source type would return more than its record limit then either modify filters to reduce the row count or use a different source type.\n                                                For example, a report that returns 30 thousand records would need to be split into three smaller reports or switch to another source type.\n                                            </p>\n                                            <table class=\"slds-table slds-table_cell-buffer slds-table_bordered slds-table_col-bordered\">\n                                                <thead>\n                                                    <tr class=\"slds-line-height_reset\">\n                                                        <th class=\"slds-text-title_caps slds-nowrap\">Source Type</th>\n                                                        <th class=\"slds-text-title_caps slds-cell-wrap\">Limits</th>\n                                                    </tr>\n                                                </thead>\n                                                <tbody>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>List Views</b></td>\n                                                        <td class=\"slds-cell-wrap\">Up to 50 million records.</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Reports</b></td>\n                                                        <td class=\"slds-cell-wrap\">\n                                                            Up to 10 thousand records.\n                                                            <br/>\n                                                            <a href=\"https://help.salesforce.com/articleView?id=reports_changing_format.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Tabular report format</a> only.\n                                                            <br/>\n                                                            Report must be saved in a <a href=\"https://trailhead.salesforce.com/content/learn/projects/create-reports-and-dashboards-for-sales-and-marketing-managers?trail_id=learn-admin-essentials\" target=\"_blank\" rel=\"noopener noreferrer\">custom folder</a>.\n                                                        </td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>SOQL</b></td>\n                                                        <td class=\"slds-cell-wrap\">Up to 50 million records.</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Apex</b></td>\n                                                        <td class=\"slds-cell-wrap\">\n                                                            Up to 50 million records.\n                                                            <br/>\n                                                            Class must implement <code class=\"keyword\">Iterable&lt;Map&lt;String, Object&gt;&gt;</code> and provide a no-argument constructor.\n                                                        </td>\n                                                    </tr>\n                                                </tbody>\n                                            </table>\n                                        </p>\n\n                                        <p>\n                                            <b>Alias SOQL aggregate functions</b>. Aggregate functions like <code class=\"keyword\">COUNT</code>, <code class=\"keyword\">MIN</code>, <code class=\"keyword\">MAX</code>, <code class=\"keyword\">AVG</code>, <code class=\"keyword\">SUM</code> and others\n                                            must be <a href=\"https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_groupby_alias.htm\" target=\"_blank\" rel=\"noopener noreferrer\">aliased</a> to be selectable in the Field Mappings step.\n                                            For example, consider the query <code class=\"keyword\">SELECT COUNT(Id) <b>RecordCount</b>, Type FROM Account GROUP BY Type</code>.\n                                            Without the <b>RecordCount</b> alias then only the <b>Type</b> field would be available on the Field Mappings step.\n                                        </p>\n\n                                        <p>\n                                            <b>Test your data source before automating</b>.\n                                            Confirm fields and filters by first previewing list views and running reports.\n                                            Execute SOQL queries in a tool like <a href=\"https://help.salesforce.com/articleView?id=code_dev_console_tab_query_editor.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Developer Console</a> or <a href=\"https://developer.salesforce.com/docs/atlas.en-us.dataLoader.meta/dataLoader/data_loader.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Data Loader</a>.\n                                        </p>\n\n                                    </aura:set>\n\n                                </c:MA_WizardCoachingCmp>\n\n                            </aura:if>\n\n                            <!-- Stage: Choose Action -->\n\n                            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 2 )}\">\n\n                                <c:MA_WizardCoachingCmp>\n\n                                    <aura:set attribute=\"leftTitle\" value=\"About This Step\"/>\n                                    <aura:set attribute=\"leftContent\">\n                                        <p>\n                                            Select the target action you want to process the source records.\n                                        </p>\n                                        <p>\n                                            Note, Process Builders and Flows are grouped together because the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.api_action.meta/api_action/actions_obj_flow.htm\" target=\"_blank\" rel=\"noopener noreferrer\">REST API</a> does not distinguish between them.\n                                            You may like to use a naming convention to help you tell them apart. For example, adding the word \"Flow\" to the names of your flows (e.g. \"My Account Flow\").\n                                        </p>\n                                        <p>\n                                            If you don't see the action you want listed, ensure that it is <b>active</b> and is a <b>supported type</b>.\n                                        </p>\n                                    </aura:set>\n\n                                    <aura:set attribute=\"rightTitle\" value=\"Guidance\"/>\n                                    <aura:set attribute=\"rightContent\">\n                                        <p>\n                                            <table class=\"slds-table slds-table_cell-buffer slds-table_bordered\">\n                                                <thead>\n                                                    <tr class=\"slds-line-height_reset\">\n                                                        <th class=\"slds-text-title_caps slds-nowrap\">Action Type</th>\n                                                        <th class=\"slds-text-title_caps slds-cell-wrap\">Supported Types</th>\n                                                    </tr>\n                                                </thead>\n                                                <tbody>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Process Builder</b></td>\n                                                        <td class=\"slds-cell-wrap\">Processes that start when <a href=\"https://help.salesforce.com/articleView?id=process_start.htm\" target=\"_blank\" rel=\"noopener noreferrer\">invoked by another process</a>, not when a record is created or updated.</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Flows</b></td>\n                                                        <td class=\"slds-cell-wrap\">Autolaunched flows. Flows that <a href=\"https://help.salesforce.com/articleView?id=flow_concepts_type.htm\" target=\"_blank\" rel=\"noopener noreferrer\">don't require user interaction</a> like screens.</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Quick Actions</b></td>\n                                                        <td class=\"slds-cell-wrap\">Create a Record, Update a Record, and Log a Call types.</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Email Alerts</b></td>\n                                                        <td class=\"slds-cell-wrap\">All</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Workflow Rules</b></td>\n                                                        <td class=\"slds-cell-wrap\">Active rules.</td>\n                                                    </tr>\n                                                    <tr>\n                                                        <td class=\"slds-nowrap\"><b>Apex</b></td>\n                                                        <td class=\"slds-cell-wrap\">\n                                                            <p>\n                                                                Classes annotated with <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm\" target=\"_blank\" rel=\"noopener noreferrer\">@InvocableMethod</a> or <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_anonymous_block.htm\" target=\"_blank\" rel=\"noopener noreferrer\">anonymous blocks</a>.\n                                                            </p>\n                                                            <p>\n                                                                For anonymous blocks, your script must include the following method definition,\n                                                                which will be passed the current batch of source records. Each execution of your script occurs in its own transaction.\n                                                                <code class=\"block\">\n                                                                    void execute( List&lt;Map&lt;String, Object&gt;&gt; sourceRecordsBatch ) {\n                                                                    &nbsp;&nbsp;&nbsp;&nbsp;// your logic here\n                                                                    }\n                                                                </code>\n                                                            </p>\n                                                            <p>\n                                                                Apex classes and anonymous blocks are invoked once per batch of source records, just like the <code class=\"keyword\">execute</code> method of a <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Batchable Class</a> or a <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_bulk.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Bulk Trigger</a>.\n                                                                However, unlike batchable or trigger code, no state is preserved within the script between executions. Though you may choose to manage and preserve state yourself between executions via DML to records or custom settings.\n                                                            </p>\n                                                        </td>\n                                                    </tr>\n                                                </tbody>\n                                            </table>\n                                        </p>\n                                    </aura:set>\n\n                                </c:MA_WizardCoachingCmp>\n\n                            </aura:if>\n\n                            <!-- Stage: Field Mappings -->\n\n                            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 3 )}\">\n\n                                <c:MA_WizardCoachingCmp>\n\n                                    <aura:set attribute=\"leftTitle\" value=\"About This Step\"/>\n                                    <aura:set attribute=\"leftContent\">\n                                        <p>\n                                            Map source fields as inputs to the target action.\n                                        </p>\n                                        <p>\n                                            For example, some action types like Process Builder, Workflow Rules, and Email Alerts require a record ID to be mapped to them from the source data.\n                                        </p>\n                                    </aura:set>\n\n                                    <aura:set attribute=\"rightTitle\" value=\"Guidance\"/>\n                                    <aura:set attribute=\"rightContent\">\n                                        <p>\n                                            <b>Don't see the Source Field you're looking for?</b>\n                                            <ul>\n                                                <li>Confirm the field is included in your source type.</li>\n                                                <li>Ensure that your user has <a href=\"https://trailhead.salesforce.com/content/learn/modules/data_security?trail_id=security\" target=\"_blank\" rel=\"noopener noreferrer\">read object and field permissions</a>.</li>\n                                                <li>If using a Named Credential, ensure that user also has appropriate object and field permissions.</li>\n                                                <li>\n                                                    If using SOQL, alias the aggregate functions. Aggregate functions like <code class=\"keyword\">COUNT</code>, <code class=\"keyword\">MIN</code>, <code class=\"keyword\">MAX</code>, <code class=\"keyword\">AVG</code>, <code class=\"keyword\">SUM</code> and others\n                                                    must be <a href=\"https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_groupby_alias.htm\" target=\"_blank\" rel=\"noopener noreferrer\">aliased</a> to be selectable in the Field Mappings step.\n                                                    For example, consider the query <code class=\"keyword\">SELECT COUNT(Id) <b>RecordCount</b>, Type FROM Account GROUP BY Type</code>.\n                                                    Without the <b>RecordCount</b> alias then only the <b>Type</b> field would be available on the Field Mappings step.\n                                                </li>\n                                                <li>\n                                                    If using SOQL, child relationship queries are not shown in the Field Mappings step.\n                                                    For example, consider the query <code class=\"keyword\">SELECT Id, Name, ( SELECT FirstName FROM Contacts ) FROM Account</code>.\n                                                    The child relationship query <code class=\"keyword\">SELECT FirstName FROM Contacts</code> is ignored.\n                                                    Therefore, and for performance, do not use child relationship queries in your <code class=\"keyword\">SELECT</code> statement.\n                                                </li>\n                                            </ul>\n                                        </p>\n                                        <p>\n                                            <b>Don't see the Target Field you're looking for?</b>\n                                            <ul>\n                                                <li>For Flows, ensure the variable's <a href=\"https://help.salesforce.com/articleView?id=flow_ref_resources_variable.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Availability Outside the Flow</a> has <b>Available for input</b> selected.</li>\n                                                <li>For Quick Actions, ensure the field is on the <a href=\"https://help.salesforce.com/articleView?id=action_layout_editor_about.htm\" target=\"_blank\" rel=\"noopener noreferrer\">action's layout</a>.</li>\n                                                <li>For Invocable Apex, ensure the class variable has the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableVariable.htm\" target=\"_blank\" rel=\"noopener noreferrer\">@InvocableVariable</a> annotation.</li>\n                                                <li>For Anonymous Apex, the field mappings step is not used. Instead, your script handles all field mapping and logic within its <code class=\"keyword\">execute</code> method.</li>\n                                            </ul>\n                                        </p>\n                                    </aura:set>\n\n                                </c:MA_WizardCoachingCmp>\n\n                            </aura:if>\n\n                            <!-- Stage: Schedule -->\n\n                            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 4 )}\">\n\n                                <c:MA_WizardCoachingCmp>\n\n                                    <aura:set attribute=\"leftTitle\" value=\"About This Step\"/>\n                                    <aura:set attribute=\"leftContent\">\n                                        <p>\n                                            Choose the schedule frequency when to run this Mass Action Configuration.\n                                        </p>\n                                        <p>\n                                            <b>On Demand</b> runs only when you click the <b>Run</b> button or if you use Process Builder, Flow, or Apex to\n                                            invoke the provided <code class=\"keyword\">MA_RunConfigInvocable</code> invocable Apex class (labeled \"MAS: Run Mass Action\").\n                                        </p>\n                                        <p>\n                                            <b>Scheduled</b> provides simple options to choose the hour, day, month, and year to run the configuration repeatedly.\n                                        </p>\n                                        <p>\n                                            <b>Custom</b> allows you to specify your own cron expression which allows more advanced options than the provided simple scheduler.\n                                            Learn more about how to write cron expressions in the \"Using the System.Schedule Method\" section of the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Apex Scheduler</a> documentation.\n                                        </p>\n                                        <p>\n                                            Note, only <b>active</b> configurations will run regardless the schedule frequency chosen.\n                                        </p>\n                                    </aura:set>\n\n                                    <aura:set attribute=\"rightTitle\" value=\"Guidance\"/>\n                                    <aura:set attribute=\"rightContent\">\n                                        <p>\n                                            Salesforce has a limit on the number of scheduled Apex jobs at one time. Traditionally this is 100 scheduled jobs.\n                                            If you encounter an error trying to save an active configuration with a scheduled or custom frequency,\n                                            you may have reached the limit and need to either deactivate other configurations or unschedule other Apex jobs in your org.\n                                            Learn more about these limits in the \"Apex Scheduler Limits\" section of the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Apex Scheduler</a> documentation.\n                                        </p>\n                                        <p>\n                                            <b>Example cron expressions for custom schedule frequency:</b>\n                                                <table class=\"slds-table slds-table_cell-buffer slds-table_bordered\">\n                                                    <thead>\n                                                        <tr class=\"slds-line-height_reset\">\n                                                            <th class=\"slds-text-title_caps slds-nowrap\">Expression</th>\n                                                            <th class=\"slds-text-title_caps slds-cell-wrap\">Description</th>\n                                                        </tr>\n                                                    </thead>\n                                                    <tbody>\n                                                        <tr>\n                                                            <td class=\"slds-nowrap\"><code>0 0 13 * * ?</code></td>\n                                                            <td class=\"slds-cell-wrap\">Runs every day at 1 PM.</td>\n                                                        </tr>\n                                                        <tr>\n                                                            <td class=\"slds-nowrap\"><code>0 0 22 ? * 6L</code></td>\n                                                            <td class=\"slds-cell-wrap\">Runs the last Friday of every month at 10 PM.</td>\n                                                        </tr>\n                                                        <tr>\n                                                            <td class=\"slds-nowrap\"><code>0 0 10 ? * MON-FRI\t</code></td>\n                                                            <td class=\"slds-cell-wrap\">Runs Monday through Friday at 10 AM.</td>\n                                                        </tr>\n                                                        <tr>\n                                                            <td class=\"slds-nowrap\"><code>0 0 20 * * ? 2010</code></td>\n                                                            <td class=\"slds-cell-wrap\">Runs every day at 8 PM during the year 2010.</td>\n                                                        </tr>\n                                                        <tr>\n                                                            <td class=\"slds-nowrap\"><code>0 0 8 13 2 ?</code></td>\n                                                            <td class=\"slds-cell-wrap\">Runs every 13th of February at 8 AM.</td>\n                                                        </tr>\n                                                    </tbody>\n                                                </table>\n                                        </p>\n                                    </aura:set>\n\n                                </c:MA_WizardCoachingCmp>\n\n                            </aura:if>\n\n                    </div>\n\n                </c:strike_wizard>\n\n            </div>\n        </div>\n\n        <!-- avoid showing form until have data for input labels and values, also avoids errors in debug mode -->\n        <aura:if isTrue=\"{!and( not( empty( v.record ) ), not( empty( v.objectDescribe ) ) )}\">\n\n            <!-- Stage: Details -->\n\n            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 0 )}\">\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <c:slds_section title=\"Detail Information\"/>\n                    </div>\n\n                </div>\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <div class=\"slds-form slds-form_stacked\">\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Name.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Name.helpText}\"/>\n                            <lightning:input aura:id=\"inputName\"\n                                name=\"inputName\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Name.label}\"\n                                value=\"{!v.record.name}\"\n                                required=\"true\"\n                                type=\"text\"\n                                messageWhenValueMissing=\"Name is required.\"\n                                class=\"slds-var-p-top_x-small\"\n                                onblur=\"{!c.handleInputNameFieldBlur}\"/>\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.DeveloperName__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.DeveloperName__c.helpText}\"/>\n                            <lightning:input aura:id=\"inputDeveloperName\"\n                                name=\"inputDeveloperName\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.DeveloperName__c.label}\"\n                                value=\"{!v.record.developerName}\"\n                                required=\"true\"\n                                type=\"text\"\n                                messageWhenValueMissing=\"Unique Name is required.\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Description__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Description__c.helpText}\"/>\n                            <lightning:textarea aura:id=\"inputDescription\"\n                                name=\"inputDescription\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Description__c.label}\"\n                                value=\"{!v.record.description}\"\n                                required=\"false\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Active__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Active__c.helpText}\"/>\n                            <lightning:input aura:id=\"inputActive\"\n                                name=\"inputActive\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Active__c.label}\"\n                                value=\"{!v.record.active}\"\n                                checked=\"{!v.record.active}\"\n                                required=\"false\"\n                                type=\"checkbox\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Batch_Size__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Batch_Size__c.helpText}\"/>\n                            <lightning:input aura:id=\"inputBatchSize\"\n                                name=\"inputBatchSize\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Batch_Size__c.label}\"\n                                value=\"{!v.record.batchSize}\"\n                                required=\"true\"\n                                type=\"number\"\n                                min=\"1\"\n                                max=\"200\"\n                                messageWhenValueMissing=\"Batch Size is required.\"\n                                messageWhenRangeUnderflow=\"Batch Size must be between 1 and 200.\"\n                                messageWhenRangeOverflow=\"Batch Size must be between 1 and 200.\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Named_Credential__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Named_Credential__c.helpText}\"/>\n                            <lightning:combobox aura:id=\"inputNamedCredential\"\n                                name=\"inputNamedCredential\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Named_Credential__c.label}\"\n                                value=\"{!v.record.namedCredential}\"\n                                required=\"false\"\n                                options=\"{!v.targetNamedCredentials}\"\n                                placeholder=\"Select a Named Credential\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                        </div>\n                    </div>\n\n                </div>\n\n            </aura:if>\n\n            <!-- Stage: Choose Source -->\n\n            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 1 )}\">\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <c:slds_section title=\"Source Information\"/>\n                    </div>\n\n                </div>\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <div class=\"slds-form slds-form_stacked\">\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Source_Type__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Source_Type__c.helpText}\"/>\n                            <lightning:combobox aura:id=\"inputSourceType\"\n                                name=\"inputSourceType\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Source_Type__c.label}\"\n                                value=\"{!v.sourceType}\"\n                                options=\"{!v.objectDescribe.fields.Source_Type__c.picklistValues}\"\n                                placeholder=\"Select a Source Type\"\n                                required=\"true\"\n                                messageWhenValueMissing=\"Source Type is required.\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                            <aura:if isTrue=\"{!equals( v.sourceType, 'Report' )}\">\n\n                                <c:slds_label label=\"Report Folder\"\n                                              helpText=\"Choose a folder that has the report to use as the source records.\"/>\n                                <lightning:combobox aura:id=\"inputSourceReportFolder\"\n                                    name=\"inputSourceReportFolder\"\n                                    variant=\"label-hidden\"\n                                    label=\"Report Folder\"\n                                    value=\"{!v.sourceReportFolderId}\"\n                                    options=\"{!v.sourceReportFolders}\"\n                                    placeholder=\"Select a Report Folder\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Report Folder is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                                <c:slds_label label=\"Report (tabular format only)\"\n                                              helpText=\"{!v.objectDescribe.fields.Source_Report_ID__c.helpText}\"/>\n                                <lightning:combobox aura:id=\"inputSourceReport\"\n                                    name=\"inputSourceReport\"\n                                    variant=\"label-hidden\"\n                                    label=\"Report (tabular format only)\"\n                                    value=\"{!v.sourceReportId}\"\n                                    options=\"{!v.sourceReports}\"\n                                    placeholder=\"Select a Tabular Report\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Report is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                                <c:slds_label label=\"Report Column - choose a column that uniquely identifies each record in the report\"\n                                              helpText=\"{!v.objectDescribe.fields.Source_Report_Column_Name__c.helpText}\"/>\n                                <lightning:combobox aura:id=\"inputSourceReportColumn\"\n                                    name=\"inputSourceReportColumn\"\n                                    variant=\"label-hidden\"\n                                    label=\"Report Column - choose a column that uniquely identifies each record in the report\"\n                                    value=\"{!v.sourceReportColumnName}\"\n                                    options=\"{!v.sourceReportColumns}\"\n                                    placeholder=\"Select a Report Column\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Report Column is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!equals( v.sourceType, 'ListView' )}\">\n\n                                <c:slds_label label=\"Object\"\n                                              helpText=\"Choose an object that has the list view to use as the source records.\"/>\n                                <lightning:combobox aura:id=\"inputSourceListViewSobjectType\"\n                                    name=\"inputSourceListViewSobjectType\"\n                                    variant=\"label-hidden\"\n                                    label=\"Object\"\n                                    value=\"{!v.sourceListViewSobjectType}\"\n                                    options=\"{!v.sourceListViewSobjectTypes}\"\n                                    placeholder=\"Select an Object\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Object is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                                <c:slds_label label=\"List View\"\n                                              helpText=\"{!v.objectDescribe.fields.Source_List_View_ID__c.helpText}\"/>\n                                <lightning:combobox aura:id=\"inputSourceListView\"\n                                    name=\"inputSourceListView\"\n                                    variant=\"label-hidden\"\n                                    label=\"List View\"\n                                    value=\"{!v.sourceListViewId}\"\n                                    options=\"{!v.sourceListViews}\"\n                                    placeholder=\"Select a List View\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"List View is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!equals( v.sourceType, 'SOQL' )}\">\n\n                                <c:slds_label label=\"SOQL Query\"\n                                              helpText=\"{!v.objectDescribe.fields.Source_SOQL_Query__c.helpText}\"/>\n                                <lightning:textarea aura:id=\"inputSourceSoqlQuery\"\n                                    name=\"inputSourceSoqlQuery\"\n                                    variant=\"label-hidden\"\n                                    label=\"{!v.objectDescribe.fields.Source_SOQL_Query__c.label}\"\n                                    value=\"{!v.record.sourceSoqlQuery}\"\n                                    required=\"true\"\n                                    onblur=\"{!c.handleOnBlurInputSourceSoqlQuery}\"\n                                    maxlength=\"{!v.objectDescribe.fields.Source_SOQL_Query__c.length}\"\n                                    messageWhenValueMissing=\"SOQL Query is required.\"\n                                    messageWhenTooLong=\"SOQL Query is too long.\"\n                                    class=\"slds-var-p-top_x-small slds-text-font_monospace\"/>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!equals( v.sourceType, 'Apex' )}\">\n\n                                <c:slds_label label=\"Apex Class\"\n                                              helpText=\"{!v.objectDescribe.fields.Source_Apex_Class__c.helpText}\"/>\n                                <lightning:input aura:id=\"inputSourceApexClass\"\n                                    name=\"inputSourceApexClass\"\n                                    variant=\"label-hidden\"\n                                    label=\"{!v.objectDescribe.fields.Source_Apex_Class__c.label}\"\n                                    value=\"{!v.record.sourceApexClass}\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Apex Class is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!not(empty(v.sourceTypeURL))}\">\n\n                                <div class=\"slds-form-element\">\n                                    <div class=\"slds-form-element__control\">\n                                        <a href=\"{!v.sourceTypeURL}\" target=\"_blank\" rel=\"noopener noreferrer\">View selected source to confirm fields and filters</a>\n                                    </div>\n                                </div>\n\n                            </aura:if>\n\n                        </div>\n                    </div>\n\n                </div>\n\n            </aura:if>\n\n            <!-- Stage: Choose Action -->\n\n            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 2 )}\">\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <c:slds_section title=\"Action Information\"/>\n                    </div>\n\n                </div>\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <div class=\"slds-form slds-form_stacked\">\n\n                            <c:slds_label label=\"Action Type\"\n                                          helpText=\"{!v.objectDescribe.fields.Target_Type__c.helpText}\"/>\n                            <lightning:combobox aura:id=\"inputTargetType\"\n                                name=\"inputTargetType\"\n                                variant=\"label-hidden\"\n                                label=\"Action Type\"\n                                value=\"{!v.targetType}\"\n                                options=\"{!v.objectDescribe.fields.Target_Type__c.picklistValues}\"\n                                placeholder=\"Select an Action Type\"\n                                required=\"true\"\n                                messageWhenValueMissing=\"Action Type is required.\"\n                                class=\"slds-var-p-top_x-small\"/>\n\n                            <aura:if isTrue=\"{!equals( v.targetType, 'Workflow' )}\">\n\n                                <div class=\"slds-form-element slds-var-p-top_x-small\">\n\n                                    <label class=\"slds-form-element__label\">\n                                        <abbr title=\"required\" class=\"slds-required\">*</abbr>\n                                        Action\n                                    </label>\n\n                                    <div class=\"slds-input\" disabled=\"disabled\">\n                                        For each source record, all <b>active</b> Workflow Rules will run whose <b>Rule Criteria</b> matches the record.\n                                        <br/>\n                                        <b>Evaluation Criteria</b>, which normally decides when a rule fires, is ignored because you are explicitly running the rules with Mass Action Scheduler.\n                                        <br/>\n                                        Learn more with the <a href=\"https://help.salesforce.com/articleView?id=workflow_rules_define.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Set the Criteria for Your Workflow Rule</a> help article.\n                                    </div>\n\n                                </div>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!equals( v.targetType, 'Apex' )}\">\n\n                                <c:slds_label label=\"Apex Type\"\n                                              helpText=\"Choose how to invoke the Apex code. Supported types include invocable Apex methods annotated with @InvocableMethod, or anonymous blocks.\"/>\n                                <lightning:combobox aura:id=\"inputTargetApexType\"\n                                    name=\"inputTargetApexType\"\n                                    variant=\"label-hidden\"\n                                    label=\"Apex Type\"\n                                    value=\"{!v.targetApexType}\"\n                                    options=\"{!v.targetApexTypes}\"\n                                    placeholder=\"Select an Apex Type\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Apex Type is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n\n                                <aura:if isTrue=\"{!equals( v.targetApexType, 'Anonymous' )}\">\n                                    <c:slds_label label=\"Apex Code\"\n                                                  helpText=\"{!v.objectDescribe.fields.Target_Apex_Script__c.helpText}\"/>\n                                    <lightning:textarea aura:id=\"inputTargetApexScript\"\n                                        name=\"inputTargetApexScript\"\n                                        variant=\"label-hidden\"\n                                        label=\"{!v.objectDescribe.fields.Target_Apex_Script__c.label}\"\n                                        value=\"{!v.record.targetApexScript}\"\n                                        required=\"true\"\n                                        onblur=\"{!c.handleOnBlurInputTargetApexScript}\"\n                                        maxlength=\"{!v.objectDescribe.fields.Target_Apex_Script__c.length}\"\n                                        messageWhenValueMissing=\"Apex code is required.\"\n                                        messageWhenTooLong=\"Apex code is too long.\"\n                                        class=\"slds-var-p-top_x-small slds-text-font_monospace\"/>\n                                </aura:if>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!v.targetTypeRequiresSobject}\">\n                                <c:slds_label label=\"Object\"\n                                              helpText=\"Choose an object that has the custom actions to run on the source records.\"/>\n                                <lightning:combobox aura:id=\"inputTargetSobjectType\"\n                                    name=\"inputTargetSobjectType\"\n                                    variant=\"label-hidden\"\n                                    label=\"Object\"\n                                    value=\"{!v.targetSobjectType}\"\n                                    options=\"{!v.targetSobjectTypes}\"\n                                    placeholder=\"Select an Object\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Object is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!v.isValidToRenderTargetInvocableActions}\">\n                                <c:slds_label label=\"Action\"\n                                              helpText=\"Choose the specific action to run on the source records.\"/>\n                                <lightning:combobox aura:id=\"inputTargetAction\"\n                                    name=\"inputTargetAction\"\n                                    variant=\"label-hidden\"\n                                    label=\"Action\"\n                                    value=\"{!v.targetInvocableAction}\"\n                                    options=\"{!v.targetInvocableActions}\"\n                                    placeholder=\"Select an Action\"\n                                    required=\"true\"\n                                    messageWhenValueMissing=\"Action is required.\"\n                                    class=\"slds-var-p-top_x-small\"/>\n                            </aura:if>\n\n                        </div>\n                    </div>\n\n                </div>\n\n            </aura:if>\n\n            <!-- Stage: Field Mappings -->\n\n            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 3 )}\">\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <c:slds_section title=\"Field Mappings\"/>\n                    </div>\n\n                </div>\n\n                <div class=\"slds-var-p-horizontal_medium\">\n\n                    <aura:if isTrue=\"{!empty(v.targetFieldMappings)}\">\n\n                        <p>\n                            The selected action type has no fields to map.\n                            <br/>\n                            You may proceed to schedule this configuration.\n                        </p>\n\n                    </aura:if>\n\n                    <aura:if isTrue=\"{!not(empty(v.targetFieldMappings))}\">\n\n                        <table class=\"slds-table slds-table_bordered\">\n                            <thead>\n                                <tr class=\"slds-text-title_caps\">\n                                    <th scope=\"col\">Source Field</th>\n                                    <th scope=\"col\">Target Field</th>\n                                </tr>\n                            </thead>\n                            <tbody>\n                                <aura:iteration var=\"targetFieldMapping\" items=\"{!v.targetFieldMappings}\" indexVar=\"index\">\n                                    <tr>\n                                        <td width=\"50%\">\n\n                                            <aura:if isTrue=\"{!equals( v.sourceFieldsInputType, 'text' )}\">\n\n                                                <lightning:input aura:id=\"inputMappingSourceFieldName\"\n                                                    name=\"inputMappingSourceFieldName\"\n                                                    label=\"{!targetFieldMapping.targetField.label}\"\n                                                    variant=\"label-hidden\"\n                                                    value=\"{!targetFieldMapping.sourceFieldName}\"\n                                                    placeholder=\"Enter source field name\"\n                                                    required=\"{!targetFieldMapping.targetField.required}\"/>\n\n                                            </aura:if>\n\n                                            <aura:if isTrue=\"{!equals( v.sourceFieldsInputType, 'combobox' )}\">\n\n                                                <lightning:combobox aura:id=\"inputMappingSourceFieldName\"\n                                                    name=\"inputMappingSourceFieldName\"\n                                                    label=\"{!targetFieldMapping.targetField.label}\"\n                                                    variant=\"label-hidden\"\n                                                    value=\"{!targetFieldMapping.sourceFieldName}\"\n                                                    options=\"{!v.sourceFields}\"\n                                                    placeholder=\"Select a Field\"\n                                                    required=\"{!targetFieldMapping.targetField.required}\"/>\n\n                                            </aura:if>\n\n                                        </td>\n                                        <td width=\"50%\">\n\n                                            <aura:if isTrue=\"{!targetFieldMapping.targetField.required}\">\n\n                                                <abbr class=\"slds-required\" title=\"required\">*</abbr>\n\n                                                <aura:set attribute=\"else\">\n\n                                                    <span class=\"slds-var-m-right_xxx-small\" style=\"opacity:0\">*</span>\n\n                                                </aura:set>\n\n                                            </aura:if>\n\n                                            <span class=\"slds-var-m-right_xx-small\">{!targetFieldMapping.targetField.label}</span>\n\n                                            <aura:if isTrue=\"{!not(empty(targetFieldMapping.targetField.description))}\">\n                                                <lightning:helptext content=\"{!targetFieldMapping.targetField.description}\"/>\n                                            </aura:if>\n\n                                        </td>\n                                    </tr>\n                                </aura:iteration>\n                            </tbody>\n                        </table>\n\n                    </aura:if>\n\n                </div>\n\n            </aura:if>\n\n            <!-- Stage: Schedule -->\n\n            <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, 4 )}\">\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <c:slds_section title=\"Schedule Information\"/>\n                    </div>\n\n                </div>\n\n                <div class=\"slds-grid slds-var-p-horizontal_medium\">\n\n                    <div class=\"slds-col\">\n                        <div class=\"slds-form slds-form_stacked\">\n\n                            <c:slds_label label=\"{!v.objectDescribe.fields.Schedule_Frequency__c.label}\"\n                                          helpText=\"{!v.objectDescribe.fields.Schedule_Frequency__c.helpText}\"/>\n                            <lightning:radioGroup aura:id=\"inputScheduleFrequency\"\n                                name=\"inputScheduleFrequency\"\n                                variant=\"label-hidden\"\n                                label=\"{!v.objectDescribe.fields.Schedule_Frequency__c.label}\"\n                                value=\"{!v.scheduleSelectionsFrequency}\"\n                                options=\"{!v.objectDescribe.fields.Schedule_Frequency__c.picklistValues}\"\n                                type=\"button\"\n                                required=\"true\"\n                                messageWhenValueMissing=\"Schedule Frequency is required.\"\n                                class=\"slds-var-p-top_x-small label-hidden\"/>\n\n                            <!--\n                                Unfortunately, the radioGroup component changes the value type to an array,\n                                so even though my source value is a single string I need to check both data types\n                                or introduce a shadow variable to bind to the radio group and use change events\n                                to copy the newly selected value; neither of which I want to do\n                                https://org62.lightning.force.com/one/one.app#/sObject/0D50M00003LvvAqSAJ/view\n                             -->\n                            <aura:if isTrue=\"{!or( equals( v.scheduleSelectionsFrequency, 'Scheduled' ), and( not( empty( v.scheduleSelectionsFrequency ) ), equals( v.scheduleSelectionsFrequency[0], 'Scheduled' ) ) )}\">\n\n                                <div class=\"slds-var-p-top_medium\">\n\n                                    <p>\n                                        Select the hours, days of month or weekdays, and months\n                                        that you want to schedule the action to run.\n                                    </p>\n\n                                    <div class=\"slds-grid\">\n\n                                        <div class=\"slds-col slds-var-m-vertical_medium\">\n\n                                            <c:slds_label label=\"{!v.objectDescribe.fields.Schedule_HourOfDay__c.label}\"\n                                                          helpText=\"{!v.objectDescribe.fields.Schedule_HourOfDay__c.helpText}\"/>\n                                            <lightning:dualListbox aura:id=\"inputScheduleHourOfDay\"\n                                                name=\"inputScheduleHourOfDay\"\n                                                variant=\"label-hidden\"\n                                                label=\"{!v.objectDescribe.fields.Schedule_HourOfDay__c.label}\"\n                                                sourceLabel=\"Available Options\"\n                                                selectedLabel=\"Selected Options\"\n                                                options=\"{!v.scheduleOptionsHourOfDay}\"\n                                                value=\"{!v.scheduleSelectionsHourOfDay}\"\n                                                required=\"true\"\n                                                onchange=\"{!c.handleInputListBoxChanged}\"/>\n\n                                        </div>\n\n                                    </div>\n\n                                    <div class=\"slds-grid\">\n\n                                        <div class=\"slds-col slds-var-m-vertical_medium\">\n\n                                            <c:slds_label label=\"{!v.objectDescribe.fields.Schedule_DayOfWeek__c.label}\"\n                                                          helpText=\"{!v.objectDescribe.fields.Schedule_DayOfWeek__c.helpText}\"/>\n                                            <lightning:dualListbox aura:id=\"inputScheduleWeekday\"\n                                                name=\"inputScheduleWeekday\"\n                                                variant=\"label-hidden\"\n                                                label=\"{!v.objectDescribe.fields.Schedule_DayOfWeek__c.label}\"\n                                                sourceLabel=\"Available Options\"\n                                                selectedLabel=\"Selected Options\"\n                                                options=\"{!v.scheduleOptionsDayOfWeek}\"\n                                                value=\"{!v.scheduleSelectionsDayOfWeek}\"\n                                                onchange=\"{!c.handleInputListBoxChanged}\"/>\n\n                                        </div>\n\n                                    </div>\n\n                                    <div class=\"slds-grid\">\n\n                                        <div class=\"slds-col slds-var-m-vertical_medium\">\n\n                                            <c:slds_label label=\"{!v.objectDescribe.fields.Schedule_DayOfMonth__c.label}\"\n                                                          helpText=\"{!v.objectDescribe.fields.Schedule_DayOfMonth__c.helpText}\"/>\n                                            <lightning:dualListbox aura:id=\"inputScheduleDayOfMonth\"\n                                                name=\"inputScheduleDayOfMonth\"\n                                                variant=\"label-hidden\"\n                                                label=\"{!v.objectDescribe.fields.Schedule_DayOfMonth__c.label}\"\n                                                sourceLabel=\"Available Options\"\n                                                selectedLabel=\"Selected Options\"\n                                                options=\"{!v.scheduleOptionsDayOfMonth}\"\n                                                value=\"{!v.scheduleSelectionsDayOfMonth}\"\n                                                onchange=\"{!c.handleInputListBoxChanged}\"/>\n\n                                        </div>\n\n                                    </div>\n\n                                    <div class=\"slds-grid\">\n\n                                        <div class=\"slds-col slds-var-m-vertical_medium\">\n\n                                            <c:slds_label label=\"{!v.objectDescribe.fields.Schedule_MonthOfYear__c.label}\"\n                                                          helpText=\"{!v.objectDescribe.fields.Schedule_MonthOfYear__c.helpText}\"/>\n                                            <lightning:dualListbox aura:id=\"inputScheduleMonthOfYear\"\n                                                name=\"inputScheduleMonthOfYear\"\n                                                variant=\"label-hidden\"\n                                                label=\"{!v.objectDescribe.fields.Schedule_MonthOfYear__c.label}\"\n                                                sourceLabel=\"Available Options\"\n                                                selectedLabel=\"Selected Options\"\n                                                options=\"{!v.scheduleOptionsMonthOfYear}\"\n                                                value=\"{!v.scheduleSelectionsMonthOfYear}\"\n                                                required=\"true\"\n                                                onchange=\"{!c.handleInputListBoxChanged}\"/>\n\n                                        </div>\n\n                                    </div>\n\n                                </div>\n\n                            </aura:if>\n\n                            <aura:if isTrue=\"{!or( equals( v.scheduleSelectionsFrequency, 'Custom' ), and( not( empty( v.scheduleSelectionsFrequency ) ), equals( v.scheduleSelectionsFrequency[0], 'Custom' ) ) )}\">\n\n                                <div class=\"slds-var-p-top_medium\">\n\n                                    <c:slds_label label=\"{!v.objectDescribe.fields.Schedule_Cron__c.label}\"\n                                                  helpText=\"{!v.objectDescribe.fields.Schedule_Cron__c.helpText}\"/>\n                                    <lightning:input aura:id=\"inputScheduleCron\"\n                                         name=\"inputScheduleCron\"\n                                         variant=\"label-hidden\"\n                                         label=\"{!v.objectDescribe.fields.Schedule_Cron__c.label}\"\n                                         type=\"text\"\n                                         value=\"{!v.record.scheduleCron}\"\n                                         required=\"true\"/>\n\n                                    <div class=\"slds-var-m-vertical_small\">\n                                        Please refer to the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Apex Scheduler Developer Documentation</a>\n                                        for details on creating a cron expression.\n                                    </div>\n\n                                </div>\n\n                            </aura:if>\n\n                        </div>\n                    </div>\n\n                </div>\n\n            </aura:if>\n\n            <!-- Navigation Controls -->\n\n            <div class=\"slds-grid slds-var-p-around_medium slds-var-m-top_medium slds-grid_pull-padded-medium slds-grid_align-center\">\n\n                <div class=\"slds-col slds-var-p-horizontal_medium\">\n                    <lightning:button aura:id=\"wizardPreviousButton\"\n                        label=\"Previous\"\n                        title=\"Previous\"\n                        variant=\"neutral\"\n                        disabled=\"{!not( greaterthan( v.wizardActiveStageIndex, 0 ) )}\"\n                        onclick=\"{!c.handleNavigationButtonClick}\"/>\n                </div>\n\n                <aura:if isTrue=\"{!lessthan( v.wizardActiveStageIndex, ( v.wizardStageNames.length - 1 ) )}\">\n\n                    <div class=\"slds-col slds-var-p-horizontal_medium\">\n                        <lightning:button aura:id=\"wizardNextButton\"\n                            label=\"Next\"\n                            title=\"Next\"\n                            variant=\"brand\"\n                            disabled=\"{!not( lessthan( v.wizardActiveStageIndex, ( v.wizardStageNames.length - 1 ) ) )}\"\n                            onclick=\"{!c.handleNavigationButtonClick}\"/>\n                    </div>\n\n                </aura:if>\n\n                <aura:if isTrue=\"{!equals( v.wizardActiveStageIndex, ( v.wizardStageNames.length - 1 ) )}\">\n\n                    <div class=\"slds-col slds-var-p-horizontal_medium\">\n                        <lightning:button aura:id=\"wizardSaveButton\"\n                            label=\"Save\"\n                            title=\"Save\"\n                            variant=\"brand\"\n                            onclick=\"{!c.handleSaveButtonClick}\"/>\n                    </div>\n\n                </aura:if>\n\n            </div>\n\n            <aura:set attribute=\"else\">\n\n                <lightning:spinner variant=\"brand\" size=\"large\"/>\n\n            </aura:set>\n\n        </aura:if>\n\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_EditConfigCmp/MA_EditConfigCmp.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>MA_EditConfigCmp</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/MA_EditConfigCmp/MA_EditConfigCmp.css",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n */\n\n/**\n * Make it more obvious that the user can\n * click to select an option from the picklist.\n */\n.THIS lightning-combobox * {\n    cursor: pointer;\n}\n\n/**\n * W-5212157\n * https://salesforce.stackexchange.com/questions/220616/summer-18-lightning-input-variant-label-hidden-hides-the-label-but-occupies-th/221202#221202\n */\n.THIS .label-hidden > label,\n.THIS .label-hidden legend {\n    display: none;\n}\n\n/**\n * The strike_wizard component applies this class\n * to the chevrons that are incomplete. To further\n * express to users they cannot jump ahead then\n * change mouse cursor on hover.\n */\n.THIS .slds-is-incomplete * {\n    cursor: not-allowed;\n}\n\n/**\n * Styling copied from Trailhead website.\n */\n.THIS .keyword {\n    color: #d14;\n    background-color: #f7f7f9;\n    border: t(borderWidthThin) solid #e1e1e8;\n    border-radius: t(borderRadiusSmall);\n    padding: t(varSpacingXxxSmall) t(varSpacingXxSmall);\n}\n\n/**\n * Renders newlines and whitespace indentation\n * similar to the <pre> tag but without the\n * ridiculous leading whitespace.\n */\n.THIS code.block {\n    color: #d14;\n    white-space: pre-line;\n    display: block;\n}\n\n/**\n * This CSS selector places the tag name after our class name\n * because the `class` attribute we put on <lightning:textarea>\n * is applied to the outer DOM element and not on the actual\n * `textarea` tag within the component. Therefore, our selector\n * needs to cascade to the `textarea` elements in the component.\n */\n.THIS textarea[name=\"inputTargetApexScript\"],\n.THIS textarea[name=\"inputSourceSoqlQuery\"] {\n    height: 200px;\n}\n\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/MA_EditConfigCmp/MA_EditConfigCmpController.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n */\n({\n    onInit : function( component, event, helper ) {\n\n        var recordId = component.get( 'v.recordId' );\n\n        // initialize wizard to first step\n        var wizard = component.find( 'wizard' );\n        wizard.moveToStage( 0 );\n        component.set( 'v.wizardActiveStageIndex', 0 );\n\n        Promise.resolve()\n            .then( $A.getCallback( function() {\n\n                let promises = [];\n\n                promises.push( helper.getObjectDescribeAsync( component )\n                    .then( $A.getCallback( function( objectDescribe ) {\n\n                        component.set( 'v.objectDescribe', objectDescribe );\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Object Describe', err, 'error' );\n\n                    }))\n                );\n\n                promises.push( helper.getRecordAsync( component, recordId )\n                    .then( $A.getCallback( function( record ) {\n\n                        component.set( 'v.record', record );\n                        component.set( 'v.sourceType', record.sourceType );\n                        component.set( 'v.targetType', record.targetType );\n                        component.set( 'v.targetSobjectType', record.targetSobjectType );\n                        component.set( 'v.targetInvocableAction', record.targetActionName );\n\n                        if ( record.targetType === 'Apex' ) {\n\n                            if ( !$A.util.isEmpty( record.targetActionName ) ) {\n                                component.set( 'v.targetApexType', 'Invocable' );\n                            }\n                            else if ( !$A.util.isEmpty( record.targetApexScript ) ) {\n                                component.set( 'v.targetApexType', 'Anonymous' );\n                            }\n\n                        }\n\n                        helper.initScheduleOptions( component );\n\n                        return record;\n\n                    })).then( $A.getCallback( function( record ) {\n\n                        if ( !$A.util.isUndefinedOrNull( record.sourceReportID ) ) {\n\n                            return helper.getReportAsync( component, record.sourceReportID )\n                                .then( $A.getCallback( function( report ) {\n\n                                    if ( !$A.util.isUndefinedOrNull( report ) ) {\n                                        component.set( 'v.sourceReport', report );\n                                        component.set( 'v.sourceReportId', ( report.Id && report.Id.substring( 0, 15 ) ) );\n                                        component.set( 'v.sourceReportFolderId', ( report.OwnerId && report.OwnerId.substring( 0, 15 ) ) );\n                                        component.set( 'v.sourceReportColumnName', record.sourceReportColumnName );\n                                    }\n\n                                })).catch( $A.getCallback( function( err ) {\n\n                                    helper.toastMessage( 'Error Getting Report', err, 'error' );\n\n                                }));\n\n                        }\n\n                        if ( !$A.util.isUndefinedOrNull( record.sourceListViewID ) ) {\n\n                            return helper.getListViewAsync( component, record.sourceListViewID )\n                                .then( $A.getCallback( function( listView ) {\n\n                                    if ( !$A.util.isUndefinedOrNull( listView ) ) {\n                                        component.set( 'v.sourceListView', listView );\n                                        component.set( 'v.sourceListViewId', ( listView.Id && listView.Id.substring( 0, 15 ) ) );\n                                        component.set( 'v.sourceListViewSobjectType', listView.SobjectType );\n                                    }\n\n                                })).catch( $A.getCallback( function( err ) {\n\n                                    helper.toastMessage( 'Error Getting List View', err, 'error' );\n\n                                }));\n\n                        }\n\n                    })).then( $A.getCallback( function() {\n\n                        // avoid race condition where as the page loads,\n                        // several change handlers call controller methods\n                        // and those methods end up reading/writing attribtues\n                        // before the above async operations have completed.\n                        // https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues/94\n\n                        component.set( 'v.didInitConfig', true );\n\n                        return Promise.all([\n                            helper.handleSourceTypeChange( component ),\n                            helper.handleTargetTypeChange( component )\n                        ]);\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Mass Action Configuration', err, 'error' );\n\n                    }))\n                );\n\n                promises.push( helper.getNamedCredentialsAsync( component )\n                    .then( $A.getCallback( function( namedCredentials ) {\n\n                        var emptyOption = {\n                            'label': '--None--',\n                            'value': null\n                        };\n\n                        component.set( 'v.targetNamedCredentials', [ emptyOption ].concat( namedCredentials ) );\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Named Credentials', err, 'error' );\n\n                    }))\n                );\n\n                return Promise.all( promises );\n\n            })).catch( $A.getCallback( function( err ) {\n\n                helper.toastMessage( 'Error initializing component', err, 'error' );\n\n            }));\n\n    },\n\n    handleNavigationButtonClick : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        var wizard = component.find( 'wizard' );\n        var currentStageIndex = wizard.get( 'v.activeChevron' );\n\n        var button = event.getSource();\n        var buttonLabel = button.get( 'v.label' );\n\n        if ( buttonLabel == 'Previous' ) {\n\n            wizard.moveToStage( currentStageIndex - 1 );\n\n        } else if ( buttonLabel == 'Next' ) {\n\n            var inputCmps = []; // fields to validate to proceed to next step\n\n            if ( currentStageIndex === 0 ) {                // Details\n\n                inputCmps = [\n                    component.find( 'inputName' ),\n                    component.find( 'inputDeveloperName' ),\n                    component.find( 'inputDescription' ),\n                    component.find( 'inputActive' ),\n                    component.find( 'inputBatchSize' ),\n                    component.find( 'inputNamedCredential' )\n                ];\n\n            } else if ( currentStageIndex === 1 ) {         // Choose Source\n\n                inputCmps = [\n                    component.find( 'inputSourceType' ),\n                    component.find( 'inputSourceReportFolder' ),\n                    component.find( 'inputSourceReport' ),\n                    component.find( 'inputSourceReportColumn' ),\n                    component.find( 'inputSourceListViewSobjectType' ),\n                    component.find( 'inputSourceListView' ),\n                    component.find( 'inputSourceSoqlQuery' ),\n                    component.find( 'inputSourceApexClass' )\n                ];\n\n            } else if ( currentStageIndex === 2 ) {         // Choose Action\n\n                inputCmps = [\n                    component.find( 'inputTargetType' ),\n                    component.find( 'inputTargetSobjectType' ),\n                    component.find( 'inputTargetAction' ),\n                    component.find( 'inputTargetApexType' ),\n                    component.find( 'inputTargetApexScript' )\n                ];\n\n            } else if ( currentStageIndex === 3 ) {         // Field Mappings\n\n                var inputSourceFieldNames = component.find( 'inputMappingSourceFieldName' );\n\n                if ( $A.util.isArray( inputSourceFieldNames ) ) {\n                    for ( var i = 0; i < inputSourceFieldNames.length; i++ ) {\n                        inputCmps.push( inputSourceFieldNames[i] );\n                    }\n                } else {\n                    inputCmps.push( inputSourceFieldNames );\n                }\n\n            }\n\n            helper.validateInputsAsync( component, inputCmps )\n                .then( $A.getCallback( function( validationResult ) {\n\n                    var isValidToProceed = !validationResult.hasErrors;\n\n                    if ( isValidToProceed ) {\n\n                        return Promise.resolve()\n                            .then( $A.getCallback( function() {\n\n                                // if advancing to field mappings section then\n                                // determine the action inputs and any current mappings\n                                if ( currentStageIndex === 2 ) {\n\n                                    return helper.renderTargetFieldMappingsAsync( component );\n                                }\n\n                            })).then( $A.getCallback( function() {\n\n                                wizard.advanceProgress();\n\n                            }));\n\n                    } else {\n\n                        validationResult.components.forEach( function( validationComponentResult ) {\n                            if ( validationComponentResult.hasError ) {\n                                helper.toastMessage( 'Step Incomplete', validationComponentResult.messageWhenInvalid, 'error' );\n                                validationComponentResult.component.reportValidity();\n                            }\n                        });\n\n                    }\n\n                })).catch( $A.getCallback( function( err ) {\n\n                    helper.toastMessage( 'Error Advancing to Next Step', err, 'error' );\n\n                }));\n\n        }\n\n    },\n\n    handleSaveButtonClick : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        var inputCmps = [\n            component.find( 'inputScheduleFrequency' ),\n            component.find( 'inputScheduleHourOfDay' ),\n            component.find( 'inputScheduleWeekday' ),\n            component.find( 'inputScheduleDayOfMonth' ),\n            component.find( 'inputScheduleMonthOfYear' ),\n            component.find( 'inputScheduleCron' )\n        ];\n\n        helper.validateInputsAsync( component, inputCmps )\n            .then( $A.getCallback( function( validationResult ) {\n\n                var isValidToSave = !validationResult.hasErrors;\n\n                if ( isValidToSave ) {\n\n                    return helper.saveRecordAsync( component )\n                        .then( $A.getCallback( function( result ) {\n\n                            if ( result.success ) {\n\n                                helper.toastMessage( 'Save Successful', '', 'success' );\n\n                                // Cause lightning data service to invalidate it's cache.\n                                // I added this after realizing the compact layout was not\n                                // picking up changes to fields by this component.\n                                // I started out firing the force:refreshView event but\n                                // that only worked if the record already existed, if we\n                                // just saved a new record then we needed to still navigate to it.\n                                // And I didn't know how to listen for the refreshView event to complete\n                                // but I did find that I could use a callback in the LDS reloadRecord method.\n                                var lds = component.find( 'lds' );\n                                lds.set( 'v.recordId', result.recordId );\n                                lds.reloadRecord( true, function() {\n                                    helper.navigateToRecord( result.recordId );\n                                });\n\n                            } else {\n\n                                helper.toastMessage( 'Save Failed', '', 'error' );\n\n                            }\n\n                        }));\n\n                } else {\n\n                    validationResult.components.forEach( function( validationComponentResult ) {\n                        if ( validationComponentResult.hasError ) {\n                            helper.toastMessage( 'Step Incomplete', validationComponentResult.messageWhenInvalid, 'error' );\n                            validationComponentResult.component.reportValidity();\n                        }\n                    });\n\n                }\n\n            })).catch( $A.getCallback( function( err ) {\n\n                helper.toastMessage( 'Error Saving Configuration', err, 'error' );\n\n            }));\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    handleInputNameFieldBlur : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        var inputCmp = event.getSource();\n        var inputValue = inputCmp.get( 'v.value' );\n\n        // predict the developer name from the name, a familiar feature to admins\n        if ( !helper.isEmpty( inputValue ) && helper.isEmpty( component.get( 'v.record.developerName' ) ) ) {\n            component.set( 'v.record.developerName', inputValue.trim().replace( /[ ]+/g, '_' ) );\n        }\n\n    },\n\n    handleOnBlurInputSourceSoqlQuery : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        var inputCmp = event.getSource();\n        var inputValue = inputCmp.get( 'v.value' );\n\n        if ( !$A.util.isUndefinedOrNull( inputValue ) ) {\n            inputCmp.set( 'v.value', inputValue.trim() );\n        }\n\n    },\n\n    handleOnBlurInputTargetApexScript : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        var inputCmp = event.getSource();\n        var inputValue = inputCmp.get( 'v.value' );\n\n        if ( !$A.util.isUndefinedOrNull( inputValue ) ) {\n            inputCmp.set( 'v.value', inputValue.trim() );\n        }\n\n    },\n\n    handleInputListBoxChanged : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        var selectedOptions = event.getParam( 'value' );\n\n        if ( !helper.isEmpty( selectedOptions ) ) {\n            selectedOptions.sort();\n        }\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    handleSourceTypeChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleSourceTypeChange( component );\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    handleSourceReportFolderChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleSourceReportFolderChange( component );\n\n    },\n\n    handleSourceReportChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleSourceReportChange( component );\n\n    },\n\n    // -----------------------------------------------------------------\n\n    handleSourceListViewSobjectTypeChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleSourceListViewSobjectTypeChange( component );\n\n    },\n\n    handleSourceListViewChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleSourceListViewChange( component );\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    handleTargetTypeChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleTargetTypeChange( component );\n\n    },\n\n    handleTargetApexTypeChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.handleTargetTypeChange( component );\n\n    },\n\n    handleTargetSobjectTypeChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.renderTargetInvocableActions( component );\n\n    },\n\n    handleTargetTypeRequiresSobjectChange : function( component, event, helper ) {\n\n        if ( component.get( 'v.didInitConfig' ) !== true ) {\n            return;\n        }\n\n        helper.renderTargetSobjectTypes( component );\n\n    }\n\n})\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/MA_EditConfigCmp/MA_EditConfigCmpHelper.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n */\n({\n    initScheduleOptions : function( component ) {\n\n        var helper = this;\n\n        var scheduleOptionsHourOfDay = [];\n        var scheduleOptionsDayOfMonth = [];\n        var scheduleOptionsMonthOfYear = [];\n        var scheduleOptionsDayOfWeek = [];\n\n        for ( let i = 0; i < 24; i++ ) {\n            scheduleOptionsHourOfDay.push({\n                'label' : ( i == 0 ? '12:00 AM' : i == 12 ? '12:00 PM' : ( i < 12 ? i + ':00 AM' : ( i - 12 ) + ':00 PM' ) ).padStart( 8, '0' ),\n                'value' : i.toString().padStart( 2, '0' ) + '.' + i.toString()\n            });\n        }\n\n        for ( let i = 1; i <= 31; i++ ) {\n            scheduleOptionsDayOfMonth.push({\n                'label' : i.toString(),\n                'value' : i.toString().padStart( 2, '0' ) + '.' + i.toString()\n            });\n        }\n\n        var monthValues = [ 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' ];\n        var localeMonthNames = $A.get( '$Locale.nameOfMonths' );\n        for ( let i = 0; i < localeMonthNames.length; i++ ) {\n            if ( !helper.isEmpty( localeMonthNames[i].fullName ) ) {\n                scheduleOptionsMonthOfYear.push({\n                    'label' : localeMonthNames[i].fullName.toUpperCase(),               // display in user's locale\n                    'value' : i.toString().padStart( 2, '0' ) + '.' + monthValues[i]    // but capture in english for cron expr.\n                });                                                                     // left pad with number for easy sorting\n            }\n        }\n\n        var weekdayValues = [ 'SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT' ];\n        var localeWeekdayNames = $A.get( '$Locale.nameOfWeekdays' );\n        for ( let i = 0; i < localeWeekdayNames.length; i++ ) {\n            if ( !helper.isEmpty( localeWeekdayNames[i].fullName ) ) {\n                scheduleOptionsDayOfWeek.push({\n                    'label' : localeWeekdayNames[i].fullName.toUpperCase(),             // display in user's locale\n                    'value' : i.toString().padStart( 2, '0' ) + '.' + weekdayValues[i]  // but capture in english for cron expr.\n                });                                                                     // left pad with number for easy sorting\n            }\n        }\n\n        component.set( 'v.scheduleOptionsHourOfDay', scheduleOptionsHourOfDay );\n        component.set( 'v.scheduleOptionsDayOfMonth', scheduleOptionsDayOfMonth );\n        component.set( 'v.scheduleOptionsMonthOfYear', scheduleOptionsMonthOfYear );\n        component.set( 'v.scheduleOptionsDayOfWeek', scheduleOptionsDayOfWeek );\n\n        var record = component.get( 'v.record' );\n\n        component.set( 'v.scheduleSelectionsFrequency', record.scheduleFrequency );\n\n        // add the \"NN.\" prefix to the values used for sorting\n        // so match the schedule options format so the selections are visually shown on the config page\n\n        // exactly one of dayOfMonth or dayOfWeek must be specified and the other must be '?',\n        // in our case, '?' means no selections for that value as the other field was specified\n\n        if ( !$A.util.isUndefinedOrNull( record.scheduleHourOfDay ) ) {\n            component.set( 'v.scheduleSelectionsHourOfDay', record.scheduleHourOfDay.split(',').map( function( hourOfDay ) { return hourOfDay.padStart( 2, '0' ) + '.' + hourOfDay; } ) );\n        } else {\n            component.set( 'v.scheduleSelectionsHourOfDay', [] );\n        }\n\n        if ( !$A.util.isUndefinedOrNull( record.scheduleDayOfMonth ) && record.scheduleDayOfMonth != '?' ) {\n            component.set( 'v.scheduleSelectionsDayOfMonth', record.scheduleDayOfMonth.split(',').map( function( dayOfMonth ) { return dayOfMonth.padStart( 2, '0' ) + '.' + dayOfMonth; } ) );\n        } else {\n            component.set( 'v.scheduleSelectionsDayOfMonth', [] );\n        }\n\n        if ( !$A.util.isUndefinedOrNull( record.scheduleMonthOfYear ) ) {\n            component.set( 'v.scheduleSelectionsMonthOfYear', record.scheduleMonthOfYear.split(',').map( function( monthOfYear ) { return monthValues.indexOf( monthOfYear ).toString().padStart( 2, '0' ) + '.' + monthOfYear; } ) );\n        } else {\n            component.set( 'v.scheduleSelectionsMonthOfYear', [] );\n        }\n\n        if ( !$A.util.isUndefinedOrNull( record.scheduleDayOfWeek ) && record.scheduleDayOfWeek != '?' ) {\n            component.set( 'v.scheduleSelectionsDayOfWeek', record.scheduleDayOfWeek.split(',').map( function( dayOfWeek ) { return weekdayValues.indexOf( dayOfWeek ).toString().padStart( 2, '0' ) + '.' + dayOfWeek; } ) );\n        } else {\n            component.set( 'v.scheduleSelectionsDayOfWeek', [] );\n        }\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    handleSourceTypeChange : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var sourceType = component.get( 'v.sourceType' );\n        var record = component.get( 'v.record' );\n\n        if ( sourceType != 'Report' ) {\n\n            record.sourceReportID = null;\n            record.sourceReportColumnName = null;\n\n            component.set( 'v.sourceReport', null );\n            component.set( 'v.sourceReportId', null );\n            component.set( 'v.sourceReportFolderId', null );\n            component.set( 'v.sourceReportColumns', null );\n            component.set( 'v.sourceReportColumnName', null );\n\n        } else {\n\n            if ( helper.isEmpty( component.get( 'v.sourceReportFolders' ) ) ) {\n\n                promises.push( helper.getReportFoldersAsync( component )\n                    .then( $A.getCallback( function( reportFolders ) {\n\n                        component.set( 'v.sourceReportFolders', reportFolders );\n                        helper.handleSourceReportFolderChange( component );\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Report Folders', err, 'error' );\n\n                    }))\n                );\n\n            }\n\n        }\n\n        if ( sourceType != 'ListView' ) {\n\n            record.sourceListViewID = null;\n\n            component.set( 'v.sourceListView', null );\n            component.set( 'v.sourceListViewId', null );\n            component.set( 'v.sourceListViewSobjectType', null );\n\n        } else {\n\n            if ( helper.isEmpty( component.get( 'v.sourceListViewSobjectTypes' ) ) ) {\n\n                promises.push( helper.getObjectNamesWithListViewsAsync( component )\n                    .then( $A.getCallback( function( objectNames ) {\n\n                        component.set( 'v.sourceListViewSobjectTypes', objectNames );\n                        helper.handleSourceListViewSobjectTypeChange( component );\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Object Names', err, 'error' );\n\n                    }))\n                );\n\n            }\n\n        }\n\n        if ( sourceType != 'SOQL' ) {\n\n            record.sourceSoqlQuery = null;\n\n        }\n\n        component.set( 'v.record', record );\n        component.set( 'v.sourceTypeURL', null );\n\n        return Promise.all( promises );\n\n    },\n\n    handleSourceReportFolderChange : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var sourceType = component.get( 'v.sourceType' );\n        var report = component.get( 'v.sourceReport' );\n        var folderId = component.get( 'v.sourceReportFolderId' );\n\n        if ( sourceType == 'Report' ) {\n\n            var reportFolderId = report && report.OwnerId && report.OwnerId.substring( 0, 15 );\n            folderId = folderId && folderId.substring( 0, 15 );\n\n            if ( folderId != reportFolderId ) {\n\n                component.set( 'v.sourceReport', null );\n                component.set( 'v.sourceReportId', null );\n                component.set( 'v.sourceReportColumnName', null );\n                component.set( 'v.record.sourceReportID', null );\n                component.set( 'v.record.sourceReportColumnName', null );\n\n            }\n\n            promises.push( helper.getReportsByFolderAsync( component, folderId )\n                .then( $A.getCallback( function( reports ) {\n\n                    component.set( 'v.sourceReports', reports );\n                    return helper.handleSourceReportChange( component );\n\n                })).catch( $A.getCallback( function( err ) {\n\n                    helper.toastMessage( 'Error Getting Reports By Folder', err, 'error' );\n\n                }))\n            );\n\n        }\n\n        return Promise.all( promises );\n\n    },\n\n    handleSourceReportChange : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var sourceType = component.get( 'v.sourceType' );\n        var reportId = component.get( 'v.sourceReportId' );\n\n        if ( sourceType == 'Report' ) {\n\n            if ( helper.isEmpty( reportId ) ) {\n\n                component.set( 'v.sourceTypeURL', null );\n                component.set( 'v.sourceReport', null );\n                component.set( 'v.sourceReportColumns', null );\n                component.set( 'v.sourceReportColumnName', null );\n                component.set( 'v.record.sourceReportID', null );\n                component.set( 'v.record.sourceReportColumnName', null );\n\n            } else {\n\n                promises.push( helper.getReportAsync( component, reportId )\n                    .then( $A.getCallback( function( report ) {\n\n                        component.set( 'v.sourceTypeURL', '/lightning/r/Report/' + report.Id + '/view' );\n                        component.set( 'v.sourceReport', report );\n                        component.set( 'v.record.sourceReportID', ( report.Id && report.Id.substring( 0, 15 ) ) );\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Report', err, 'error' );\n\n                    }))\n                );\n\n                promises.push( helper.getReportColumnsAsync( component, reportId )\n                    .then( $A.getCallback( function( reportColumns ) {\n\n                        component.set( 'v.sourceReportColumns', reportColumns );\n\n                        var columnName = component.get( 'v.sourceReportColumnName' );\n                        var columnFound = false;\n\n                        for ( var i = 0; i < reportColumns.length; i++ ) {\n\n                            if ( reportColumns[i].value == columnName ) {\n                                columnFound = true;\n                                break;\n                            }\n                        }\n\n                        if ( !columnFound ) {\n                            component.set( 'v.sourceReportColumnName', null );\n                            component.set( 'v.record.sourceReportColumnName', null );\n                        } else {\n                            component.set( 'v.record.sourceReportColumnName', columnName );\n                        }\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting Report Columns', err, 'error' );\n\n                    }))\n                );\n\n            }\n\n        }\n\n        return Promise.all( promises );\n\n    },\n\n    handleSourceListViewSobjectTypeChange : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var sourceType = component.get( 'v.sourceType' );\n        var listView = component.get( 'v.sourceListView' );\n        var sobjectType = component.get( 'v.sourceListViewSobjectType' );\n\n        if ( sourceType == 'ListView' ) {\n\n            if ( !$A.util.isUndefinedOrNull( listView ) && listView.SobjectType != sobjectType ) {\n\n                component.set( 'v.sourceListViewId', null );\n                component.set( 'v.record.sourceListViewID', null );\n\n            }\n\n            promises.push( helper.getListViewsByObjectAsync( component, sobjectType )\n                .then( $A.getCallback( function( listViews ) {\n\n                    component.set( 'v.sourceListViews', listViews );\n                    return helper.handleSourceListViewChange( component );\n\n                })).catch( $A.getCallback( function( err ) {\n\n                    helper.toastMessage( 'Error Getting List Views By Object', err, 'error' );\n\n                }))\n            );\n\n        }\n\n        return Promise.all( promises );\n\n    },\n\n    handleSourceListViewChange : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var sourceType = component.get( 'v.sourceType' );\n        var listViewId = component.get( 'v.sourceListViewId' );\n\n        if ( sourceType == 'ListView' ) {\n\n            if ( helper.isEmpty( listViewId ) ) {\n\n                component.set( 'v.sourceTypeURL', null );\n                component.set( 'v.sourceListView', null );\n                component.set( 'v.record.sourceListViewID', null );\n\n            } else {\n\n                promises.push( helper.getListViewAsync( component, listViewId )\n                    .then( $A.getCallback( function( listView ) {\n\n                        component.set( 'v.sourceTypeURL', '/lightning/o/' + listView.SobjectType + '/list?filterName=' + listView.Id );\n                        component.set( 'v.sourceListView', listView );\n                        component.set( 'v.record.sourceListViewID', ( listView.Id && listView.Id.substring( 0, 15 ) ) );\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        helper.toastMessage( 'Error Getting List View', err, 'error' );\n\n                    }))\n                );\n\n            }\n\n        }\n\n        return Promise.all( promises );\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    handleTargetTypeChange : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var targetType = component.get( 'v.targetType' );\n        var targetApexType = component.get( 'v.targetApexType' );\n        var targetActionName = component.get( 'v.targetInvocableAction' );\n\n        var record = component.get( 'v.record' );\n\n        // if true then we need to display prompt to user\n        // to choose an object before we can show action options\n        var targetTypeRequiresSobject = false;\n        var targetTypeRequiresAction = false;\n\n        if ( helper.isEmpty( targetType ) || targetType == 'Workflow' ) {\n\n            targetTypeRequiresSobject = false;\n            targetTypeRequiresAction = false;\n\n            targetApexType = null;\n            targetActionName = null;\n\n            record.targetSobjectType = null;\n            record.targetApexScript = null;\n\n        } else if ( targetType == 'Flow' ) {\n\n            targetTypeRequiresSobject = false;\n            targetTypeRequiresAction = true;\n\n            targetApexType = null;\n            //targetActionName = null;\n\n            record.targetSobjectType = null;\n            record.targetApexScript = null;\n\n        } else if ( targetType == 'QuickAction' ) {\n\n            targetTypeRequiresSobject = true;\n            targetTypeRequiresAction = true;\n\n            targetApexType = null;\n            //targetActionName = null;\n\n            //record.targetSobjectType = null;\n            record.targetApexScript = null;\n\n        } else if ( targetType == 'EmailAlert' ) {\n\n            targetTypeRequiresSobject = true;\n            targetTypeRequiresAction = true;\n\n            targetApexType = null;\n            //targetActionName = null;\n\n            //record.targetSobjectType = null;\n            record.targetApexScript = null;\n\n        } else if ( targetType == 'Apex' ) {\n\n            targetTypeRequiresSobject = false;\n            targetTypeRequiresAction = true;\n\n            record.targetSobjectType = null;\n\n            if ( targetApexType === 'Invocable' ) {\n\n                targetTypeRequiresAction = true;\n                record.targetApexScript = null;\n\n            } else if ( targetApexType === 'Anonymous' ) {\n\n                targetTypeRequiresAction = false;\n                targetActionName = null;\n\n                // provide a template as convenience\n                if ( $A.util.isEmpty( record.targetApexScript ) ) {\n                    record.targetApexScript = (\n                        'void execute( List<Map<String, Object>> sourceRecordsBatch ) { \\n' +\n                        '    // your logic here \\n' +\n                        '} \\n'\n                    );\n                }\n\n            }\n\n        }\n\n        component.set( 'v.targetTypeRequiresSobject', targetTypeRequiresSobject );\n        component.set( 'v.targetTypeRequiresAction', targetTypeRequiresAction );\n        component.set( 'v.targetApexType', targetApexType );\n        component.set( 'v.targetInvocableAction', targetActionName );\n\n        record.targetActionName = targetActionName;\n        component.set( 'v.record', record );\n\n        promises.push( helper.renderTargetSobjectTypes( component ) );\n        promises.push( helper.renderTargetInvocableActions( component ) );\n\n        return Promise.all( promises );\n\n    },\n\n    /**\n     * Determines if conditions are satisfactory to fetch and render\n     * sobject options that have invocable actions. Designed to be called whenever\n     * the target type requires sobject input field changes and once conditions met then options appear.\n     */\n    renderTargetSobjectTypes : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var targetTypeRequiresSobject = component.get( 'v.targetTypeRequiresSobject' );\n\n        if ( targetTypeRequiresSobject === true ) {\n\n            var targetType = component.get( 'v.targetType' );\n\n            promises.push( helper.getObjectsWithInvocableActionsAsync( component, targetType )\n                .then( $A.getCallback( function( results ) {\n\n                    component.set( 'v.targetSobjectTypes', results );\n\n                }))\n            );\n\n        } else {\n\n            component.set( 'v.targetSobjectType', null );\n            component.set( 'v.targetSobjectTypes', null );\n\n        }\n\n        return Promise.all( promises );\n\n    },\n\n    /**\n     * Determines if conditions are satisfactory to fetch and render\n     * the target invocable action options. Designed to be called whenever\n     * the target input fields change and once conditions met then options appear.\n     */\n    renderTargetInvocableActions : function( component ) {\n\n        var helper = this;\n\n        var promises = [];\n\n        var targetType = component.get( 'v.targetType' );\n        var targetApexType = component.get( 'v.targetApexType' );\n        var targetTypeRequiresSobject = component.get( 'v.targetTypeRequiresSobject' );\n        var targetTypeRequiresAction = component.get( 'v.targetTypeRequiresAction' );\n        var targetSobjectType = component.get( 'v.targetSobjectType' );\n        var targetAction = component.get( 'v.targetInvocableAction' );\n\n        var isValidToRenderActions = true;\n\n        if ( helper.isEmpty( targetType ) ||\n             ( !targetTypeRequiresAction ) ||\n             ( targetTypeRequiresSobject && helper.isEmpty( targetSobjectType ) ) ||\n             ( targetType === 'Apex' && targetApexType !== 'Invocable' ) ) {\n\n            isValidToRenderActions = false;\n\n        }\n\n        if ( isValidToRenderActions ) {\n\n            promises.push( helper.getInvocableActionsAsync( component, targetType, ( targetSobjectType || '' ) )\n                .then( $A.getCallback( function( actions ) {\n\n                    component.set( 'v.targetInvocableActions', actions );\n\n                    // if currently selected target action is not in this list then clear the field\n                    var targetActionFound = actions.find( function( elmt ) { return elmt.value === targetAction; } );\n                    component.set( 'v.targetInvocableAction', ( targetActionFound && targetActionFound.value ) );\n\n                }))\n            );\n\n        } else {\n\n            component.set( 'v.targetInvocableActions', null );\n\n            // Don't clear selected target action here because of timing\n            // this would clear out the record's initial value on component init.\n            // Instead, we try to handle this in the controller function \"handleTargetTypeChange\"\n            //component.set( 'v.targetInvocableAction', null );\n\n        }\n\n        component.set( 'v.isValidToRenderTargetInvocableActions', isValidToRenderActions );\n\n        return Promise.all( promises );\n\n    },\n\n    renderTargetFieldMappingsAsync : function( component ) {\n\n        var helper = this;\n\n        var sourceType = component.get( 'v.sourceType' );\n        var sourceReportId = component.get( 'v.sourceReportId' );\n        var sourceListViewId = component.get( 'v.sourceListViewId' );\n        var sourceSoqlQuery = component.get( 'v.record.sourceSoqlQuery' )\n\n        var targetType = component.get( 'v.targetType' );\n        var targetAction = component.get( 'v.targetInvocableAction' );\n        var targetSobjectType = component.get( 'v.targetSobjectType' );\n\n        var sourceFields = []; // columns from source report or list view\n        var targetFields = []; // inputs from target action\n\n        // provide empty option for source field mapping\n        // so user can unmap a field without navigating away\n        sourceFields.push({\n            'label': '--None--',\n            'vaue': null\n        });\n\n        return Promise.resolve()\n            .then( $A.getCallback( function() {\n\n                if ( sourceType == 'Report' ) {\n\n                    component.set( 'v.sourceFieldsInputType', 'combobox' );\n\n                    return helper.getReportColumnsAsync( component, sourceReportId )\n                        .catch( $A.getCallback( function( err ) {\n                            return Promise.reject( 'Error getting report columns: ' + helper.unwrapAuraErrorMessage( err ) );\n                        }));\n\n                } else if ( sourceType == 'ListView' ) {\n\n                    component.set( 'v.sourceFieldsInputType', 'combobox' );\n\n                    return helper.getListViewColumnsAsync( component, sourceListViewId )\n                        .catch( $A.getCallback( function( err ) {\n                            return Promise.reject( 'Error getting list view columns: ' + helper.unwrapAuraErrorMessage( err ) );\n                        }));\n\n                } else if ( sourceType == 'SOQL' ) {\n\n                    component.set( 'v.sourceFieldsInputType', 'combobox' );\n\n                    return helper.getSoqlQueryColumnsAsync( component, sourceSoqlQuery )\n                        .catch( $A.getCallback( function( err ) {\n                            return Promise.reject( 'Error getting SOQL query columns: ' + helper.unwrapAuraErrorMessage( err ) );\n                        }));\n\n                } else if ( sourceType == 'Apex' ) {\n\n                    component.set( 'v.sourceFieldsInputType', 'text' );\n\n                    return null;\n\n                }\n\n            })).then( $A.getCallback( function( sourceFieldsResult ) {\n\n                if ( !$A.util.isEmpty( sourceFieldsResult ) ) {\n                    // performs in-place sort of array\n                    sourceFieldsResult.sort( function( first, second ) {\n                        return first.label.localeCompare( second.label );\n                    });\n                    sourceFields.push( ...sourceFieldsResult );\n                }\n\n            })).then( $A.getCallback( function() {\n\n                return helper.getInvocableActionInputsAsync( component, targetType, ( targetAction || '' ), ( targetSobjectType || '' ) );\n\n            })).then( $A.getCallback( function( targetFieldsResult ) {\n\n                if ( !$A.util.isEmpty( targetFieldsResult ) ) {\n                    // performs in-place sort of array\n                    targetFieldsResult.sort( function( first, second ) {\n                        return first.name.localeCompare( second.name );\n                    });\n                    targetFields.push( ...targetFieldsResult );\n                }\n\n            })).then( $A.getCallback( function() {\n\n                // target action types that we don't prompt user for to avoid confusion\n                var ignoreDataTypes = [ 'SOBJECT', 'BLOB' ];\n\n                var recordFieldMappings = component.get( 'v.record.fieldMappings' ); // what currently has been mapped in database\n                var targetFieldMappings = []; // what user will work with in UI to assign source fields to target fields\n\n                for ( var i = 0; i < targetFields.length; i++ ) {\n\n                    var targetField = targetFields[i];\n\n                    if ( !ignoreDataTypes.includes( targetField.dataType ) ) {\n\n                        var recordFieldMapping = { 'sourceFieldName' : null, 'targetFieldName' : null };\n\n                        // find existing mapping for this target field, if any exists\n                        for ( var j = 0; j < recordFieldMappings.length; j++ ) {\n                            if ( targetField.name == recordFieldMappings[j].targetFieldName ) {\n                                recordFieldMapping = recordFieldMappings[j];\n                                break;\n                            }\n                        }\n\n                        targetFieldMappings.push({\n                            'targetField' : targetField,\n                            'sourceFieldName' : recordFieldMapping.sourceFieldName\n                        });\n\n                    }\n\n                }\n\n                component.set( 'v.sourceFields', sourceFields );\n                component.set( 'v.targetFields', targetFields );\n                component.set( 'v.targetFieldMappings', targetFieldMappings );\n\n            }));\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    /**\n     * Given an array of aura components representing inputs (have a v.value attribute)\n     * then returns a validation result object with any errors for each component.\n     */\n    validateInputsAsync : function( component, inputCmps ) {\n\n        var helper = this;\n\n        var sourceType = component.get( 'v.sourceType' );\n        var sourceTypeIsReport = ( sourceType === 'Report' );\n        var sourceTypeIsListView = ( sourceType === 'ListView' );\n        var sourceTypeIsSoqlQuery = ( sourceType === 'SOQL' );\n        var sourceTypeIsApex = ( sourceType === 'Apex' );\n\n        var targetType = component.get( 'v.targetType' );\n        var targetTypeIsFlows = ( targetType === 'Flow' );\n        var targetTypeIsWorkflows = ( targetType === 'Workflow' );\n        var targetTypeIsQuickActions = ( targetType === 'QuickAction' );\n        var targetTypeIsEmailAlerts = ( targetType === 'EmailAlert' );\n        var targetTypeIsApex = ( targetType === 'Apex' );\n\n        var targetApexType = component.get( 'v.targetApexType' );\n        var targetApexTypeIsInvocable = ( targetApexType === 'Invocable' );\n        var targetApexTypeIsAnonymous = ( targetApexType === 'Anonymous' );\n\n        var targetTypeRequiresSobject = component.get( 'v.targetTypeRequiresSobject' );\n        var targetTypeRequiresAction = component.get( 'v.targetTypeRequiresAction' );\n\n        var scheduleFrequency = component.get( 'v.scheduleSelectionsFrequency' );\n        var scheduleFrequenceIsScheduled = ( scheduleFrequency == 'Scheduled' || ( !$A.util.isUndefinedOrNull( scheduleFrequency ) && scheduleFrequency.length && scheduleFrequency[0] == 'Scheduled' ) );\n        var scheduleFrequenceIsCustom = ( scheduleFrequency == 'Custom' || ( !$A.util.isUndefinedOrNull( scheduleFrequency ) && scheduleFrequency.length && scheduleFrequency[0] == 'Custom' ) );\n\n        var inputScheduleWeekdayIsEmpty = helper.isEmpty( component.get( 'v.scheduleSelectionsDayOfWeek' ) );\n        var inputScheduleDayOfMonthIsEmpty = helper.isEmpty( component.get( 'v.scheduleSelectionsDayOfMonth' ) );\n\n        var objectDescribe = component.get( 'v.objectDescribe' );\n\n        return Promise.all( inputCmps.map( function( inputCmp ) {\n\n            var validationComponentResult = {\n                hasError : false,\n                message : null,\n                component : inputCmp\n            };\n\n            var inputValidityAsync = Promise.resolve( validationComponentResult );\n\n            if ( !$A.util.isUndefinedOrNull( inputCmp ) ) {\n\n                var inputLabel = inputCmp.get( 'v.label' );\n                var inputValue = inputCmp.get( 'v.value' );\n\n                var inputIsEmpty = helper.isEmpty( inputValue );\n                var inputIsInvalid = !inputCmp.checkValidity();\n\n                // populate a default error message,\n                // but don't assign to the validation component result\n                // unless we indeed determine the input component is invalid\n                var messageWhenValueMissing = inputLabel + ' is required.';\n\n                switch ( inputCmp.getLocalId() ) {\n\n                    // Details\n\n                    case 'inputName':\n                    case 'inputDeveloperName':\n                    case 'inputBatchSize':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( inputIsEmpty || inputIsInvalid ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Source\n\n                    case 'inputSourceType':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( inputIsEmpty || inputIsInvalid ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Source: Report\n\n                    case 'inputSourceReportFolder':\n                    case 'inputSourceReport':\n                    case 'inputSourceReportColumn':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( sourceTypeIsReport && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Source: List View\n\n                    case 'inputSourceListViewSobjectType':\n                    case 'inputSourceListView':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( sourceTypeIsListView && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Source: SOQL Query\n\n                    case 'inputSourceSoqlQuery':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( sourceTypeIsSoqlQuery && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        }).then( $A.getCallback( function( inputValidity ) {\n                            // if we haven't already determined the field to be invalid\n                            // then perform more rigorous soql query validation\n                            if ( sourceTypeIsSoqlQuery && !inputValidity.invalid ) {\n                                return helper.validateSoqlQueryAsync( component, inputValue )\n                                    .then( $A.getCallback( function( validationResult ) {\n                                        return {\n                                            'invalid': !validationResult.valid,\n                                            'messageWhenInvalid': validationResult.message\n                                        };\n                                    }));\n                            }\n                            return inputValidity;\n                        }));\n                        break;\n\n                    // Source: Apex Class\n\n                    case 'inputSourceApexClass':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( sourceTypeIsApex && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Target\n\n                    case 'inputTargetType':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( inputIsEmpty || inputIsInvalid ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    case 'inputTargetSobjectType':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( targetTypeRequiresSobject && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    case 'inputTargetAction':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( targetTypeRequiresAction && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Target: Apex\n\n                    case 'inputTargetApexType':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( targetTypeIsApex && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    case 'inputTargetApexScript':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( targetTypeIsApex && targetApexTypeIsAnonymous && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Target: Field Mappings\n\n                    case 'inputMappingSourceFieldName':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( ( inputIsEmpty && inputCmp.get( 'v.required' ) ) || inputIsInvalid ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Schedule\n\n                    case 'inputScheduleFrequency':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( inputIsEmpty || inputIsInvalid ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    case 'inputScheduleHourOfDay':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( scheduleFrequenceIsScheduled && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    case 'inputScheduleWeekday':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( scheduleFrequenceIsScheduled && ( ( inputIsEmpty == inputScheduleDayOfMonthIsEmpty ) || inputIsInvalid ) ),\n                            'messageWhenInvalid': `Select options for either \"${objectDescribe.fields.Schedule_DayOfWeek__c.label}\" or \"${objectDescribe.fields.Schedule_DayOfMonth__c.label}\" but not both. Exactly one is required.`\n                        });\n                        break;\n\n                    case 'inputScheduleDayOfMonth':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( scheduleFrequenceIsScheduled && ( ( inputIsEmpty == inputScheduleWeekdayIsEmpty ) || inputIsInvalid ) ),\n                            'messageWhenInvalid': `Select options for either \"${objectDescribe.fields.Schedule_DayOfWeek__c.label}\" or \"${objectDescribe.fields.Schedule_DayOfMonth__c.label}\" but not both. Exactly one is required.`\n                        });\n                        break;\n\n                    case 'inputScheduleMonthOfYear':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( scheduleFrequenceIsScheduled && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    case 'inputScheduleCron':\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( scheduleFrequenceIsCustom && ( inputIsEmpty || inputIsInvalid ) ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                    // Default\n\n                    default:\n                        inputValidityAsync = Promise.resolve({\n                            'invalid': ( inputIsInvalid ),\n                            'messageWhenInvalid': messageWhenValueMissing\n                        });\n                        break;\n\n                }\n\n                return Promise.resolve( inputValidityAsync )\n                    .then( $A.getCallback( function( inputValidity ) {\n\n                        // Consider the input invalid based on either our custom logic above\n                        // or that the input component's natural validation (e.g. required=\"true\") is violated.\n                        validationComponentResult.hasError = inputValidity.invalid;\n                        validationComponentResult.messageWhenInvalid = inputValidity.messageWhenInvalid;\n\n                        return validationComponentResult;\n\n                    }));\n\n            } else {\n\n                return inputValidityAsync;\n\n            }\n\n        })).then( $A.getCallback( function( validationComponentResults ) {\n\n            var validationResult = {\n                hasErrors : false,\n                components : validationComponentResults\n            };\n\n            validationComponentResults.forEach( function( validationComponentResult, idx ) {\n                validationResult.hasErrors = ( validationResult.hasErrors || validationComponentResult.hasError );\n            });\n\n            return validationResult;\n\n        }));\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    saveRecordAsync : function( component ) {\n\n        var helper = this;\n        var record = component.get( 'v.record' );\n\n        // source\n        record.sourceType = component.get( 'v.sourceType' );\n        record.sourceReportID = component.get( 'v.sourceReportId' );\n        record.sourceReportColumnName = component.get( 'v.sourceReportColumnName' );\n        record.sourceListViewID = component.get( 'v.sourceListViewId' );\n\n        // target\n        record.targetType = component.get( 'v.targetType' );\n        record.targetSobjectType = component.get( 'v.targetSobjectType' );\n        record.targetActionName = component.get( 'v.targetInvocableAction' );\n\n        // schedule\n\n        /*\n            Unfortunately, the radioGroup component changes the value type to an array,\n            so even though my source value is a single string I need to check both data types\n            or introduce a shadow variable to bind to the radio group and use change events\n            to copy the newly selected value; neither of which I want to do.\n            https://org62.lightning.force.com/one/one.app#/sObject/0D50M00003LvvAqSAJ/view\n         */\n        var scheduleFrequency = component.get( 'v.scheduleSelectionsFrequency' );\n        var scheduleHourOfDay = component.get( 'v.scheduleSelectionsHourOfDay' );\n        var scheduleDayOfWeek = component.get( 'v.scheduleSelectionsDayOfWeek' );\n        var scheduleDayOfMonth = component.get( 'v.scheduleSelectionsDayOfMonth' );\n        var scheduleMonthOfYear = component.get( 'v.scheduleSelectionsMonthOfYear' );\n\n        record.scheduleFrequency = ( $A.util.isArray( scheduleFrequency ) ? ( scheduleFrequency.length > 0 ? scheduleFrequency[0] : null ) : scheduleFrequency );\n\n        // if manual then null the other schedule fields\n        // if scheduled then parse the schedule fields, null the cron field\n        // if custom then null the schedule fields except cron field\n\n        if ( record.scheduleFrequency == 'Manual' ) {\n\n            record.scheduleCron = null;\n            record.scheduleSecondOfMinute = null;\n            record.scheduleMinuteOfHour = null;\n            record.scheduleHourOfDay = null;\n            record.scheduleDayOfMonth = null;\n            record.scheduleMonthOfYear = null;\n            record.scheduleDayOfWeek = null;\n\n        }\n        else if ( record.scheduleFrequency == 'Scheduled' ) {\n\n            // parse the \"NN.\" from the values used for sorting then join them by commas.\n            // exactly one of dayOfMonth or dayOfWeek must be specified and the other must be '?'\n\n            record.scheduleCron = null;\n            record.scheduleSecondOfMinute = '0';\n            record.scheduleMinuteOfHour = '0';\n            record.scheduleHourOfDay = scheduleHourOfDay.map( function( hourOfDay ) { return hourOfDay.split('.')[1]; } ).join(',');\n            record.scheduleDayOfMonth = scheduleDayOfMonth.map( function( dayOfMonth ) { return dayOfMonth.split('.')[1]; } ).join(',') || '?';\n            record.scheduleMonthOfYear = scheduleMonthOfYear.map( function( monthOfYear ) { return monthOfYear.split('.')[1]; } ).join(',');\n            record.scheduleDayOfWeek = scheduleDayOfWeek.map( function( dayOfWeek ) { return dayOfWeek.split('.')[1]; } ).join(',') || '?';\n\n        }\n        else if ( record.scheduleFrequency == 'Custom' ) {\n\n            record.scheduleSecondOfMinute = null;\n            record.scheduleMinuteOfHour = null;\n            record.scheduleHourOfDay = null;\n            record.scheduleDayOfMonth = null;\n            record.scheduleMonthOfYear = null;\n            record.scheduleDayOfWeek = null;\n\n        }\n\n        // because source fields can be mapped to multiple target fields\n        // but a target field can only have one mapping then we build up a map\n        // of target fields to their source field\n        var targetFieldMappings = {};\n        component.get( 'v.targetFieldMappings' ).forEach( function( item ) {\n            targetFieldMappings[item.targetField.name] = item.sourceFieldName;\n        });\n\n        /*\n         * https://success.salesforce.com/issues_view?id=a1p30000000SyhIAAS\n         * Due to known issue that execution contexts started from Apex REST endpoints\n         * cannot schedule or abort jobs, then my first workaround attempt was\n         * to modify the trigger to emit a platform event to get into a different\n         * context. However, platform events run as the \"Automated Process\" user.\n         * That wouldn't normally be a problem except when our jobs run they make\n         * API callouts using the either a Named Credential or the user's Session ID.\n         * If the configuration record doesn't use Named Credentials (one of the major\n         * features of Version 2.0), then the \"Automated Process\" user's session id is null\n         * and the http callout fails. Womp womp.\n         *\n         * Therefore, for saving the configuration record, instead of going through\n         * the Apex REST API and instead of the trigger emitting a platform event,\n         * this method goes through normal AuraEnabled apex method and the trigger\n         * schedules and aborts the job synchronously. This ensures the job itself\n         * runs as a real user with a valid session id.\n         */\n\n        // return helper.enqueueRestRequest( component, 'saveConfiguration', {\n        //     'wrapperJson' : record,\n        //     'fieldMappingsJson' : targetFieldMappings\n        // });\n        return helper.enqueueAction( component, 'c.saveConfiguration', {\n            'wrapperJson' : JSON.stringify( record ),\n            'fieldMappingsJson' : JSON.stringify( targetFieldMappings )\n        });\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    getObjectDescribeAsync : function( component ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getConfigurationObjectDescribe', {\n        });\n\n    },\n\n    getRecordAsync : function( component, recordId ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getConfiguration', {\n            'recordId' : recordId\n        });\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    getObjectNamesAsync : function( component ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getObjectNames', {\n        });\n\n    },\n\n    getObjectNamesWithListViewsAsync : function( component ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getObjectNamesWithListViews', {\n        });\n\n    },\n\n    getListViewsByObjectAsync : function( component, objectName ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getListViewsByObject', {\n            'objectName' : objectName\n        });\n\n    },\n\n    getListViewAsync : function( component, listViewId ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getListView', {\n            'recordId' : listViewId\n        });\n\n    },\n\n    getListViewColumnsAsync : function( component, listViewId ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getListViewColumns', {\n            'listViewId' : listViewId\n        });\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    getReportFoldersAsync : function( component ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getReportFolders', {\n        });\n\n    },\n\n    getReportsByFolderAsync : function( component, folderId ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getReportsByFolder', {\n            'folderId' : folderId\n        });\n\n    },\n\n    getReportAsync : function( component, reportId ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getReport', {\n            'recordId' : reportId\n        });\n\n    },\n\n    getReportColumnsAsync : function( component, reportId ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getReportColumns', {\n            'reportId' : reportId\n        });\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    validateSoqlQueryAsync : function( component, query ) {\n\n        // This used to make async calls, but it doesn't anymore.\n        // I've kept the method name, signature and response\n        // the same so as to minimize impact to other parts of the\n        // codebase and because this might become async in the future...\n\n        var helper = this;\n\n        return Promise.resolve()\n            .then( $A.getCallback( function() {\n\n                if ( helper.isEmpty( query ) ) {\n\n                    return {\n                        'valid': false,\n                        'message': 'SOQL Query is required.'\n                    };\n\n                } else {\n\n                    // Originally, I used third-party soql-parse library\n                    // to parse the query to know things like what the\n                    // SELECT clause was, and aliases of functions, etc.\n                    // However, the parser was not complete and the effort\n                    // to make a fully compliant SOQL parser is out of scope\n                    // for Mass Action Scheduler. Therefore, my approach now\n                    // is to brute force inspect the query for simple patterns\n                    // so that I can deduce what fields are being selected.\n                    // Whether the query is valid is another story; we'll find\n                    // out soon enough once the configuration runs :)\n\n                    // ================================================================= //\n                    // Caution with Regular Expressions with asterisks followed by /     //\n                    // https://twitter.com/DouglasCAyers/status/1147002313158090752      //\n                    // ================================================================= //\n\n                    // normalize the spaces in the query string (e.g. no new lines or tabs)\n                    // and uppercase the string so that we can be case-insensitive in our checks\n                    let trimmedQuery = (\n                        query                                   // original query\n                        .replace( /(\\s*(\\W+)\\s*)/g, ' $2 ' )    // include one whitespace around non-words e.g. \"(SELECT\" => \" ( SELECT\"\n                        .replace( /\\s+/g, ' ' )                 // remove new lines, redundant whitespace\n                        .trim()                                 // trim whitespace from start/end of query\n                        .toUpperCase()                          // uppercase everything so we're case-insensitive\n                    );\n\n                    // SOQL queries must start with SELECT, quick check this isn't a SOSL query\n                    if ( !trimmedQuery.startsWith( 'SELECT ' ) ) {\n                        return {\n                            'valid': false,\n                            'message': 'SOQL Query must start with a SELECT clause.'\n                        };\n                    }\n\n                    let indexOfFromClause = trimmedQuery.indexOf( ' FROM ' );\n\n                    // Make sure there's a FROM clause because\n                    // the real validation is going to be inspecting\n                    // the text between the SELECT and FROM statements\n                    if ( indexOfFromClause < 0 ) {\n                        return {\n                            'valid': false,\n                            'message': 'SOQL Query must include a FROM clause.'\n                        };\n                    }\n\n                    // At this point we know we have both keywords \"SELECT\" and \"FROM\" in our query string\n                    // so now let's grab what's between them to determine what fields were selected\n                    let selectClause = trimmedQuery.substring( 'SELECT '.length, indexOfFromClause );\n\n                    // SOQL allows child relationship sub-queries in the SELECT clause.\n                    // Mass Action Scheduler doesn't support this, and it makes this brute\n                    // force parsing of the query to determine the actual selected fields.\n                    // Therefore, we don't support sub-queries in the SELECT clause.\n                    if ( selectClause.includes( ' SELECT ' ) ) {\n                        return {\n                            'valid': false,\n                            'message': 'Parent-to-child relationship subqueries are not supported.'\n                        };\n                    }\n\n                    // Given we have what we need, let's determine the selected fields.\n                    let selectedFields = (\n                        selectClause\n                        .split( ',' )\n                        .filter( field => {\n                            // exclude non-aliased functions\n                            return !( /\\)\\s*$/.test( field ) )\n                        })\n                        .map( field => {\n                            return (\n                                field.includes( ')' ) ?                             // is function alias?\n                                field.substring( field.lastIndexOf( ')' ) + 1 ) :   // grab the alias\n                                field                                               // it's just a field\n                            ).replace( /\\s+/g, '' )                                 // remove all whitespace\n                        })\n\n                    );\n\n                    return {\n                        'valid': true,\n                        'selectedFields': selectedFields\n                    };\n\n                }\n\n            }));\n\n    },\n\n    getSoqlQueryResultsAsync : function( component, query, batchSize ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getSoqlQueryResults', {\n            'query' : query,\n            'batchSize' : batchSize\n        });\n\n    },\n\n    getSoqlQueryColumnsAsync : function( component, soqlQuery ) {\n\n        var helper = this;\n\n        return Promise.resolve()\n            .then( $A.getCallback( function() {\n\n                return helper.validateSoqlQueryAsync( component, soqlQuery )\n                    .then( $A.getCallback( function( validationResult ) {\n\n                        if ( validationResult.valid ) {\n\n                            return validationResult.selectedFields.map( fieldName => {\n                                return {\n                                    'label': fieldName,\n                                    'value': fieldName\n                                }\n                            });\n\n                        } else {\n\n                            return Promise.reject( validationResult.message );\n\n                        }\n\n                    })).catch( $A.getCallback( function( err ) {\n\n                        return Promise.reject( 'Error validating SOQL query: ' + helper.unwrapAuraErrorMessage( err ) );\n\n                    }));\n\n            }));\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    getNamedCredentialsAsync : function( component ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getNamedCredentials', {\n        });\n\n    },\n\n    getObjectsWithInvocableActionsAsync : function( component, actionType ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getObjectsWithInvocableActions', {\n            'actionType' : actionType\n        });\n\n    },\n\n    getInvocableActionsAsync : function( component, actionType, objectName ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getInvocableActions', {\n            'actionType' : actionType,\n            'objectName' : objectName\n        });\n\n    },\n\n    getInvocableActionInputsAsync : function( component, actionType, actionName, objectName ) {\n\n        var helper = this;\n\n        return helper.enqueueRestRequest( component, 'getInvocableActionInputs', {\n            'actionType' : actionType,\n            'actionName' : actionName,\n            'objectName' : objectName\n        });\n\n    },\n\n    // ----------------------------------------------------------------------------------\n\n    /**\n     * The $A.util.isEmpty() function does not check for blank strings (only whitespace).\n     * This method trims string arguments first so '   ' is considered empty.\n     */\n    isEmpty : function( value ) {\n        if ( ( typeof value ).toLowerCase() === 'string' ) {\n            return $A.util.isEmpty( value.trim() );\n        } else {\n            return $A.util.isEmpty( value );\n        }\n    },\n\n    showSpinner : function( component ) {\n\n        $A.util.removeClass( component.find( 'spinner' ), 'slds-hide' );\n\n        // Minimize flickering of the spinner hiding/showing\n        // quickly in succession of multiple async events.\n        // As you'd do with a type-ahead widget, when an async event\n        // starts and the spinner is shown then clear the timeout\n        // that would hide the spinner. This avoids the flickering.\n        // When the async event ends, it'll call hide spinner again\n        // which will start a new timer.\n        let spinnerTimerIds = component.get( 'v.spinnerTimerIds' );\n        spinnerTimerIds.forEach( ( spinnerTimerId ) => clearTimeout( spinnerTimerId ) );\n        component.set( 'v.spinnerTimerIds', [] );\n\n    },\n\n    hideSpinner : function( component ) {\n\n        // see comments in `showSpinner` about minimizing flickering\n        let spinnerTimerId = setTimeout(\n            $A.getCallback( function() {\n                $A.util.addClass( component.find( 'spinner' ), 'slds-hide' );\n            }),\n            250\n        );\n\n        let spinnerTimerIds = component.get( 'v.spinnerTimerIds' );\n        spinnerTimerIds.push( spinnerTimerId );\n        component.set( 'v.spinnerTimerIds', spinnerTimerIds );\n\n    },\n\n    toastMessage : function( title, message, type ) {\n\n        // https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/ref_force_showToast.htm\n\n        var helper = this;\n\n        // convenience so code can toast errors without\n        // themselves figuring out how to get the real message from them\n        if ( message instanceof Error ) {\n            message = helper.unwrapAuraErrorMessage( message );\n        }\n\n        $A.get( 'e.force:showToast' ).setParams({\n            title : ( title || 'Message' ),\n            message : ( message || '' ),\n            type : ( type || 'info' )\n        }).fire();\n\n    },\n\n    navigateToRecord : function( recordId ) {\n\n        var event = $A.get( 'e.force:navigateToSObject' );\n\n        if ( event ) {\n\n            event.setParams({\n                'recordId' : recordId\n            }).fire();\n\n        } else if ( ( typeof sforce !== 'undefined' ) && ( typeof sforce.one !== 'undefined' ) ) {\n\n            sforce.one.navigateToSObject( recordId );\n\n        } else {\n\n            window.location.href = '/' + recordId;\n\n        }\n\n    },\n\n    navigateToURL : function( url ) {\n\n        var event = $A.get( 'e.force:navigateToURL' );\n\n        if ( event ) {\n\n            event.setParams({\n                'url' : url\n            }).fire();\n\n        } else if ( ( typeof sforce !== 'undefined' ) && ( typeof sforce.one !== 'undefined' ) ) {\n\n            sforce.one.navigateToURL( url );\n\n        } else {\n\n            window.location.href = url;\n\n        }\n\n    },\n\n    /**\n     * For posting REST request to the MA_EditConfigRestController apex class.\n     *\n     * @param component\n     *      The Lightning component with a 'urlInfo' and 'lc_api' attributes.\n     *      'urlInfo' is used to generate the REST API URL.\n     *      'lc_api' is used to invoke the REST API as workaround to Lightning session ids.\n     * @param operation\n     *      Name of the actual action to invoke in the REST controller.\n     * @param params\n     *      Parameters to pass to the actual action to invoke.\n     * @returns a promise.\n     */\n    enqueueRestRequest : function( component, operation, params ) {\n\n        var helper = this;\n\n        helper.showSpinner( component );\n\n        return Promise.resolve()\n            .then( $A.getCallback( function() {\n\n                // return cached value if we've retrieved it before,\n                // otherwise fetch the url info as a promise\n                var urlInfo = component.get( 'v.urlInfo' );\n\n                if ( helper.isEmpty( urlInfo ) ) {\n                    return component.find( 'lc_url' ).getUrlInfo();\n                } else {\n                    return urlInfo;\n                }\n\n            })).then( $A.getCallback( function( urlInfo ) {\n\n                component.set( 'v.urlInfo', urlInfo );\n\n                var nsslash = ( urlInfo.namespace ? urlInfo.namespace + '/' : '' );\n\n                return component.find( 'lc_api' ).restRequest({\n                    'url' : urlInfo.orgDomainURL + '/services/apexrest/' + nsslash + 'config/edit?operation=' + operation,\n                    'method' : 'POST',\n                    'body' : JSON.stringify( ( params || {} ) )\n                });\n\n            })).then( $A.getCallback( function( response ) {\n\n                helper.hideSpinner( component );\n                if ( response.success ) {\n                    return response.result;\n                } else {\n                    return Promise.reject( response.error );\n                }\n\n            })).catch( $A.getCallback( function( err ) {\n\n                helper.hideSpinner( component );\n                console.error( 'Error enqueuing rest request: ' + JSON.stringify({\n                    'operation' : operation,\n                    'params' : params,\n                    'error' : err.message\n                }, null, 2));\n                throw err;\n\n            }));\n\n    },\n\n    /**\n     * For invoking @AuraEnabled apex actions in a normal\n     * Lightning component fashion.\n     *\n     * @param component\n     *      The Lightning component that specifies the Apex controller\n     *      of the @AuraEnabled method to invoke.\n     * @param actionName\n     *      The @AuraEnabled method name.\n     * @param params\n     *      The @AuraEnabled method parameters.\n     * @returns a promise.\n     */\n    enqueueAction : function( component, actionName, params ) {\n\n        var helper = this;\n\n        var p = new Promise( $A.getCallback( function( resolve, reject ) {\n\n            helper.showSpinner( component );\n\n            var action = component.get( actionName );\n\n            if ( params ) {\n                action.setParams( params );\n            }\n\n            action.setCallback( helper, function( response ) {\n\n                helper.hideSpinner( component );\n\n                if ( component.isValid() && response.getState() === 'SUCCESS' ) {\n\n                    resolve( response.getReturnValue() );\n\n                } else {\n\n                    console.error( 'Error calling action \"' + actionName + '\" with state: ' + response.getState() );\n\n                    helper.logActionErrors( response.getError() );\n\n                    reject( helper.getMessageFromActionResponseError( response.getError() ) );\n\n                }\n            });\n\n            $A.enqueueAction( action );\n\n        }));\n\n        return p;\n    },\n\n    logActionErrors : function( errors ) {\n        if ( errors ) {\n            if ( errors.length > 0 ) {\n                for ( var i = 0; i < errors.length; i++ ) {\n                    console.error( 'Error: ' + errors[i].message );\n                }\n            } else {\n                console.error( 'Error: ' + ( errors.message || errors ) );\n            }\n        } else {\n            console.error( 'Unknown error' );\n        }\n    },\n\n    getMessageFromActionResponseError : function( errors ) {\n        var text = '';\n        if ( errors ) {\n            if ( errors.length > 0 ) {\n                for ( var i = 0; i < errors.length; i++ ) {\n                    text += '\\n' + errors[i].message;\n                }\n            } else {\n                text = ( errors.message || errors );\n            }\n        }\n        return text;\n    },\n\n    /**\n     * When using $A.getCallback() function, if an error is thrown\n     * then it wraps the error in an AuraError. The AuraError, unfortunately,\n     * has a new message property whose value is \"Error in $A.getCallback[YOUR_ORIGINAL_ERROR_MESSAGE]\".\n     * The only way to obtain YOUR_ORIGINAL_ERROR_MESSAGE is to substring\n     * the AuraError text out of its message.\n     */\n    unwrapAuraErrorMessage : function( err ) {\n\n        var message = err.message;\n\n        var startStr = 'Error in $A.getCallback() [';\n        var endStr = ']';\n\n        var startIdx = err.message.indexOf( startStr );\n        var endIdx = err.message.lastIndexOf( endStr );\n\n        if ( startIdx >= 0 && endIdx >= 0 ) {\n            message = err.message.substring( startIdx + startStr.length, endIdx );\n        }\n\n        return message;\n    }\n})\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/MA_FlowStagePathCmp/MA_FlowStagePathCmp.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<!--\nhttps://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_config_for_flow_screens_stages.htm\n-->\n<aura:component implements=\"lightning:availableForFlowScreens\" access=\"global\">\n\n    <!-- Attributes that store $Flow.ActiveStages and $Flow.CurrentStage -->\n    <aura:attribute name=\"stages\" type=\"String[]\" description=\"The path steps to show\" required=\"true\"/>\n    <aura:attribute name=\"currentStage\" type=\"String\" description=\"The path step to highlight\" required=\"true\"/>\n\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.init}\" />\n\n    <div class=\"slds-p-bottom_small\">\n        <lightning:progressIndicator aura:id=\"progressIndicator\" currentStep=\"{!v.currentStage}\" type=\"path\" />\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_FlowStagePathCmp/MA_FlowStagePathCmp.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>MA_FlowStagePathCmp</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/MA_FlowStagePathCmp/MA_FlowStagePathCmp.design",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<design:component label=\"MAS: Flow Stage Path\">\n\n    <design:attribute name=\"stages\" label=\"Stages\" description=\"List of stages to display in the path.\"/>\n\n    <design:attribute name=\"currentStage\" label=\"Current Stage\" description=\"Which stage to highlight as current position.\"/>\n\n</design:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_FlowStagePathCmp/MA_FlowStagePathCmpController.js",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n*/\n({\n    init : function( component, event, helper ) {\n        var progressIndicator = component.find( 'progressIndicator' );\n        for ( let step of component.get( 'v.stages' ) ) {\n            $A.createComponent(\n                'lightning:progressStep',\n                {\n                    'aura:id': 'step_' + step,\n                    label: step,\n                    value: step\n                },\n                function( newProgressStep, status, errorMessage ) {\n                    // Add the new step to the progress array\n                    if ( status === 'SUCCESS' ) {\n                        var body = progressIndicator.get( 'v.body' );\n                        body.push( newProgressStep );\n                        progressIndicator.set( 'v.body', body );\n                    } else if ( status === 'INCOMPLETE' ) {\n                        console.error( 'No response from server, or client is offline.' );\n                    } else if ( status === 'ERROR' ) {\n                        console.error( 'Error: ' + errorMessage );\n                    }\n                }\n            );\n        }\n    }\n});\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/MA_RunConfigCmp/MA_RunConfigCmp.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<aura:component controller=\"MA_RunConfigCmpController\" implements=\"force:lightningQuickActionWithoutHeader,force:hasRecordId\" access=\"global\">\n\n    <!-- Attributes -->\n\n    <aura:attribute name=\"recordId\"\n                    type=\"String\"\n                    description=\"The ID of the record to be displayed. Provided by force:hasRecordId interface.\"/>\n\n    <aura:attribute name=\"record\"\n                    type=\"Mass_Action_Configuration__c\"/>\n\n    <!-- Events -->\n\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.onInit}\"/>\n\n    <!-- Markup -->\n\n    <lightning:card title=\"Run Mass Action Now?\">\n\n        <aura:set attribute=\"footer\">\n\n            <lightning:button label=\"Cancel\"\n                              variant=\"neutral\"\n                              onclick=\"{!c.handleCancelButtonClick}\"/>\n\n            <lightning:button label=\"Run\"\n                              variant=\"brand\"\n                              disabled=\"{!not(v.record.active)}\"\n                              onclick=\"{!c.handleRunButtonClick}\"/>\n\n        </aura:set>\n\n        <aura:set attribute=\"actions\">\n\n        </aura:set>\n\n        <p class=\"slds-var-p-around_small\">\n            Submits background batch job that invokes the target action on the source records.\n        </p>\n\n        <aura:if isTrue=\"{!and(not(empty(v.record)), not(v.record.active))}\">\n            <div class=\"slds-notify slds-notify_alert slds-theme_warning\" role=\"alert\">\n                <div>\n                    <p>This Mass Action can't be run because it is inactive.</p>\n                    <p>To run, activate this Mass Action then try again.</p>\n                </div>\n            </div>\n        </aura:if>\n\n    </lightning:card>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_RunConfigCmp/MA_RunConfigCmp.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>MA_RunConfigCmp</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/MA_RunConfigCmp/MA_RunConfigCmpController.js",
    "content": "({\n    onInit : function( component, event, helper ) {\n\n        helper.enqueueAction( component, 'c.getConfiguration', {\n\n            'recordId' : component.get( 'v.recordId' )\n\n        }).then( $A.getCallback( function( record ) {\n\n            component.set( 'v.record', record );\n\n        }));\n\n    },\n\n    handleRunButtonClick : function( component, event, helper ) {\n\n        helper.enqueueAction( component, 'c.enqueueAction', {\n\n            'configId' : component.get( 'v.recordId' )\n\n        }).then( $A.getCallback( function( result ) {\n\n            if ( result.success ) {\n                helper.toastMessage( 'Job Submitted', result.jobId, 'success' );\n            } else {\n                helper.toastMessage( 'Error', result.message, 'error' );\n            }\n\n            $A.get( 'e.force:closeQuickAction' ).fire();\n\n        }));\n\n    },\n\n    handleCancelButtonClick : function( component, event, helper ) {\n\n        $A.get( 'e.force:closeQuickAction' ).fire();\n\n    }\n})"
  },
  {
    "path": "force-app/main/default/aura/MA_RunConfigCmp/MA_RunConfigCmpHelper.js",
    "content": "({\n    // -----------------------------------------------------------------\n\n    showSpinner : function( component ) {\n\n        $A.util.removeClass( component.find( 'spinner' ), 'slds-hide' );\n\n    },\n\n    hideSpinner : function( component ) {\n\n        $A.util.addClass( component.find( 'spinner' ), 'slds-hide' );\n\n    },\n\n    toastMessage : function( title, message, type ) {\n\n        // https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/ref_force_showToast.htm\n\n        var helper = this;\n\n        // convenience so code can toast errors without\n        // themselves figuring out how to get the real message from them\n        if ( message instanceof Error ) {\n            message = helper.unwrapAuraErrorMessage( message );\n        }\n\n        $A.get( 'e.force:showToast' ).setParams({\n            title : ( title || 'Message' ),\n            message : ( message || '' ),\n            type : ( type || 'info' )\n        }).fire();\n\n    },\n\n    navigateToRecord : function( recordId ) {\n\n        var event = $A.get( 'e.force:navigateToSObject' );\n\n        if ( event ) {\n\n            event.setParams({\n                'recordId' : recordId\n            }).fire();\n\n        } else if ( ( typeof sforce !== 'undefined' ) && ( typeof sforce.one !== 'undefined' ) ) {\n\n            sforce.one.navigateToSObject( recordId );\n\n        } else {\n\n            window.location.href = '/' + recordId;\n\n        }\n\n    },\n\n    navigateToURL : function( url ) {\n\n        var event = $A.get( 'e.force:navigateToURL' );\n\n        if ( event ) {\n\n            event.setParams({\n                'url' : url\n            }).fire();\n\n        } else if ( ( typeof sforce !== 'undefined' ) && ( typeof sforce.one !== 'undefined' ) ) {\n\n            sforce.one.navigateToURL( url );\n\n        } else {\n\n            window.location.href = url;\n\n        }\n\n    },\n\n    /**\n     * For invoking @AuraEnabled apex actions in a normal\n     * Lightning component fashion.\n     *\n     * @param component\n     *      The Lightning component that specifies the Apex controller\n     *      of the @AuraEnabled method to invoke.\n     * @param actionName\n     *      The @AuraEnabled method name.\n     * @param params\n     *      The @AuraEnabled method parameters.\n     * @returns a promise.\n     */\n    enqueueAction : function( component, actionName, params ) {\n\n        var helper = this;\n\n        var p = new Promise( $A.getCallback( function( resolve, reject ) {\n\n            helper.showSpinner( component );\n\n            var action = component.get( actionName );\n\n            if ( params ) {\n                action.setParams( params );\n            }\n\n            action.setCallback( helper, function( response ) {\n\n                helper.hideSpinner( component );\n\n                if ( component.isValid() && response.getState() === 'SUCCESS' ) {\n\n                    resolve( response.getReturnValue() );\n\n                } else {\n\n                    console.error( 'Error calling action \"' + actionName + '\" with state: ' + response.getState() );\n\n                    helper.logActionErrors( response.getError() );\n\n                    reject( helper.getMessageFromActionResponseError( response.getError() ) );\n\n                }\n            });\n\n            $A.enqueueAction( action );\n\n        }));\n\n        return p;\n    },\n\n    logActionErrors : function( errors ) {\n        if ( errors ) {\n            if ( errors.length > 0 ) {\n                for ( var i = 0; i < errors.length; i++ ) {\n                    console.error( 'Error: ' + errors[i].message );\n                }\n            } else {\n                console.error( 'Error: ' + ( errors.message || errors ) );\n            }\n        } else {\n            console.error( 'Unknown error' );\n        }\n    },\n\n    getMessageFromActionResponseError : function( errors ) {\n        var text = '';\n        if ( errors ) {\n            if ( errors.length > 0 ) {\n                for ( var i = 0; i < errors.length; i++ ) {\n                    text += '\\n' + errors[i].message;\n                }\n            } else {\n                text = ( errors.message || errors );\n            }\n        }\n        return text;\n    },\n\n    /**\n     * When using $A.getCallback() function, if an error is thrown\n     * then it wraps the error in an AuraError. The AuraError, unfortunately,\n     * has a new message property whose value is \"Error in $A.getCallback[YOUR_ORIGINAL_ERROR_MESSAGE]\".\n     * The only way to obtain YOUR_ORIGINAL_ERROR_MESSAGE is to substring\n     * the AuraError text out of its message.\n     */\n    unwrapAuraErrorMessage : function( err ) {\n\n        var message = err.message;\n\n        var startStr = 'Error in $A.getCallback() [';\n        var endStr = ']';\n\n        var startIdx = err.message.indexOf( startStr );\n        var endIdx = err.message.lastIndexOf( endStr );\n\n        if ( startIdx >= 0 && endIdx >= 0 ) {\n            message = err.message.substring( startIdx + startStr.length, endIdx );\n        }\n\n        return message;\n    }\n})"
  },
  {
    "path": "force-app/main/default/aura/MA_WizardCoachingCmp/MA_WizardCoachingCmp.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<aura:component>\n\n    <aura:attribute name=\"leftTitle\" type=\"String\"/>\n    <aura:attribute name=\"rightTitle\" type=\"String\"/>\n\n    <aura:attribute name=\"leftContent\" type=\"Aura.Component[]\"/>\n    <aura:attribute name=\"rightContent\" type=\"Aura.Component[]\"/>\n\n    <div class=\"slds-path__coach slds-grid slds-wrap slds-gutters\">\n\n        <div class=\"slds-col slds-size_1-of-1 slds-medium-size_1-of-2\">\n            <div class=\"slds-grid slds-grid_align-spread slds-path__coach-title\">\n                <h2>{!v.leftTitle}</h2>\n            </div>\n            <div class=\"slds-text-longform\">\n                {!v.leftContent}\n            </div>\n        </div>\n\n        <div class=\"slds-col slds-size_1-of-1 slds-medium-size_1-of-2 slds-border_left\">\n            <div class=\"slds-grid slds-grid_align-spread slds-path__coach-title\">\n                <h2>{!v.rightTitle}</h2>\n            </div>\n            <div class=\"slds-text-longform\">\n                {!v.rightContent}\n            </div>\n        </div>\n\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/MA_WizardCoachingCmp/MA_WizardCoachingCmp.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>MA_WizardCoachingCmp</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/defaultTokens/defaultTokens.tokens",
    "content": "<!--\nStrike by Appiphony\n\nVersion: 1.0.0\nWebsite: http://www.lightningstrike.io\nGitHub: https://github.com/appiphony/Strike-Components\nLicense: BSD 3-Clause License\n-->\n<aura:tokens extends=\"force:base\">\n    <aura:token name=\"fontSizeSmall\" value=\"0.75rem\"/>\n    <aura:token name=\"spacingXxLarge\" value=\"3rem\"/>\n    <aura:token name=\"fontSizeXxLarge\" value=\"1.75rem\"/>\n    <aura:token name=\"fontSizeXLarge\" value=\"1.25rem\"/>\n    <aura:token name=\"fontSizeXSmall\" value=\"0.625rem\"/>\n    <aura:token name=\"colorBorderInpuDisabled\" value=\"#a8b7c7\"/>\n    <aura:token name=\"fontSizeTextSmall\" value=\"0.8125rem\"/>\n    <aura:token name=\"colorBackgroundDestructive\" value=\"#c23934\"/>\n    <aura:token name=\"colorBackgroundDestructiveActive\" value=\"#870500\"/>\n    <aura:token name=\"colorBackgroundPathComplete\" value=\"#4bca81\"/>\n    <aura:token name=\"colorBackgroundPathCompleteHover\" value=\"rgba(4,132,75,.95)\"/>\n    <aura:token name=\"colorBorderInverse\" value=\"#061c3f\"/>\n    <aura:token name=\"fontSizeTextXxSmall\" value=\".625rem\"/>\n    <aura:token name=\"zIndexOverlay\" value=\"8000\"/>\n</aura:tokens>\n<!--\nCopyright 2017 Appiphony, LLC\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following\ndisclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\ndisclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote\nproducts derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/defaultTokens/defaultTokens.tokens-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>A Lightning Component Bundle</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/lax/lax.cmp",
    "content": "<!--\n    MIT License\n\n    Copyright (c) 2017 Ruslan Kurchenko\n\n    Permission is hereby granted, free of charge, to any person obtaining a copy\n    of this software and associated documentation files (the \"Software\"), to deal\n    in the Software without restriction, including without limitation the rights\n    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n    copies of the Software, and to permit persons to whom the Software is\n    furnished to do so, subject to the following conditions:\n\n    The above copyright notice and this permission notice shall be included in all\n    copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n    SOFTWARE.\n-->\n<aura:component>\n    <aura:attribute name=\"context\" type=\"Object\" required=\"true\" description=\"Consumer's component object\"/>\n    <aura:attribute name=\"attributeName\" type=\"String\" default=\"lax\" description=\"Controls dynamic attribute name generated on consumer's component object\"/>\n\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.onInit}\"/>\n</aura:component>"
  },
  {
    "path": "force-app/main/default/aura/lax/lax.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>lax</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/lax/laxController.js",
    "content": "/**\n * @license\n * MIT License\n * Copyright (c) 2017 Ruslan Kurchenko\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * The controller of Lax Aura Component\n * @namespace LaxController\n */\n// eslint-disable-next-line no-unused-expressions,strict\n({\n    /**\n     * Initialization function called every time Lax Aura Component instantiated\n     * @memberof LaxController#\n     * @param component {Object} - the lax component object\n     */\n    onInit: function onInit(component, event, helper) {\n      helper.init(component, event);\n    }\n  });"
  },
  {
    "path": "force-app/main/default/aura/lax/laxHelper.js",
    "content": "/**\n * @license\n * MIT License\n * Copyright (c) 2017 Ruslan Kurchenko\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * The controller of Lax Aura Component\n * @namespace LaxHelper\n */\n\n// eslint-disable-next-line no-unused-expressions,strict\n(\n    {\n    /**\n     * Initialization function called every time Lax Aura Component instantiated\n     * @memberof LaxHelper#\n     * @param component {Object} - the lax component object\n     */\n      init: function init(component) {\n        var helper = this,\n          contextComponent = component.get('v.context');\n  \n        var laxProps = {\n          _component: {\n            writable: false,\n            configurable: false,\n            enumerable: false,\n            value: contextComponent\n          }\n        };\n  \n        var laxPrototype = this.getLax(function(globalEventListeners) {\n          helper.initEventListeners(globalEventListeners, contextComponent, 'onLaxPrototypeInit');\n        });\n  \n        var localEventListeners = {};\n        helper.initEventListeners(localEventListeners, contextComponent, 'onLaxInit');\n  \n        // Create an object that is inherit all the functionality from\n        // the Lax object due to prototype inheritance\n        var lax = Object.create(laxPrototype, laxProps);\n  \n        lax.getEventListeners = function () {\n          return localEventListeners;\n        };\n  \n        // Create property on the context component object that is refer on\n        // newly created Lax object\n        var contextComponentAttribute = component.get('v.attributeName');\n        var componentProps = {\n          writable: false,\n          configurable: false,\n          enumerable: false,\n          value: lax\n        };\n        Object.defineProperty(contextComponent, contextComponentAttribute, componentProps);\n      },\n  \n      /**\n     * The function creates the Lax object and save it on the helper.\n     * Helpers of Aura components are static, it allows to share prototype\n     * Lax object on a helper instance.\n     * @memberOf LaxHelper#\n     * @returns {Lax}\n     */\n      getLax: function getLax(onInit) {\n        if (!this._lax) {\n          this._lax = this.createLax(onInit);\n        }\n  \n        return this._lax;\n      },\n  \n      /**\n     * Creates a prototype Lax object.\n     * The function calls when the first Lax component in the app instantiates.\n     * @memberOf LaxHelper#\n     * @returns {Lax}\n     */\n      createLax: function createLax(onInit) {\n        var helper = this;\n  \n        var errors = helper.defineErrors();\n        var eventListeners = {};\n  \n        /**\n       * Creates a unified function to be assign as a callback on the aura action.\n       * @param resolve {Function} the function called if the action is success\n       * @param reject {Function} the function called if the action is failed\n       * @returns {Function}\n       */\n        function actionRouter(resolve, reject, finallyCallback) {\n          var lax = this;\n  \n          return function (response) {\n            var state = response.getState(),\n              listOfListeners = [\n                laxPrototype.getEventListeners(), lax.getEventListeners()\n              ];\n  \n            if (state === 'SUCCESS') {\n              var resultValue = util\n                .getEventListenersByName(listOfListeners, 'apexAction.onSuccess')\n                .reduce(function (val, listener) {\n                  return listener(val);\n                }, response.getReturnValue());\n  \n              resolve(resultValue);\n            } else {\n              var message = 'Unknown error';\n  \n              var responseErrors = response.getError();\n              if (responseErrors && Array.isArray(responseErrors) && responseErrors.length > 0) {\n                message = responseErrors[0].message;\n              }\n  \n              var errorConstructor = state === 'INCOMPLETE' ? errors.IncompleteActionError : errors.ApexActionError;\n  \n              var err = util\n                .getEventListenersByName(listOfListeners, 'apexAction.onError')\n                .reduce(function (err, listener) {\n                  return listener(err);\n                }, new errorConstructor(message, responseErrors, response));\n  \n              reject(err);\n            }\n  \n            if (finallyCallback) {\n              finallyCallback();\n            }\n          };\n        }\n  \n        /**\n       * Creates a unified function to be assign as a callback on the component creation action.\n       * @param resolve {Function} the function called if the component creation successfully\n       * @param reject {Function} the function called if the component failed to create\n       * @returns {Function}\n       */\n        function createComponentActionRouter(resolve, reject) {\n          var lax = this;\n  \n          return function (component, status, message) {\n            var result = { status: status },\n              isMultiple = $A.util.isArray(message),\n              listOfListeners = [\n                laxPrototype.getEventListeners(), lax.getEventListeners()\n              ];\n  \n            if (isMultiple) {\n              result.components = component;\n              result.statusMessages = message;\n            } else {\n              result.component = component;\n              result.message = message;\n            }\n  \n            if (status === 'SUCCESS') {\n              var resultComponent = util\n                .getEventListenersByName(listOfListeners, 'createComponentAction.onSuccess')\n                .reduce(function (cmp, listener) {\n                  return listener(cmp)\n                }, component);\n  \n              resolve(resultComponent);\n            } else {\n              var errorConstructor = status === 'INCOMPLETE' ? errors.IncompleteActionError : errors.CreateComponentError,\n                error = null;\n  \n              if (isMultiple) {\n                var msg = 'An error occurred while a component creation process.';\n                error = new errorConstructor(msg, result.statusMessages, result);\n              } else {\n                error = new errorConstructor(message, null, result);\n              }\n  \n              var resultError = util\n                .getEventListenersByName(listOfListeners, 'createComponentAction.onError')\n                .reduce(function (e, listener) {\n                  return listener(e);\n                }, error);\n  \n              reject(resultError);\n            }\n          };\n        }\n  \n  \n        /**\n         * Creates a unified function to assign it as a callback on the LDS action.\n         * The returned function is a router for the result of the action.\n         * @param resolve {Function} the function called if the action is success\n         * @param reject {Function} the function called if the action is failed\n         * @returns {Function}\n         */\n        function ldsActionRouter(resolve, reject) {\n          var lax = this;\n  \n          return function(result) {\n            var listOfListeners = [\n                laxPrototype.getEventListeners(), lax.getEventListeners()\n              ];\n  \n            if (result.state === 'SUCCESS' || result.state === 'DRAFT') {\n              var resultValue = util\n                .getEventListenersByName(listOfListeners, 'ldsAction.onSuccess')\n                .reduce(function (val, listener) {\n                  return listener(val);\n                }, result);\n  \n              resolve(resultValue);\n            } else {\n              var error = null;\n              if (result.state === 'ERROR') {\n                var message = 'Unknown error';\n  \n                if (result.error && Array.isArray(result.error) && result.error.length > 0) {\n                  message = result.error[0].message;\n                }\n  \n                error = new errors.LdsActionError(message, result.error, result);\n              } else if (result.state === 'INCOMPLETE') {\n                error = new errors.IncompleteActionError('You are currently offline.', result.error, result);\n              } else {\n                error = new Error('Unknown action state');\n              }\n  \n              var resultError = util\n                .getEventListenersByName(listOfListeners, 'ldsAction.onError')\n                .reduce(function (e, listener) {\n                  return listener(e);\n                }, error);\n  \n              reject(resultError);\n            }\n          };\n        }\n  \n        var util = {\n        /**\n         * Create an object and bind it with passed in Promise prototype.\n         * It has own chaining functions (<code>then</code>, <code>catch</code>),\n         * with Aura context functionality. It allows to avoid of <code>$A.getCallback</code>\n         * on callback functions.\n         * @param promise {Promise}\n         * @returns {LaxPromise}\n         */\n          createAuraContextPromise: function (promise) {\n            var lp = Object.create(null, {\n              _contextPromise: {\n                writable: false,\n                configurable: false,\n                enumerable: true,\n                value: promise\n              }\n            });\n            // eslint-disable-next-line no-use-before-define\n            return Object.assign(lp, laxPromise);\n          },\n  \n          removeAuraErrorMessagePrefix: function (message) {\n            var result = message;\n            var prefix = 'Error in $A.getCallback() [';\n  \n            if (message && message.indexOf(prefix) > -1) {\n                result = message.replace(prefix, '').slice(0, -1)\n            }\n  \n            return result;\n          },\n  \n          assignCatchFilters: function (handleErrors, callback, promise) {\n            return function routeError(error) {\n              for (var i = 0; i < handleErrors.length; i = i + 1) {\n                var errorType = handleErrors[i];\n                if (errorType === Error ||\n                (errorType !== null && errorType.prototype instanceof Error)) {\n  \n                  if (error instanceof errorType || error.name === errorType.name) {\n                    return util.tryCatch(callback).call(promise, error);\n                  }\n                }\n              }\n  \n              return Promise.reject(error);\n            };\n          },\n  \n          tryCatch: function (callback) {\n            return function tryCallback() {\n              try {\n                return callback.apply(this, arguments);\n              } catch (e) {\n                return Promise.reject(e);\n              }\n            };\n          },\n  \n          registerError: function (error) {\n            errors[error.name] = error;\n          },\n  \n          isApplicationEvent: function (eventName) {\n            return eventName.indexOf('e.') === 0 && eventName.indexOf(':') > 0;\n          },\n  \n          getEventListenersByName: function (listOfListeners, eventHandlerName) {\n            var handlers = [];\n  \n            listOfListeners.forEach(function (listeners) {\n              util.pushIfValueExist(\n                handlers,\n                util.delve(listeners, eventHandlerName)\n              );\n            });\n  \n            return handlers;\n          },\n  \n          /**\n           * {@link https://github.com/developit/dlv}\n           */\n          delve: function (obj, key, def, p) {\n            p = 0;\n            key = key.split ? key.split('.') : key;\n            while (obj && p < key.length) obj = obj[key[p++]];\n            return (obj === undefined || p < key.length) ? def : obj;\n          },\n  \n          pushIfValueExist: function (arr, value) {\n            if (!$A.util.isUndefinedOrNull(value)) arr.push(value);\n          }\n        };\n  \n        /**\n       * The container of the actual context promise.\n       * It helps to call chain function (<code>then</code>, <code>catch</code>)\n       * in the Aura context. The client can avoid of <code>$A.getCallback</code> calls.\n       * @class LaxPromise\n       */\n        var laxPromise =\n      /**\n       * @lends LaxPromise#\n       */\n      {\n        /**\n         * Attaches callbacks for the resolution and/or rejection of the Promise.\n         * @param onSuccess {Function|undefined} The callback to execute when the Promise is resolved.\n         * @param onError {Function=} The callback to execute when the Promise is rejected.\n         * @returns {LaxPromise} A {@link LaxPromise} for the completion of which ever callback is executed.\n         */\n        then: function (onSuccess, onError) {\n          var promise = this._contextPromise.then(\n            (onSuccess ?  $A.getCallback(onSuccess) : undefined),\n            (onError ?  $A.getCallback(onError) : undefined)\n          );\n  \n          return util.createAuraContextPromise(promise);\n        },\n  \n        /**\n         * Attaches a callback for only the rejection of the Promise.\n         * @param onError {Function} The callback to execute when the Promise is rejected.\n         * @returns {LaxPromise} A {@link LaxPromise} for the completion of the callback.\n         * @example\n         * component.lax.enqueue('c.save', { record: record })\n         *  .then(id => {\n         *    component.set('v.record.id', id);\n         *  })\n         *  .catch(errors => {\n         *    console.error(errors);\n         *  });\n         */\n        catch: function (onError) {\n          var promise;\n          var callback = onError;\n          var len = arguments.length;\n          if (len > 1) {\n            var errorTypes = new Array(len - 1);\n            for (var i = 0; i < len - 1; i = i + 1) {\n              errorTypes[i] = arguments[i];\n            }\n            var onErrorCallback = arguments[len - 1];\n  \n            callback = util.assignCatchFilters(errorTypes, onErrorCallback, this);\n          }\n  \n          promise = this.then(undefined, function(e) {\n            e.message = util.removeAuraErrorMessagePrefix(e.message);\n            return callback(e);\n          });\n  \n          return util.createAuraContextPromise(promise);\n        },\n  \n        /**\n         * The method returns a {@link LaxPromise}.\n         * When the Promise is settled, whether fulfilled or rejected, the specified callback function is executed.\n         * This provides a way for code that must be executed once the Promise has been dealt with to be run\n         * whether the promise was fulfilled successfully or rejected.\n         *\n         * This lets you avoid duplicating code in both the promise's then() and catch() handlers.\n         * @param callback {Function} The function to run whe the Promise is settled\n         * @returns {LaxPromise}\n         */\n        finally: function (callback) {\n          var self = this,\n            promise;\n          \n          if (typeof Promise.prototype.finally === 'function') {\n            promise = self._contextPromise.finally($A.getCallback(callback));\n          } else {\n            promise = this\n              .then(function(value) {\n                return self._contextPromise.constructor.resolve($A.getCallback(callback)()).then(function() { return value; });\n              })\n              .catch(function(reason) {\n                return self._contextPromise.constructor.resolve($A.getCallback(callback)()).then(function() { throw reason; });\n              });\n          }\n  \n          return util.createAuraContextPromise(promise);\n        },\n  \n        /**\n         * Attaches a callback for only the rejection of the Promise\n         * and for only actions that returns \"ERROR\" state\n         * @param onError {Function} The callback to execute when the Promise is rejected.\n         * @returns {LaxPromise} A {@link LaxPromise} for the completion of the callback.\n         */\n        error: function (onError) {\n          var fn = util.assignCatchFilters([errors.ApexActionError, errors.CreateComponentError], onError, this);\n          return this.then(undefined, fn);\n        },\n  \n        /**\n         * Attaches a callback for only the rejection of the Promise\n         * and for only actions that returns \"INCOMPLETE\" state\n         * @param onIncomplete {Function} The callback to execute when the Promise is rejected.\n         * @returns {LaxPromise} A {@link LaxPromise} for the completion of the callback.\n         */\n        incomplete: function (onIncomplete) {\n          var fn = util.assignCatchFilters([errors.IncompleteActionError], onIncomplete, this);\n          return this.then(undefined, fn);\n        }\n      };\n  \n        /**\n       * The container of the actual Lightning Data Service (LDS). It delegates\n       * actions to LDS and provide and API to chain them. Actions callback functions don't\n       * require <code>$A.getCallback()</code> wrapper.\n       * @class LaxDataService\n       */\n        var laxDataService =\n      /**\n       * @lends LaxDataService#\n       */\n      {\n  \n        /**\n         * The function to save the record that loaded to LDS edit <code>EDIT</code> mode.\n         * It used to create a record and save it or to save the changes to an existing one.\n         * @see https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/data_service_save_record.htm\n         * @returns {LaxPromise}\n         */\n        saveRecord: function () {\n          var self = this;\n          var promise = new Promise(function (resolve, reject) {\n            self._service.saveRecord(ldsActionRouter.call(self, resolve, reject));\n          });\n  \n          return util.createAuraContextPromise(promise);\n        },\n  \n        /**\n         * The function to load a record template to the LDS <code>targetRecord</code> attribute.\n         * It doesn't return a result to callback function.\n         * It simply prepares an empty record and assigns it to the <code>targetRecord</code> attribute.\n         * @param sobjectType {String=} the object API name for the new record.\n         * @param recordTypeId {String=} the 18 character ID of the record type for the new record.\n         * If not specified, the default record type for the object is used, as defined in the user’s profile.\n         * @param skipCache {Boolean=} whether to load the record template from the server instead of the\n         * client-side Lightning Data Service cache. Defaults to false.\n         * @returns {LaxPromise}\n         */\n        getNewRecord: function (sobjectType, recordTypeId, skipCache) {\n          var self = this;\n          var promise = new Promise(function (resolve) {\n            function getNewRecordCallback () {\n              resolve();\n            }\n  \n            self._service.getNewRecord(sobjectType, recordTypeId, skipCache, getNewRecordCallback);\n          });\n  \n          return util.createAuraContextPromise(promise);\n        },\n  \n        /**\n         * The function to delete a record using LDS.\n         * @returns {LaxPromise}\n         */\n        deleteRecord: function () {\n          var self = this;\n          var promise = new Promise(function (resolve, reject) {\n            self._service.deleteRecord(ldsActionRouter.call(self, resolve, reject));\n          });\n  \n          return util.createAuraContextPromise(promise);\n        }\n      };\n  \n        /**\n       * The object based on builder pattern to call Aura action.\n       * It is instantiated to be used by {@link Lax} as a prototype of actual actions.\n       * This type of action does not use Promise approach and subsequently can be called as storable.\n       * @class LaxActionBuilder\n       */\n        var laxActionBuilder =\n      /**\n       * @lends LaxActionBuilder#\n       */\n      {\n  \n        /**\n         * Assign the success callback on Aura action\n         * @param callback {Function}\n         * @returns {LaxActionBuilder}\n         */\n        setThen: function setThen(callback) {\n          this._resolveCallback = callback;\n          return this;\n        },\n  \n        /**\n         * Assigns the failure callback on Aura action. This function called when the error occurs.\n         * @param callback {Function}\n         * @returns {LaxActionBuilder}\n         */\n        setCatch: function setCatch(callback) {\n          this._rejectCallback = callback;\n          return this;\n        },\n  \n        /**\n         * Assigns the finally callback on Aura action. This function called after success or failure callback. It doesn't\n         * depend on the result of an action.\n         * @param callback {Function}\n         * @returns {LaxActionBuilder}\n         */\n        setFinally: function setFinally(callback) {\n          this._finallyCallback = callback;\n          return this;\n        },\n  \n        /**\n         * Sets parameters for the action.\n         * @param params {Object}\n         * @returns {LaxActionBuilder}\n         */\n        setParams: function setParams(params) {\n          this._action.setParams(params);\n          return this;\n        },\n  \n        /**\n         * Marks the action as a {@link https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_storable_actions.htm|Storable}\n         * @returns {LaxActionBuilder}\n         */\n        setStorable: function setStorable() {\n          this._action.setStorable();\n          return this;\n        },\n  \n        /**\n         * Marks the action as a {@link https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_background_actions.htm|Background}\n         * @returns {LaxActionBuilder}\n         */\n        setBackground: function setBackground() {\n          this._action.setBackground();\n          return this;\n        },\n  \n        /**\n         * Enqueues the action. The function do not return the object itself and should be\n         * called at the end of the builder chain.\n         * @returns {void}\n         */\n        enqueue: function enqueue() {\n          this._action.setCallback(this._component,\n            actionRouter.call(this._lax, this._resolveCallback, this._rejectCallback, this._finallyCallback));\n          $A.enqueueAction(this._action);\n        }\n  \n      };\n  \n        /**\n       * The object based on builder pattern to fire Lightning Application or Component events.\n       * @class LaxEventBuilder\n       */\n        var laxEventBuilder =\n        /**\n         * @lends LaxEventBuilder#\n         */\n        {\n        /**\n         * Sets data for the event attributes. A parameter’s name must match the name attribute\n         * of one of the event’s <code>aura:attribute</code> tags.\n         * @param params {Object} the data of event attributes\n         * @returns {LaxEventBuilder}\n         */\n          setParams: function setParams(params) {\n            this._event.setParams(params);\n            return this;\n          },\n  \n          /**\n         * Fires the event.\n         * @returns {void}\n         */\n          fire: function fire() {\n            this._event.fire();\n          }\n  \n        };\n  \n        /**\n       * The object with list of Aura Server-Side action options\n       * @typedef {Object} ActionOptions\n       * @property storable {Boolean} Marks action as a <a href=\"https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_storable_actions.htm\">Storable</a>\n       * @property background {Boolean} Marks action as a <a href=\"https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_background_actions.htm\">Background</a>\n       * @property abortable {Boolean} Marks action as a <a href=\"https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_abortable_actions.htm\">Abortable</a>\n       */\n  \n        /**\n       * The object that contains a properties for Aura Server-Side Action\n       * @typedef {Object} ActionProperties\n       * @property name {String} The name of the action. It must be the same as Apex @AuraEnabled method\n       * @property params {Object} The object with parameters values for the action. It is based on Apex @AuraEnabled method\n       * @property options {Object} The object with list of options that can be applied to the action\n       */\n  \n        /**\n       * The action main object of the component that is used as a shared prototype across all lax components\n       * created in the application. See <code>init</code> function of the laxHelper.js where the lax assigned as prototype.\n       * @class Lax\n       */\n        var laxPrototype =\n        /**\n         * @lends Lax#\n         */\n        {\n        /**\n         * Enqueues the action by the name and with passed in params and options.\n         * The function returns Promise, subsequently client can chain the actions\n         * by assigning <code>then</code> callbacks or handle the error by <code>catch</code> callback.\n         * @param actionName {String} the name of the action (Apex controller method name)\n         * @param params [Object] the object that contains parameters for the action\n         * @param options [ActionOptions] the object with list of options for the action\n         * @returns {LaxPromise}\n         * @example\n         * component.lax.enqueue('c.getContact', { id: recordId }, { background: true })\n         *   .then(contact => {\n         *     component.set('v.record', contact);\n         *   });\n         */\n          enqueue: function enqueue(actionName, params, options) {\n            var self = this;\n            var promise = new Promise(function (resolve, reject) {\n              var action = self._component.get(actionName);\n  \n              if (params) {\n                action.setParams(params);\n              }\n  \n              if (options) {\n                if (options.background) {\n                  action.setBackground();\n                }\n                if (options.storable) {\n                  action.setStorable();\n                }\n              }\n  \n              action.setCallback(self._component, actionRouter.call(self, resolve, reject));\n              $A.enqueueAction(action);\n            });\n  \n            return util.createAuraContextPromise(promise);\n          },\n  \n          /**\n         * Enqueues the list of actions parallel.\n         * The function return {@link Promise} that subsequently can be used to chain callback.\n         * The success callback assigned on the {@link Promise} called after all actions ready and an error have not thrown.\n         * @param actions {ActionProperties[]}\n         * @returns {LaxPromise}\n         * @example\n         * component.lax.enqueueAll([\n         *   // { name : '...', params: {...}, options: {...} }\n         *   { name: 'c.getContacts' },\n         *   { name: 'c.getAccounts' },\n         *   { name: 'c.getOpportunities' }\n         * ])\n         * .then(results => {\n         *   // results: [ [contacts], [accounts], [opportunities] ]\n         *   var contacts = results[0];\n         *   var accounts = results[1];\n         *   var opportunities = results[2];\n         * });\n         */\n          enqueueAll: function enqueueAll(actions) {\n            var self = this;\n            var promises = actions.map(function (a) {\n              return self.enqueue.call(self, a.name, a.params, a.options);\n            });\n  \n            return util.createAuraContextPromise(Promise.all(promises));\n          },\n  \n          /**\n         * Creates the action linked to {@link LaxActionBuilder} by the provided name.\n         * @param actionName {String} the name of the action (Apex controller method)\n         * @returns {LaxActionBuilder}\n         * @example\n         * component.lax\n         *  .action('c.getContact')\n         *  .setStorable()\n         *  .setParams({ id: recordId })\n         *  .setThen(contact => {\n         *    component.set('v.record', contact)\n         *  })\n         *  .setCatch(error => {\n         *    console.error(error);\n         *  })\n         *  .enqueue();\n         */\n          action: function action(actionName) {\n            var c = this._component;\n            var props = {\n              _component: {\n                writable: false,\n                configurable: false,\n                enumerable: false,\n                value: c\n              },\n              _action: {\n                writable: false,\n                configurable: false,\n                enumerable: false,\n                value: c.get(actionName)\n              },\n              _lax: {\n                writable: false,\n                configurable: false,\n                enumerable: false,\n                value: this\n              }\n            };\n            return Object.create(laxActionBuilder, props);\n          },\n  \n          /**\n         * Creates an object with {LaxEventBuilder} prototype with the context\n         * event by provided name. The function apply Application and Component event name.\n         * @param eventName {String} the name of the event\n         * @returns {LaxEventBuilder}\n         */\n          event: function event(eventName) {\n            var props = {\n              _event: {\n                writable: false,\n                configurable: false,\n                enumerable: false,\n                value: util.isApplicationEvent(eventName) ? $A.get(eventName) : this._component.getEvent(eventName)\n              }\n            };\n            return Object.create(laxEventBuilder, props);\n          },\n  \n          /**\n         * Creates a container of actual Lightning Data Service object.\n         * @param id {String} the aura:id of the <code>force:record</code> (Lightning Data Service) tag\n         * @returns {LaxDataService}\n         */\n          lds: function lds(id) {\n            var service = this._component.find(id);\n            var serviceProp = {\n              _service: {\n                writable: false,\n                configurable: false,\n                enumerable: false,\n                value: service\n              }\n            };\n  \n            return Object.create(laxDataService, serviceProp);\n          },\n  \n          /**\n         * Create a component from a type and a set of attributes.\n         * It accepts the name of a type of component, a map of attributes,\n         * and returns {LaxPromise} to assign a callback function to notify caller.\n         * @param {String} type The type of component to create, e.g. \"ui:button\".\n         * @param {Object} attributes A map of attributes to send to the component. These take the same form as on the markup,\n         * including events <code>{\"press\":component.getReference(\"c.handlePress\")}</code>, and id <code>{\"aura:id\":\"myComponentId\"}</code>.\n         * @example\n         * lax.createComponent(\"aura:text\",{value:'Hello World'})\n         *   .then(function(auraTextComponent){\n         *        // auraTextComponent - is an instance of aura:text containing the value Hello World\n         *   });\n         * @returns {LaxPromise}\n         */\n          createComponent: function createComponent(type, attributes) {\n            var self = this;\n            var promise = new Promise(function (resolve, reject) {\n              $A.createComponent(type, attributes, createComponentActionRouter.call(self, resolve, reject));\n            });\n  \n            return util.createAuraContextPromise(promise);\n          },\n  \n          /**\n         * Create an array of components from a list of types and attributes.\n         * It accepts a list of component names and attribute maps, and returns\n         * {LaxPromise} to assign a callback function to notify caller.\n         * @param {Array} components The list of components to create, e.g. <code>[\"ui:button\",{\"press\":component.getReference(\"c.handlePress\")}]</code>\n         * @example\n         * lax.createComponents([\n         *      [\"aura:text\",{value:'Hello'}],\n         *      [\"ui:button\",{label:'Button'}],\n         *      [\"aura:text\",{value:'World'}]\n         *  ])\n         *  .then(function(components) {\n         *      // components - is an array of 3 components\n         *      // 0 - Text Component containing Hello\n         *      // 1 - Button Component with label Button\n         *      // 2 - Text component containing World\n         *  });\n         *  @return {LaxPromise}\n         */\n          createComponents: function createComponents(components) {\n            var self = this;\n            var promise = new Promise(function (resolve, reject) {\n              $A.createComponents(components, createComponentActionRouter.call(self, resolve, reject));\n            });\n  \n            return util.createAuraContextPromise(promise);\n          },\n  \n          getEventListeners: function () {\n            return eventListeners;\n          },\n  \n          util: {\n            registerError: util.registerError\n          },\n  \n          errors: errors\n        };\n  \n        if (onInit) {\n          // callback to decorate events workflow (ApexAction)\n          onInit(eventListeners);\n        }\n  \n        return laxPrototype;\n      },\n  \n      initEventListeners: function (listenersContainer, component, auraMethodName) {\n        var method = component[auraMethodName];\n        if (method) {\n          Object.assign(listenersContainer, method.call(component));\n        }\n      },\n  \n      defineErrors: function () {\n        function ApexActionError(message, entries, action) {\n          this.name = 'ApexActionError';\n          this.message = message;\n          this.entries = entries;\n          this.action = action;\n          this.stack = (new Error()).stack;\n        }\n        ApexActionError.prototype = Object.create(Error.prototype);\n  \n  \n        function IncompleteActionError(message, entries, action) {\n          this.name = 'IncompleteActionError';\n          this.message = message;\n          this.entries = entries;\n          this.action = action;\n          this.stack = (new Error()).stack;\n        }\n        IncompleteActionError.prototype = Object.create(Error.prototype);\n  \n        function LdsActionError(message, entries, action) {\n          this.name = 'LdsActionError';\n          this.message = message;\n          this.entries = entries;\n          this.action = action;\n          this.stack = (new Error()).stack;\n        }\n        LdsActionError.prototype = Object.create(Error.prototype);\n  \n        function CreateComponentError(message, entries, action) {\n          this.name = 'CreateComponentError';\n          this.message = message;\n          this.entries = entries;\n          this.action = action;\n          this.stack = (new Error()).stack;\n        }\n        CreateComponentError.prototype = Object.create(Error.prototype);\n  \n        return {\n          ApexActionError: ApexActionError,\n          IncompleteActionError: IncompleteActionError,\n          LdsActionError: LdsActionError,\n          CreateComponentError: CreateComponentError\n        };\n      }\n    });\n  "
  },
  {
    "path": "force-app/main/default/aura/slds_label/slds_label.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<aura:component>\n\n    <aura:attribute name=\"label\"\n                    type=\"String\"\n                    required=\"true\"/>\n\n    <aura:attribute name=\"helpText\"\n                    type=\"String\"\n                    required=\"false\"/>\n\n    <div>\n\n        <label class=\"slds-form-element__label slds-var-m-right_xx-small\">\n            {!v.label}\n        </label>\n\n        <aura:if isTrue=\"{!not(empty(v.helpText))}\">\n            <lightning:helptext content=\"{!v.helpText}\"/>\n        </aura:if>\n\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/slds_label/slds_label.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>slds_label</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/slds_section/slds_section.cmp",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n-->\n<!--\n    https://www.lightningdesignsystem.com/components/expandable-section/\n-->\n<aura:component >\n\n    <aura:attribute name=\"title\" type=\"String\"\n                    description=\"Section Title\"/>\n\n    <div class=\"slds-section\">\n        <h3 class=\"slds-section__title slds-theme_shade\">\n            <span class=\"slds-truncate slds-p-horizontal_small\" title=\"{!v.title}\">{!v.title}</span>\n        </h3>\n    </div>\n\n</aura:component>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/slds_section/slds_section.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>slds_section</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/strike_evt/strike_evt.evt",
    "content": "<!--\nStrike by Appiphony\n\nVersion: 1.0.0\nWebsite: http://www.lightningstrike.io\nGitHub: https://github.com/appiphony/Strike-Components\nLicense: BSD 3-Clause License\n-->\n<aura:event type=\"COMPONENT\" description=\"Event template\" >\n\t<aura:attribute name=\"data\" type=\"Object\"/>\n</aura:event>\n<!--\nCopyright 2017 Appiphony, LLC\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following\ndisclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\ndisclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote\nproducts derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/strike_evt/strike_evt.evt-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>strike_evt</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/strike_wizard/strike_wizard.cmp",
    "content": "<!--\nStrike by Appiphony\n\nVersion: 0.8.0\nWebsite: http://www.lightningstrike.io\nGitHub: https://github.com/appiphony/Strike-Components\nLicense: BSD 3-Clause License\n-->\n<aura:component implements=\"flexipage:availableForAllPageTypes,force:appHostable\" access=\"global\">\n\n    <!-- PUBLIC USER DEFINED ATTRIBUTES -->\n    <aura:attribute name=\"stageNames\" type=\"String[]\" default=\"['One','Two','Three','Four','Five']\" description=\"The name of each chevron\" required=\"true\"/>\n    <aura:attribute name=\"activeChevron\" type=\"Integer\" default=\"0\" description=\"Used to set the starting position of the active chevron\"/>\n    <aura:attribute name=\"advanceButton\" type=\"Boolean\" default=\"{!false}\" description=\"Used to override default button\"/>\n\n    <aura:attribute name=\"advanceButtonNextLabel\" type=\"string\" default=\"Mark Stage as Completed\" description=\"Button label used to mark a stage as completed and advance to the next chevron\"/>\n    <aura:attribute name=\"advanceButtonSelectLabel\" type=\"string\" default=\"Mark as Current Stage\" description=\"Button label used to mark a selected chevron as the current chevron\"/>\n    <aura:attribute name=\"advanceButtonCompletedLabel\" type=\"string\" default=\"Process Completed\" description=\"Button label used to indicate the process has been completed\"/>\n\n    <aura:attribute name=\"displayMode\" type=\"string\" default=\"wizard\" description=\"Simple for Basic navigation or Wizard for flows\"/>\n    <aura:attribute name=\"disableBackwardNavOnComplete\" type=\"Boolean\" default=\"{!false}\" description=\"Restricts backward navigation to stages marked as complete\"/>\n    <aura:attribute name=\"disableForwardNavOnIncomplete\" type=\"Boolean\" default=\"{!false}\" description=\"Restricts forward navigation to stages marked as incomplete\"/>\n    <aura:attribute name=\"forceProcessFlow\" type=\"Boolean\" default=\"{!false}\" description=\"Restricts all navigation\"/>\n    <aura:attribute name=\"collapseExpandButton\" type=\"Boolean\" default=\"{!false}\" description=\"A boolean value that is used to hide or show the toggle body button\"/>\n    <aura:attribute name=\"error\" type=\"Boolean\" default=\"{!false}\" description=\"A boolean value that is used to toggle the error state\"/>\n    <aura:attribute name=\"processComplete\" type=\"Boolean\" default=\"{!false}\"/>\n\n    <!-- INTERNAL ATTRIBUTES -->\n    <aura:attribute name=\"chevrons\" type=\"Map\" access=\"private\"/>\n    <aura:attribute name=\"currentChevron\" type=\"Integer\" access=\"private\" />\n    <aura:attribute name=\"initialized\" type=\"Boolean\" default=\"{!false}\" access=\"private\"/>\n    <aura:attribute name=\"advanceButtonText\" type=\"String\" default=\"Mark Stage as Completed\" access=\"private\"/>\n    <aura:attribute name=\"toggleButtonStyle\" type=\"Boolean\" default=\"{!true}\" access=\"private\"/>\n    <aura:attribute name=\"toggleBodyView\" type=\"Boolean\" default=\"{!true}\" access=\"public\"/> <!-- Doug, 12/31/2018, I exposed this attribute -->\n\n    <!-- HANDLERS AND EVENTS-->\n    <aura:handler name=\"init\" value=\"{!this}\" action=\"{!c.init}\"/>\n    <aura:handler name=\"change\" value=\"{!v.error}\" action=\"{!c.handleErrorState}\"/>\n    <aura:registerEvent name=\"strike_evt_chevron\" type=\"c:strike_evt\"/>\n\n    <!-- PUBLIC METHODS -->\n    <aura:method name=\"moveToStage\" action=\"{!c.changeChevronMethod}\">\n        <aura:attribute name=\"targetChevron\" type=\"Integer\" default=\"0\" description=\"Used to set the position of the active chevron\"/>\n    </aura:method>\n    <aura:method name=\"advanceProgress\" action=\"{!c.advanceButtonClick}\"/>\n    <aura:method name=\"showError\" action=\"{!c.showErrorMethod}\"/>\n    <aura:method name=\"hideError\" action=\"{!c.hideErrorMethod}\"/>\n    <aura:method name=\"toastMessage\" action=\"{!c.toastMessage}\">\n        <aura:attribute name=\"title\" type=\"String\" default=\"\"/>\n        <aura:attribute name=\"message\" type=\"String\" default=\"Stage saved successfully\"/>\n        <aura:attribute name=\"key\" type=\"String\" default=\"dislike\"/>\n        <aura:attribute name=\"duration\" type=\"Integer\" default=\"5000\"/>\n        <aura:attribute name=\"type\" type=\"String\" default=\"success\"/>\n        <aura:attribute name=\"mode\" type=\"String\" default=\"wizard\"/>\n    </aura:method>\n\n    <div class=\"slds-grid\">\n        <aura:if isTrue=\"{!v.collapseExpandButton}\">\n            <lightning:buttonIcon class=\"slds-button slds-button_icon-border-filled slds-path__trigger slds-no-flex slds-m-horizontal_small slds-flip_vertical\"\n                iconName=\"{!if(v.toggleBodyView, 'utility:chevrondown', 'utility:chevronup')}\"\n                title=\"Toggle coaching and guidance\"\n                alternativeText=\"toggle\"\n                size=\"medium\"\n                variant=\"border\"\n                onclick=\"{!c.toggleBody}\"/>\n        </aura:if>\n        <div class=\"{!'slds-tabs_path slds-path slds-path_has-coaching' + if(v.toggleBodyView, ' slds-is-expanded ', '')}\" role=\"application\">\n            <ul class=\"slds-tabs_path__nav\" role=\"tablist\">\n                <aura:iteration items=\"{!v.chevrons}\" var=\"chevron\" indexVar=\"index\">\n                    <li class=\"{!'slds-tabs_path__item ' + chevron.class}\" role=\"presentation\" id=\"{!index}\" onclick=\"{!c.chevronClick}\">\n                        <a href=\"javascript:void(0);\" class=\"slds-tabs_path__link\">\n                            <span class=\"slds-tabs_path__stage\">\n                                <lightning:icon variant=\"bare\" class=\"slds-button__icon\" iconName=\"utility:check\" size=\"x-small\" alternativeText=\"{!chevron.name}\"/>\n                            </span>\n                            <span class=\"slds-tabs_path__title\">{!chevron.name}</span>\n                        </a>\n                    </li>\n                </aura:iteration>\n            </ul>\n        </div>\n        <aura:if isTrue=\"{!and(v.advanceButton, v.displayMode == 'wizard')}\">\n            <lightning:button aura:id=\"advanceButton\"\n                class=\"{!'slds-path__mark-complete slds-no-flex sw-advance-button slds-m-left_small' + if(v.toggleButtonStyle == true, '', ' slds-path__mark-current') + if(v.body[0] != null, ' slds-m-horizontal_small', ' slds-m-left_small')}\"\n                variant=\"brand\"\n                onclick=\"{!c.advanceButtonClick}\"\n                disabled=\"{!v.error}\">\n                <aura:if isTrue=\"{!v.toggleButtonStyle}\">\n                    <lightning:icon variant=\"bare\" class=\"slds-button__icon slds-button__icon_left\" iconName=\"utility:check\" size=\"x-small\"/>\n                </aura:if>\n                {!v.advanceButtonText}\n            </lightning:button>\n        </aura:if>\n    </div>\n\n    <div aura:id=\"chevron-body\" class=\"{!'slds-path__content' + if(v.toggleBodyView == false, ' slds-hide', '')}\">\n        {!v.body}\n    </div>\n</aura:component>\n<!--\nCopyright 2017 Appiphony, LLC\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following\ndisclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\ndisclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote\nproducts derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/aura/strike_wizard/strike_wizard.cmp-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<AuraDefinitionBundle xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <description>A Lightning Component Bundle</description>\n</AuraDefinitionBundle>\n"
  },
  {
    "path": "force-app/main/default/aura/strike_wizard/strike_wizard.css",
    "content": "/*\nStrike by Appiphony\n\nVersion: 0.8.0\nWebsite: http://www.lightningstrike.io\nGitHub: https://github.com/appiphony/Strike-Components\nLicense: BSD 3-Clause License\n*/\n.THIS .sw-advance-button {\n    min-width: 240px;\n}\n\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-lost+.slds-tabs--path__item:before {\n    background-color: t(colorBackgroundDestructive);\n}\n\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-lost:hover,\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-lost:hover+.slds-tabs--path__item:before {\n    background-color: t(colorBackgroundDestructiveActive);\n}\n\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-complete+.slds-is-lost:before {\n    background-color: t(colorBackgroundPathComplete);\n}\n\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-complete:hover+.slds-is-lost:before {\n    background-color: t(colorBackgroundPathCompleteHover);\n}\n\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-active+.slds-is-lost:before {\n    background-color: t(colorBackgroundInverse);\n}\n\n.THIS .slds-tabs--path .slds-tabs--path__item.slds-is-active:hover+.slds-is-lost:before {\n    background-color: t(colorBackgroundAltInverse);\n}\n\n.THIS .slds-path__mark-current[disabled]:hover,\n.THIS .slds-path__mark-current[disabled]:focus {\n    background-color: t(colorBackgroundShade);\n}\n/*\nCopyright 2017 Appiphony, LLC\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following\ndisclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\ndisclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote\nproducts derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/strike_wizard/strike_wizardController.js",
    "content": "/*\nStrike by Appiphony\n\nVersion: 0.8.0\nWebsite: http://www.lightningstrike.io\nGitHub: https://github.com/appiphony/Strike-Components\nLicense: BSD 3-Clause License\n*/\n({\n    init: function(component, event, helper) {\n        var displayMode = component.get('v.displayMode').toLowerCase();\n        helper.buildInitState(component, displayMode);\n    },\n    advanceButtonClick: function(component, event, helper) {\n        if (component.get('v.processComplete')) return;\n        if (component.get('v.error')) return;\n        var currentChevron = component.get('v.currentChevron');\n        helper.renderAdvanceButtonClick(component, currentChevron);\n    },\n    chevronClick: function(component, event, helper) {\n        if (component.get('v.processComplete')) return;\n        var targetChevron = Number(event.currentTarget.id);\n        helper.moveToChevron(component, targetChevron);\n    },\n    changeChevronMethod: function(component, event, helper) {\n        var params = event.getParam('arguments');\n        helper.moveToChevron(component, params.targetChevron);\n    },\n    showErrorMethod: function(component, event, helper) {\n        component.set('v.error', true);\n    },\n    hideErrorMethod: function(component, event, helper) {\n        component.set('v.error', false);\n    },\n    toggleBody: function(component, event, helper) {\n        component.set('v.toggleBodyView', !component.get('v.toggleBodyView'));\n        var chevronBody = component.find(\"chevron-body\");\n        $A.util.toggleClass(chevronBody, \"toggle\");\n    },\n    toastMessage: function(component, event, helper) {\n        helper.showToast(component, event)\n    },\n    handleErrorState: function(component, event, helper) {\n        var error = event.getParam('value');\n        (error) ? helper.showErrorState(component) : helper.hideErrorState(component);\n    }\n})\n/*\nCopyright 2017 Appiphony, LLC\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following\ndisclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\ndisclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote\nproducts derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/aura/strike_wizard/strike_wizardHelper.js",
    "content": "/*\nStrike by Appiphony\n\nVersion: 0.8.0\nWebsite: http://www.lightningstrike.io\nGitHub: https://github.com/appiphony/Strike-Components\nLicense: BSD 3-Clause License\n*/\n({\n    buildInitState: function(component, displayMode) {\n        var stageNames = component.get('v.stageNames');\n        var activeChevron = component.get('v.activeChevron');\n        var forceProcessFlow = component.get('v.forceProcessFlow');\n        var disableBackwardNavOnComplete = component.get('v.disableBackwardNavOnComplete');\n        var disableForwardNavOnIncomplete = component.get('v.disableForwardNavOnIncomplete');\n        var error = component.get('v.error');\n        var chevrons = [];\n\n        for (var i = 0; i < stageNames.length; i++) {\n            if (displayMode == 'simple') {\n                chevrons.push({\n                    'active': (i == activeChevron) ? true : false,\n                    'class': (i == activeChevron) ? 'slds-is-active' : 'slds-is-incomplete',\n                    'current': false,\n                    'name': stageNames[i],\n                    'status': 'incomplete',\n                    'disabled': false\n                })\n            } else if (displayMode == 'wizard') {\n                if (activeChevron == 0 && i == 0) {\n                    chevrons.push({\n                        'active': (i == activeChevron) ? true : false,\n                        'class': (i == activeChevron) ? (error) ? 'slds-is-current slds-is-lost' : 'slds-is-current' : 'slds-is-incomplete',\n                        'current': (i == activeChevron) ? true : false,\n                        'name': stageNames[i],\n                        'status': 'incomplete',\n                        'disabled': forceProcessFlow\n                    })\n                } else {\n                    if (i == activeChevron) {\n                        chevrons.push({\n                            'name': stageNames[i],\n                            'active': true,\n                            'current': true,\n                            'class': (error) ? 'slds-is-current slds-is-lost' : 'slds-is-current',\n                            'status': 'incomplete',\n                            'disabled': false\n                        })\n                    } else if (i > activeChevron) {\n                        chevrons.push({\n                            'name': stageNames[i],\n                            'active': false,\n                            'current': false,\n                            'class': 'slds-is-incomplete',\n                            'status': 'incomplete',\n                            'disabled': forceProcessFlow || disableForwardNavOnIncomplete\n                        })\n                        component.set('v.toggleButtonStyle', true);\n                    } else {\n                        chevrons.push({\n                            'name': stageNames[i],\n                            'active': false,\n                            'current': false,\n                            'class': 'slds-is-complete',\n                            'status': 'complete',\n                            'disabled': forceProcessFlow || disableBackwardNavOnComplete\n                        })\n                        component.set('v.toggleButtonStyle', false);\n                    }\n                }\n            }\n        }\n        if (activeChevron != 0) component.set('v.initialized', true);\n        (activeChevron == 0) ? component.set('v.currentChevron', 1): component.set('v.currentChevron', activeChevron);\n        component.set('v.chevrons', chevrons);\n        component.set('v.processComplete', false);\n        component.set('v.advanceButtonText', component.get('v.advanceButtonNextLabel'));\n    },\n    renderSimpleMode: function(component, targetChevron) {\n        var chevrons = component.get('v.chevrons');\n        var results = {};\n\n        for (var i = 0; i < chevrons.length; i++) {\n            var chevron = chevrons[i];\n            chevron.class = '';\n            if (i == targetChevron) {\n                chevron.active = true;\n                chevron.current = false;\n                results.current = i || 0;\n                chevron.class += 'slds-is-active slds-is-incomplete';\n            } else {\n                chevron.active = false;\n                chevron.current = false;\n                results.current = i || 0;\n                chevron.class += 'slds-is-incomplete';\n            }\n        }\n\n        component.set('v.activeChevron', targetChevron);\n        component.set('v.chevrons', chevrons);\n        this.sendResultsToParent(component, results, 'click');\n    },\n    renderWizardMode: function(component, targetChevron) {\n        var chevrons = component.get('v.chevrons');\n        var results = {};\n        var error = component.get('v.error');\n        var setNextAsCurrent = false;\n\n        if (component.get('v.forceProcessFlow') == true) return;\n\n        for (var i = 0; i < chevrons.length; i++) {\n            var chevron = chevrons[i];\n            chevron.class = '';\n\n            if (i == targetChevron) {\n                if (chevron.current == true) {\n                    chevron.active = false;\n                    results.current = i || 0;\n                    chevron.class = 'slds-is-current';\n                    if (error) chevron.class += ' slds-is-lost';\n                    component.set('v.advanceButtonText', component.get('v.advanceButtonNextLabel'));\n                    component.set('v.toggleButtonStyle', true);\n                    setNextAsCurrent = true;\n                } else {\n                    results.active = i || 0;\n                    chevron.active = true;\n                    chevron.class = 'slds-is-active';\n                    component.set('v.advanceButtonText', component.get('v.advanceButtonSelectLabel'));\n                    component.set('v.toggleButtonStyle', false);\n                    (chevron.status == 'complete') ? chevron.class += ' slds-is-complete': chevron.class += ' slds-is-incomplete';\n                }\n            } else {\n                if (chevron.current == true) {\n                    results.current = i || 0;\n                    chevron.class = 'slds-is-current';\n                    if (error) chevron.class += ' slds-is-lost';\n                } else {\n                    chevron.current = false;\n                    (chevron.status == 'complete') ? chevron.class += ' slds-is-complete': chevron.class += ' slds-is-incomplete';\n                }\n                chevron.active = false;\n            }\n        }\n\n        if (setNextAsCurrent) component.set('v.currentChevron', targetChevron + 1);\n        else component.set('v.currentChevron', targetChevron);\n\n        component.set('v.chevrons', chevrons);\n        this.sendResultsToParent(component, results, 'click');\n    },\n    showErrorState: function(component) {\n        var chevrons = component.get('v.chevrons');\n        var activeChevron = component.get('v.activeChevron');\n        var processComplete = component.get('v.processComplete');\n\n        if (!processComplete) {\n            for (var i = 0; i < chevrons.length; i++) {\n                var chevron = chevrons[i];\n\n                if (chevron.class.indexOf('slds-is-active') >= 0) { // If selected\n                    chevron.class = 'slds-is-active';\n                } else {\n                    chevron.class = '';\n                }\n\n                if (i == activeChevron) {\n                    chevron.active = false;\n                    chevron.class += ' slds-is-current slds-is-lost';\n                    chevron.current = true;\n                    chevron.status = 'incomplete';\n                } else if (i < activeChevron) {\n                    chevron.active = false;\n                    chevron.class += ' slds-is-complete';\n                    chevron.current = false;\n                    chevron.status = 'complete';\n                } else if (i > activeChevron) {\n                    chevron.active = false;\n                    chevron.class += ' slds-is-incomplete';\n                    chevron.current = false;\n                    chevron.status = 'incomplete';\n                }\n            }\n        }\n\n        component.set('v.chevrons', chevrons);\n    },\n    hideErrorState:  function(component) {\n        var chevrons = component.get('v.chevrons');\n\n        chevrons.forEach(function(chevron) {\n            chevron.class = chevron.class.replace('slds-is-lost', '');\n        });\n\n        component.set('v.chevrons', chevrons);\n    },\n    renderAdvanceButtonClick: function(component, activeChevron) {\n        var disableBackwardNavOnComplete = component.get('v.disableBackwardNavOnComplete');\n        var disableForwardNavOnIncomplete = component.get('v.disableForwardNavOnIncomplete');\n        var forceProcessFlow = component.get('v.forceProcessFlow');\n\n        if (component.get('v.displayMode').toLowerCase() == 'simple') return;\n\n        var chevrons = component.get('v.chevrons');\n        var error = component.get('v.error');\n        var results = {};\n\n        if (activeChevron == chevrons.length) {\n            chevrons[activeChevron - 1].class = 'slds-is-complete';\n            chevrons[activeChevron - 1].status = 'complete';\n            chevrons[activeChevron - 1].active = true;\n            chevrons[activeChevron - 1].current = false;\n            component.set('v.chevrons', chevrons);\n            component.set('v.advanceButtonText', component.get('v.advanceButtonCompletedLabel'));\n            component.set('v.activeChevron', null);\n            component.set('v.processComplete', true);\n            return;\n        }\n\n        (component.get('v.initialized') == true) ? activeChevron += 1 : activeChevron;\n\n        for (var i = 0; i < chevrons.length; i++) {\n            if (i == activeChevron) {\n                chevrons[i].class = 'slds-is-current';\n                if (error) chevrons[i].class += ' slds-is-lost';\n                chevrons[i].status = 'incomplete';\n                chevrons[i].current = true;\n                chevrons[i].disabled = false;\n                component.set('v.currentChevron', i + 1);\n                component.set('v.activeChevron', i);\n            } else if (i < activeChevron) {\n                chevrons[i].class = 'slds-is-complete';\n                chevrons[i].status = 'complete';\n                chevrons[i].current = false;\n                chevrons[i].disabled = forceProcessFlow || disableBackwardNavOnComplete;\n            } else if (i > activeChevron) {\n                chevrons[i].current = false;\n                chevrons[i].status = 'incomplete';\n                chevrons[i].class = 'slds-is-incomplete';\n                chevrons[i].disabled = forceProcessFlow || disableForwardNavOnIncomplete;\n            }\n\n            if (chevrons[i].current == true) results.current = i || 0;\n            if (chevrons[i].active == true) results.active = i || 0;\n        }\n\n        component.set('v.advanceButtonText', component.get('v.advanceButtonNextLabel'));\n        component.set('v.toggleButtonStyle', true);\n        component.set('v.chevrons', chevrons);\n        component.set('v.initialized', false);\n        this.sendResultsToParent(component, results, 'save');\n    },\n    moveToChevron : function(component, targetChevron) {\n        var helper = this;\n        var chevrons = component.get('v.chevrons');\n        var chevron = chevrons[targetChevron];\n        if (chevron.disabled == true) return;\n\n        if (!component.get('v.advanceButton') && component.get('v.displayMode').toLowerCase() == 'wizard') {\n            helper.renderAdvanceButtonClick(component, targetChevron);\n        } else {\n            (component.get('v.displayMode').toLowerCase() == 'wizard' && component.get('v.advanceButton') == true) ? helper.renderWizardMode(component, targetChevron) : helper.renderSimpleMode(component, targetChevron);\n        }\n    },\n    sendResultsToParent: function(component, results, type) {\n        var clickEvent = component.getEvent('strike_evt_chevron');\n        clickEvent.setParams({\n            data: {\n                'results': results,\n                'type': type\n            }\n        })\n        clickEvent.fire();\n    },\n    showToast: function(component, event) {\n        if (component.get('v.displayMode').toLowerCase() == 'simple') return;\n        var params = event.getParam('arguments');\n        var toastEvent = $A.get(\"e.force:showToast\");\n        if (typeof(toastEvent) !== 'undefined') {\n            if (params) {\n                toastEvent.setParams({\n                    \"title\": params.title,\n                    \"message\": params.message,\n                    \"key\": params.key,\n                    \"duration\": params.duration,\n                    \"type\": params.type,\n                    \"mode\": params.mode\n\n                });\n            }\n            toastEvent.fire();\n        }\n    }\n})\n/*\nCopyright 2017 Appiphony, LLC\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the\nfollowing conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following\ndisclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\ndisclaimer in the documentation and/or other materials provided with the distribution.\n3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote\nproducts derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/LC_URLController.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class LC_URLController {\n\n    @AuraEnabled\n    public static Map<String, String> getUrlInfo() {\n\n        String namespace = getNamespaceOfClass( 'LC_URLController' );\n        String orgDomainURL = URL.getOrgDomainUrl().toExternalForm();\n        String salesforceBaseURL = URL.getSalesforceBaseUrl().toExternalForm();\n\n        Map<String, String> result = new Map<String, String>();\n\n        result.put( 'orgDomainURL', orgDomainURL );\n        result.put( 'salesforceBaseURL', salesforceBaseURL );\n        result.put( 'namespace', namespace );\n\n        return result;\n    }\n\n    private static String getNamespaceOfClass( String className ) {\n\n        String namespace = [ SELECT NamespacePrefix FROM ApexClass WHERE Name = :className LIMIT 1 ].NamespacePrefix;\n\n        return ( String.isBlank( namespace ) ? '' : namespace );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/LC_URLController.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/LC_URLControllerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class LC_URLControllerTest {\n\n    @IsTest\n    static void test_get_url_info() {\n\n        String namespace = [ SELECT NamespacePrefix FROM ApexClass WHERE Name = 'LC_URLController' LIMIT 1 ].NamespacePrefix;\n        namespace = ( String.isBlank( namespace ) ? '' : namespace );\n\n        Test.startTest();\n\n        Map<String, String> urlInfo = LC_URLController.getUrlInfo();\n\n        System.assertEquals( URL.getOrgDomainUrl().toExternalForm(), urlInfo.get( 'orgDomainURL' ) );\n        System.assertEquals( URL.getSalesforceBaseUrl().toExternalForm(), urlInfo.get( 'salesforceBaseURL' ) );\n        System.assertEquals( namespace, urlInfo.get( 'namespace' ) );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/LC_URLControllerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/LC_VisualforceDomainController.cls",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n */\npublic with sharing class LC_VisualforceDomainController {\n\n    // Aura Component\n\n    @AuraEnabled( cacheable = true )\n    public static String getVisualforceDomainURL() {\n        PageReference vfPage = Page.LC_VisualforceDomainPage;\n        return ( Test.isRunningTest() ? 'https://visualforce.com' : vfPage.getContent().toString().trim() );\n    }\n\n    // -----------------------------------------------------------------------------\n\n    // Visualforce Page\n\n    public String getDomainURL() {\n        URL requestURL = URL.getCurrentRequestUrl();\n        return requestURL.toExternalForm().substringBefore( requestURL.getPath() );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/LC_VisualforceDomainController.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/LC_VisualforceDomainControllerTest.cls",
    "content": "/*\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n */\n@IsTest\nprivate class LC_VisualforceDomainControllerTest {\n\n    // Aura Component\n\n    @IsTest\n    static void test_get_visualforce_domain_url() {\n\n        Test.startTest();\n\n        String vfDomainURL = LC_VisualforceDomainController.getVisualforceDomainURL();\n\n        System.assertEquals( 'https://visualforce.com', vfDomainURL );\n\n        Test.stopTest();\n\n    }\n\n    // -----------------------------------------------------------------------------\n\n    // Visualforce Page\n\n    @IsTest\n    static void test_get_domain_url() {\n\n        Test.setCurrentPage( Page.LC_VisualforceDomainPage );\n\n        Test.startTest();\n\n        LC_VisualforceDomainController controller = new LC_VisualforceDomainController();\n\n        String domainURL = controller.getDomainURL();\n\n        // The test is not running in Visualforce context,\n        // so best we can get here is domain in Apex context.\n        System.assertEquals( URL.getSalesforceBaseUrl().toExternalForm(), domainURL );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/LC_VisualforceDomainControllerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_AnonymousApexExecuteResult.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * Represents some parts of an XML response from Anonymous Apex SOAP API.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/sforce_api_calls_executeanonymous_result.htm\n */\npublic inherited sharing class MA_AnonymousApexExecuteResult {\n\n    public Integer column { get; set; }\n\n    public String compileProblem { get; set; }\n\n    public Boolean compiled { get; set; }\n\n    public String exceptionMessage { get; set; }\n\n    public String exceptionStackTrace { get; set; }\n\n    public Integer line { get; set; }\n\n    public Boolean success { get; set; }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_AnonymousApexExecuteResult.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_AsyncApexJobMock.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * Test coverage provided by MA_MassActionBatchUtilsTest.\n */\npublic inherited sharing class MA_AsyncApexJobMock {\n\n    // These are fake job ids that parse via ID.valueOf()\n    // but don't actually exist. This allows test/mock code\n    // to instantiate AsyncApexJobs or pass job ids to methods\n    // and reliably get back a test/mock job record later.\n    // Checkmarx security scanner labels these \"low risk hardcoded ids\".\n    // They are hardcoded on purpose for testing/mocking purposes.\n    public static final ID QUEUED_JOB_ID                = '707f40000000001';\n    public static final ID PREPARING_JOB_ID             = '707f40000000002';\n    public static final ID PROCESSING_JOB_ID            = '707f40000000003';\n    public static final ID ABORTED_JOB_ID               = '707f40000000004';\n    public static final ID FAILED_JOB_ID                = '707f40000000005';\n    public static final ID COMPLETED_JOB_ID             = '707f40000000006';\n    public static final ID COMPLETED_WITH_ERRORS_JOB_ID = '707f40000000007';\n\n    public static final Set<ID> MOCK_JOB_IDS = new Set<ID>{\n        QUEUED_JOB_ID,\n        PREPARING_JOB_ID,\n        PROCESSING_JOB_ID,\n        ABORTED_JOB_ID,\n        FAILED_JOB_ID,\n        COMPLETED_JOB_ID,\n        COMPLETED_WITH_ERRORS_JOB_ID\n    };\n\n    private static final Map<ID, AsyncApexJob> MOCK_JOBS_MAP = new Map<ID, AsyncApexJob>{\n        QUEUED_JOB_ID => mockJob( QUEUED_JOB_ID, 'Queued', null, null, null, null ),\n        PREPARING_JOB_ID => mockJob( PREPARING_JOB_ID, 'Preparing', null, null, null, null ),\n        PROCESSING_JOB_ID => mockJob( PROCESSING_JOB_ID, 'Processing', null, 2, 0, 0 ),\n        ABORTED_JOB_ID => mockJob( ABORTED_JOB_ID, 'Aborted', null, 2, 1, 0 ),\n        FAILED_JOB_ID => mockJob( FAILED_JOB_ID, 'Failed', 'Test Job Failed', 2, 0, 2 ),\n        COMPLETED_JOB_ID => mockJob( COMPLETED_JOB_ID, 'Completed', null, 2, 2, 0 ),\n        COMPLETED_WITH_ERRORS_JOB_ID => mockJob( COMPLETED_WITH_ERRORS_JOB_ID, 'Completed', 'Test Job Completed with Errors', 2, 0, 2 )\n    };\n\n    public static AsyncApexJob getJobById( ID jobId ) {\n        return MOCK_JOBS_MAP.get( jobId );\n    }\n\n    private static AsyncApexJob mockJob( ID jobId, String status, String extendedStatus, Integer totalJobItems, Integer jobItemsProcessed, Integer numberOfErrors ) {\n        // this object has non-writable fields so we use the json serialization trick to populate a mock record\n        return (AsyncApexJob) JSON.deserialize( JSON.serialize( new Map<String, Object>{\n            'Id' => jobId,\n            'Status' => status,\n            'ExtendedStatus' => extendedStatus,\n            'TotalJobItems' => totalJobItems,\n            'JobItemsProcessed' => jobItemsProcessed,\n            'NumberOfErrors' => numberOfErrors,\n            'CreatedDate' => DateTime.now(),\n            'CompletedDate' => DateTime.now()\n        }), AsyncApexJob.class );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_AsyncApexJobMock.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexErrorEventInvocable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * This class explicitly uses 'without sharing' because it runs not as a real user\n * but rather as the Automated Process user, an entity we can't grant permissions to.\n */\npublic without sharing class MA_BatchApexErrorEventInvocable {\n\n    @InvocableMethod(\n        label = 'MAS: Batch Apex Error Event Handler'\n        description = 'Creates Mass Action Logs from batch job errors when running Mass Action Configurations.'\n    )\n    public static List<Response> execute( List<Request> requests ) {\n\n        List<Response> responses = new List<Response>();\n\n        System.debug( 'MA_BatchApexErrorEventInvocable.execute: size=' + requests.size() );\n\n        Set<ID> jobIds = new Set<ID>();\n        for ( Request evt : requests ) {\n            if ( String.isNotBlank( evt.asyncApexJobId ) ) {\n                jobIds.add( ID.valueOf( evt.asyncApexJobId ) );\n            }\n        }\n\n        Map<ID, AsyncApexJob> jobIdToJobMap = MA_MassActionBatchUtils.getJobsByJobIdMap( jobIds );\n\n        Map<ID, Mass_Action_Log__c> jobIdtoParentLogMap = MA_MassActionBatchUtils.getParentLogsByJobIdMap( jobIdToJobMap.values() );\n\n        List<Mass_Action_Batch_Apex_Status_Event__e> jobStatusEvents = new List<Mass_Action_Batch_Apex_Status_Event__e>();\n\n        for ( Request evt : requests ) {\n\n            ID asyncApexJobId = ID.valueOf( evt.AsyncApexJobId );\n            AsyncApexJob job = jobIdToJobMap.get( asyncApexJobId );\n            Mass_Action_Log__c parentLog = jobIdToParentLogMap.get( asyncApexJobId );\n\n            // if either the job or parent log are null then\n            // this batch error event is not for mass action scheduler, skip it\n            if ( job != null && parentLog != null ) {\n\n                jobStatusEvents.add( new Mass_Action_Batch_Apex_Status_Event__e(\n                    Job_ID__c = job.Id,\n                    Phase__c = evt.Phase,\n                    Message_Type__c = 'Error',\n                    Message__c = 'Error in job phase ' + evt.Phase + ': ' + evt.Message,\n                    Long_Message__c = (\n                        'Phase: ' + evt.Phase + '\\n' +\n                        'Message: ' + evt.Message + '\\n' +\n                        'ExceptionType: ' + evt.ExceptionType + '\\n' +\n                        'StackTrace: ' + evt.StackTrace\n                    ),\n                    Job_Scope__c = evt.JobScope,\n                    // It is very important that we use the event's created date\n                    // and not when we're processing the event because platform events\n                    // are handled asynchronously. If we use \"now\" vs. \"then\" then\n                    // our log records will be out of order chronologically.\n                    // The logs would appear in the order we got to insert them\n                    // rather than the real time of when the cause occurred.\n                    Timestamp__c = String.valueOf( evt.CreatedDate.getTime() )\n                ));\n\n            }\n\n        }\n\n        List<Database.SaveResult> results = MA_MassActionBatchUtils.publish( jobStatusEvents );\n\n        for ( Database.SaveResult result : results ) {\n            responses.add( new Response( result ) );\n        }\n\n        return responses;\n    }\n\n    /**\n     * Mirrors the BatchApexErrorEvent record.\n     * Designed for process builder to map the fields to this invocable request parameter.\n     * https://developer.salesforce.com/docs/atlas.en-us.220.0.platform_events.meta/platform_events/sforce_api_objects_batchapexerrorevent.htm\n     */\n    public inherited sharing class Request {\n\n        @InvocableVariable(\n            label = 'Async Apex Job ID'\n            description = 'ID of the batch Apex job that fired this event.'\n            required = true\n        )\n        public String asyncApexJobId;\n\n        @InvocableVariable(\n            label = 'Phase'\n            description = 'The phase of the batch job when it encountered an error. One of START, EXECUTE, or FINISH.'\n            required = true\n        )\n        public String phase;\n\n        @InvocableVariable(\n            label = 'Job Scope'\n            description = 'The Record IDs that are in scope if the event was fired from the execute() method of a batch job.'\n            required = true\n        )\n        public String jobScope;\n\n        @InvocableVariable(\n            label = 'Message'\n            description = 'Exception message text.'\n            required = true\n        )\n        public String message;\n\n        @InvocableVariable(\n            label = 'Exception Type'\n            description = 'The Apex exception type name.'\n            required = true\n        )\n        public String exceptionType;\n\n        @InvocableVariable(\n            label = 'Stack Trace'\n            description = 'The Apex stacktrace of the exception, if available.'\n            required = true\n        )\n        public String stackTrace;\n\n        @InvocableVariable(\n            label = 'Replay ID'\n            description = 'ID value that is populated by the system and refers to the position of the event in the event stream.'\n            required = true\n        )\n        public String replayId;\n\n        @InvocableVariable(\n            label = 'Request ID'\n            description = 'The unique ID of the batch job that fired the event.'\n            required = true\n        )\n        public String requestId;\n\n        @InvocableVariable(\n            label = 'Created By ID'\n            description = 'Who published this event.'\n            required = true\n        )\n        public ID createdById;\n\n        @InvocableVariable(\n            label = 'Created Date'\n            description = 'When the event was published.'\n            required = true\n        )\n        public DateTime createdDate;\n\n        public Request() {}\n\n        public Request( BatchApexErrorEvent evt ) {\n            this.asyncApexJobId = evt.AsyncApexJobId;\n            this.phase = evt.Phase;\n            this.jobScope = evt.JobScope;\n            this.message = evt.Message;\n            this.exceptionType = evt.ExceptionType;\n            this.stackTrace = evt.StackTrace;\n            this.replayId = evt.ReplayId;\n            this.requestId = evt.RequestId;\n            this.createdById = evt.CreatedById;\n            this.createdDate = evt.CreatedDate;\n        }\n\n    }\n\n    public inherited sharing class Response {\n\n        @InvocableVariable(\n            label = 'Event ID'\n            description = 'ID of the published Mass_Action_Batch_Apex_Status_Event__e event.'\n        )\n        public ID eventId;\n\n        @InvocableVariable(\n            label = 'Success'\n            description = 'True if the event was published, false otherwise.'\n        )\n        public Boolean success;\n\n        @InvocableVariable(\n            label = 'Errors'\n            description = 'List of errors trying to publish the event.'\n        )\n        public List<String> errors = new List<String>();\n\n        public Response() {}\n\n        public Response( Database.SaveResult result ) {\n            this.eventId = result.id;\n            this.success = result.success;\n            for ( Database.Error err : result.getErrors() ) {\n                errors.add( err.getStatusCode() + ' : ' + err.getMessage() );\n            }\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexErrorEventInvocable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexErrorEventInvocableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_BatchApexErrorEventInvocableTest {\n\n    @IsTest\n    static void test_invocable() {\n\n        AsyncApexJob job = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.PROCESSING_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true\n        );\n\n        insert config;\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = job.Id,\n            Submitted_Date__c = DateTime.now(),\n            Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n            Message__c = 'Batch job enqueued',\n            Message_Type__c = 'Informational'\n        );\n\n        insert parentLog;\n\n        Test.startTest();\n\n        BatchApexErrorEvent evt = (BatchApexErrorEvent) JSON.deserialize( JSON.serialize( new Map<String, Object>{\n            'AsyncApexJobId' => job.Id,\n            'Phase' => 'START',\n            'Message' => 'TEST ERROR MESSAGE',\n            'ExceptionType' => 'TEST EXCEPTION TYPE',\n            'StackTrace' => 'TEST STACK TRACE',\n            'JobScope' => 'TEST JOB SCOPE',\n            'ReplayId' => 'TEST REPLAY ID',\n            'RequestId' => 'TEST REQUEST ID',\n            'CreatedById' => UserInfo.getUserId(),\n            'CreatedDate' => DateTime.now()\n        }), BatchApexErrorEvent.class );\n\n        List<MA_BatchApexErrorEventInvocable.Request> requests = new List<MA_BatchApexErrorEventInvocable.Request>{\n            new MA_BatchApexErrorEventInvocable.Request( evt )\n        };\n\n        List<MA_BatchApexErrorEventInvocable.Response> responses = MA_BatchApexErrorEventInvocable.execute( requests );\n\n        Test.stopTest();\n\n        Test.getEventBus().deliver();\n\n        System.assertEquals( requests.size(), responses.size() );\n        System.assertEquals( true, responses[0].success );\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        System.assertEquals( 'Batch job ' + job.Status.toLowerCase(), parentLog.Message__c );\n        System.assertEquals( 'Informational', parentLog.Message_Type__c );\n\n        System.assertEquals( 1, parentLog.Mass_Action_Logs__r.size() );\n        System.assertEquals( 'Error in job phase ' + evt.Phase + ': ' + evt.Message, parentLog.Mass_Action_Logs__r[0].Message__c );\n        System.assertEquals( 'Error', parentLog.Mass_Action_Logs__r[0].Message_Type__c );\n        System.assertEquals( evt.JobScope, parentLog.Mass_Action_Logs__r[0].Job_Scope__c );\n\n    }\n\n    @IsTest\n    static void instantiate_request_and_response() {\n\n        // Gotta get that code coverage!\n\n        Test.startTest();\n\n        MA_BatchApexErrorEventInvocable.Request req = new MA_BatchApexErrorEventInvocable.Request();\n\n        MA_BatchApexErrorEventInvocable.Response res = new MA_BatchApexErrorEventInvocable.Response();\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexErrorEventInvocableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexStatusEventTriggerHandler.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * This class explicitly uses 'without sharing' because it runs not as a real user\n * but rather as the Automated Process user, an entity we can't grant permissions to.\n */\npublic without sharing class MA_BatchApexStatusEventTriggerHandler {\n\n    public MA_BatchApexStatusEventTriggerHandler() {}\n\n    // -------------------------------------------------------\n    // INSERT\n    // -------------------------------------------------------\n\n    public void handleAfterInsert( List<Mass_Action_Batch_Apex_Status_Event__e> newList, Map<ID, Mass_Action_Batch_Apex_Status_Event__e> newMap ) {\n\n        System.debug( 'MA_BatchApexStatusEventTriggerHandler.handleAfterInsert' );\n\n        Set<ID> jobIds = new Set<ID>();\n        for ( Mass_Action_Batch_Apex_Status_Event__e evt : newList ) {\n            if ( String.isNotBlank( evt.Job_ID__c ) ) {\n                jobIds.add( ID.valueOf( evt.Job_ID__c ) );\n            }\n        }\n\n        Map<ID, AsyncApexJob> jobIdToJobMap = MA_MassActionBatchUtils.getJobsByJobIdMap( jobIds );\n\n        Map<ID, Mass_Action_Log__c> jobIdtoParentLogMap = MA_MassActionBatchUtils.getParentLogsByJobIdMap( jobIdToJobMap.values() );\n\n        Map<String, RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Map<String, Mass_Action_Log__c> parentLogsToUpdateMap = new Map<String, Mass_Action_Log__c>();\n        List<Mass_Action_Log__c> childLogsToInsertList = new List<Mass_Action_Log__c>();\n\n        // Platform event triggers may receive up to 2,000 events.\n        // Apex triggers are limited to 200 records per batch.\n        // Since we are doing DML in this event handler, to mitigate exceeding a governor limit\n        // then we'll chunk the events into smaller batches.\n        // https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_subscribe_batch_resume.htm\n\n        Integer BATCH_LIMIT = 200;\n        Integer batchLimitCounter = 0;\n        String lastEventReplayId;\n\n        for ( Mass_Action_Batch_Apex_Status_Event__e evt : newList ) {\n\n            batchLimitCounter++;\n            if ( batchLimitCounter > BATCH_LIMIT ) {\n                System.debug( 'MA_BatchApexStatusEventTriggerHandler.handleAfterInsert: reached batch limit of ' + BATCH_LIMIT + ', will requeue remaining ' + ( newList.size() - BATCH_LIMIT ) + ' events for processing' );\n                break;\n            }\n\n            System.debug( 'MA_BatchApexStatusEventTriggerHandler.handleAfterInsert: event=' + JSON.serializePretty( evt ) );\n\n            ID asyncApexJobId = ID.valueOf( evt.Job_ID__c );\n            AsyncApexJob job = jobIdToJobMap.get( asyncApexJobId );\n            Mass_Action_Log__c parentLog = jobIdToParentLogMap.get( asyncApexJobId );\n\n            // if either the job or parent log are null then\n            // this batch error event is not for mass action scheduler, skip it\n            if ( job != null && parentLog != null ) {\n\n                Mass_Action_Log__c parentLogToUpdate = parentLogsToUpdateMap.get( parentLog.Id );\n\n                if ( parentLogToUpdate == null ) {\n\n                    Boolean jobFailed = ( job.Status == 'Failed' );\n                    Boolean jobHasErrors = ( String.isNotBlank( job.ExtendedStatus ) || job.NumberOfErrors > 0 );\n\n                    String messageType = (\n                        ( job.Status == 'Aborted' || job.Status == 'Failed' || jobHasErrors ) ? 'Error' :\n                        ( job.CompletedDate != null && job.TotalJobItems == job.JobItemsProcessed ) ? 'Success' :\n                        'Informational'\n                    );\n\n                    String message = 'Batch job ' + (\n                        ( job.Status == 'Completed' && jobHasErrors ) ? 'completed with errors' :\n                        String.isBlank( job.Status ) ? 'information' :\n                        job.Status.toLowerCase()\n                    );\n\n                    parentLogsToUpdateMap.put( parentLog.Id, new Mass_Action_Log__c(\n                        Id = parentLog.Id,\n                        Message_Type__c = messageType,\n                        Message__c = message,\n                        Submitted_Date__c = job.CreatedDate,\n                        Total_Batches__c = job.TotalJobItems,\n                        Processed_Batches__c = job.JobItemsProcessed,\n                        Failed_Batches__c = job.NumberOfErrors\n                    ));\n\n                }\n\n                childLogsToInsertList.add( new Mass_Action_Log__c(\n                    RecordTypeId = logRecordTypeInfosMap.get( 'Child_Log' ).getRecordTypeId(),\n                    Mass_Action_Configuration__c = parentLog.Mass_Action_Configuration__c,\n                    Parent_Log__c = parentLog.Id,\n                    Job_ID__c = parentLog.Job_ID__c,\n                    Message_Type__c = evt.Message_Type__c,\n                    Message__c = evt.Message__c,\n                    Long_Message__c = evt.Long_Message__c,\n                    Job_Scope__c = evt.Job_Scope__c,\n                    Timestamp__c = evt.Timestamp__c\n                ));\n\n            }\n\n            lastEventReplayId = evt.ReplayId;\n\n        }\n\n        System.debug( 'MA_BatchApexStatusEventTriggerHandler.handleAfterInsert: inserting child logs and updating parent logs' );\n\n        Database.DMLOptions dmo = new Database.DMLOptions();\n        dmo.allowFieldTruncation = true;\n\n        Database.insert( childLogsToInsertList, dmo );\n        Database.update( parentLogsToUpdateMap.values(), dmo );\n\n        // When the trigger stops its flow of execution, either intentionally or because of an unhandled exception,\n        // such as a limit exception, it fires again with a new batch (the sObject list in Trigger.New).\n        // The new batch starts with the event message after the one with the replay ID that you set.\n        // Therefore, we don't want to set this resume checkpoint until we know that the above DML operations complete.\n        // https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_subscribe_batch_resume.htm\n        if ( String.isNotBlank( lastEventReplayId ) ) {\n            System.debug( 'MA_BatchApexStatusEventTriggerHandler.handleAfterInsert: setting resume checkpoint: lastEventReplayId=' + lastEventReplayId );\n            EventBus.TriggerContext.currentContext().setResumeCheckpoint( lastEventReplayId );\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexStatusEventTriggerHandler.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexStatusEventTriggerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_BatchApexStatusEventTriggerTest {\n\n    @IsTest\n    static void test_publish() {\n\n        AsyncApexJob job = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.COMPLETED_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true\n        );\n\n        insert config;\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = job.Id,\n            Submitted_Date__c = DateTime.now(),\n            Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n            Message__c = 'Batch job enqueued',\n            Message_Type__c = 'Informational'\n        );\n\n        insert parentLog;\n\n        Test.startTest();\n\n        Mass_Action_Batch_Apex_Status_Event__e evt = new Mass_Action_Batch_Apex_Status_Event__e(\n            Job_ID__c = job.Id,\n            Phase__c = 'FINISH',\n            Message_Type__c = 'Success',\n            Message__c = 'TEST MESSAGE',\n            Long_Message__c = 'TEST LONG MESSAGE',\n            Job_Scope__c = 'TEST JOB SCOPE',\n            Timestamp__c = 'TEST TIMESTAMP'\n        );\n\n        EventBus.publish( evt );\n\n        Test.stopTest();\n\n        Test.getEventBus().deliver();\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        System.assertEquals( 'Batch job ' + job.Status.toLowerCase(), parentLog.Message__c );\n        System.assertEquals( 'Success', parentLog.Message_Type__c );\n\n        System.assertEquals( 1, parentLog.Mass_Action_Logs__r.size() );\n        System.assertEquals( evt.Message__c, parentLog.Mass_Action_Logs__r[0].Message__c );\n        System.assertEquals( 'Success', parentLog.Mass_Action_Logs__r[0].Message_Type__c );\n        System.assertEquals( evt.Job_Scope__c, parentLog.Mass_Action_Logs__r[0].Job_Scope__c );\n\n    }\n\n    @IsTest\n    static void test_publish_bulk() {\n\n        AsyncApexJob job = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.COMPLETED_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true\n        );\n\n        insert config;\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = job.Id,\n            Submitted_Date__c = DateTime.now(),\n            Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n            Message__c = 'Batch job enqueued',\n            Message_Type__c = 'Informational'\n        );\n\n        insert parentLog;\n\n        Test.startTest();\n\n        List<Mass_Action_Batch_Apex_Status_Event__e> events = new List<Mass_Action_Batch_Apex_Status_Event__e>();\n        for ( Integer i = 0; i < 201; i++ ) {\n            events.add( new Mass_Action_Batch_Apex_Status_Event__e(\n                Job_ID__c = job.Id,\n                Phase__c = 'FINISH',\n                Message_Type__c = 'Success',\n                Message__c = 'TEST MESSAGE ' + i,\n                Long_Message__c = 'TEST LONG MESSAGE ' + i,\n                Job_Scope__c = 'TEST JOB SCOPE ' + i,\n                Timestamp__c = 'TEST TIMESTAMP ' + i\n            ));\n        }\n\n        // Our event trigger handler chunks the published events\n        // into batches of 200 to keep the scope low because the\n        // handler performs DML operations. By default, the event bus\n        // could deliver up to 2,000 events at a time. We could run\n        // into SOQL and DML governor limits in this trigger handler.\n        // The test, then, is to ensure that multiple waves will occur\n        // and that the expected number of mass action logs are created.\n\n        // Publish 201 events\n        EventBus.publish( events );\n\n        // Delivers 201 events, but the handler will set a resume checkpoint\n        // after processing the first 200 events.\n        Test.getEventBus().deliver();\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        Integer firstWaveCountOfLogs = parentLog.Mass_Action_Logs__r.size();\n\n        System.debug( 'FIRST WAVE' );\n        System.debug( JSON.serializePretty( parentLog ) );\n\n        // Publish all events after the resume checkpoint.\n        // In this test, that would be the 201st event.\n        Test.getEventBus().deliver();\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        Integer secondWaveCountOfLogs = parentLog.Mass_Action_Logs__r.size();\n\n        System.debug( 'SECOND WAVE' );\n        System.debug( JSON.serializePretty( parentLog ) );\n\n        Test.stopTest();\n\n        // assert total events published in each wave and overall\n        System.assertEquals( firstWaveCountOfLogs + 1, secondWaveCountOfLogs );\n        System.assertEquals( events.size(), secondWaveCountOfLogs );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_BatchApexStatusEventTriggerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigCmpController.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_EditConfigCmpController {\n\n    /**\n     * This method accepts the JSON serialization of the configuration and field mappings\n     * because when defining the method params as the custom class type was getting internal server error.\n     * I think possibly related to general serialization bugs with Lightning:\n     * https://developer.salesforce.com/forums/?id=906F00000005GiwIAE\n     * https://blog.texei.com/lightning-components-auraenabled-method-parameters-whats-working-and-what-s-not-83c351356104\n     */\n    @AuraEnabled\n    public static Map<String, Object> saveConfiguration( String wrapperJson, String fieldMappingsJson ) {\n\n        SavePoint sp = Database.setSavepoint();\n\n        try {\n\n            return MA_MassActionUtils.saveConfiguration( wrapperJson, fieldMappingsJson );\n\n        } catch ( Exception e ) {\n\n            Database.rollback( sp );\n\n            System.debug( LoggingLevel.ERROR, 'MA_EditConfigCmpController.saveConfiguration: ' + e.getMessage() + ' : ' + e.getStackTraceString() );\n\n            throw new AuraHandledException( e.getMessage() );\n\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigCmpController.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigCmpControllerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_EditConfigCmpControllerTest {\n\n    @IsTest\n    static void test_saveConfiguration() {\n\n        MA_MassActionConfigWrapper wrapper = new MA_MassActionConfigWrapper();\n        wrapper.name = 'Test Config';\n        wrapper.developerName = 'Test_Config';\n        wrapper.active = false;\n        wrapper.batchSize = 200;\n        wrapper.namedCredential = 'Mass_Action_Test_Named_Credential';\n        wrapper.sourceType = 'ListView';\n        wrapper.sourceListViewID = '00Bf40000017w5h';\n        wrapper.targetType = 'Flow';\n        wrapper.targetActionName = 'Test_Flow';\n        wrapper.scheduleFrequency = 'Custom';\n        wrapper.scheduleCron = '0 0 1 * * ?';\n\n        String wrapperJson = JSON.serialize( wrapper );\n\n        String fieldMappingsJson = JSON.serialize( new Map<String, String>{\n            'TargetField' => 'SourceField'\n        });\n\n        Test.startTest();\n\n        // Test Success\n\n        Map<String, Object> result = MA_EditConfigCmpController.saveConfiguration( wrapperJson, fieldMappingsJson );\n\n        System.assertEquals( true, result.get( 'success' ) );\n\n        Mass_Action_Configuration__c config = MA_MassActionUtils.getConfiguration( (ID) result.get( 'recordId' ) );\n\n        System.assertEquals( wrapper.name, config.Name );\n        System.assertEquals( wrapper.active, config.Active__c );\n        System.assertEquals( wrapper.batchSize, config.Batch_Size__c );\n        System.assertEquals( wrapper.namedCredential, config.Named_Credential__c );\n        System.assertEquals( wrapper.sourceType, config.Source_Type__c );\n        System.assertEquals( wrapper.sourceListViewID, config.Source_List_View_ID__c );\n        System.assertEquals( wrapper.targetType, config.Target_Type__c );\n        System.assertEquals( wrapper.targetActionName, config.Target_Action_Name__c );\n        System.assertEquals( wrapper.scheduleFrequency, config.Schedule_Frequency__c );\n        System.assertEquals( wrapper.scheduleCron, config.Schedule_Cron__c );\n\n        System.assertEquals( 1, config.Mass_Action_Mappings__r.size() );\n        System.assertEquals( 'TargetField', config.Mass_Action_Mappings__r[0].Target_Field_Name__c );\n        System.assertEquals( 'SourceField', config.Mass_Action_Mappings__r[0].Source_Field_Name__c );\n\n        // Test Error\n\n        try {\n\n            MA_EditConfigCmpController.saveConfiguration( null, null );\n\n            System.assert( false, 'should fail' );\n\n        } catch ( Exception e ) {\n\n            System.assert( true, 'should fail' );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigCmpControllerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigRestController.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@RestResource( urlMapping = '/config/edit/*' )\nglobal with sharing class MA_EditConfigRestController {\n\n    /**\n     * Entry point into this REST class.\n     *\n     * Expects one URL parameter named 'operation',\n     * which translates to an actual Apex method in this class.\n     *\n     * Expects JSON body with parameters to pass to the actual\n     * Apex method indicated by the 'operation' URL parameter.\n     *\n     * Example:\n     *   POST: /services/apexrest/dca_mass_action/config/edit?operation=getReportsByFolder\n     *   {\n     *     \"reportId\" : \"00lf4000000pezaAAA\"\n     *   }\n     *\n     * See handleRequestOperation(..) method comments for full details.\n     */\n    @HttpPost\n    global static void handlePost() {\n\n        RestRequest req = RestContext.request;\n        RestResponse res = RestContext.response;\n\n        Map<String, String> requestUrlParams;\n        Map<String, Object> requestBodyParams;\n        Map<String, Object> responseBodyParams;\n\n        try {\n\n            System.debug( 'MA_EditConfigRestController.handlePost: request: ' + req );\n\n            requestUrlParams = req.params;\n            requestBodyParams = (Map<String, Object>) JSON.deserializeUntyped( ( req.requestBody == null ) ? '{}' : req.requestBody.toString() );\n            responseBodyParams = new Map<String, Object>{ 'success' => true };\n\n            String operation = requestUrlParams.get( 'operation' );\n\n            System.debug( 'MA_EditConfigRestController.handlePost: requestUrlParams: ' + JSON.serializePretty( requestUrlParams ) );\n            System.debug( 'MA_EditConfigRestController.handlePost: requestBody: ' + JSON.serializePretty( requestBodyParams ) );\n\n            handleRequestOperation( operation, requestBodyParams, responseBodyParams );\n\n        } catch ( Exception e ) {\n\n            System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );\n\n            responseBodyParams = new Map<String, Object>{\n                'success' => false,\n                'error' => e.getMessage()\n            };\n\n        }\n\n        res.responseBody = Blob.valueOf( JSON.serializePretty( responseBodyParams ) );\n        res.statusCode = 200;//( (Boolean) responseBodyParams.get( 'success' ) ) ? 200 : 400;\n\n        // To avoid customers having to setup their own CORS Whitelist then\n        // I whitelist their VF domain for them on the fly in the http response.\n        // https://github.com/douglascayers/sfdx-lightning-api-component-component#access-denied-or-no-access-control-allow-origin-header-is-present-on-the-requested-resource-origin-httpsyourinstancevisualforcecom-is-therefore-not-allowed-access\n        res.addHeader( 'Access-Control-Allow-Origin', req.headers.get( 'Origin' ) );\n        res.addHeader( 'Content-Type', 'application/json; charset=utf-8' );\n\n        System.debug( 'MA_EditConfigRestController.handlePost: response: ' + res );\n        System.debug( 'MA_EditConfigRestController.handlePost: responseBody: ' + res.responseBody.toString() );\n\n    }\n\n    /**\n     * This method serves as a translation layer between the REST API request and\n     * the actual implementation methods. Originally, the implementation methods\n     * for each operation were @AuraEnabled and called directly from Lightning components.\n     *\n     * To adapt those operations for use with the LC_API component then this class was\n     * introduced as a pure REST API endpoint for the same operations. However, since\n     * Apex REST services can only include a single @HttpGet, @HttpPost, etc. methods\n     * then I chose a single REST class and http method to handle all operations rather\n     * than creating a separate REST class for each operation. Thus, the need for this\n     * translation method.\n     *\n     * @param operation\n     *      Which implementation method to call.\n     *      These are the same names as the original AuraEnabled methods.\n     * @param requestBody\n     *      Map of key=value parameters from the REST request.\n     *      Method arguments will be pulled from these.\n     * @param responseBody\n     *      Map of key=value parameters for the REST response.\n     *      This method puts 'result' key into the map, or 'success=false' and 'error=...' entries if operation is not supported.\n     *\n     * Exceptions bubble up to calling method.\n     */\n    private static void handleRequestOperation( String operation, Map<String, Object> requestBody, Map<String, Object> responseBody ) {\n\n        switch on ( operation ) {\n\n            // -----------------------------------------------------------------------------\n\n            when 'getObjectsWithInvocableActions' {\n                responseBody.put( 'result', getObjectsWithInvocableActions(\n                    MA_MassActionUtils.REST_API_SERVICES_URL,\n                    (String) requestBody.get( 'actionType' )\n                ));\n            }\n\n            when 'getInvocableActions' {\n                responseBody.put( 'result', getInvocableActions(\n                    MA_MassActionUtils.REST_API_SERVICES_URL,\n                    (String) requestBody.get( 'actionType' ),\n                    (String) requestBody.get( 'objectName' )\n                ));\n            }\n\n            when 'getInvocableActionInputs' {\n                responseBody.put( 'result', getInvocableActionInputs(\n                    MA_MassActionUtils.REST_API_SERVICES_URL,\n                    (String) requestBody.get( 'actionType' ),\n                    (String) requestBody.get( 'actionName' ),\n                    (String) requestBody.get( 'objectName' )\n                ));\n            }\n\n            // -----------------------------------------------------------------------------\n\n            when 'getReportFolders' {\n                responseBody.put( 'result', getReportFolders() );\n            }\n\n            when 'getReportsByFolder' {\n                responseBody.put( 'result', getReportsByFolder(\n                    (ID) requestBody.get( 'folderId' )\n                ));\n            }\n\n            when 'getReport' {\n                responseBody.put( 'result', getReport(\n                    (ID) requestBody.get( 'recordId' )\n                ));\n            }\n\n            when 'getReportColumns' {\n                responseBody.put( 'result', getReportColumns(\n                    (String) requestBody.get( 'reportId' )\n                ));\n            }\n\n            // -----------------------------------------------------------------------------\n\n            when 'getObjectNames' {\n                responseBody.put( 'result', getObjectNames() );\n            }\n\n            when 'getObjectNamesWithListViews' {\n                responseBody.put( 'result', getObjectNamesWithListViews() );\n            }\n\n            when 'getListViewsByObject' {\n                responseBody.put( 'result', getListViewsByObject(\n                    (String) requestBody.get( 'objectName' )\n                ));\n            }\n\n            when 'getListView' {\n                responseBody.put( 'result', getListView(\n                    (ID) requestBody.get( 'recordId' )\n                ));\n            }\n\n            when 'getListViewColumns' {\n                responseBody.put( 'result', getListViewColumns(\n                    MA_MassActionUtils.REST_API_SERVICES_URL,\n                    (ID) requestBody.get( 'listViewId' )\n                ));\n            }\n\n            // -----------------------------------------------------------------------------\n\n            when 'getSoqlQueryResults' {\n                responseBody.put( 'result', getSoqlQueryResults(\n                    MA_MassActionUtils.REST_API_SERVICES_URL,\n                    (String) requestBody.get( 'query' ),\n                    (Integer) requestBody.get( 'batchSize' )\n                ));\n            }\n\n            when 'getSoqlQueryNextRecordsResults' {\n                responseBody.put( 'result', getSoqlQueryNextRecordsResults(\n                    MA_MassActionUtils.REST_API_SERVICES_URL,\n                    (String) requestBody.get( 'nextRecordsId' ),\n                    (Integer) requestBody.get( 'batchSize' )\n                ));\n            }\n\n            // -----------------------------------------------------------------------------\n\n            when 'getNamedCredentials' {\n                responseBody.put( 'result', getNamedCredentials() );\n            }\n\n            // -----------------------------------------------------------------------------\n\n            when 'getConfiguration' {\n                responseBody.put( 'result', getConfiguration(\n                    (ID) requestBody.get( 'recordId' )\n                ));\n            }\n\n            when 'getConfigurationObjectDescribe' {\n                responseBody.put( 'result', getConfigurationObjectDescribe() );\n            }\n\n            when 'saveConfiguration' {\n                responseBody.put( 'result', saveConfiguration(\n                    JSON.serialize( requestBody.get( 'wrapperJson' ) ),\n                    JSON.serialize( requestBody.get( 'fieldMappingsJson' ) )\n                ));\n            }\n\n            // -----------------------------------------------------------------------------\n\n            when else {\n\n                responseBody.put( 'success', false );\n                responseBody.put( 'error', 'Unsupported operation value: ' + operation );\n\n            }\n\n        }\n\n    }\n\n    // -----------------------------------------------------------------------------\n\n    /**\n     * This method is primarily designed for showing list of objects for Email Alerts and Quick Actions.\n     * Rather than display user a list of all objects in their org that may or may not have actions setup\n     * we instead use the Actions REST API to know the objects (if any) that have actions configured for them.\n     * This has the benefit of reducing the unusable object options the user must sift through.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     */\n    private static List<Map<String, Object>> getObjectsWithInvocableActions( String baseURL, String actionType ) {\n\n        Map<String, SObjectType> globalDescribeMap = Schema.getGlobalDescribe();\n\n        List<ObjectNameWrapper> wrappers = new List<ObjectNameWrapper>();\n\n        for ( String objectName : MA_MassActionUtils.getObjectsWithInvocableActions( baseURL, actionType ) ) {\n            if ( globalDescribeMap.containsKey( objectName ) ) {\n                DescribeSObjectResult objDescribe = globalDescribeMap.get( objectName ).getDescribe();\n                wrappers.add( new ObjectNameWrapper( objDescribe.getLabel(), objDescribe.getName() ) );\n            }\n        }\n\n        wrappers.sort();\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( ObjectNameWrapper wrapper : wrappers ) {\n            options.add( new Map<String, Object>{\n                'label' => String.format( '{0} ({1})', new String[] { wrapper.objectLabel, wrapper.objectName } ),\n                'value' => wrapper.objectName\n            });\n        }\n\n        return options;\n    }\n\n    /**\n     * Get list of actions that can be invoked.\n     * Used when user is configuring the target action to invoke.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Specific kind of actions to retrieve like Flows or Email Alerts.\n     *      Value should match API value of Mass_Action_Configuration__c.Target_Type__c picklist entry.\n     * @param objectName\n     *      Only required for certain action types like Quick Actions or Email Alerts.\n     *      In the REST API, some actions are object specific and this indicates for which object to return their actions.\n     */\n    private static List<Map<String, Object>> getInvocableActions( String baseURL, String actionType, String objectName ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( Map<String, Object> action : MA_MassActionUtils.getInvocableActions( baseURL, actionType, objectName ) ) {\n            options.add( new Map<String, Object>{\n                'label' => action.get( 'label' ),\n                'value' => action.get( 'name' )\n            });\n        }\n\n        return options;\n    }\n\n    /**\n     * Get list of action inputs.\n     * Used when user is configuring the target action to invoke.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Specific kind of action like Flows or Email Alerts.\n     *      Value should match API value of Mass_Action_Configuration__c.Target_Type__c picklist entry.\n     * @param actionName\n     *      Specific action name whose inputs to retrieve like the Flow API name or Quick Action API name.\n     * @param objectName\n     *      Only required for certain action types like Quick Actions or Email Alerts.\n     *      In the REST API, some actions are object specific and this indicates for which object to return their actions.\n     */\n    private static List<Map<String, Object>> getInvocableActionInputs( String baseURL, String actionType, String actionName, String objectName ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        if ( actionType == 'Workflow' ) {\n\n            options.add( new Map<String, Object>{\n                'label' => 'Record ID',\n                'name' => 'ContextId',\n                'dataType' => 'ID',\n                'required' => true\n            });\n\n        } else {\n\n            for ( Map<String, Object> input : MA_MassActionUtils.getInvocableActionInputs( baseURL, actionType, actionName, objectName ) ) {\n                options.add( new Map<String, Object>{\n                    'label' => input.get( 'label' ),\n                    'name' => input.get( 'name' ),\n                    'dataType' => String.valueOf( input.get( 'type' ) ).toUpperCase(),\n                    'required' => Boolean.valueOf( input.get( 'required' ) ),\n                    'description' => String.valueOf( input.get( 'description' ) )\n                });\n            }\n\n        }\n\n        return options;\n    }\n\n    // -----------------------------------------------------------------------------\n\n    private static List<Map<String, Object>> getReportFolders() {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( Folder folder : [ SELECT id, name FROM Folder WHERE type = 'Report' AND developerName != null ORDER BY name ] ) {\n            options.add( new Map<String, Object>{\n                'label' => folder.name,\n                'value' => String.valueOf( folder.id ).left( 15 )\n            });\n        }\n\n        return options;\n    }\n\n    private static List<Map<String, Object>> getReportsByFolder( ID folderId ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( Report record : [ SELECT id, name FROM Report WHERE ownerId = :folderId AND format = 'Tabular' ORDER BY name ] ) {\n            options.add( new Map<String, Object>{\n                'label' => record.name,\n                'value' => String.valueOf( record.id ).left( 15 )\n            });\n        }\n\n        return options;\n    }\n\n    private static Report getReport( ID recordId ) {\n\n        Report rpt = null;\n\n        for ( Report record : [ SELECT id, name, ownerId, owner.name, folderName FROM Report WHERE id = :recordId LIMIT 1 ] ) {\n            rpt = record;\n        }\n\n        return rpt;\n    }\n\n    private static List<Map<String, Object>> getReportColumns( ID reportId ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        if ( String.isNotBlank( reportId ) ) {\n\n            Reports.ReportExtendedMetadata metadata = Reports.ReportManager.describeReport( reportId ).getReportExtendedMetadata();\n            Map<String, Reports.DetailColumn> reportColumnsMap = metadata.getDetailColumnInfo();\n\n            for ( Reports.DetailColumn column : reportColumnsMap.values() ) {\n                options.add( new Map<String, Object>{\n                    'label' => column.getLabel(),\n                    'value' => column.getName(),\n                    'dataType' => String.valueOf( column.getDataType().name() ).toUpperCase()\n                });\n            }\n\n        }\n\n        return options;\n    }\n\n    // -----------------------------------------------------------------------------\n\n    private static List<Map<String, Object>> getObjectNames() {\n\n        Map<String, SObjectType> globalDescribeMap = Schema.getGlobalDescribe();\n\n        List<ObjectNameWrapper> wrappers = new List<ObjectNameWrapper>();\n\n        for ( String key : globalDescribeMap.keySet() ) {\n            DescribeSObjectResult objDescribe = globalDescribeMap.get( key ).getDescribe();\n            wrappers.add( new ObjectNameWrapper( objDescribe.getLabel(), objDescribe.getName() ) );\n        }\n\n        wrappers.sort();\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( ObjectNameWrapper wrapper : wrappers ) {\n            options.add( new Map<String, Object>{\n                'label' => String.format( '{0} ({1})', new String[] { wrapper.objectLabel, wrapper.objectName } ),\n                'value' => wrapper.objectName\n            });\n        }\n\n        return options;\n    }\n\n    private static List<Map<String, Object>> getObjectNamesWithListViews() {\n\n        Set<String> sobjectsWithListViews = new Set<String>();\n        for ( AggregateResult result : [\n            SELECT SObjectType\n            FROM ListView\n            WHERE IsSoqlCompatible = true AND SObjectType != null\n            GROUP BY SObjectType\n            ORDER BY SObjectType ASC\n            LIMIT 2000\n        ]) {\n            // lowercase the object names to match keys in the global describe map\n            // because the Set method `contains` is case-sensitive\n            sobjectsWithListViews.add( ( (String) result.get( 'SObjectType' ) ).toLowerCase() );\n        }\n\n        Map<String, SObjectType> globalDescribeMap = Schema.getGlobalDescribe();\n\n        List<ObjectNameWrapper> wrappers = new List<ObjectNameWrapper>();\n\n        for ( String key : globalDescribeMap.keySet() ) {\n            if ( sobjectsWithListViews.contains( key ) ) {\n                DescribeSObjectResult objDescribe = globalDescribeMap.get( key ).getDescribe();\n                wrappers.add( new ObjectNameWrapper( objDescribe.getLabel(), objDescribe.getName() ) );\n            }\n        }\n\n        wrappers.sort();\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( ObjectNameWrapper wrapper : wrappers ) {\n            options.add( new Map<String, Object>{\n                'label' => String.format( '{0} ({1})', new String[] { wrapper.objectLabel, wrapper.objectName } ),\n                'value' => wrapper.objectName\n            });\n        }\n\n        return options;\n    }\n\n    private static List<Map<String, Object>> getListViewsByObject( String objectName ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( ListView record : [ SELECT id, name FROM ListView WHERE sobjectType = :objectName AND IsSoqlCompatible = true ORDER BY name ] ) {\n            options.add( new Map<String, Object>{\n                'label' => record.name,\n                'value' => String.valueOf( record.id ).substring( 0, 15 )\n            });\n        }\n\n        return options;\n    }\n\n    private static ListView getListView( ID recordId ) {\n\n        ListView lv = null;\n\n        for ( ListView record : [ SELECT id, name, sobjectType FROM ListView WHERE id = :recordId LIMIT 1 ] ) {\n            lv = record;\n        }\n\n        return lv;\n    }\n\n    /**\n     * The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     * or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     */\n    private static List<Map<String, Object>> getListViewColumns( String baseURL, ID listViewId ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        if ( String.isNotBlank( listViewId ) ) {\n\n            MA_ListViewDescribeResult describeResult = MA_MassActionUtils.describeListView( baseURL, listViewId );\n\n            for ( Map<String, Object> column : describeResult.columns ) {\n                options.add( new Map<String, Object>{\n                    'label' => column.get( 'label' ),\n                    'value' => column.get( 'fieldNameOrPath' ),\n                    'dataType' => String.valueOf( column.get( 'type' ) ).toUpperCase()\n                });\n            }\n\n        }\n\n        return options;\n    }\n\n    // -----------------------------------------------------------------------------\n\n    /**\n     * The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     * or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     */\n    private static MA_SoqlQueryExecuteResult getSoqlQueryResults( String baseURL, String query, Integer batchSize ) {\n\n        return MA_MassActionUtils.executeSoqlQuery( baseURL, query, batchSize );\n\n    }\n\n    /**\n     * The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     * or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     */\n    private static MA_SoqlQueryExecuteResult getSoqlQueryNextRecordsResults( String baseURL, String nextRecordsId, Integer batchSize ) {\n\n        return MA_MassActionUtils.executeSoqlQueryNextRecords( baseURL, nextRecordsId, batchSize );\n\n    }\n\n    // -----------------------------------------------------------------------------\n\n    private static List<Map<String, Object>> getNamedCredentials() {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        // for production use, filter out our test named credential\n        String whereClause = ' WHERE developerName != \\'Mass_Action_Test_Named_Credential\\' ';\n\n        // for code coverage, this is a separate if statement rather than if/else\n        // because with if/else one of the paths would never get tested =/\n        if ( Test.isRunningTest() ) {\n            whereClause = ' WHERE developerName  = \\'Mass_Action_Test_Named_Credential\\' ';\n        }\n\n        String query =\n            ' SELECT ' +\n                ' id, masterLabel, developerName ' +\n            ' FROM ' +\n                ' NamedCredential ' +\n            whereClause\n        ;\n\n        for ( NamedCredential credential : Database.query( query ) ) {\n            options.add( new Map<String, Object>{\n                'label' => credential.masterLabel,\n                'value' => credential.developerName\n            });\n        }\n\n        return options;\n    }\n\n    // -----------------------------------------------------------------------------\n\n    private static MA_MassActionConfigWrapper getConfiguration( ID recordId ) {\n\n        // return json without org's namespace so our code doesn't have to worry about it\n        return new MA_MassActionConfigWrapper( MA_MassActionUtils.getConfiguration( recordId ) );\n    }\n\n    private static Map<String, Object> getConfigurationObjectDescribe() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n\n        // https://salesforce.stackexchange.com/questions/218982/why-is-schema-describesobjectstypes-slower-than-schema-getglobaldescribe\n        DescribeSObjectResult objectDescribe = ( (SObject) Type.forName( objectName ).newInstance() ).getSObjectType().getDescribe();\n\n        Map<String, Object> describeMap = new Map<String, Object>{\n            'name' => objectDescribe.getName(),\n            'localName' => objectDescribe.getLocalName(),\n            'label' => objectDescribe.getLabel(),\n            'labelPlural' => objectDescribe.getLabelPlural(),\n            'keyPrefix' => objectDescribe.getKeyPrefix(),\n            'fields' => getFieldDescribeMaps( objectDescribe.fields.getMap() )\n        };\n\n        return describeMap;\n    }\n\n    /**\n     * This method accepts the JSON serialization of the configuration and field mappings\n     * because when defining the method params as the custom class type was getting internal server error.\n     * I think possibly related to general serialization bugs with Lightning:\n     * https://developer.salesforce.com/forums/?id=906F00000005GiwIAE\n     * https://blog.texei.com/lightning-components-auraenabled-method-parameters-whats-working-and-what-s-not-83c351356104\n     */\n    private static Map<String, Object> saveConfiguration( String wrapperJson, String fieldMappingsJson ) {\n\n        SavePoint sp = Database.setSavepoint();\n\n        try {\n\n            return MA_MassActionUtils.saveConfiguration( wrapperJson, fieldMappingsJson );\n\n        } catch ( Exception e ) {\n\n            Database.rollback( sp );\n\n            System.debug( LoggingLevel.ERROR, 'MA_EditConfigRestController.saveConfiguration: ' + e.getMessage() + ' : ' + e.getStackTraceString() );\n\n            throw e;\n\n        }\n\n    }\n\n    // -----------------------------------------------------------------------------\n\n    private static Map<String, Map<String, Object>> getFieldDescribeMaps( Map<String, SObjectField> fieldsMap ) {\n\n        Map<String, Map<String, Object>> describeMaps = new Map<String, Map<String, Object>>();\n\n        for ( String fieldName : fieldsMap.keySet() ) {\n\n            DescribeFieldResult fieldDescribe = fieldsMap.get( fieldName ).getDescribe();\n\n            // using local name to stay namespace agnostic wherever this code runs\n            describeMaps.put( fieldDescribe.getLocalName(), new Map<String, Object>{\n                'name' => fieldDescribe.getName(),\n                'localName' => fieldDescribe.getLocalName(),\n                'label' => fieldDescribe.getLabel(),\n                'helpText' => fieldDescribe.getInlineHelpText(),\n                'byteLength' => fieldDescribe.getByteLength(),\n                'length' => fieldDescribe.getLength(),\n                'type' => fieldDescribe.getType(),\n                'picklistValues' => getPicklistValuesMaps( fieldDescribe.getPicklistValues() ),\n                'isAccessible' => fieldDescribe.isAccessible(),\n                'isCreateable' => fieldDescribe.isCreateable(),\n                'isUpdateable' => fieldDescribe.isUpdateable()\n            });\n\n        }\n\n        return describeMaps;\n    }\n\n    private static List<Map<String, Object>> getPicklistValuesMaps( List<PicklistEntry> picklistEntries ) {\n\n        List<Map<String, Object>> options = new List<Map<String, Object>>();\n\n        for ( PicklistEntry pke : picklistEntries ) {\n            if ( pke.isActive() ) {\n                options.add( new Map<String, Object>{\n                    'label' => pke.getLabel(),\n                    'value' => pke.getValue()\n                });\n            }\n        }\n\n        return options;\n    }\n\n    private class ObjectNameWrapper implements Comparable {\n\n        private String objectLabel { get; set; }\n        private String objectName { get; set; }\n\n        public ObjectNameWrapper( String objectLabel, String objectName ) {\n            this.objectLabel = objectLabel;\n            this.objectName = objectName;\n        }\n\n        public Integer compareTo( Object other ) {\n\n            ObjectNameWrapper thisWrapper = this;\n            ObjectNameWrapper thatWrapper = (ObjectNameWrapper) other;\n\n            Integer compareResult = ( thisWrapper.objectLabel.compareTo( thatWrapper.objectLabel ) );\n\n            if ( compareResult == 0 ) {\n                compareResult = ( thisWrapper.objectName.compareTo( thatWrapper.objectName ) );\n            }\n\n            return compareResult;\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigRestController.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigRestControllerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_EditConfigRestControllerTest {\n\n    @IsTest\n    static void test_getObjectsWithInvocableActions_Flow() {\n\n        String operation = 'getObjectsWithInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Flow'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 0, result.size() );\n\n    }\n\n    @IsTest\n    static void test_getObjectsWithInvocableActions_QuickAction() {\n\n        String operation = 'getObjectsWithInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'QuickAction'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( 1, result.size() );\n        System.assertEquals( 'Account', ((Map<String, Object>) result[0]).get( 'value' ) );\n\n    }\n\n    @IsTest\n    static void test_getObjectsWithInvocableActions_EmailAlert() {\n\n        String operation = 'getObjectsWithInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'EmailAlert'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( 1, result.size() );\n        System.assertEquals( 'Account', ((Map<String, Object>) result[0]).get( 'value' ) );\n\n    }\n\n    @IsTest\n    static void test_getObjectsWithInvocableActions_Apex() {\n\n        String operation = 'getObjectsWithInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Apex'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( 0, result.size() );\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getInvocableActions_Flow() {\n\n        String operation = 'getInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Flow',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Flow', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Flow', resultAction.get( 'value' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActions_QuickAction() {\n\n        String operation = 'getInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'QuickAction',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Quick Action', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Quick_Action', resultAction.get( 'value' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActions_EmailAlert() {\n\n        String operation = 'getInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'EmailAlert',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Email Alert', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Email_Alert', resultAction.get( 'value' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActions_Apex() {\n\n        String operation = 'getInvocableActions';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Apex',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Apex', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Apex', resultAction.get( 'value' ) );\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getInvocableActionInputs_Workflow() {\n\n        String operation = 'getInvocableActionInputs';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Workflow',\n            'actionName' => '',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Record ID', resultAction.get( 'label' ) );\n        System.assertEquals( 'ContextId', resultAction.get( 'name' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActionInputs_Flow() {\n\n        String operation = 'getInvocableActionInputs';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Flow',\n            'actionName' => 'Test_Flow',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Input', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Input', resultAction.get( 'name' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActionInputs_QuickAction() {\n\n        String operation = 'getInvocableActionInputs';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'QuickAction',\n            'actionName' => 'Test_Quick_Action',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Input', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Input', resultAction.get( 'name' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActionInputs_EmailAlert() {\n\n        String operation = 'getInvocableActionInputs';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'EmailAlert',\n            'actionName' => 'Test_Email_Alert',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Input', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Input', resultAction.get( 'name' ) );\n\n    }\n\n    @IsTest\n    static void test_getInvocableActionInputs_Apex() {\n\n        String operation = 'getInvocableActionInputs';\n        Map<String, Object> params = new Map<String, Object>{\n            'actionType' => 'Apex',\n            'actionName' => 'Test_Apex',\n            'objectName' => 'Account'\n        };\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( operation, params );\n\n        Test.stopTest();\n\n        List<Object> result = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, result.size() );\n\n        Map<String, Object> resultAction = (Map<String, Object>) result[0];\n\n        System.assertEquals( 'Test Input', resultAction.get( 'label' ) );\n        System.assertEquals( 'Test_Input', resultAction.get( 'name' ) );\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest( SeeAllData = true )\n    static void test_get_reports() {\n\n        // Reports and Report Folders cannot be created in unit tests as these are considered 'metadata'.\n        // So we rely on the package bundling test folder/report and must use SeeAllData = true.\n\n        Folder f = [ SELECT Id FROM Folder WHERE DeveloperName = 'Mass_Action_Test_Reports' ];\n        Report r = [ SELECT Id FROM Report WHERE DeveloperName = 'MA_Test_Account_Report' ];\n\n        Map<String, Object> responseBodyMap;\n\n        Test.startTest();\n\n        // ---\n\n        responseBodyMap = test_handlePost( 'getReportFolders', new Map<String, Object>() );\n\n        List<Object> reportFolders = (List<Object>) responseBodyMap.get( 'result' );\n\n        Boolean folderFound = false;\n        for ( Object item : reportFolders ) {\n            Map<String, Object> reportFolder = (Map<String, Object>) item;\n            folderFound = ( folderFound || ( String.valueOf( reportFolder.get( 'value' ) ).left( 15 ) == String.valueOf( f.Id ).left( 15 ) ) );\n        }\n        System.assertEquals( true, folderFound, 'should have found folder' );\n\n        // ---\n\n        responseBodyMap = test_handlePost( 'getReportsByFolder', new Map<String, Object>{\n            'folderId' => f.Id\n        });\n\n        List<Object> reports = (List<Object>) responseBodyMap.get( 'result' );\n\n        Boolean reportFound = false;\n        for ( Object item : reports ) {\n            Map<String, Object> rpt = (Map<String, Object>) item;\n            reportFound = ( reportFound || ( String.valueOf( rpt.get( 'value' ) ).left( 15 ) == String.valueOf( r.Id ).left( 15 ) ) );\n        }\n        System.assertEquals( true, reportFound, 'should have found report' );\n\n        // ---\n\n        responseBodyMap = test_handlePost( 'getReport', new Map<String, Object>{\n            'recordId' => r.Id\n        });\n\n        Map<String, Object> rpt = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( r.Id, rpt.get( 'Id' ) );\n\n        // ---\n\n        responseBodyMap = test_handlePost( 'getReportColumns', new Map<String, Object>{\n            'reportId' => r.Id\n        });\n\n        List<Object> reportColumns = (List<Object>) responseBodyMap.get( 'result' );\n\n        Boolean columnFound = false;\n        for ( Object item : reportColumns ) {\n            Map<String, Object> reportColumn = (Map<String, Object>) item;\n            columnFound = ( columnFound || reportColumn.get( 'value' ) == 'ACCOUNT_ID' );\n        }\n        System.assertEquals( true, columnFound, 'report should have account id column' );\n\n        // --\n\n        Test.stopTest();\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getObjectNames() {\n\n        Map<String, SObjectType> globalDescribeMap = Schema.getGlobalDescribe();\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getObjectNames', new Map<String, Object>() );\n\n        Test.stopTest();\n\n        List<Object> objectNames = (List<Object>) responseBodyMap.get( 'result' );\n\n        for ( Object item : objectNames ) {\n            Map<String, Object> objectName = (Map<String, Object>) item;\n            System.assert( globalDescribeMap.containsKey( String.valueOf( objectName.get( 'value' ) ) ) );\n        }\n\n    }\n\n    @IsTest\n    static void test_getObjectNamesWithListViews() {\n\n        Set<String> sobjectsWithListViews = new Set<String>();\n        for ( AggregateResult result : [\n            SELECT SObjectType\n            FROM ListView\n            WHERE IsSoqlCompatible = true AND SObjectType != null\n            GROUP BY SObjectType\n            ORDER BY SObjectType ASC\n            LIMIT 2000\n        ]) {\n            // lowercase the object names to match keys in the global describe map\n            // because the Set method `contains` is case-sensitive\n            sobjectsWithListViews.add( ( (String) result.get( 'SObjectType' ) ).toLowerCase() );\n        }\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getObjectNamesWithListViews', new Map<String, Object>() );\n\n        Test.stopTest();\n\n        List<Object> objectNames = (List<Object>) responseBodyMap.get( 'result' );\n\n        for ( Object item : objectNames ) {\n            Map<String, Object> objectName = (Map<String, Object>) item;\n            System.assert( sobjectsWithListViews.contains( String.valueOf( objectName.get( 'value' ) ).toLowerCase() ) );\n        }\n\n    }\n\n    @IsTest\n    static void test_getListViewsByObject() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getListViewsByObject', new Map<String, Object>{\n            'objectName' => objectName\n        });\n\n        Test.stopTest();\n\n        List<Object> listViews = (List<Object>) responseBodyMap.get( 'result' );\n\n        Boolean found = false;\n        for ( Object item : listViews ) {\n            Map<String, Object> listView = (Map<String, Object>) item;\n            found = ( found || String.valueOf( listView.get( 'label' ) ).equalsIgnoreCase( lv.Name ) );\n        }\n\n        System.assertEquals( true, found );\n\n    }\n\n    @IsTest\n    static void test_getListViewById() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getListView', new Map<String, Object>{\n            'recordId' => lv.Id\n        });\n\n        Test.stopTest();\n\n        Map<String, Object> listView = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( lv.Id, listView.get( 'Id' ), 'should find list view' );\n\n    }\n\n    @IsTest\n    static void test_getListViewColumns() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getListViewColumns', new Map<String, Object>{\n            'listViewId' => lv.Id\n        });\n\n        Test.stopTest();\n\n        List<Object> listViewColumns = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 3, listViewColumns.size() );\n\n        Boolean hasAccountIdColumn = false;\n        Boolean hasAccountNameColumn = false;\n        Boolean hasOwnerIdColumn = false;\n\n        for ( Object item : listViewColumns ) {\n\n            Map<String, Object> listViewColumn = (Map<String, Object>) item;\n\n            switch on ( (String) listViewColumn.get( 'label' ) ) {\n                when 'Account ID' {\n                    System.assertEquals( 'Id', listViewColumn.get( 'value' ) );\n                    System.assertEquals( 'ID', listViewColumn.get( 'dataType' ) );\n                    hasAccountIdColumn = true;\n                }\n                when 'Account Name' {\n                    System.assertEquals( 'Name', listViewColumn.get( 'value' ) );\n                    System.assertEquals( 'STRING', listViewColumn.get( 'dataType' ) );\n                    hasAccountNameColumn = true;\n                }\n                when 'Owner ID' {\n                    System.assertEquals( 'Owner.Id', listViewColumn.get( 'value' ) );\n                    System.assertEquals( 'ID', listViewColumn.get( 'dataType' ) );\n                    hasOwnerIdColumn = true;\n                }\n            }\n\n        }\n\n        System.assert( hasAccountIdColumn, 'missing Account ID column' );\n        System.assert( hasAccountNameColumn, 'missing Account Name column' );\n        System.assert( hasOwnerIdColumn, 'missing Owner ID column' );\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getSoqlQueryResults() {\n\n        // we return mock results, the query doesn't matter\n        // other than to provide the illusion of realism\n        // because we execute the query via the REST API\n        String query = 'SELECT Id, Name FROM Account LIMIT 1';\n\n        Test.startTest();\n\n        // Test Success (no next records url)\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getSoqlQueryResults', new Map<String, Object>{\n            'query' => query\n        });\n\n        Map<String, Object> result = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( 1, (Integer) result.get( 'totalSize' ) );\n        System.assertEquals( true, (Boolean) result.get( 'done' ) );\n        System.assert( String.isBlank( (String) result.get( 'nextRecordsUrl' ) ) );\n\n        List<Object> records = (List<Object>) result.get( 'records' );\n        System.assertEquals( 1, records.size() );\n\n        for ( Object item : records ) {\n            Map<String, Object> row = (Map<String, Object>) item;\n            System.assertEquals( '001f400000CukanAAB', row.get( Account.Id.getDescribe().getName() ) );\n            System.assertEquals( 'Test Account 1', row.get( Account.Name.getDescribe().getName() ) );\n        }\n\n        // Test Success (yes next records url)\n\n        responseBodyMap = test_handlePost( 'getSoqlQueryResults', new Map<String, Object>{\n            'query' => query,\n            'batchSize' => 500\n        });\n\n        result = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( 501, (Integer) result.get( 'totalSize' ), 'should be 1 more than requested query options batch size' );\n        System.assertEquals( false, (Boolean) result.get( 'done' ) );\n        System.assert( String.isNotBlank( (String) result.get( 'nextRecordsUrl' ) ) );\n\n        records = (List<Object>) result.get( 'records' );\n        System.assertEquals( 1, records.size() );\n\n        for ( Object item : records ) {\n            Map<String, Object> row = (Map<String, Object>) item;\n            System.assertEquals( '001f400000CukanAAB', row.get( Account.Id.getDescribe().getName() ) );\n            System.assertEquals( 'Test Account 1', row.get( Account.Name.getDescribe().getName() ) );\n        }\n\n        // Test Error\n\n        try {\n\n            responseBodyMap = test_handlePost( 'getSoqlQueryResults', new Map<String, Object>{\n                'query' => 'TEST_FAIL'\n            });\n\n            System.assertEquals( false, responseBodyMap.get( 'success' ), 'should fail' );\n            System.assert( ( (String) responseBodyMap.get( 'error' ) ).startsWithIgnoreCase( 'SOQL Query Error:' ), 'failed for wrong reason' );\n\n        } catch ( Exception e ) {\n\n            System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );\n            System.assert( false, 'failed for wrong reason: ' + e.getMessage() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_getSoqlQueryNextRecordsResults() {\n\n        Test.startTest();\n\n        // Test Success\n\n        Integer queryOptionsBatchSize = 500;\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getSoqlQueryNextRecordsResults', new Map<String, Object>{\n            'nextRecordsId' => '01gf400001MMCpeAAH-' + queryOptionsBatchSize\n        });\n\n        Map<String, Object> result = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( queryOptionsBatchSize + 1, (Integer) result.get( 'totalSize' ), 'should be one more than query options batch size' );\n        System.assertEquals( true, (Boolean) result.get( 'done' ) );\n        System.assert( String.isBlank( (String) result.get( 'nextRecordsUrl' ) ) );\n\n        List<Object> records = (List<Object>) result.get( 'records' );\n        System.assertEquals( 1, records.size() );\n\n        for ( Object item : records ) {\n            Map<String, Object> row = (Map<String, Object>) item;\n            System.assertEquals( '001f400000lxT2JAAU', row.get( Account.Id.getDescribe().getName() ) );\n            System.assertEquals( 'Test Account 2', row.get( Account.Name.getDescribe().getName() ) );\n        }\n\n        // Test Error\n\n        try {\n\n            responseBodyMap = test_handlePost( 'getSoqlQueryNextRecordsResults', new Map<String, Object>{\n                'nextRecordsId' => 'TEST_FAIL'\n            });\n\n            System.assertEquals( false, responseBodyMap.get( 'success' ), 'should fail' );\n            System.assert( ( (String) responseBodyMap.get( 'error' ) ).startsWithIgnoreCase( 'SOQL Query Error:' ), 'failed for wrong reason' );\n\n        } catch ( Exception e ) {\n\n            System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );\n            System.assert( false, 'failed for wrong reason: ' + e.getMessage() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getNamedCredentials() {\n\n        String namedCredential = 'Mass_Action_Test_Named_Credential';\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getNamedCredentials', new Map<String, Object>() );\n\n        Test.stopTest();\n\n        List<Object> namedCredentials = (List<Object>) responseBodyMap.get( 'result' );\n        System.assertEquals( 1, namedCredentials.size() );\n\n        for ( Object item : namedCredentials ) {\n            Map<String, Object> credential = (Map<String, Object>) item;\n            System.assertEquals( namedCredential, credential.get( 'value' ) );\n        }\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getConfiguration() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = '00Bf40000017w5h',\n            Target_Type__c = 'Flow',\n            Target_Action_Name__c = 'Test_Flow',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c fieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'SourceField',\n            Target_Field_Name__c = 'TargetField'\n        );\n\n        insert fieldMapping;\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getConfiguration', new Map<String, Object>{\n            'recordId' => config.Id\n        });\n\n        Object result = responseBodyMap.get( 'result' );\n\n        MA_MassActionConfigWrapper wrapper = (MA_MassActionConfigWrapper) JSON.deserialize( JSON.serialize( result ), MA_MassActionConfigWrapper.class );\n\n        System.assertEquals( config.Id, wrapper.recordId );\n        System.assertEquals( config.Name, wrapper.name );\n        System.assertEquals( config.DeveloperName__c, wrapper.developerName );\n        System.assertEquals( config.Description__c, wrapper.description );\n        System.assertEquals( config.Active__c, wrapper.active );\n        System.assertEquals( config.Batch_Size__c, wrapper.batchSize );\n        System.assertEquals( config.Named_Credential__c, wrapper.namedCredential );\n        System.assertEquals( config.Source_Type__c, wrapper.sourceType );\n        System.assertEquals( config.Source_List_View_ID__c, wrapper.sourceListViewID );\n        System.assertEquals( config.Source_Report_ID__c, wrapper.sourceReportID );\n        System.assertEquals( config.Source_Report_Column_Name__c, wrapper.sourceReportColumnName );\n        System.assertEquals( config.Target_Type__c, wrapper.targetType );\n        System.assertEquals( config.Target_SObject_Type__c, wrapper.targetSobjectType );\n        System.assertEquals( config.Target_Action_Name__c, wrapper.targetActionName );\n        System.assertEquals( config.Target_Apex_Script__c, wrapper.targetApexScript );\n        System.assertEquals( config.Schedule_Frequency__c, wrapper.scheduleFrequency );\n        System.assertEquals( config.Schedule_Cron__c, wrapper.scheduleCron );\n        System.assertEquals( config.Schedule_SecondOfMinute__c, wrapper.scheduleSecondOfMinute );\n        System.assertEquals( config.Schedule_MinuteOfHour__c, wrapper.scheduleMinuteOfHour );\n        System.assertEquals( config.Schedule_HourOfDay__c, wrapper.scheduleHourOfDay );\n        System.assertEquals( config.Schedule_DayOfMonth__c, wrapper.scheduleDayOfMonth );\n        System.assertEquals( config.Schedule_MonthOfYear__c, wrapper.scheduleMonthOfYear );\n        System.assertEquals( config.Schedule_DayOfWeek__c, wrapper.scheduleDayOfWeek );\n\n        System.assertEquals( 1, wrapper.fieldMappings.size() );\n        System.assertEquals( fieldMapping.Source_Field_Name__c, wrapper.fieldMappings[0].sourceFieldName );\n        System.assertEquals( fieldMapping.Target_Field_Name__c, wrapper.fieldMappings[0].targetFieldName );\n\n        Mass_Action_Configuration__c config2 = wrapper.toConfiguration();\n\n        System.assertEquals( config.Id, config2.Id );\n        System.assertEquals( config.Name, config2.Name );\n        System.assertEquals( config.DeveloperName__c, config2.DeveloperName__c );\n        System.assertEquals( config.Description__c, config2.Description__c );\n        System.assertEquals( config.Active__c, config2.Active__c );\n        System.assertEquals( config.Batch_Size__c, config2.Batch_Size__c );\n        System.assertEquals( config.Named_Credential__c, config2.Named_Credential__c );\n        System.assertEquals( config.Source_Type__c, config2.Source_Type__c );\n        System.assertEquals( config.Source_List_View_ID__c, config2.Source_List_View_ID__c );\n        System.assertEquals( config.Source_Report_ID__c, config2.Source_Report_ID__c );\n        System.assertEquals( config.Source_Report_Column_Name__c, config2.Source_Report_Column_Name__c );\n        System.assertEquals( config.Target_Type__c, config2.Target_Type__c );\n        System.assertEquals( config.Target_SObject_Type__c, config2.Target_SObject_Type__c );\n        System.assertEquals( config.Target_Action_Name__c, config2.Target_Action_Name__c );\n        System.assertEquals( config.Target_Apex_Script__c, config2.Target_Apex_Script__c );\n        System.assertEquals( config.Schedule_Frequency__c, config2.Schedule_Frequency__c );\n        System.assertEquals( config.Schedule_Cron__c, config2.Schedule_Cron__c );\n        System.assertEquals( config.Schedule_SecondOfMinute__c, config2.Schedule_SecondOfMinute__c );\n        System.assertEquals( config.Schedule_MinuteOfHour__c, config2.Schedule_MinuteOfHour__c );\n        System.assertEquals( config.Schedule_HourOfDay__c, config2.Schedule_HourOfDay__c );\n        System.assertEquals( config.Schedule_DayOfMonth__c, config2.Schedule_DayOfMonth__c );\n        System.assertEquals( config.Schedule_MonthOfYear__c, config2.Schedule_MonthOfYear__c );\n        System.assertEquals( config.Schedule_DayOfWeek__c, config2.Schedule_DayOfWeek__c );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_getConfigurationObjectDescribe() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        DescribeSObjectResult objectDescribe = Schema.getGlobalDescribe().get( objectName ).getDescribe();\n        Map<String, SObjectField> fieldsMap = objectDescribe.fields.getMap();\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'getConfigurationObjectDescribe', new Map<String, Object>() );\n\n        Test.stopTest();\n\n        Map<String, Object> configDesc = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( objectDescribe.getName(), configDesc.get( 'name' ) );\n        System.assertEquals( objectDescribe.getLocalName(), configDesc.get( 'localName' ) );\n        System.assertEquals( objectDescribe.getLabel(), configDesc.get( 'label' ) );\n        System.assertEquals( objectDescribe.getLabelPlural(), configDesc.get( 'labelPlural' ) );\n\n        Map<String, Object> configFieldsDesc = (Map<String, Object>) configDesc.get( 'fields' );\n\n        for ( String fieldLocalName : configFieldsDesc.keySet() ) {\n\n            Map<String, Object> configFieldDesc = (Map<String, Object>) configFieldsDesc.get( fieldLocalName );\n            DescribeFieldResult fieldDesc = fieldsMap.get( String.valueOf( configFieldDesc.get( 'name' ) ) ).getDescribe();\n\n            System.assertEquals( fieldDesc.getName(), configFieldDesc.get( 'name' ) );\n            System.assertEquals( fieldDesc.getLocalName(), configFieldDesc.get( 'localName' ) );\n            System.assertEquals( fieldDesc.getLabel(), configFieldDesc.get( 'label' ) );\n            System.assertEquals( fieldDesc.getInlineHelpText(), configFieldDesc.get( 'helpText' ) );\n\n        }\n\n    }\n\n    @IsTest\n    static void test_saveConfiguration() {\n\n        MA_MassActionConfigWrapper wrapper = new MA_MassActionConfigWrapper();\n        wrapper.name = 'Test Config';\n        wrapper.developerName = 'Test_Config';\n        wrapper.active = false;\n        wrapper.batchSize = 200;\n        wrapper.namedCredential = 'Mass_Action_Test_Named_Credential';\n        wrapper.sourceType = 'ListView';\n        wrapper.sourceListViewID = '00Bf40000017w5h';\n        wrapper.targetType = 'Flow';\n        wrapper.targetActionName = 'Test_Flow';\n        wrapper.scheduleFrequency = 'Custom';\n        wrapper.scheduleCron = '0 0 1 * * ?';\n\n        Map<String, String> fieldMappings = new Map<String, String>{\n            'TargetField' => 'SourceField'\n        };\n\n        Test.startTest();\n\n        // Test Success\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'saveConfiguration', new Map<String, Object>{\n            'wrapperJson' => wrapper,\n            'fieldMappingsJson' => fieldMappings\n        });\n\n        Map<String, Object> result = (Map<String, Object>) responseBodyMap.get( 'result' );\n\n        System.assertEquals( true, responseBodyMap.get( 'success' ) );\n\n        Mass_Action_Configuration__c config = MA_MassActionUtils.getConfiguration( (ID) result.get( 'recordId' ) );\n\n        System.assertEquals( wrapper.name, config.Name );\n        System.assertEquals( wrapper.active, config.Active__c );\n        System.assertEquals( wrapper.batchSize, config.Batch_Size__c );\n        System.assertEquals( wrapper.namedCredential, config.Named_Credential__c );\n        System.assertEquals( wrapper.sourceType, config.Source_Type__c );\n        System.assertEquals( wrapper.sourceListViewID, config.Source_List_View_ID__c );\n        System.assertEquals( wrapper.targetType, config.Target_Type__c );\n        System.assertEquals( wrapper.targetActionName, config.Target_Action_Name__c );\n        System.assertEquals( wrapper.scheduleFrequency, config.Schedule_Frequency__c );\n        System.assertEquals( wrapper.scheduleCron, config.Schedule_Cron__c );\n\n        System.assertEquals( 1, config.Mass_Action_Mappings__r.size() );\n        System.assertEquals( 'TargetField', config.Mass_Action_Mappings__r[0].Target_Field_Name__c );\n        System.assertEquals( 'SourceField', config.Mass_Action_Mappings__r[0].Source_Field_Name__c );\n\n        // Test Error\n\n        try {\n\n            responseBodyMap = test_handlePost( 'saveConfiguration', new Map<String, Object>() );\n\n            System.assertEquals( false, responseBodyMap.get( 'success' ), 'should fail' );\n\n        } catch ( Exception e ) {\n\n            System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );\n            System.assert( false, 'failed for wrong reason: ' + e.getMessage() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_getCalloutRestEndpointURL() {\n\n        Test.startTest();\n\n        System.assertEquals( 'callout:TestNamedCredential' + MA_MassActionUtils.REST_API_PATH, MA_MassActionUtils.getCalloutRestEndpointURL( 'TestNamedCredential' ) );\n        System.assertEquals( MA_MassActionUtils.REST_API_SERVICES_URL, MA_MassActionUtils.getCalloutRestEndpointURL( null ) );\n        System.assertEquals( MA_MassActionUtils.REST_API_SERVICES_URL, MA_MassActionUtils.getCalloutRestEndpointURL( '' ) );\n        System.assertEquals( MA_MassActionUtils.REST_API_SERVICES_URL, MA_MassActionUtils.getCalloutRestEndpointURL( ' ' ) );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_getCalloutSoapEndpointURL() {\n\n        Test.startTest();\n\n        System.assertEquals( 'callout:TestNamedCredential' + MA_MassActionUtils.SOAP_API_PATH, MA_MassActionUtils.getCalloutSoapEndpointURL( 'TestNamedCredential' ) );\n        System.assertEquals( MA_MassActionUtils.SOAP_API_SERVICES_URL, MA_MassActionUtils.getCalloutSoapEndpointURL( null ) );\n        System.assertEquals( MA_MassActionUtils.SOAP_API_SERVICES_URL, MA_MassActionUtils.getCalloutSoapEndpointURL( '' ) );\n        System.assertEquals( MA_MassActionUtils.SOAP_API_SERVICES_URL, MA_MassActionUtils.getCalloutSoapEndpointURL( ' ' ) );\n\n        Test.stopTest();\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    @IsTest\n    static void test_unsupported_operation() {\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        Map<String, Object> responseBodyMap = test_handlePost( 'FAKE_OPERATION', new Map<String, Object>() );\n\n        Test.stopTest();\n\n        System.assertEquals( false, responseBodyMap.get( 'success' ), 'should fail' );\n\n    }\n\n    @IsTest\n    static void test_calloutMock_noMatchingURL() {\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        // Test GET\n\n        HttpRequest getReq = new HttpRequest();\n        getReq.setMethod( 'GET' );\n        getReq.setEndpoint( 'nowhere' );\n\n        HttpResponse getRes = new Http().send( getReq );\n        System.assertEquals( 'ERROR', getRes.getStatus() );\n        System.assertEquals( 400, getRes.getStatusCode() );\n        System.assert( getRes.getBody().startsWithIgnoreCase( 'Unsupported endpoint' ) );\n\n        // Test POST\n\n        HttpRequest postReq = new HttpRequest();\n        postReq.setMethod( 'POST' );\n        postReq.setEndpoint( 'nowhere' );\n\n        HttpResponse postRes = new Http().send( postReq );\n        System.assertEquals( 'ERROR', postRes.getStatus() );\n        System.assertEquals( 400, postRes.getStatusCode() );\n        System.assert( postRes.getBody().startsWithIgnoreCase( 'Unsupported endpoint' ) );\n\n        Test.stopTest();\n\n    }\n\n    // --------------------------------------------------------------------------\n\n    static Map<String, Object> test_handlePost( String operation, Map<String, Object> params ) {\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        RestRequest req = new RestRequest();\n        RestResponse res = new RestResponse();\n\n        RestContext.request = req;\n        RestContext.response = res;\n\n        req.httpMethod = 'POST';\n        req.requestURI = '/config/edit/';\n        req.addParameter( 'operation', operation );\n        req.requestBody = Blob.valueOf( JSON.serializePretty( params ) );\n        req.addHeader( 'Origin', 'https://testdomain.my.salesforce.com' );\n        req.addHeader( 'Content-Type', 'application/json; charset=utf-8' );\n        req.addHeader( 'Accepts', 'application/json' );\n\n        MA_EditConfigRestController.handlePost();\n\n        System.debug( res );\n        System.debug( res.responseBody.toString() );\n\n        Map<String, Object> responseBodyMap = (Map<String, Object>) JSON.deserializeUntyped( res.responseBody.toString() );\n\n        return responseBodyMap;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_EditConfigRestControllerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_Exceptions.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic inherited sharing class MA_Exceptions {\n\n    /**\n     * Thrown by MA_MassActionUtils when encounter error\n     * executing anonymous apex via SOAP API.\n     */\n    public inherited sharing class AnonymousApexException extends InvokeActionException {\n\n        public String compileProblem { get; set; }\n\n        public String exceptionMessage { get; set; }\n\n        public String exceptionStackTrace { get; set; }\n\n        public AnonymousApexException( HttpRequest request, HttpResponse response, String compileProblem, String exceptionMessage, String exceptionStackTrace ) {\n            super( request, response );\n            this.compileProblem = compileProblem;\n            this.exceptionMessage = exceptionMessage;\n            this.exceptionStackTrace = exceptionStackTrace;\n            this.setMessage( sanitizeMessage( String.format(\n                'Anonymous Apex Error:\\ncompileProblem: {0}\\nexceptionMessage: {1}\\nexceptionStackTrace: {2}\\n\\n{3}',\n                new Object[] { compileProblem, exceptionMessage, exceptionStackTrace, super.getMessage() }\n            )));\n        }\n\n        public AnonymousApexException( HttpRequest request, HttpResponse response, String compileProblem, String exceptionMessage, String exceptionStackTrace, Exception cause ) {\n            this( request, response, compileProblem, exceptionMessage, exceptionStackTrace );\n            this.initCause( cause );\n        }\n\n    }\n\n    /**\n     * Thrown by MA_MassActionUtils when encounter error\n     * executing a SOQL query via REST API.\n     */\n    public inherited sharing class SOQLQueryException extends InvokeActionException {\n\n        public String query { get; set; }\n\n        public String errorType { get; set; }\n\n        public String errorMessage { get; set; }\n\n        public SOQLQueryException( HttpRequest request, HttpResponse response, String query, String errorType, String errorMessage ) {\n            super( request, response );\n            this.query = query;\n            this.errorType = errorType;\n            this.errorMessage = errorMessage;\n            this.setMessage( sanitizeMessage( String.format(\n                'SOQL Query Error:\\nquery: {0}\\nerrorType: {1}\\nerrorMessage: {2}\\n\\n{3}',\n                new Object[] { query, errorType, errorMessage, super.getMessage() }\n            )));\n        }\n\n        public SOQLQueryException( HttpRequest request, HttpResponse response, String query, String errorType, String errorMessage, Exception cause ) {\n            this( request, response, query, errorType, errorMessage );\n            this.initCause( cause );\n        }\n\n    }\n\n    /**\n     * Thrown by MA_MassActionBatchUtils when configuration record\n     * has an unknown source type and no batch class for it.\n     */\n    public inherited sharing class UnsupportedSourceTypeException extends Exception {\n\n        public ID configId { get; set; }\n\n        public String sourceType { get; set; }\n\n        public UnsupportedSourceTypeException( ID configId, String sourceType ) {\n            this.configId = configId;\n            this.sourceType = sourceType;\n            this.setMessage( sanitizeMessage( String.format(\n                'Error: Unsupported Source Type: {0}',\n                new Object[] { sourceType }\n            )));\n        }\n\n        public UnsupportedSourceTypeException( ID configId, String sourceType, Exception cause ) {\n            this( configId, sourceType );\n            this.initCause( cause );\n        }\n\n    }\n\n    /**\n     * Indicates that in a Mass_Action_Mapping__c record the\n     * source field name was not a key in the source data map.\n     */\n    public inherited sharing class NoSourceFieldException extends Exception {\n\n        public Map<String, Object> sourceData { get; set; }\n\n        public String sourceFieldName { get; set; }\n\n        public NoSourceFieldException( Map<String, Object> sourceData, String sourceFieldName ) {\n            this.sourceData = sourceData;\n            this.sourceFieldName = sourceFieldName;\n            this.setMessage( sanitizeMessage( String.format(\n                'Error: Field path [{0}] not found on source record [{1}]. Please review the Mass Action Mappings',\n                new String [] { sourceFieldName, JSON.serialize( sourceData ) }\n            )));\n        }\n\n        public NoSourceFieldException( Map<String, Object> sourceData, String sourceFieldName, Exception cause ) {\n            this( sourceData, sourceFieldName );\n            this.initCause( cause );\n        }\n\n    }\n\n    /**\n     * Indicates there was an error making http request to invoke action.\n     * Errors that occur within Process Builder, Flow, etc. might not be\n     * immediately known and thus not thrown with this exception but instead\n     * reported by standard Salesforce behavior.\n     */\n    public inherited sharing virtual class InvokeActionException extends Exception {\n\n        public HttpRequest request { get; set; }\n\n        public HttpResponse response { get; set; }\n\n        public InvokeActionException( HttpRequest request, HttpResponse response ) {\n            this.request = request;\n            this.response = response;\n            this.setMessage( sanitizeMessage( String.format(\n                'Invoke Action Error: {0}\\n{1}\\n\\n{2}\\n{3}',\n                new Object[] { response.toString(), response.getBody(), request.toString(), request.getBody() }\n            )));\n        }\n\n        public InvokeActionException( HttpRequest request, HttpResponse response, Exception cause ) {\n            this( request, response );\n            this.initCause( cause );\n        }\n\n    }\n\n    /**\n     * Indicates there was an error deploying metadata with Apex API.\n     */\n    public inherited sharing class MetadataDeployException extends Exception {\n\n        public Metadata.DeployResult result { get; set; }\n\n        public MetadataDeployException( Metadata.DeployResult result ) {\n            this.result = result;\n            this.setMessage( sanitizeMessage( String.format(\n                'Metadata Deployment Error: {0}: {1}\\n{2}',\n                new Object[] { result.errorStatusCode, result.errorMessage, JSON.serializePretty( result ) }\n            )));\n        }\n\n        public MetadataDeployException( Metadata.DeployResult result, Exception cause ) {\n            this( result );\n            this.initCause( cause );\n        }\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    public static Exception buildException( Type t, String message ) {\n        Exception ex = (Exception) t.newInstance();\n        ex.setMessage( sanitizeMessage( message ) );\n        return ex;\n    }\n\n    public static Exception buildException( Type t, String message, Exception cause ) {\n        Exception ex = buildException( t, message );\n        ex.initCause( cause );\n        return ex;\n    }\n\n    /**\n     * Looks for sensitive information and removes it from the message,\n     * such as redacting session ids. A session id might be exposed when\n     * displaying an http request's headers or body value.\n     */\n    public static String sanitizeMessage( String message ) {\n        return message.replaceAll( '(?i)(?<=<apex:sessionId>).*(?=</apex:sessionId>)', 'SESSION_ID_REMOVED' );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_Exceptions.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ExceptionsTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_ExceptionsTest {\n\n    @IsTest\n    static void test_AnonymousApexException() {\n\n        Test.startTest();\n\n        HttpRequest request = new HttpRequest();\n        request.setMethod( 'GET' );\n        request.setEndpoint( 'https://www.salesforce.com' );\n\n        HttpResponse response = new HttpResponse();\n        response.setBody( 'test' );\n\n        String compileProblem = 'compileProblem';\n        String exceptionMessage = 'exceptionMessage';\n        String exceptionStackTrace = 'exceptionStackTrace';\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw new MA_Exceptions.AnonymousApexException( request, response, compileProblem, exceptionMessage, exceptionStackTrace, cause );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assertEquals( request, e.request );\n            System.assertEquals( response, e.response );\n            System.assertEquals( compileProblem, e.compileProblem );\n            System.assertEquals( exceptionMessage, e.exceptionMessage );\n            System.assertEquals( exceptionStackTrace, e.exceptionStackTrace );\n            System.assert( e.getMessage().startsWithIgnoreCase( 'Anonymous Apex Error:' ) );\n            System.assertEquals( cause, e.getCause() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_SOQLQueryException() {\n\n        Test.startTest();\n\n        HttpRequest request = new HttpRequest();\n        request.setMethod( 'GET' );\n        request.setEndpoint( 'https://www.salesforce.com' );\n\n        HttpResponse response = new HttpResponse();\n        response.setBody( 'test' );\n\n        String query = 'SELECT Id, Name FROM Foo__c';\n        String errorType = 'errorType';\n        String errorMessage = 'the error message';\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw new MA_Exceptions.SOQLQueryException( request, response, query, errorType, errorMessage, cause );\n\n        } catch ( MA_Exceptions.SOQLQueryException e ) {\n\n            System.assertEquals( request, e.request );\n            System.assertEquals( response, e.response );\n            System.assertEquals( query, e.query );\n            System.assertEquals( errorType, e.errorType );\n            System.assertEquals( errorMessage, e.errorMessage );\n            System.assert( e.getMessage().startsWithIgnoreCase( 'SOQL Query Error:' ) );\n            System.assertEquals( cause, e.getCause() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_UnsupportedSourceTypeException() {\n\n        Test.startTest();\n\n        ID configId = null;\n        String sourceType = '';\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw new MA_Exceptions.UnsupportedSourceTypeException( configId, sourceType, cause );\n\n        } catch ( MA_Exceptions.UnsupportedSourceTypeException e ) {\n\n            System.assertEquals( configId, e.configId );\n            System.assertEquals( sourceType, e.sourceType );\n            System.assert( e.getMessage().startsWithIgnoreCase( 'Error: Unsupported Source Type' ) );\n            System.assertEquals( cause, e.getCause() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_NoSourceFieldException() {\n\n        Test.startTest();\n\n        Map<String, Object> sourceData = new Map<String, Object>{ 'A' => 1 };\n        String sourceFieldName = 'fieldName';\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw new MA_Exceptions.NoSourceFieldException( sourceData, sourceFieldName, cause );\n\n        } catch ( MA_Exceptions.NoSourceFieldException e ) {\n\n            System.assertEquals( sourceData, e.sourceData );\n            System.assertEquals( sourceFieldName, e.sourceFieldName );\n            System.assert( e.getMessage().startsWithIgnoreCase( 'Error: Field path' ) );\n            System.assertEquals( cause, e.getCause() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_InvokeActionException() {\n\n        Test.startTest();\n\n        HttpRequest request = new HttpRequest();\n        request.setMethod( 'GET' );\n        request.setEndpoint( 'https://www.salesforce.com' );\n\n        HttpResponse response = new HttpResponse();\n        response.setBody( 'test' );\n\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw new MA_Exceptions.InvokeActionException( request, response, cause );\n\n        } catch ( MA_Exceptions.InvokeActionException e ) {\n\n            System.assertEquals( request, e.request );\n            System.assertEquals( response, e.response );\n\n            System.assert( e.getMessage().containsIgnoreCase( response.getBody() ) );\n            System.assert( e.getMessage().containsIgnoreCase( request.getEndpoint() ) );\n            System.assertEquals( cause, e.getCause() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_MetadataDeployException() {\n\n        Test.startTest();\n\n        Metadata.DeployResult result = new Metadata.DeployResult();\n        result.errorStatusCode = Metadata.StatusCode.INTERNAL_ERROR;\n        result.errorMessage = 'the error message';\n        result.success = false;\n\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw new MA_Exceptions.MetadataDeployException( result, cause );\n\n        } catch ( MA_Exceptions.MetadataDeployException e ) {\n\n            System.assertEquals( result, e.result );\n\n            System.assert( e.getMessage().containsIgnoreCase( String.valueOf( result.errorStatusCode ) ) );\n            System.assert( e.getMessage().containsIgnoreCase( result.errorMessage ) );\n            System.assertEquals( cause, e.getCause() );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_buildException() {\n\n        Test.startTest();\n\n        Type t = System.NullPointerException.class;\n        String message = 'the error message';\n        Exception cause = new System.NoAccessException();\n\n        try {\n\n            throw MA_Exceptions.buildException( t, message, cause );\n\n        } catch ( System.NullPointerException e ) {\n\n            System.assert( e.getMessage().startsWithIgnoreCase( message ) );\n            System.assertEquals( cause, e.getCause() );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'threw wrong exception' );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ExceptionsTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_HttpCalloutMock.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * Most code coverage comes from MA_EditConfigRestControllerTest\n */\npublic inherited sharing class MA_HttpCalloutMock implements HttpCalloutMock {\n\n    public HttpResponse respond( HttpRequest request ) {\n\n        HttpResponse response = new HttpResponse();\n\n        switch on ( request.getMethod().toLowerCase() ) {\n\n            when 'get' {\n                response = respondToGet( request );\n            }\n\n            when 'post' {\n                response = respondToPost( request );\n            }\n\n        }\n\n        return response;\n    }\n\n    private HttpResponse respondToGet( HttpRequest request ) {\n\n        HttpResponse response = new HttpResponse();\n        response.setStatus( 'OK' );\n        response.setStatusCode( 200 );\n\n        // List View Describe\n        if ( matches( request.getEndpoint(), '(.)*/sobjects/[\\\\w]+/listviews/[\\\\w]+/describe(/.*)*' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"id\" : \"00Bf40000017w5h\", ' +\n                '   \"query\" : \"SELECT Id, Name, Owner.Id FROM Account\", ' +\n                '   \"sobjectType\" : \"Account\", ' +\n                '   \"columns\" : [ ' +\n                '     { ' +\n                '       \"label\" : \"Account ID\", ' +\n                '       \"fieldNameOrPath\" : \"Id\", ' +\n                '       \"type\" : \"id\" ' +\n                '     }, ' +\n                '     { ' +\n                '       \"label\" : \"Account Name\", ' +\n                '       \"fieldNameOrPath\" : \"Name\", ' +\n                '       \"type\" : \"string\" ' +\n                '     }, ' +\n                '     { ' +\n                '       \"label\" : \"Owner ID\", ' +\n                '       \"fieldNameOrPath\" : \"Owner.Id\", ' +\n                '       \"type\" : \"id\" ' +\n                '     } ' +\n                '   ] ' +\n                ' } '\n            );\n\n        }\n        // Flows\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/flow(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"actions\" : [ { ' +\n                '     \"label\" : \"Test Flow\", ' +\n                '     \"name\" : \"Test_Flow\", ' +\n                '     \"type\" : \"FLOW\", ' +\n                '     \"url\" : \"/services/data/v54.0/actions/custom/flow/Test_Flow\" ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Quick Actions\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/quickAction(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"Account\" : \"/services/data/v54.0/actions/custom/quickAction/Account\" ' +\n                ' } '\n            );\n\n        }\n        // Quick Actions for an object\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/quickAction/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"actions\" : [ { ' +\n                '     \"label\" : \"Test Quick Action\", ' +\n                '     \"name\" : \"Test_Quick_Action\", ' +\n                '     \"type\" : \"QUICKACTION\", ' +\n                '     \"url\" : \"/services/data/v54.0/actions/custom/quickAction/Account/Test_Quick_Action\" ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Email Alerts\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/emailAlert(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"Account\" : \"/services/data/v54.0/actions/custom/emailAlert/Account\" ' +\n                ' } '\n            );\n\n        }\n        // Email Alerts for an object\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/emailAlert/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"actions\" : [ { ' +\n                '     \"label\" : \"Test Email Alert\", ' +\n                '     \"name\" : \"Test_Email_Alert\", ' +\n                '     \"type\" : \"EMAILALERT\", ' +\n                '     \"url\" : \"/services/data/v54.0/actions/custom/emailalert/Account/Test_Email_Alert\" ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Apex\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/apex(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"actions\" : [ { ' +\n                '     \"label\" : \"Test Apex\", ' +\n                '     \"name\" : \"Test_Apex\", ' +\n                '     \"type\" : \"APEX\", ' +\n                '     \"url\" : \"/services/data/v54.0/actions/custom/apex/Test_Apex\" ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Flow Inputs\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/flow/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"inputs\" : [ { ' +\n                '     \"label\" : \"Test Input\", ' +\n                '     \"name\" : \"Test_Input\", ' +\n                '     \"type\" : \"STRING\", ' +\n                '     \"required\" : true, ' +\n                '     \"description\" : null ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Quick Action Inputs\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/quickAction/[\\\\w]+/[\\\\w]+(/.*)*' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"inputs\" : [ { ' +\n                '     \"label\" : \"Test Input\", ' +\n                '     \"name\" : \"Test_Input\", ' +\n                '     \"type\" : \"STRING\", ' +\n                '     \"required\" : true, ' +\n                '     \"description\" : null ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Email Alert Inputs\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/emailAlert/[\\\\w]+/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"inputs\" : [ { ' +\n                '     \"label\" : \"Test Input\", ' +\n                '     \"name\" : \"Test_Input\", ' +\n                '     \"type\" : \"STRING\", ' +\n                '     \"required\" : true, ' +\n                '     \"description\" : null ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // Apex Inputs\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/apex/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"inputs\" : [ { ' +\n                '     \"label\" : \"Test Input\", ' +\n                '     \"name\" : \"Test_Input\", ' +\n                '     \"type\" : \"STRING\", ' +\n                '     \"required\" : true, ' +\n                '     \"description\" : null ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // SOQL Query (success)\n        else if ( matches( request.getEndpoint(), '(.*)/query(/)?\\\\?q=SELECT(.*)' ) ) {\n\n            Boolean isDone = true;\n            String nextRecordsUrl = null;\n            Integer batchSize = null;\n            Integer totalSize = 1;\n\n            String queryOptions = request.getHeader( 'Sforce-Query-Options' );\n\n            // get batch size query option, if set\n            if ( String.isNotEmpty( queryOptions ) ) {\n                for ( String optionPair : queryOptions.split( ';' ) ) {\n                    if ( optionPair.deleteWhitespace().startsWithIgnoreCase( 'batchSize=' ) ) {\n                        batchSize = Integer.valueOf( optionPair.split( '=' )[1].trim() );\n                    }\n                }\n            }\n\n            // if a batch size was given, simulate that there's another page of records to return\n            if ( batchSize != null ) {\n                isDone = false;\n                nextRecordsUrl = request.getEndpoint().substringBefore( '/query' ) + '/query/01gf400001MMCpeAAH-' + batchSize;\n                totalSize = batchSize + 1;\n            }\n\n            response.setBody(\n                ' { ' +\n                '   \"totalSize\" : ' + totalSize + ', ' +\n                '   \"done\" : ' + isDone + ', ' +\n        ( String.isNotBlank( nextRecordsUrl ) ?\n            (   '   \"nextRecordsUrl\" : \"' + nextRecordsUrl + '\", ' ) :\n                ''\n        ) +\n                '   \"records\" : [ { ' +\n                '     \"attributes\" : { ' +\n                '       \"type\" : \"Account\", ' +\n                '       \"url\" : \"/services/data/v54.0/sobjects/Account/001f400000CukanAAB\" ' +\n                '     }, ' +\n                '     \"Id\" : \"001f400000CukanAAB\", ' +\n                '     \"Name\" : \"Test Account 1\" ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // SOQL Query Next Records URL\n        else if ( matches( request.getEndpoint(), '(.*)/query/(\\\\w){15,18}-(\\\\d+)(.*)' ) ) {\n\n            Pattern p = Pattern.compile( '(\\\\w){15,18}-(\\\\d+)' );\n            Matcher m = p.matcher( request.getEndpoint() );\n\n            Integer totalSize = 2;\n            while ( m.find() ) {\n                totalSize = Integer.valueOf( m.group().substringAfter( '-' ) ) + 1;\n            }\n\n            response.setBody(\n                ' { ' +\n                '   \"totalSize\" : ' + totalSize + ', ' +\n                '   \"done\" : true, ' +\n                '   \"records\" : [ { ' +\n                '     \"attributes\" : { ' +\n                '       \"type\" : \"Account\", ' +\n                '       \"url\" : \"/services/data/v54.0/sobjects/Account/001f400000lxT2JAAU\" ' +\n                '     }, ' +\n                '     \"Id\" : \"001f400000lxT2JAAU\", ' +\n                '     \"Name\" : \"Test Account 2\" ' +\n                '   } ] ' +\n                ' } '\n            );\n\n        }\n        // SOQL Query (failure)\n        else if ( matches( request.getEndpoint(), '(.*)/query(/)?(\\\\?q=)?TEST_FAIL(.*)' ) ) {\n\n            response.setStatus( 'ERROR' );\n            response.setStatusCode( 400 );\n            response.setBody(\n                ' [ ' +\n                '   { ' +\n                '     \"errorCode\" : \"TEST_FAIL\", ' +\n                '     \"message\" : \"Test Fail\" ' +\n                '   } ' +\n                ' ] '\n            );\n\n        }\n        else {\n\n            response.setStatus( 'ERROR' );\n            response.setStatusCode( 400 );\n            response.setBody(\n                'Unsupported endpoint: ' + request.getEndpoint() + '\\n' +\n                'If you expected this to not return an error, add support for this endpoint in the callout mock class.'\n            );\n\n        }\n\n        return response;\n    }\n\n    private HttpResponse respondToPost( HttpRequest request ) {\n\n        HttpResponse response = new HttpResponse();\n        response.setStatus( 'OK' );\n        response.setStatusCode( 200 );\n\n        // Workflow Rules\n        if ( matches( request.getEndpoint(), '(.)*/process/rules(/)?' ) ) {\n\n            response.setBody(\n                ' { ' +\n                '   \"errors\" : null, ' +\n                '   \"success\" : true ' +\n                ' } '\n            );\n\n        }\n        // Flows\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/flow/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' [ { ' +\n                '   \"actionName\" : \"Mass_Action_Configuration__c.Test_Flow, ' +\n                '   \"errors\" : [ ], ' +\n                '   \"isSuccess\" : true, ' +\n                '   \"outputValues\" : null ' +\n                ' } ] '\n            );\n\n        }\n        // Quick Actions\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/quickAction/[\\\\w]+/[\\\\w]+(/.*)*' ) ) {\n\n            response.setBody(\n                ' [ { ' +\n                '   \"actionName\" : \"Mass_Action_Configuration__c.Test_Quick_Action\", ' +\n                '   \"errors\" : [ ], ' +\n                '   \"isSuccess\" : true, ' +\n                '   \"outputValues\" : null ' +\n                ' } ] '\n            );\n        }\n        // Email Alerts\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/emailAlert/[\\\\w]+/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' [ { ' +\n                '   \"actionName\" : \"Mass_Action_Configuration__c.Test_Email_Alert, ' +\n                '   \"errors\" : [ ], ' +\n                '   \"isSuccess\" : true, ' +\n                '   \"outputValues\" : null ' +\n                ' } ] '\n            );\n\n        }\n        // Invocable Apex\n        else if ( matches( request.getEndpoint(), '(.)*/actions/custom/apex/[\\\\w]+(/)?' ) ) {\n\n            response.setBody(\n                ' [ { ' +\n                '   \"actionName\" : \"Test_Apex, ' +\n                '   \"errors\" : [ ], ' +\n                '   \"isSuccess\" : true, ' +\n                '   \"outputValues\" : { \"foo\" : \"bar\" } ' +\n                ' } ] '\n            );\n\n\n        }\n        // Anonymous Apex (failure)\n        else if ( matches( request.getBody(), '(.*)\\\\<apex:executeAnonymous\\\\>(.*)TEST_FAIL(.*)' ) ) {\n\n            response.setBody(\n                ' <?xml version=\"1.0\" encoding=\"UTF-8\"?> ' +\n                ' <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns=\"http://soap.sforce.com/2006/08/apex\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> ' +\n                    ' <soapenv:Body> ' +\n                        ' <executeAnonymousResponse> ' +\n                            ' <result> ' +\n                                ' <column>5</column> ' +\n                                ' <line>12</line> ' +\n                                ' <compiled>false</compiled> ' +\n                                ' <compileProblem xsi:nil=\"true\">COMPILE_FAIL</compileProblem> ' +\n                                ' <exceptionMessage xsi:nil=\"true\">EXCEPTION_FAIL</exceptionMessage> ' +\n                                ' <exceptionStackTrace xsi:nil=\"true\">STACKTRACE_FAIL</exceptionStackTrace> ' +\n                                ' <success>false</success> ' +\n                            ' </result> ' +\n                        ' </executeAnonymousResponse> ' +\n                    ' </soapenv:Body> ' +\n                ' </soapenv:Envelope> '\n            );\n\n        }\n        // Anonymous Apex (soap fault)\n        else if ( matches( request.getBody(), '(.*)\\\\<apex:executeAnonymous\\\\>(.*)TEST_SOAP_FAULT(.*)' ) ) {\n\n            response.setStatus( 'ERROR' );\n            response.setStatusCode( 500 );\n            response.setBody(\n                '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' +\n                '<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">' +\n                    '<soapenv:Body>' +\n                        '<soapenv:Fault>' +\n                            '<faultcode>soapenv:Client</faultcode>' +\n                            '<faultstring>TEST_SOAP_FAULT</faultstring>' +\n                        '</soapenv:Fault>' +\n                    '</soapenv:Body>' +\n                '</soapenv:Envelope>'\n            );\n\n        }\n        // Anonymous Apex (success)\n        else if ( matches( request.getBody(), '(.*)\\\\<apex:executeAnonymous\\\\>(.*)' ) ) {\n\n            response.setBody(\n                ' <?xml version=\"1.0\" encoding=\"UTF-8\"?> ' +\n                ' <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns=\"http://soap.sforce.com/2006/08/apex\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> ' +\n                    ' <soapenv:Body> ' +\n                        ' <executeAnonymousResponse> ' +\n                            ' <result> ' +\n                                ' <column>-1</column> ' +\n                                ' <line>-1</line> ' +\n                                ' <compiled>true</compiled> ' +\n                                ' <compileProblem xsi:nil=\"true\"/> ' +\n                                ' <exceptionMessage xsi:nil=\"true\"/> ' +\n                                ' <exceptionStackTrace xsi:nil=\"true\"/> ' +\n                                ' <success>true</success> ' +\n                            ' </result> ' +\n                        ' </executeAnonymousResponse> ' +\n                    ' </soapenv:Body> ' +\n                ' </soapenv:Envelope> '\n            );\n\n        }\n        else {\n\n            response.setStatus( 'ERROR' );\n            response.setStatusCode( 400 );\n            response.setBody(\n                'Unsupported endpoint: ' + request.getEndpoint() + '\\n' +\n                'If you expected this to not return an error, add support for this endpoint in the callout mock class.'\n            );\n\n        }\n\n        return response;\n    }\n\n    private Boolean matches( String text, String regex ) {\n\n        Pattern p = Pattern.compile( regex );\n        Matcher m = p.matcher( text );\n\n        return m.matches();\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_HttpCalloutMock.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_InstallHandler.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * This class explicitly uses 'without sharing' because it is invoked by the package install handler\n * and it is documented that the use of 'with sharing' by apex classes called by the handler may prevent installation.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_install_handler.htm\n */\n/*\n * IMPORTANT!!! ALL APEX CLASSES THAT ARE EXPLICITLY OR IMPLICITLY INVOKED BY THIS\n * INSTALL HANDLER AT INSTALL TIME MUST USE \"WITHOUT SHARING\" KEYWORD OR THE INSTALL\n * WILL FAIL DUE TO INSTALL USER NOT BEING GRANTED SUFFICIENT PRIVILEGES.\n */\npublic without sharing class MA_InstallHandler implements System.InstallHandler {\n\n    public void onInstall( InstallContext context ) {\n\n        new MA_UpgradePageLayoutsService().upgrade();\n\n        Database.executeBatch( new MA_SetConfigUniqueNameBatchable() );\n\n        Database.executeBatch( new MA_UpgradeMassActionLogsBatchable() );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_InstallHandler.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_InstallHandlerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_InstallHandlerTest {\n\n    @IsTest\n    static void test_new_install() {\n\n        System.assertEquals( 0, [ SELECT COUNT() FROM AsyncApexJob WHERE JobType = 'BatchApex' ] );\n\n        Test.startTest();\n\n        Test.testInstall( new MA_InstallHandler(), null );\n\n        Test.stopTest();\n\n        System.assertEquals( 2, [ SELECT COUNT() FROM AsyncApexJob WHERE JobType = 'BatchApex' ] );\n\n    }\n\n    @IsTest\n    static void test_upgrade() {\n\n        System.assertEquals( 0, [ SELECT COUNT() FROM AsyncApexJob WHERE JobType = 'BatchApex' ] );\n\n        Test.startTest();\n\n        Test.testInstall( new MA_InstallHandler(), new Version( 1, 0 ) );\n\n        Test.stopTest();\n\n        System.assertEquals( 2, [ SELECT COUNT() FROM AsyncApexJob WHERE JobType = 'BatchApex' ] );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_InstallHandlerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_IterableSourceBatchable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_IterableSourceBatchable implements Database.Batchable<Map<String, Object>>,\n                                                                Database.Stateful,\n                                                                Database.AllowsCallouts,\n                                                                Database.RaisesPlatformEvents {\n\n    private ID configId { get; set; }\n\n    private Mass_Action_Configuration__c config { get; set; }\n\n    private Iterable<Map<String, Object>> iterable { get; set; }\n\n    public MA_IterableSourceBatchable( ID configId, Iterable<Map<String, Object>> iterable ) {\n        this.configId = configId;\n        this.iterable = iterable;\n    }\n\n    // ------------------------------------------------------------------------\n\n    public Iterable<Map<String, Object>> start( Database.BatchableContext context ) {\n\n        System.debug( 'MA_IterableSourceBatchable.start: ' + context + ', configId=' + this.configId );\n\n        this.config = MA_MassActionUtils.getConfiguration( this.configId );\n\n        MA_MassActionBatchUtils.handleBatchJobStarted( this.configId, context.getJobId() );\n\n        return this.iterable;\n    }\n\n    public void execute( Database.BatchableContext context, List<Map<String, Object>> records ) {\n\n        System.debug( 'MA_IterableSourceBatchable.execute: ' + context + ', configId=' + this.configId );\n\n        List<Map<String, Object>> sourceRowMaps = convertRecordsToMaps( records );\n\n        MA_MassActionUtils.invokeTargetAction( this.config, sourceRowMaps );\n\n        MA_MassActionBatchUtils.handleBatchJobExecution( this.configId, context.getJobId(), records.size(), JSON.serializePretty( records ) );\n\n    }\n\n    public void finish( Database.BatchableContext context ) {\n\n        System.debug( 'MA_IterableSourceBatchable.finish: ' + context + ', configId=' + this.configId );\n\n        MA_MassActionBatchUtils.handleBatchJobFinished( this.configId, context.getJobId() );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    private List<Map<String, Object>> convertRecordsToMaps( List<Map<String, Object>> records ) {\n\n        List<Map<String, Object>> maps = new List<Map<String, Object>>();\n\n        for ( Map<String, Object> record : records ) {\n            maps.add( convertRecordToMap( record ) );\n        }\n\n        return maps;\n    }\n\n    private Map<String, Object> convertRecordToMap( Map<String, Object> record ) {\n\n        return MA_MapUtils.visitFieldPaths( record );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_IterableSourceBatchable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_IterableSourceBatchableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_IterableSourceBatchableTest {\n\n    /**\n     * Stubs out a simple configuration record with\n     * source properties defined. Test methods should set\n     * the target properties before calling `test_batchable` method.\n     */\n    private static Mass_Action_Configuration__c buildTestConfiguration() {\n\n        return new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'SOQL',\n            Source_SOQL_Query__c = 'SELECT Id FROM Account'\n        );\n\n    }\n\n    @IsTest\n    static void test_batchable_Workflow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_Flow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Flow';\n        config.Target_Action_Name__c = 'Test_Flow';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_QuickAction() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'QuickAction';\n        config.Target_Action_Name__c = 'Test_Quick_Action';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_EmailAlert() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'EmailAlert';\n        config.Target_Action_Name__c = 'Test_Email_Alert';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_InvocableApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = 'Test_Apex';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_AnonymousApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = null;\n        config.Target_Apex_Script__c = 'void execute( List<Map<String, Object>> sourceRecordsBatch ) { System.debug( sourceRecordsBatch ); }';\n\n        test_batchable( config );\n\n    }\n\n    static void test_batchable( Mass_Action_Configuration__c config ) {\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ListOfMapsIterable iterable = new ListOfMapsIterable( new List<Map<String, Object>>{\n            new Map<String, Object>{\n                'Id' => acct.Id,\n                'Name' => acct.Name\n            }\n        });\n\n        ID jobId = Database.executeBatch( new MA_IterableSourceBatchable( config.Id, iterable ), config.Batch_Size__c.intValue() );\n\n        Test.stopTest();\n\n        AsyncApexJob job = MA_MassActionBatchUtils.getJobById( jobId );\n\n        config = [\n            SELECT\n                Id,\n                Last_Run_Completed_Date__c,\n                Last_Run_Completed_With_Errors__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id = :config.Id\n        ];\n\n        System.debug( [ SELECT Id, Message__c FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( job.CompletedDate, config.Last_Run_Completed_Date__c );\n        System.assertEquals( false, config.Last_Run_Completed_With_Errors__c );\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_bad_field_mapping() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_SObject_Type__c = 'Account';\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'NON_EXISTENT_FIELD',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        ListOfMapsIterable iterable = new ListOfMapsIterable( new List<Map<String, Object>>{\n            new Map<String, Object>{\n                'Id' => acct.Id,\n                'Name' => acct.Name\n            }\n        });\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_IterableSourceBatchable( config.Id, iterable ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.NoSourceFieldException e ) {\n\n            System.assertEquals( configFieldMapping.Source_Field_Name__c, e.sourceFieldName );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_bad_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_FAIL'; // callout mock looks for this keyword\n\n        insert config;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        ListOfMapsIterable iterable = new ListOfMapsIterable( new List<Map<String, Object>>{\n            new Map<String, Object>{\n                'Id' => acct.Id,\n                'Name' => acct.Name\n            }\n        });\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_IterableSourceBatchable( config.Id, iterable ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_soap_fault_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_SOAP_FAULT'; // callout mock looks for this keyword\n\n        insert config;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        ListOfMapsIterable iterable = new ListOfMapsIterable( new List<Map<String, Object>>{\n            new Map<String, Object>{\n                'Id' => acct.Id,\n                'Name' => acct.Name\n            }\n        });\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_IterableSourceBatchable( config.Id, iterable ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    private class ListOfMapsIterable implements Iterable<Map<String, Object>> {\n\n        private List<Map<String, Object>> records { get; set; }\n\n        public ListOfMapsIterable( List<Map<String, Object>> records ) {\n            this.records =  records;\n        }\n\n        public Iterator<Map<String, Object>> iterator() {\n            return this.records.iterator();\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_IterableSourceBatchableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_JobChangeEvent.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * Exists only to support a strongly typed payload\n * that's easy to use in Apex for the Mass_Action_Job_Change_Event__e platform event.\n */\npublic inherited sharing class MA_JobChangeEvent {\n\n    /**\n     * Mass Action Configuration record IDs whose scheduled jobs to change.\n     */\n    public List<ID> configIds { get; set; }\n\n    public ScheduleOperation scheduleChangeOperation { get; set; }\n\n    public MA_JobChangeEvent() {\n        this.configIds = new List<ID>();\n    }\n\n    public enum ScheduleOperation {\n        SCHEDULE,\n        UNSCHEDULE\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_JobChangeEvent.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_JobChangeEventTriggerHandler.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * When users save Mass Action Configurations using the MA_EditConfigCmp component,\n * it invokes our custom Apex REST endpoint via the LC_API component. Therefore, the Mass Action Configuration\n * trigger handler ends up being invoked from within the execution context of Apex REST.\n *\n * Due to known issue that execution contexts started from Apex REST endpoints\n * cannot schedule or abort jobs, then our workaround is to use platform events\n * to move into another execution context.\n * https://success.salesforce.com/issues_view?id=a1p30000000SyhIAAS\n *\n * This is the trigger handler for those platform events to handle scheduling and unscheduling\n * the Apex jobs driven by the Mass Action Configuration records.\n */\npublic with sharing class MA_JobChangeEventTriggerHandler {\n\n    public MA_JobChangeEventTriggerHandler() {}\n\n    // -------------------------------------------------------\n    // INSERT\n    // -------------------------------------------------------\n\n    public void handleAfterInsert( List<Mass_Action_Job_Change_Event__e> newList, Map<ID, Mass_Action_Job_Change_Event__e> newMap ) {\n\n        System.debug( 'MA_JobChangeEventTriggerHandler.handleAfterInsert' );\n\n        for ( Mass_Action_Job_Change_Event__e changeEvent : newList ) {\n\n            MA_JobChangeEvent eventPayload = (MA_JobChangeEvent) JSON.deserialize( changeEvent.Payload__c, MA_JobChangeEvent.class );\n            System.debug( 'MA_JobChangeEventTriggerHandler.handleAfterInsert: event=' + eventPayload );\n\n            switch on ( eventPayload.scheduleChangeOperation ) {\n                when SCHEDULE {\n                    MA_MassActionScheduleUtils.scheduleMassActions( eventPayload.configIds );\n                }\n                when UNSCHEDULE {\n                    MA_MassActionScheduleUtils.unscheduleMassActions( eventPayload.configIds );\n                }\n                when else {\n                    System.debug( LoggingLevel.WARN, 'MA_JobChangeEventTriggerHandler.handleAfterInsert: Unexpected operation: ' + eventPayload.scheduleChangeOperation );\n                }\n            }\n\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_JobChangeEventTriggerHandler.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_JobChangeEventTriggerHandlerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_JobChangeEventTriggerHandlerTest {\n\n    @IsTest\n    static void test_schedule_jobs() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c configA = new Mass_Action_Configuration__c(\n            Name = 'Test Config A',\n            DeveloperName__c = 'Test_Config_A',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Scheduled',\n            Schedule_SecondOfMinute__c = '0',\n            Schedule_MinuteOfHour__c = '0',\n            Schedule_HourOfDay__c = '1',\n            Schedule_DayOfMonth__c = '*',\n            Schedule_MonthOfYear__c = '*',\n            Schedule_DayOfWeek__c = '?'\n        );\n\n        Mass_Action_Configuration__c configB = new Mass_Action_Configuration__c(\n            Name = 'Test Config B',\n            DeveloperName__c = 'Test_Config_B',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        insert configA;\n        insert configB;\n\n        // deliver the events fired from the Mass_Action_Configuration__c triggers\n        Test.getEventBus().deliver();\n\n        // then abort any scheduled jobs that may have been scheduled from those triggers\n        // because in this test class we want to test our own specific event payloads\n        for ( CronTrigger job : [ SELECT Id FROM CronTrigger WHERE CronJobDetail.Name LIKE 'MA_MassAction_%' ] ) {\n            System.abortJob( job.Id );\n        }\n\n        MA_MassActionScheduleUtils.unscheduleMassActions( new List<ID>{ configA.Id, configB.Id } );\n\n        Test.startTest();\n\n        MA_JobChangeEvent eventPayload = new MA_JobChangeEvent();\n        eventPayload.configIds = new List<ID>{ configA.Id, configB.Id };\n        eventPayload.scheduleChangeOperation = MA_JobChangeEvent.ScheduleOperation.SCHEDULE;\n\n        List<Mass_Action_Job_Change_Event__e> events = new List<Mass_Action_Job_Change_Event__e>{\n            new Mass_Action_Job_Change_Event__e(\n                Payload__c = JSON.serialize( eventPayload )\n            )\n        };\n\n        EventBus.publish( events );\n\n        Test.stopTest();\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configA.Id) ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configB.Id) ] );\n\n    }\n\n    @IsTest\n    static void test_unschedule_jobs() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c configA = new Mass_Action_Configuration__c(\n            Name = 'Test Config A',\n            DeveloperName__c = 'Test_Config_A',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Scheduled',\n            Schedule_SecondOfMinute__c = '0',\n            Schedule_MinuteOfHour__c = '0',\n            Schedule_HourOfDay__c = '1',\n            Schedule_DayOfMonth__c = '*',\n            Schedule_MonthOfYear__c = '*',\n            Schedule_DayOfWeek__c = '?'\n        );\n\n        Mass_Action_Configuration__c configB = new Mass_Action_Configuration__c(\n            Name = 'Test Config B',\n            DeveloperName__c = 'Test_Config_B',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        insert configA;\n        insert configB;\n\n        // deliver the events fired from the Mass_Action_Configuration__c triggers\n        Test.getEventBus().deliver();\n\n        // then abort any scheduled jobs that may have been scheduled from those triggers\n        // because in this test class we want to test our own specific event payloads\n        for ( CronTrigger job : [ SELECT Id FROM CronTrigger WHERE CronJobDetail.Name LIKE 'MA_MassAction_%' ] ) {\n            System.abortJob( job.Id );\n        }\n\n        MA_MassActionScheduleUtils.scheduleMassActions( new List<ID>{ configA.Id, configB.Id } );\n\n        Test.startTest();\n\n        MA_JobChangeEvent eventPayload = new MA_JobChangeEvent();\n        eventPayload.configIds = new List<ID>{ configA.Id, configB.Id };\n        eventPayload.scheduleChangeOperation = MA_JobChangeEvent.ScheduleOperation.UNSCHEDULE;\n\n        List<Mass_Action_Job_Change_Event__e> events = new List<Mass_Action_Job_Change_Event__e>{\n            new Mass_Action_Job_Change_Event__e(\n                Payload__c = JSON.serialize( eventPayload )\n            )\n        };\n\n        EventBus.publish( events );\n\n        Test.stopTest();\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configA.Id) ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configB.Id) ] );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_JobChangeEventTriggerHandlerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewDescribeResult.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * Represents some parts of a JSON response from List View REST API.\n * \"/services/data/<version>/sobjects/<sobjectName>/listviews/<listViewId>/describe\"\n */\npublic inherited sharing class MA_ListViewDescribeResult {\n\n    public ID id { get; set; }\n\n    public String query { get; set; }\n\n    public String sobjectType { get; set; }\n\n    public List<Map<String, String>> columns { get; set; }\n\n    public MA_ListViewDescribeResult() {\n        this.columns = new List<Map<String, String>>();\n    }\n\n    /**\n     * Extract a list of single property from the columns map.\n     * For example, to get all of the 'fieldNameOrPath' properties.\n     * Conceptually, it's like this: https://stackoverflow.com/questions/19590865/from-an-array-of-objects-extract-value-of-a-property-as-array\n     */\n    public List<String> getColumnProperty( String property ) {\n\n        List<String> values = new List<String>();\n\n        for ( Map<String, String> column : columns ) {\n            values.add( column.get( property ) );\n        }\n\n        return values;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewDescribeResult.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewDescribeResultTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_ListViewDescribeResultTest {\n\n    @IsTest\n    static void test_object() {\n\n        Test.startTest();\n\n        MA_ListViewDescribeResult result = new MA_ListViewDescribeResult();\n        result.id = '00Bf40000017w5h';\n        result.query = 'SELECT Id FROM Account';\n        result.sobjectType = 'Account';\n        result.columns = new List<Map<String, String>>{\n            new Map<String, String>{\n                'label' => 'Account ID',\n                'fieldNameOrPath' => 'Id',\n                'type' => 'id'\n            }\n        };\n\n        System.assertEquals( 'Id', result.getColumnProperty( 'fieldNameOrPath' )[0] );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewDescribeResultTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewSourceBatchable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_ListViewSourceBatchable implements Database.Batchable<SObject>,\n                                                                Database.Stateful,\n                                                                Database.AllowsCallouts,\n                                                                Database.RaisesPlatformEvents {\n\n    private ID configId { get; set; }\n\n    private Mass_Action_Configuration__c config { get; set; }\n\n    private MA_ListViewDescribeResult listViewDescribe { get; set; }\n\n    public MA_ListViewSourceBatchable( ID configId ) {\n        this.configId = configId;\n    }\n\n    // ------------------------------------------------------------------------\n\n    public Database.QueryLocator start( Database.BatchableContext context ) {\n\n        System.debug( 'MA_ListViewSourceBatchable.start: ' + context + ', configId=' + this.configId );\n\n        this.config = MA_MassActionUtils.getConfiguration( this.configId );\n\n        this.listViewDescribe = MA_MassActionUtils.describeListView( MA_MassActionUtils.getCalloutRestEndpointURL( this.config.Named_Credential__c ), this.config.Source_List_View_ID__c );\n\n        Database.QueryLocator queryLocator = Database.getQueryLocator( this.listViewDescribe.query );\n\n        MA_MassActionBatchUtils.handleBatchJobStarted( this.configId, context.getJobId() );\n\n        return queryLocator;\n    }\n\n    public void execute( Database.BatchableContext context, List<SObject> records ) {\n\n        System.debug( 'MA_ListViewSourceBatchable.execute: ' + context + ', configId=' + this.configId );\n\n        List<Map<String, Object>> sourceRowMaps = convertRecordsToMaps( records );\n\n        MA_MassActionUtils.invokeTargetAction( this.config, sourceRowMaps );\n\n        MA_MassActionBatchUtils.handleBatchJobExecution( this.configId, context.getJobId(), records.size(), JSON.serializePretty( records ) );\n\n    }\n\n    public void finish( Database.BatchableContext context ) {\n\n        System.debug( 'MA_ListViewSourceBatchable.finish: ' + context + ', configId=' + this.configId );\n\n        MA_MassActionBatchUtils.handleBatchJobFinished( this.configId, context.getJobId() );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    private List<Map<String, Object>> convertRecordsToMaps( List<SObject> records ) {\n\n        List<Map<String, Object>> maps = new List<Map<String, Object>>();\n\n        Map<String, SObjectField> fieldsMap = records.getSObjectType().getDescribe().fields.getMap();\n\n        for ( SObject record : records ) {\n            maps.add( convertRecordToMap( record, fieldsMap ) );\n        }\n\n        return maps;\n    }\n\n    private Map<String, Object> convertRecordToMap( SObject record, Map<String, SObjectField> fieldsMap ) {\n\n        Map<String, Object> recordMap = new Map<String, Object>();\n\n        for ( String fieldName : fieldsMap.keySet() ) {\n            // As of Winter '19, Apex does not provide a way to\n            // inspect a SOQL query to know which fields were queried.\n            // We can get a map of populated field values, but that map only\n            // has entries for fields from the query that were non-null.\n            // If the configuration record's field mappings reference a field\n            // whose value is null in the query result, the map we return\n            // would be lacking that map key and our validation would throw an\n            // exception. Therefore, as a workaround, we iterate all the fields\n            // from the sobject describe and attempt to grab the value from the queried record.\n            DescribeFieldResult fieldDesc = fieldsMap.get( fieldName ).getDescribe();\n            recordMap.put( fieldDesc.getName(), null );\n        }\n\n        recordMap.putAll( MA_MapUtils.visitFieldPaths( record ) );\n\n        return recordMap;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewSourceBatchable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewSourceBatchableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_ListViewSourceBatchableTest {\n\n    /**\n     * Stubs out a simple configuration record with\n     * source properties defined. Test methods should set\n     * the target properties before calling `test_batchable` method.\n     */\n    private static Mass_Action_Configuration__c buildTestConfiguration() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        return new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id\n        );\n\n    }\n\n    @IsTest\n    static void test_batchable_Workflow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_Flow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Flow';\n        config.Target_Action_Name__c = 'Test_Flow';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_QuickAction() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'QuickAction';\n        config.Target_Action_Name__c = 'Test_Quick_Action';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_EmailAlert() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'EmailAlert';\n        config.Target_Action_Name__c = 'Test_Email_Alert';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_InvocableApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = 'Test_Apex';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_AnonymousApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = null;\n        config.Target_Apex_Script__c = 'void execute( List<Map<String, Object>> sourceRecordsBatch ) { System.debug( sourceRecordsBatch ); }';\n\n        test_batchable( config );\n\n    }\n\n    static void test_batchable( Mass_Action_Configuration__c config ) {\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Owner.Id', // for code coverage, using a multiple field source name\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = Database.executeBatch( new MA_ListViewSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n        Test.stopTest();\n\n        AsyncApexJob job = MA_MassActionBatchUtils.getJobById( jobId );\n\n        config = [\n            SELECT\n                Id,\n                Last_Run_Completed_Date__c,\n                Last_Run_Completed_With_Errors__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id = :config.Id\n        ];\n\n        System.debug( [ SELECT Id, Message__c FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( job.CompletedDate, config.Last_Run_Completed_Date__c );\n        System.assertEquals( false, config.Last_Run_Completed_With_Errors__c );\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_bad_field_mapping() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_SObject_Type__c = 'Account';\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'NON_EXISTENT_FIELD',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ListViewSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.NoSourceFieldException e ) {\n\n            System.assertEquals( configFieldMapping.Source_Field_Name__c, e.sourceFieldName );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_no_list_view() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Source_List_View_ID__c = null;\n        config.Target_Type__c = 'Workflow';\n        config.Target_SObject_Type__c = 'Account';\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ListViewSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( NoDataFoundException ex ) {\n\n            // because the batchable throws the error in the start method\n            // then we're getting a synchronous exception caught rather than\n            // the job's finish method logging the error asynchronously\n            System.assert( ex.getMessage().containsIgnoreCase( 'No List View Found' ), 'failed for wrong reason' );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_bad_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_FAIL'; // callout mock looks for this keyword\n\n        insert config;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ListViewSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_soap_fault_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_SOAP_FAULT'; // callout mock looks for this keyword\n\n        insert config;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ListViewSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ListViewSourceBatchableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MapUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic inherited sharing class MA_MapUtils {\n\n    /**\n     * Returns a new map whose keys are all lowercase.\n     * This is useful when need a case-insensitive way to\n     * check if the map contains a key or to retrieve values.\n     *\n     * Because Apex does not support generics, the returned map's\n     * value type is Object, so you'll need to cast the values you retrieve.\n     */\n    public static Map<String, Object> convertKeysToLowercase( Map<String, Object> origMap ) {\n\n        if ( origMap == null ) {\n            return origMap;\n        }\n\n        Map<String, Object> newMap = new Map<String, Object>();\n\n        for ( String key : origMap.keySet() ) {\n            newMap.put( ( key == null ) ? null : key.toLowerCase(), origMap.get( key ) );\n        }\n\n        return newMap;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Visits each field on the given record and puts the values in\n     * the given record map. The map's keys are a concatenation of\n     * the given baseFieldPath and the record's field name.\n     *\n     * If a field's value is itself an SObject or Map then the method is\n     * called again on that record. This time, passing in for the\n     * baseFieldPath the value of the prior baseFieldPath + the field name.\n     *\n     * Ultimately, for a query like:\n     *      SELECT Id, FirstName, Account.Name FROM Contact\n     *\n     * This method generates a map like:\n     *      {\n     *        \"Account.Name\" : \"dca_mass_action: MA Test Account\",\n     *        \"Account.Id\" : \"001S00000106yiiIAA\",\n     *        \"Account\" : {\n     *          \"attributes\" : {\n     *            \"type\" : \"Account\",\n     *            \"url\" : \"/services/data/v54.0/sobjects/Account/001S00000106yiiIAA\"\n     *          },\n     *          \"Id\" : \"001S00000106yiiIAA\",\n     *          \"Name\" : \"dca_mass_action: MA Test Account\"\n     *        },\n     *        \"AccountId\" : \"001S00000106yiiIAA\",\n     *        \"FirstName\" : \"Doug\",\n     *        \"Id\" : \"003S0000018BxKOIA0\"\n     *      }\n     *\n     * @param record\n     *      SObject or Map whose field values to add to the record map.\n     * @param baseFieldPath\n     *      Essentially, the prefix for the keys when putting values in the record map.\n     * @param recordMap\n     *      Map of field values from the given record.\n     *      The map keys are a concatenation of `baseFieldPath + fieldName`.\n     */\n\n    public static Map<String, Object> visitFieldPaths( SObject record ) {\n\n        Map<String, Object> recordMap = new Map<String, Object>();\n\n        if ( record != null ) {\n            visitFieldPaths( record, '', recordMap );\n        }\n\n        return recordMap;\n    }\n\n    public static Map<String, Object> visitFieldPaths( Map<String, Object> record ) {\n\n        Map<String, Object> recordMap = new Map<String, Object>();\n\n        if ( record != null ) {\n            visitFieldPaths( record, '', recordMap );\n        }\n\n        return recordMap;\n    }\n\n    private static void visitFieldPaths( SObject record, String baseFieldPath, Map<String, Object> recordMap ) {\n        if ( record != null ) {\n            visitFieldPaths( record.getPopulatedFieldsAsMap(), baseFieldPath, recordMap );\n        }\n    }\n\n    private static void visitFieldPaths( Map<String, Object> record, String baseFieldPath, Map<String, Object> recordMap ) {\n\n        baseFieldPath = ( String.isBlank( baseFieldPath ) ? '' : baseFieldPath + '.' );\n\n        Map<String, Object> populatedFieldsMap = record;\n\n        for ( String fieldName : populatedFieldsMap.keySet() ) {\n\n            String fieldPath = baseFieldPath + fieldName;\n            Object fieldValue = populatedFieldsMap.get( fieldName );\n\n            recordMap.put( fieldPath, fieldValue );\n\n            if ( fieldValue instanceof SObject ) {\n                visitFieldPaths( (SObject) fieldValue, fieldPath, recordMap );\n            } else if ( fieldValue instanceof Map<String, Object> ) {\n                visitFieldPaths( (Map<String, Object>) fieldValue, fieldPath, recordMap );\n            }\n\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MapUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MapUtilsTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MapUtilsTest {\n\n    @IsTest\n    static void test_convertKeysToLowercase() {\n\n        Test.startTest();\n\n        Map<String, String> map1 = new Map<String, String>{ 'a' => 'apple', 'B' => 'BANANA', null => 'null-key' };\n        Map<String, Object> map2 = MA_MapUtils.convertKeysToLowercase( map1 );\n\n        System.assertEquals( 'apple', map1.get( 'a' ) );\n        System.assertEquals( null,    map1.get( 'A' ) );\n\n        System.assertEquals( 'apple', map2.get( 'a' ) );\n        System.assertEquals( null,    map2.get( 'A' ) );\n\n        System.assertEquals( null,     map1.get( 'b' ) );\n        System.assertEquals( 'BANANA', map1.get( 'B' ) );\n\n        System.assertEquals( 'BANANA', map2.get( 'b' ) );\n        System.assertEquals( null,     map2.get( 'B' ) );\n\n        System.assertEquals( 'null-key', map1.get( null ) );\n        System.assertEquals( 'null-key', map2.get( null ) );\n\n        System.assertEquals( null, MA_MapUtils.convertKeysToLowercase( null ) );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_visitFieldPaths_sobject() {\n\n        Account parentAcct = new Account(\n            Name = 'Test Parent Account'\n        );\n\n        insert parentAcct;\n\n        Account childAcct = new Account(\n            ParentId = parentAcct.Id,\n            Name = 'Test Child Account'\n        );\n\n        insert childAcct;\n\n        Contact cont = new Contact(\n            AccountId = childAcct.Id,\n            FirstName = 'Doug',\n            LastName = 'Ayers'\n        );\n\n        insert cont;\n\n        Contact record = [\n            SELECT\n                Id, AccountId, FirstName, LastName,\n                Account.Id, Account.Name,\n                Account.ParentId, Account.Parent.Id, Account.Parent.Name\n            FROM\n                Contact\n            WHERE\n                Id = :cont.Id\n        ];\n\n        Test.startTest();\n\n        System.debug( JSON.serializePretty( record ) );\n\n        Map<String, Object> recordMap = MA_MapUtils.visitFieldPaths( record );\n\n        System.debug( JSON.serializePretty( recordMap ) );\n\n        Test.stopTest();\n\n        System.assertEquals( record.Id, recordMap.get( 'Id' ) );\n        System.assertEquals( record.FirstName, recordMap.get( 'FirstName' ) );\n        System.assertEquals( record.LastName, recordMap.get( 'LastName' ) );\n        System.assertEquals( record.AccountId, recordMap.get( 'AccountId' ) );\n\n        System.assertEquals( record.Account.Id, recordMap.get( 'Account.Id' ) );\n        System.assertEquals( record.Account.Name, recordMap.get( 'Account.Name' ) );\n        System.assertEquals( record.Account.ParentId, recordMap.get( 'Account.ParentId' ) );\n\n        System.assertEquals( record.Account.Parent.Id, recordMap.get( 'Account.Parent.Id' ) );\n        System.assertEquals( record.Account.Parent.Name, recordMap.get( 'Account.Parent.Name' ) );\n\n    }\n\n    @IsTest\n    static void test_visitFieldPaths_map() {\n\n        Account parentAcct = new Account(\n            Name = 'Test Parent Account'\n        );\n\n        insert parentAcct;\n\n        Account childAcct = new Account(\n            ParentId = parentAcct.Id,\n            Name = 'Test Child Account'\n        );\n\n        insert childAcct;\n\n        Contact cont = new Contact(\n            AccountId = childAcct.Id,\n            FirstName = 'Doug',\n            LastName = 'Ayers'\n        );\n\n        insert cont;\n\n        Contact record = [\n            SELECT\n                Id, AccountId, FirstName, LastName,\n                Account.Id, Account.Name,\n                Account.ParentId, Account.Parent.Id, Account.Parent.Name\n            FROM\n                Contact\n            WHERE\n                Id = :cont.Id\n        ];\n\n        Test.startTest();\n\n        System.debug( JSON.serializePretty( record ) );\n\n        Map<String, Object> recordMap = MA_MapUtils.visitFieldPaths(\n            (Map<String, Object>) JSON.deserializeUntyped( JSON.serialize( record ) )\n        );\n\n        System.debug( JSON.serializePretty( recordMap ) );\n\n        Test.stopTest();\n\n        System.assertEquals( record.Id, recordMap.get( 'Id' ) );\n        System.assertEquals( record.FirstName, recordMap.get( 'FirstName' ) );\n        System.assertEquals( record.LastName, recordMap.get( 'LastName' ) );\n        System.assertEquals( record.AccountId, recordMap.get( 'AccountId' ) );\n\n        System.assertEquals( record.Account.Id, recordMap.get( 'Account.Id' ) );\n        System.assertEquals( record.Account.Name, recordMap.get( 'Account.Name' ) );\n        System.assertEquals( record.Account.ParentId, recordMap.get( 'Account.ParentId' ) );\n\n        System.assertEquals( record.Account.Parent.Id, recordMap.get( 'Account.Parent.Id' ) );\n        System.assertEquals( record.Account.Parent.Name, recordMap.get( 'Account.Parent.Name' ) );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MapUtilsTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionBatchEnqueuer.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_MassActionBatchEnqueuer implements MA_MassActionSchedulable.MA_MassActionSchedulableDispatched {\n\n    public void execute( SchedulableContext context, ID configID ) {\n\n        System.debug( 'MA_MassActionBatchEnqueuer.execute: ' + context );\n\n        MA_MassActionBatchUtils.enqueueAction( configId );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionBatchEnqueuer.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionBatchUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic inherited sharing class MA_MassActionBatchUtils {\n\n    public static ID enqueueAction( ID configId ) {\n\n        Mass_Action_Configuration__c config = MA_MassActionUtils.getConfiguration( configId );\n\n        System.debug( 'MA_MassActionBatchUtils.enqueueAction: ' + config );\n\n        ID jobId = null;\n\n        if ( config.Active__c ) {\n\n            if ( config.Source_Type__c == 'Report' ) {\n\n                jobId = enqueueReportJob( config );\n\n            } else if ( config.Source_Type__c == 'ListView' ) {\n\n                jobId = enqueueListViewJob( config );\n\n            } else if ( config.Source_Type__c == 'SOQL' ) {\n\n                jobId = enqueueSoqlJob( config );\n\n            } else if ( config.Source_Type__c == 'Apex' ) {\n\n                jobId = enqueueApexJob( config );\n\n            } else {\n\n                throw new MA_Exceptions.UnsupportedSourceTypeException( configId, config.Source_Type__c );\n\n            }\n\n            // Log that the job has been enqueued.\n            // All other success/error logs for this job\n            // will be saved as child logs to this one.\n\n            Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n            // We don't have lookup fields to AsyncApexJob records,\n            // so standardizing on the 15 character id, least common denominator.\n            // Also, must use string variable type because ID variable type\n            // always coerces the assigned value back to 18 characters.\n            String jobId15 = String.valueOf( jobId ).left( 15 );\n\n            Mass_Action_Log__c log = new Mass_Action_Log__c(\n                RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n                Mass_Action_Configuration__c = configId,\n                Job_ID__c = jobId15,\n                Submitted_Date__c = DateTime.now(),\n                Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n                Message__c = 'Batch job enqueued',\n                Message_Type__c = 'Informational'\n            );\n\n            insert log;\n\n        } else {\n\n            System.debug( LoggingLevel.WARN, 'MA_MassActionBatchUtils.enqueueAction: Not enqueueing inactive configuration' );\n\n        }\n\n        System.debug( 'MA_MassActionBatchUtils.enqueueAction: jobId: ' + jobId );\n\n        return jobId;\n    }\n\n    private static ID enqueueReportJob( Mass_Action_Configuration__c config ) {\n\n        return Database.executeBatch( new MA_ReportSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n    }\n\n    private static ID enqueueListViewJob( Mass_Action_Configuration__c config ) {\n\n        return Database.executeBatch( new MA_ListViewSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n    }\n\n    private static ID enqueueSoqlJob( Mass_Action_Configuration__c config ) {\n\n        return Database.executeBatch( new MA_IterableSourceBatchable( config.Id, new MA_SoqlSourceIterable( config.Id ) ), config.Batch_Size__c.intValue() );\n    }\n\n    private static ID enqueueApexJob( Mass_Action_Configuration__c config ) {\n\n        String namespace = null;\n        String className = config.Source_Apex_Class__c;\n\n        Type t = null;\n\n        if ( className.contains( '.' ) ) {\n            namespace = config.Source_Apex_Class__c.substringBefore( '.' );\n            className = config.Source_Apex_Class__c.substringAfter( '.' );\n        }\n\n        t = Type.forName( namespace, className );\n\n        // If don't find type then maybe the class name pattern\n        // isn't \"namespace.className\" but rather \"outerClass.innerClass\"\n        // in the current namespace.\n        if ( t == null ) {\n            t = Type.forName( null, config.Source_Apex_Class__c );\n        }\n\n        // If still don't find the type then either it\n        // doesn't exist or isn't accessible by our package.\n        if ( t == null ) {\n            throw MA_Exceptions.buildException(\n                NoDataFoundException.class,\n                'No class found for name \"' + config.Source_Apex_Class__c + '\". If it exists, it may need to be global to be accessible by the Mass Action Scheduler package.'\n            );\n        }\n\n        Iterable<Map<String, Object>> iterable = (Iterable<Map<String, Object>>) t.newInstance();\n        return Database.executeBatch( new MA_IterableSourceBatchable( config.Id, iterable ), config.Batch_Size__c.intValue() );\n\n    }\n\n    // ----------------------------------------------------\n\n    /**\n     * Designed to be invoked during the batch start method.\n     */\n    public static void handleBatchJobStarted( ID configId, ID jobId ) {\n\n        System.debug( 'MA_MassActionBatchUtils.handleBatchJobStarted: configId=' + configId + ', jobId=' + jobId );\n\n        List<Mass_Action_Batch_Apex_Status_Event__e> events = new List<Mass_Action_Batch_Apex_Status_Event__e>{\n            new Mass_Action_Batch_Apex_Status_Event__e(\n                Job_ID__c = jobId,\n                Phase__c = 'START',\n                Message_Type__c = 'Informational',\n                Message__c = 'Started',\n                Long_Message__c = 'Started',\n                // Massaging the timestamp for the \"start\" event to ensure it chronologically always is first.\n                // See comments in the getDateTimeWithoutMillis() method for more details.\n                Timestamp__c = String.valueOf( getDateTimeWithoutMillis( DateTime.now().addSeconds( -1 ) ).getTime() )\n            )\n        };\n\n        publish( events );\n\n    }\n\n    /**\n     * Designed to be invoked during the batch execute method.\n     */\n    public static void handleBatchJobExecution( ID configId, ID jobId, Integer jobScopeSize, String jobScope ) {\n\n        System.debug( 'MA_MassActionBatchUtils.handleBatchJobExecution: configId=' + configId + ', jobId=' + jobId );\n\n        List<Mass_Action_Batch_Apex_Status_Event__e> events = new List<Mass_Action_Batch_Apex_Status_Event__e>{\n            new Mass_Action_Batch_Apex_Status_Event__e(\n                Job_ID__c = jobId,\n                Phase__c = 'EXECUTE',\n                Message_Type__c = 'Success',\n                Message__c = 'Processed ' + jobScopeSize + ' records',\n                Long_Message__c = 'Processed ' + jobScopeSize + ' records',\n                Job_Scope__c = jobScope,\n                Timestamp__c = String.valueOf( DateTime.now().getTime() )\n            )\n        };\n\n        publish( events );\n\n    }\n\n    /**\n     * Designed to be invoked during the batch finish method.\n     */\n    public static void handleBatchJobFinished( ID configId, ID jobId ) {\n\n        System.debug( 'MA_MassActionBatchUtils.handleBatchJobFinished: configId=' + configId + ', jobId=' + jobId );\n\n        List<Mass_Action_Batch_Apex_Status_Event__e> events = new List<Mass_Action_Batch_Apex_Status_Event__e>{\n            new Mass_Action_Batch_Apex_Status_Event__e(\n                Job_ID__c = jobId,\n                Phase__c = 'FINISH',\n                Message_Type__c = 'Informational',\n                Message__c = 'Finished',\n                Long_Message__c = 'Finished',\n                // For the final finish event, I don't want the timestamp milliseconds\n                // stripped away, I want them to help ensure it's the last event in the sorted list\n                Timestamp__c = String.valueOf( DateTime.now().getTime() )\n            )\n        };\n\n        publish( events );\n\n        AsyncApexJob job = getJobById( jobId );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Id = configId,\n            Last_Run_Completed_Date__c = job.CompletedDate,\n            Last_Run_Completed_With_Errors__c = ( String.isNotBlank( job.ExtendedStatus ) || job.NumberOfErrors > 0 )\n        );\n\n        update config;\n\n    }\n\n    // ----------------------------------------------------\n\n    /**\n     * Returns a map of AsyncApexJob records.\n     *\n     * Useful in platform event triggers to get a map of related jobs.\n     */\n    public static Map<ID, AsyncApexJob> getJobsByJobIdMap( Set<ID> jobIds ) {\n\n        Map<ID, AsyncApexJob> jobsMap = new Map<ID, AsyncApexJob>([\n            SELECT\n                Id, ParentJobId, Status, ExtendedStatus,\n                TotalJobItems, JobItemsProcessed, NumberOfErrors,\n                CreatedDate, CompletedDate\n            FROM\n                AsyncApexJob\n            WHERE\n                Id IN :jobIds\n        ]);\n\n        if ( Test.isRunningTest() ) {\n            // acrobatics for test coverage and the fact that\n            // AsyncApexJob records can't truly be mocked\n            for ( ID jobId : jobIds ) {\n                AsyncApexJob job = getJobById( jobId );\n                if ( job != null ) {\n                    jobsMap.put( job.Id, job );\n                }\n            }\n        }\n\n        return jobsMap;\n    }\n\n    /**\n     * Finds the parent log records associated with each async apex job.\n     * Returns a map of job id to parent log record.\n     *\n     * Useful in platform event triggers to identify the parent log\n     * for the job the event is for so can know to update the log\n     * or for which log to insert child logs.\n     */\n    public static Map<ID, Mass_Action_Log__c> getParentLogsByJobIdMap( List<AsyncApexJob> jobs ) {\n\n        // It's possible that the batch error event's job id is\n        // a child job of the main batch job that represents the\n        // mass action configuration's execution.\n        // The parent log record's job id will be a parent job id.\n        // So to be able to cross-ref correctly, we need the parent job ids.\n        Set<String> parentJobIds = new Set<String>();\n        for ( AsyncApexJob job : jobs ) {\n            parentJobIds.add( String.valueOf( job.Id ).left( 15 ) );\n            parentJobIds.add( String.valueOf( String.isNotBlank( job.ParentJobId ) ? job.ParentJobId : job.Id ).left( 15 ) );\n        }\n\n        Map<ID, Mass_Action_Log__c> jobIdToParentLogMap = new Map<ID, Mass_Action_Log__c>();\n        for ( Mass_Action_Log__c parentLog : [\n            SELECT\n                Id, Job_ID__c, Mass_Action_Configuration__c\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Job_ID__c IN :parentJobIds\n                AND\n                RecordType.DeveloperName = 'Parent_Log'\n        ]) {\n            jobIdToParentLogMap.put( ID.valueOf( parentLog.Job_ID__c ), parentLog );\n        }\n\n        return jobIdToParentLogMap;\n    }\n\n    /**\n     * Utility function to get apex job details.\n     */\n    public static AsyncApexJob getJobById( ID jobId ) {\n\n        AsyncApexJob job;\n\n        for ( AsyncApexJob item : [\n            SELECT\n                Id,\n                ParentJobId,\n                CreatedDate,\n                CompletedDate,\n                Status,\n                ExtendedStatus,\n                TotalJobItems,\n                JobItemsProcessed,\n                NumberOfErrors\n            FROM\n                AsyncApexJob\n            WHERE\n                Id = :jobId\n            LIMIT 1\n        ]) {\n            job = item;\n        }\n\n        if ( Test.isRunningTest() ) {\n            // acrobatics for test coverage and the fact that\n            // AsyncApexJob records can't truly be mocked\n            System.debug( 'MA_MassActionBatchUtils.getJobById: running test, getting mock job for id ' + jobId );\n            AsyncApexJob mockJob = MA_AsyncApexJobMock.getJobById( jobId );\n            if ( mockJob != null ) {\n                job = mockJob;\n            }\n        }\n\n        return job;\n    }\n\n    /**\n     * Convenience function to publish events and debug log details about them\n     * and ensure the long text field values are abbreviated within max length allowed.\n     */\n    public static List<Database.SaveResult> publish( List<Mass_Action_Batch_Apex_Status_Event__e> events ) {\n\n        System.debug( 'MA_MassActionBatchUtils.publish: eventsToPublish=' + events.size() );\n\n        // Ensure text fields are within field length limits.\n        // Manually need to do this since event publishing doesn't\n        // accept a DMLOptions argument to enable field truncation.\n        for ( Mass_Action_Batch_Apex_Status_Event__e evt : events ) {\n            evt.Message__c = MA_StringUtils.abbreviateWithinFieldLength( evt.Message__c, Mass_Action_Batch_Apex_Status_Event__e.Message__c );\n            evt.Long_Message__c = MA_StringUtils.abbreviateWithinFieldLength( evt.Long_Message__c, Mass_Action_Batch_Apex_Status_Event__e.Long_Message__c );\n            evt.Job_Scope__c = MA_StringUtils.abbreviateWithinFieldLength( evt.Job_Scope__c, Mass_Action_Batch_Apex_Status_Event__e.Job_Scope__c );\n        }\n\n        List<Database.SaveResult> results = EventBus.publish( events );\n\n        System.debug( 'MA_MassActionBatchUtils.publish: saveResults.size=' + results.size() );\n\n        for ( Integer i = 0; i < results.size(); i ++ ) {\n\n            Database.SaveResult result = results[i];\n            Mass_Action_Batch_Apex_Status_Event__e evt = events[i];\n\n            System.debug( 'MA_MassActionBatchUtils.publish: operationId=' + EventBus.getOperationId( result ) + ', event: ' + JSON.serializePretty( evt ) );\n\n            if ( !result.isSuccess() ) {\n                for ( Database.Error err : result.getErrors() ) {\n                    System.debug( LoggingLevel.ERROR, 'MA_MassActionBatchUtils.publish: error: ' + JSON.serializePretty( err ) );\n                }\n            }\n\n        }\n\n        return results;\n    }\n\n    /**\n     * Apex DateTime precision supports milliseconds.\n     * Platform Event datetimes do not.\n     * This means that occasionally the \"start\" event would\n     * sort in the logs AFTER some \"execution\" events based on the\n     * Timestamp__c field. To mitigate this and put things on the\n     * same playing field, we truncate the milliseconds from the\n     * date/times when set on events from Apex to match the precision\n     * of the date/times provided in platform events.\n     *\n     * For example, see MA_BatchApexErrorEventInvocable when it\n     * creates a Mass_Action_Batch_Apex_Status_Event__e and sets the Timestamp__c\n     * to evt.CreatedDate. That value's precision won't include milliseconds.\n     *\n     * https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_api_considerations.htm\n     */\n    private static DateTime getDateTimeWithoutMillis( DateTime dt ) {\n        return DateTime.newInstanceGMT(\n            Date.newInstance( dt.yearGMT(), dt.monthGMT(), dt.dayGMT() ),\n            Time.newInstance( dt.hourGMT(), dt.minuteGMT(), dt.secondGMT(), 0 )\n        );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionBatchUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionBatchUtilsTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MassActionBatchUtilsTest {\n\n    /*\n     * Most of the util methods are tested by\n     * separate test classes on the batchable classes\n     */\n\n    /**\n     * The Report object is read-only in Apex. It must be created via Metadata API.\n     * Therefore our test relies on existing data being available to us, unfortunately.\n     * Also, when testing Reports API the test will run with SeeAllData = true, regardless the annotation here.\n     * I include the annotation for clarity.\n     * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_analytics_test_reports.htm\n     */\n    @IsTest( SeeAllData = true )\n    static void test_enqueue_report_job() {\n\n        Report r = [ SELECT Id FROM Report WHERE DeveloperName = 'MA_Test_Account_Report' ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'Report',\n            Source_Report_ID__c = r.Id,\n            Source_Report_Column_Name__c = 'ACCOUNT_ID',\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'ACCOUNT_ID',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = MA_MassActionBatchUtils.enqueueAction( config.Id );\n        System.assertNotEquals( null, jobId );\n\n        Test.stopTest();\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM AsyncApexJob WHERE Id = :jobId ] );\n\n    }\n\n    @IsTest\n    static void test_enqueue_listView_job() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = MA_MassActionBatchUtils.enqueueAction( config.Id );\n        System.assertNotEquals( null, jobId );\n\n        Test.stopTest();\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM AsyncApexJob WHERE Id = :jobId ] );\n\n    }\n\n    @IsTest\n    static void test_enqueue_soql_job() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'SOQL',\n            Source_SOQL_Query__c = 'SELECT Id, Name FROM Account',\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = MA_MassActionBatchUtils.enqueueAction( config.Id );\n        System.assertNotEquals( null, jobId );\n\n        Test.stopTest();\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM AsyncApexJob WHERE Id = :jobId ] );\n\n    }\n\n    @IsTest\n    static void test_enqueue_apex_job() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'Apex',\n            Source_Apex_Class__c = 'MA_MassActionBatchUtilsTest.TestIterable',\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = MA_MassActionBatchUtils.enqueueAction( config.Id );\n        System.assertNotEquals( null, jobId );\n\n        Test.stopTest();\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM AsyncApexJob WHERE Id = :jobId ] );\n\n    }\n\n    @IsTest\n    static void test_enqueue_apex_job_no_class_exists() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'Apex',\n            Source_Apex_Class__c = 'No_Class_Exists_By_This_Name',\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        try {\n\n            ID jobId = MA_MassActionBatchUtils.enqueueAction( config.Id );\n            System.assertEquals( null, jobId );\n\n        } catch ( NoDataFoundException ex ) {\n\n            System.assert( ex.getMessage().startsWithIgnoreCase( 'No class found for name' ) );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n    public class TestIterable implements Iterable<Map<String, Object>> {\n        public Iterator<Map<String, Object>> iterator() {\n            return new List<Map<String, Object>>{\n                new Map<String, Object>{ 'Id' => '001000000000000' }\n            }.iterator();\n        }\n    }\n\n    @IsTest\n    static void test_handle_batch_job_started() {\n\n        AsyncApexJob job = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.PROCESSING_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true\n        );\n\n        insert config;\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = job.Id,\n            Submitted_Date__c = DateTime.now(),\n            Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n            Message__c = 'Batch job enqueued',\n            Message_Type__c = 'Informational'\n        );\n\n        insert parentLog;\n\n        Test.startTest();\n\n        MA_MassActionBatchUtils.handleBatchJobStarted( config.Id, job.Id );\n\n        Test.getEventBus().deliver();\n\n        Test.stopTest();\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        System.assertEquals( 'Batch job ' + job.Status.toLowerCase(), parentLog.Message__c );\n        System.assertEquals( 'Informational', parentLog.Message_Type__c );\n\n        System.assertEquals( 1, parentLog.Mass_Action_Logs__r.size() );\n        System.assertEquals( 'Started', parentLog.Mass_Action_Logs__r[0].Message__c );\n        System.assertEquals( 'Informational', parentLog.Mass_Action_Logs__r[0].Message_Type__c );\n        System.assertEquals( null, parentLog.Mass_Action_Logs__r[0].Job_Scope__c );\n\n    }\n\n    @IsTest\n    static void test_handle_batch_job_execution() {\n\n        AsyncApexJob job = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.PROCESSING_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true\n        );\n\n        insert config;\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = job.Id,\n            Submitted_Date__c = DateTime.now(),\n            Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n            Message__c = 'Batch job enqueued',\n            Message_Type__c = 'Informational'\n        );\n\n        insert parentLog;\n\n        Test.startTest();\n\n        MA_MassActionBatchUtils.handleBatchJobExecution( config.Id, job.Id, 1, 'TEST JOB SCOPE' );\n\n        Test.getEventBus().deliver();\n\n        Test.stopTest();\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        System.assertEquals( 'Batch job ' + job.Status.toLowerCase(), parentLog.Message__c );\n        System.assertEquals( 'Informational', parentLog.Message_Type__c );\n\n        System.assertEquals( 1, parentLog.Mass_Action_Logs__r.size() );\n        System.assertEquals( 'Processed 1 records', parentLog.Mass_Action_Logs__r[0].Message__c );\n        System.assertEquals( 'Success', parentLog.Mass_Action_Logs__r[0].Message_Type__c );\n        System.assertEquals( 'TEST JOB SCOPE', parentLog.Mass_Action_Logs__r[0].Job_Scope__c );\n\n    }\n\n    @IsTest\n    static void test_handle_batch_job_finished() {\n\n        AsyncApexJob job = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.COMPLETED_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = true\n        );\n\n        insert config;\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = job.Id,\n            Submitted_Date__c = DateTime.now(),\n            Timestamp__c = String.valueOf( DateTime.now().getTime() ),\n            Message__c = 'Batch job enqueued',\n            Message_Type__c = 'Informational'\n        );\n\n        insert parentLog;\n\n        Test.startTest();\n\n        MA_MassActionBatchUtils.handleBatchJobFinished( config.Id, job.Id );\n\n        Test.getEventBus().deliver();\n\n        Test.stopTest();\n\n        parentLog = [\n            SELECT\n                Id, Message__c, Message_Type__c,\n                ( SELECT Message_Type__c, Message__c, Job_Scope__c FROM Mass_Action_Logs__r )\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Id = :parentLog.Id\n        ];\n\n        System.assertEquals( 'Batch job ' + job.Status.toLowerCase(), parentLog.Message__c );\n        System.assertEquals( 'Success', parentLog.Message_Type__c );\n\n        System.assertEquals( 1, parentLog.Mass_Action_Logs__r.size() );\n        System.assertEquals( 'Finished', parentLog.Mass_Action_Logs__r[0].Message__c );\n        System.assertEquals( 'Informational', parentLog.Mass_Action_Logs__r[0].Message_Type__c );\n        System.assertEquals( null, parentLog.Mass_Action_Logs__r[0].Job_Scope__c );\n\n        config = [\n            SELECT\n                Id,\n                Last_Run_Completed_Date__c,\n                Last_Run_Completed_With_Errors__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id = :config.Id\n        ];\n\n        System.assertEquals( job.CompletedDate, config.Last_Run_Completed_Date__c );\n        System.assertEquals( false, config.Last_Run_Completed_With_Errors__c );\n\n    }\n\n    @IsTest\n    static void test_mock_jobs() {\n\n        Test.startTest();\n\n        // Specific details of what the mock jobs return\n        // is validated by other test methods that use these job ids.\n        // This test method is just to ensure code coverage.\n\n        for ( ID jobId : MA_AsyncApexJobMock.MOCK_JOB_IDS ) {\n            MA_AsyncApexJobMock.getJobById( jobId );\n        }\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionBatchUtilsTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionConfigTriggerHandler.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_MassActionConfigTriggerHandler {\n\n    public MA_MassActionConfigTriggerHandler() {}\n\n    // -------------------------------------------------------\n    // INSERT\n    // -------------------------------------------------------\n\n    public void handleBeforeInsert( List<Mass_Action_Configuration__c> newList ) {\n\n        // no logic yet\n\n    }\n\n    public void handleAfterInsert( List<Mass_Action_Configuration__c> newList, Map<ID, Mass_Action_Configuration__c> newMap ) {\n\n        List<Mass_Action_Configuration__c> configsToSchedule = new List<Mass_Action_Configuration__c>();\n\n        for ( Mass_Action_Configuration__c newConfig : newList ) {\n\n            if ( newConfig.Active__c && newConfig.Schedule_Frequency__c != 'Manual' ) {\n                configsToSchedule.add( newConfig );\n            }\n\n        }\n\n        if ( configsToSchedule.size() > 0 ) {\n            scheduleMassActions( configsToSchedule );\n        }\n\n    }\n\n    // -------------------------------------------------------\n    // UPDATE\n    // -------------------------------------------------------\n\n    public void handleBeforeUpdate( List<Mass_Action_Configuration__c> oldList, Map<ID, Mass_Action_Configuration__c> oldMap,\n                                    List<Mass_Action_Configuration__c> newList, Map<ID, Mass_Action_Configuration__c> newMap ) {\n\n        // no logic yet\n\n    }\n\n    public void handleAfterUpdate( List<Mass_Action_Configuration__c> oldList, Map<ID, Mass_Action_Configuration__c> oldMap,\n                                   List<Mass_Action_Configuration__c> newList, Map<ID, Mass_Action_Configuration__c> newMap ) {\n\n        List<Mass_Action_Configuration__c> configsToReschedule = new List<Mass_Action_Configuration__c>();\n        List<Mass_Action_Configuration__c> configsToUnschedule = new List<Mass_Action_Configuration__c>();\n\n        for ( Mass_Action_Configuration__c newConfig : newList ) {\n\n            Mass_Action_Configuration__c oldConfig = oldMap.get( newConfig.Id );\n\n            System.debug( 'MA_MassActionConfigTriggerHandler.handleAfterUpdate: newConfig: ' + newConfig );\n            System.debug( 'MA_MassActionConfigTriggerHandler.handleAfterUpdate: oldConfig: ' + oldConfig );\n\n            if ( newConfig.Active__c && newConfig.Schedule_Frequency__c != 'Manual' ) {\n\n                // Since Spring '15, code coverage calculations may not count multi-line statements\n                // if the actual expression is never evaluated (e.g. if condition short-circuit)\n                // so I can either make this one super long single statement, make multiple boolean expressions\n                // that will be evaluated everytime, or create several test permutations.\n                // Creating all possible test permutations probably is the \"better practice\" but\n                // considering they are all just testing if two values don't match I think that's overkill.\n                // So I'm opting for multiple boolean expressions that will always be evaluated to ensure coverage.\n                // https://releasenotes.docs.salesforce.com/en-us/summer15/release-notes/rn_apex_expressions_coverage.htm\n                // https://twitter.com/DouglasCAyers/status/942635375939538944\n\n                Boolean activeChanged = ( oldConfig.Active__c != newConfig.Active__c );\n                Boolean frequencyChanged = ( oldConfig.Schedule_Frequency__c != newConfig.Schedule_Frequency__c );\n                Boolean cronChanged = ( oldConfig.Schedule_Cron__c != newConfig.Schedule_Cron__c );\n                Boolean secondChanged = ( oldConfig.Schedule_SecondOfMinute__c != newConfig.Schedule_SecondOfMinute__c );\n                Boolean minuteChanged = ( oldConfig.Schedule_MinuteOfHour__c != newConfig.Schedule_MinuteOfHour__c );\n                Boolean hourChanged = ( oldConfig.Schedule_HourOfDay__c != newConfig.Schedule_HourOfDay__c );\n                Boolean dayOfWeekChanged = ( oldConfig.Schedule_DayOfWeek__c != newConfig.Schedule_DayOfWeek__c );\n                Boolean dayOfMonthChanged = ( oldConfig.Schedule_DayOfMonth__c != newConfig.Schedule_DayOfMonth__c );\n                Boolean monthOfYearChanged = ( oldConfig.Schedule_MonthOfYear__c != newconfig.Schedule_MonthOfYear__c );\n\n                Boolean reschedule = ( activeChanged || frequencyChanged || cronChanged || secondChanged || minuteChanged || hourChanged || dayOfWeekChanged || dayOfMonthChanged || monthOfYearChanged );\n\n                if ( reschedule ) {\n                    configsToReschedule.add( newConfig );\n                }\n\n            } else {\n\n                configsToUnschedule.add( newConfig );\n\n            }\n\n        }\n\n        if ( configsToReschedule.size() > 0 ) {\n            rescheduleMassActions( configsToReschedule );\n        }\n\n        if ( configsToUnschedule.size() > 0 ) {\n            unscheduleMassActions( configsToUnschedule );\n        }\n\n    }\n\n    // -------------------------------------------------------\n    // DELETE\n    // -------------------------------------------------------\n\n    public void handleBeforeDelete( List<Mass_Action_Configuration__c> oldList, Map<ID, Mass_Action_Configuration__c> oldMap ) {\n\n        // no logic yet\n\n    }\n\n    public void handleAfterDelete( List<Mass_Action_Configuration__c> oldList, Map<ID, Mass_Action_Configuration__c> oldMap ) {\n\n        unscheduleMassActions( oldList );\n\n    }\n\n    // -------------------------------------------------------\n\n    private static void rescheduleMassActions( List<Mass_Action_Configuration__c> configs ) {\n\n        System.debug( 'MA_MassActionConfigTriggerHandler.rescheduleMassActions' );\n\n        unscheduleMassActions( configs );\n        scheduleMassActions( configs );\n\n    }\n\n    private static void unscheduleMassActions( List<Mass_Action_Configuration__c> configs ) {\n\n        System.debug( 'MA_MassActionConfigTriggerHandler.unscheduleMassActions' );\n\n        // publishJobChangeEvent( configs, MA_JobChangeEvent.ScheduleOperation.UNSCHEDULE );\n        MA_MassActionScheduleUtils.unscheduleMassActions( toIds( configs ) );\n\n    }\n\n    private static void scheduleMassActions( List<Mass_Action_Configuration__c> configs ) {\n\n        System.debug( 'MA_MassActionConfigTriggerHandler.scheduleMassActions' );\n\n        // publishJobChangeEvent( configs, MA_JobChangeEvent.ScheduleOperation.SCHEDULE );\n        MA_MassActionScheduleUtils.scheduleMassActions( toIds( configs ) );\n\n    }\n\n    private static List<ID> toIds( List<SObject> records ) {\n        List<ID> ids = new List<ID>();\n        for ( SObject record : records ) {\n            ids.add( record.Id );\n        }\n        return ids;\n    }\n\n    /**\n     * When users save Mass Action Configurations using the MA_EditConfigCmp component,\n     * it invokes our custom Apex REST endpoint via the LC_API component. Therefore, this\n     * trigger handler ends up being invoked from within the execution context of Apex REST.\n     *\n     * Due to known issue that execution contexts started from Apex REST endpoints\n     * cannot schedule or abort jobs, then our workaround is to use platform events\n     * to move into another execution context.\n     * https://success.salesforce.com/issues_view?id=a1p30000000SyhIAAS\n     */\n    /*\n    private static void publishJobChangeEvent( List<Mass_Action_Configuration__c> configs, MA_JobChangeEvent.ScheduleOperation scheduleOperation ) {\n\n        System.debug( 'MA_MassActionConfigTriggerHandler.publishJobChangeEvent' );\n        System.debug( 'scheduleOperation=' + scheduleOperation );\n\n        MA_JobChangeEvent eventPayload = new MA_JobChangeEvent();\n        eventPayload.configIds = new List<ID>( new Map<ID, Mass_Action_Configuration__c>( configs ).keySet() );\n        eventPayload.scheduleChangeOperation = scheduleOperation;\n\n        EventBus.publish( new Mass_Action_Job_Change_Event__e(\n            Payload__c = JSON.serialize( eventPayload )\n        ));\n\n    }\n    */\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionConfigTriggerHandler.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionConfigTriggerHandlerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MassActionConfigTriggerHandlerTest {\n\n    @IsTest\n    static void test_insert() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c activeConfig = new Mass_Action_Configuration__c(\n            Name = 'Test Config 1',\n            DeveloperName__c = 'Test_Config1',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        Mass_Action_Configuration__c inactiveConfig = new Mass_Action_Configuration__c(\n            Name = 'Test Config 2',\n            DeveloperName__c = 'Test_Config2',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        insert activeConfig;    // should publish event to schedule job\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] ); // remove if emitting platform events for scheduling\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + activeConfig.Id) ] );\n\n        insert inactiveConfig;  // since inactive, should NOT publish an event\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] ); // remove if emitting platform events for scheduling\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + inactiveConfig.Id) ] );\n\n        Test.stopTest();\n\n        /*\n         * 1/1/2019, I switched from emitting platform events in the trigger to schedule jobs.\n         * See MA_EditConfigCmpHelper.saveRecordAsync for full details.\n         */\n\n        /*\n        List<EventBusSubscriber> eventBusSubscribers = new List<EventBusSubscriber>([\n            SELECT\n                Name, Status, Position, Type, Topic\n            FROM\n                EventBusSubscriber\n            WHERE\n                Name = 'MA_JobChangeEventTrigger'\n            LIMIT 1\n        ]);\n\n        System.assertEquals( 1, eventBusSubscribers[0].Position );\n        */\n\n    }\n\n    @IsTest\n    static void test_update() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Scheduled',\n            Schedule_SecondOfMinute__c = '0',\n            Schedule_MinuteOfHour__c = '0',\n            Schedule_HourOfDay__c = '1',\n            Schedule_DayOfMonth__c = '*',\n            Schedule_MonthOfYear__c = '*',\n            Schedule_DayOfWeek__c = '?'\n        );\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        insert config; // since inactive, should NOT publish event to schedule job\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] ); // remove if emitting platform events for scheduling\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + config.Id) ] );\n\n        config.Active__c = true;\n        update config; // since active, should publish event to unschedule old job and schedule new job\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] ); // remove if emitting platform events for scheduling\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + config.Id) ] );\n\n        config.Active__c = false;\n        update config; // since inactive, should publish event to unschedule job\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] ); // remove if emitting platform events for scheduling\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + config.Id) ] );\n\n        Test.stopTest();\n\n        /*\n         * 1/1/2019, I switched from emitting platform events in the trigger to schedule jobs.\n         * See MA_EditConfigCmpHelper.saveRecordAsync for full details.\n         */\n\n        /*\n        List<EventBusSubscriber> eventBusSubscribers = new List<EventBusSubscriber>([\n            SELECT\n                Name, Status, Position, Type, Topic\n            FROM\n                EventBusSubscriber\n            WHERE\n                Name = 'MA_JobChangeEventTrigger'\n            LIMIT 1\n        ]);\n\n        System.assertEquals( 3, eventBusSubscribers[0].Position );\n        */\n\n    }\n\n    @IsTest\n    static void test_crud() {\n\n        Test.startTest();\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        update config;\n\n        delete config;\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionConfigTriggerHandlerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionConfigWrapper.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * To simplify efforts to have one code base that can be open source\n * and in a managed package, and the code not have to know about any\n * namespace then rather than serialize custom sobjects or fields to\n * our Lightning Components we instead have an abstraction layer.\n *\n * Regardless the namespace of the org the code is deployed into,\n * the Lightning Compnent javascript can always reference attributes\n * from this class without worry.\n *\n * Test code coverage provided by MA_EditConfigCmpControllerTest.\n */\npublic inherited sharing class MA_MassActionConfigWrapper {\n\n    @AuraEnabled\n    public ID recordId { get; set; }\n\n    @AuraEnabled\n    public ID ownerId { get; set; }\n\n    @AuraEnabled\n    public String name { get; set; }\n\n    @AuraEnabled\n    public String developerName { get; set; }\n\n    @AuraEnabled\n    public String namedCredential { get; set; }\n\n    @AuraEnabled\n    public Boolean active { get; set; }\n\n    @AuraEnabled\n    public Integer batchSize { get; set; }\n\n    @AuraEnabled\n    public String description { get; set; }\n\n    // source\n\n    @AuraEnabled\n    public String sourceType { get; set; }\n\n    @AuraEnabled\n    public String sourceReportID { get; set; }\n\n    @AuraEnabled\n    public String sourceReportColumnName { get; set; }\n\n    @AuraEnabled\n    public String sourceListViewID { get; set; }\n\n    @AuraEnabled\n    public String sourceSoqlQuery { get; set; }\n\n    @AuraEnabled\n    public String sourceApexClass { get; set; }\n\n    // target\n\n    @AuraEnabled\n    public String targetType { get; set; }\n\n    @AuraEnabled\n    public String targetSobjectType { get; set; }\n\n    @AuraEnabled\n    public String targetActionName { get; set; }\n\n    @AuraEnabled\n    public String targetApexScript { get; set; }\n\n    // schedule\n\n    @AuraEnabled\n    public String scheduleFrequency { get; set; }\n\n    @AuraEnabled\n    public String scheduleCron { get; set; }\n\n    @AuraEnabled\n    public String scheduleSecondOfMinute { get; set; }\n\n    @AuraEnabled\n    public String scheduleMinuteOfHour { get; set; }\n\n    @AuraEnabled\n    public String scheduleHourOfDay { get; set; }\n\n    @AuraEnabled\n    public String scheduleDayOfMonth { get; set; }\n\n    @AuraEnabled\n    public String scheduleMonthOfYear { get; set; }\n\n    @AuraEnabled\n    public String scheduleDayOfWeek { get; set; }\n\n    // system\n\n    @AuraEnabled\n    public ID createdById { get; set; }\n\n    @AuraEnabled\n    public DateTime createdDate { get; set; }\n\n    @AuraEnabled\n    public ID lastModifiedById { get; set; }\n\n    @AuraEnabled\n    public DateTime lastModifiedDate { get; set; }\n\n    @AuraEnabled\n    public List<FieldMappingWrapper> fieldMappings { get; set; }\n\n    public MA_MassActionConfigWrapper() { }\n\n    public MA_MassActionConfigWrapper( Mass_Action_Configuration__c config ) {\n\n        this.fieldMappings = new List<FieldMappingWrapper>();\n\n        // defaults\n        this.active = true;\n        this.batchSize = 200;\n\n        if ( config != null ) {\n\n            this.recordId = config.Id;\n            this.ownerId = config.OwnerId;\n            this.name = config.Name;\n            this.developerName = config.DeveloperName__c;\n            this.namedCredential = config.Named_Credential__c;\n            this.active = ( config.Active__c == null ? this.active : config.Active__c );\n            this.batchSize = ( config.Batch_Size__c == null ? this.batchSize : config.Batch_Size__c.intValue() );\n            this.description = config.Description__c;\n            // source\n            this.sourceType = config.Source_Type__c;\n            this.sourceReportID = config.Source_Report_ID__c;\n            this.sourceReportColumnName = config.Source_Report_Column_Name__c;\n            this.sourceListViewID = config.Source_List_View_ID__c;\n            this.sourceSoqlQuery = config.Source_SOQL_Query__c;\n            this.sourceApexClass = config.Source_Apex_Class__c;\n            // target\n            this.targetType = config.Target_Type__c;\n            this.targetSobjectType = config.Target_SObject_Type__c;\n            this.targetActionName = config.Target_Action_Name__c;\n            this.targetApexScript = config.Target_Apex_Script__c;\n            // schedule\n            this.scheduleFrequency = config.Schedule_Frequency__c;\n            this.scheduleCron = config.Schedule_Cron__c;\n            this.scheduleSecondOfMinute = config.Schedule_SecondOfMinute__c;\n            this.scheduleMinuteOfHour = config.Schedule_MinuteOfHour__c;\n            this.scheduleHourOfDay = config.Schedule_HourOfDay__c;\n            this.scheduleDayOfMonth = config.Schedule_DayOfMonth__c;\n            this.scheduleMonthOfYear = config.Schedule_MonthOfYear__c;\n            this.scheduleDayOfWeek = config.Schedule_DayOfWeek__c;\n            // system\n            this.createdById = config.CreatedById;\n            this.createdDate = config.CreatedDate;\n            this.lastModifiedById = config.LastModifiedById;\n            this.lastModifiedDate = config.LastModifiedDate;\n\n            for ( Mass_Action_Mapping__c mapping : config.Mass_Action_Mappings__r ) {\n                this.fieldMappings.add( new FieldMappingWrapper( mapping ) );\n            }\n\n        }\n\n    }\n\n    public Mass_Action_Configuration__c toConfiguration() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = this.name,\n            DeveloperName__c = this.developerName,\n            Named_Credential__c = this.namedCredential,\n            Active__c = ( this.active == null ? true : this.active ),\n            Batch_Size__c = ( this.batchSize == null ? 200 : this.batchSize ),\n            Description__c = this.description,\n            // source\n            Source_Type__c = this.sourceType,\n            Source_Report_ID__c = this.sourceReportID,\n            Source_Report_Column_Name__c = this.sourceReportColumnName,\n            Source_List_View_ID__c = this.sourceListViewID,\n            Source_SOQL_Query__c = this.sourceSoqlQuery,\n            Source_Apex_Class__c = this.sourceApexClass,\n            // target\n            Target_Type__c = this.targetType,\n            Target_SObject_Type__c = this.targetSobjectType,\n            Target_Action_Name__c = this.targetActionName,\n            Target_Apex_Script__c = this.targetApexScript,\n            // schedule\n            Schedule_Frequency__c = this.scheduleFrequency,\n            Schedule_Cron__c = this.scheduleCron,\n            Schedule_SecondOfMinute__c = this.scheduleSecondOfMinute,\n            Schedule_MinuteOfHour__c = this.scheduleMinuteOfHour,\n            Schedule_HourOfDay__c = this.scheduleHourOfDay,\n            Schedule_DayOfMonth__c = this.scheduleDayOfMonth,\n            Schedule_MonthOfYear__c = this.scheduleMonthOfYear,\n            Schedule_DayOfWeek__c = this.scheduleDayOfWeek\n        );\n\n        // some fields need to not be \"set\" otherwise will cause errors if set to null\n        // so only if there are actual values to assign then we leave these unset\n        if ( String.isNotBlank( this.recordId ) ) {\n            config.Id = this.recordId;\n        }\n\n        if ( String.isNotBlank( this.ownerId ) ) {\n            config.OwnerId = this.ownerId;\n        }\n\n        return config;\n    }\n\n    public inherited sharing class FieldMappingWrapper {\n\n        @AuraEnabled\n        public String sourceFieldName { get; set; }\n\n        @AuraEnabled\n        public String targetFieldName { get; set; }\n\n        public FieldMappingWrapper( Mass_Action_Mapping__c mapping ) {\n            this.sourceFieldName = mapping.Source_Field_Name__c;\n            this.targetFieldName = mapping.Target_Field_Name__c;\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionConfigWrapper.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionLogTriggerHandler.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_MassActionLogTriggerHandler {\n\n    public MA_MassActionLogTriggerHandler() {}\n\n    // -------------------------------------------------------\n    // INSERT\n    // -------------------------------------------------------\n\n    public void handleBeforeInsert( List<Mass_Action_Log__c> newList ) {\n\n        formatJobId( newList );\n        assignParentLogConfiguration( newList );\n\n    }\n\n    public void handleAfterInsert( List<Mass_Action_Log__c> newList, Map<ID, Mass_Action_Log__c> newMap ) {\n\n        // no logic yet\n\n    }\n\n    // -------------------------------------------------------\n    // UPDATE\n    // -------------------------------------------------------\n\n    public void handleBeforeUpdate( List<Mass_Action_Log__c> oldList, Map<ID, Mass_Action_Log__c> oldMap,\n                                    List<Mass_Action_Log__c> newList, Map<ID, Mass_Action_Log__c> newMap ) {\n\n        formatJobId( newList );\n        assignParentLogConfiguration( newList );\n\n    }\n\n    public void handleAfterUpdate( List<Mass_Action_Log__c> oldList, Map<ID, Mass_Action_Log__c> oldMap,\n                                   List<Mass_Action_Log__c> newList, Map<ID, Mass_Action_Log__c> newMap ) {\n\n        // no logic yet\n\n    }\n\n    // -------------------------------------------------------\n    // DELETE\n    // -------------------------------------------------------\n\n    public void handleBeforeDelete( List<Mass_Action_Log__c> oldList, Map<ID, Mass_Action_Log__c> oldMap ) {\n\n        cascadeDeleteChildLogs( oldMap.keySet() );\n\n    }\n\n    public void handleAfterDelete( List<Mass_Action_Log__c> oldList, Map<ID, Mass_Action_Log__c> oldMap ) {\n\n        // no logic yet\n\n    }\n\n    // -------------------------------------------------------\n\n    /**\n     * Designed to be called during `before delete` trigger event.\n     *\n     * If this were called during `after delete` then the parent logs\n     * will have been deleted and the child log's Parent_Log__c field\n     * will have been blanked out and so the query will not find any\n     * child logs to delete.\n     */\n    private static void cascadeDeleteChildLogs( Set<ID> parentLogIds ) {\n        delete [\n            SELECT\n                Id\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Parent_Log__c IN :parentLogIds\n                AND\n                RecordType.DeveloperName = 'Child_Log'\n            ORDER BY\n                Parent_Log__c\n        ];\n    }\n\n    /**\n     * Designed to be called during `before insert` and `before update` trigger events.\n     *\n     * We don't have lookup fields to AsyncApexJob records.\n     * When filtering by this field in SOQL, since it's technically a text field\n     * and not an ID field, then the field value and filter value must match\n     * length exactly. So standardizing on the 15 character id, least common denominator.\n     */\n    private static void formatJobId( List<Mass_Action_Log__c> newLogs ) {\n\n        for ( Mass_Action_Log__c newLog : newLogs ) {\n\n            if ( String.isNotBlank( newLog.Job_ID__c ) ) {\n                newLog.Job_ID__c = newLog.Job_ID__c.left( 15 );\n            }\n\n        }\n\n    }\n\n    /**\n     * Designed to be called during `before insert` and `before update` trigger events.\n     *\n     * Sets the new log's parent log configuration lookup field based on its record type.\n     * This is how we implement filtered related lists on the mass action configuration page.\n     * https://douglascayers.com/2015/11/18/salesforce-filter-related-lists-without-code/\n     */\n    private static void assignParentLogConfiguration( List<Mass_Action_Log__c> newLogs ) {\n\n        Map<ID, RecordTypeInfo> recordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosById();\n\n        for ( Mass_Action_Log__c newLog : newLogs ) {\n\n            RecordTypeInfo rt = recordTypeInfosMap.get( newLog.RecordTypeId );\n            Boolean isParentLog = ( rt != null && rt.getDeveloperName() == 'Parent_Log' );\n            newLog.Parent_Log_Configuration__c = ( isParentLog ? newLog.Mass_Action_Configuration__c : null );\n\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionLogTriggerHandler.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionLogTriggerHandlerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MassActionLogTriggerHandlerTest {\n\n    @IsTest\n    static void test_format_job_id() {\n\n        Test.startTest();\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        Mass_Action_Log__c log = new Mass_Action_Log__c(\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = ID.valueOf( '707f40000000001' )\n        );\n\n        System.assertEquals( 18, log.Job_ID__c.length() );\n\n        insert log;\n\n        Test.stopTest();\n\n        log = [ SELECT Job_ID__c FROM Mass_Action_Log__c WHERE Id = :log.Id ];\n\n        System.assertEquals( 15, log.Job_ID__c.length() );\n\n    }\n\n    @IsTest\n    static void test_assign_parent_log_configuration() {\n\n        Test.startTest();\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        Mass_Action_Log__c parentLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Job_ID__c = ID.valueOf( '707f40000000001' )\n        );\n\n        insert parentLog;\n\n        Mass_Action_Log__c childLog = new Mass_Action_Log__c(\n            RecordTypeId = logRecordTypeInfosMap.get( 'Child_Log' ).getRecordTypeId(),\n            Mass_Action_Configuration__c = config.Id,\n            Parent_Log__c = parentLog.Id,\n            Job_ID__c = ID.valueOf( '707f40000000001' )\n        );\n\n        insert childLog;\n\n        Test.stopTest();\n\n        System.assertEquals( 2, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Parent_Log_Configuration__c = :config.Id ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Parent_Log_Configuration__c = :config.Id AND Id = :parentLog.Id ] );\n\n    }\n\n    @IsTest\n    static void test_cascade_delete_child_logs() {\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        List<Mass_Action_Log__c> parentLogs = new List<Mass_Action_Log__c>();\n        List<Mass_Action_Log__c> childLogs = new List<Mass_Action_Log__c>();\n\n        for ( Integer i = 0; i < 200; i++ ) {\n            parentLogs.add( new Mass_Action_Log__c(\n                RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n                Mass_Action_Configuration__c = config.Id,\n                Job_ID__c = ID.valueOf( '707f40000000001' )\n            ));\n        }\n\n        insert parentLogs;\n\n        for ( Mass_Action_Log__c parentLog : parentLogs ) {\n            for ( Integer i = 0; i < 20; i++ ) {\n                childLogs.add( new Mass_Action_Log__c(\n                    Mass_Action_Configuration__c = parentLog.Mass_Action_Configuration__c,\n                    Parent_Log__c = parentLog.Id,\n                    RecordTypeId = logRecordTypeInfosMap.get( 'Child_Log' ).getRecordTypeId()\n                ));\n            }\n        }\n\n        insert childLogs;\n\n        System.assertEquals( parentLogs.size(), [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Parent_Log' ] );\n        System.assertEquals( childLogs.size(), [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Child_Log' ] );\n\n        Test.startTest();\n\n        // delete only the parent logs\n        // then assert that the child logs\n        // were cascade deleted too\n        delete parentLogs;\n\n        Test.stopTest();\n\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Parent_Log' ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Child_Log' ] );\n\n    }\n\n    @IsTest\n    static void test_crud() {\n\n        Test.startTest();\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        Mass_Action_Log__c log = new Mass_Action_Log__c(\n            Mass_Action_Configuration__c = config.Id\n        );\n\n        insert log;\n\n        update log;\n\n        delete log;\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionLogTriggerHandlerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionSchedulable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_MassActionSchedulable implements System.Schedulable, Database.AllowsCallouts {\n\n    private ID configId { get; set; }\n\n    public MA_MassActionSchedulable( ID configId ) {\n        this.configId = configId;\n    }\n\n    public void execute( System.SchedulableContext context ) {\n\n        System.debug( 'MA_MassActionSchedulable.execute: ' + context + ', configId=' + this.configId );\n\n        /*\n         * Apex that is scheduled or code that is explicitly called by scheduled apex\n         * is not updateable and throws error \"This schedulable class has jobs pending or in progress\".\n         * The workaround is to use a dispatcher design pattern that dynamically looks up a handler class,\n         * thereby avoiding the apex lock on the handler code so that it is updateable.\n         * https://help.salesforce.com/articleView?id=000004423&language=en_US&type=1\n         * https://salesforce.stackexchange.com/questions/33838/scheduled-batch-job-from-installhandler-and-further-upgrades-of-managed-package\n         * https://salesforce.stackexchange.com/questions/24446/how-to-deploy-apex-classes-that-are-scheduled\n         */\n\n        Type enqueuer = Type.forName( 'MA_MassActionBatchEnqueuer' );\n\n        MA_MassActionSchedulableDispatched dispatched = (MA_MassActionSchedulableDispatched) enqueuer.newInstance();\n        dispatched.execute( context, this.configId );\n\n    }\n\n    // ----------------------------------------------------\n\n    public interface MA_MassActionSchedulableDispatched {\n\n        void execute( System.SchedulableContext context, ID configId );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionSchedulable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionSchedulableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MassActionSchedulableTest {\n\n    @IsTest\n    static void test_schedule_listview() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        System.schedule( 'Mass Action Job', '0 0 13 * * ?', new MA_MassActionSchedulable( config.Id ) );\n\n        Test.stopTest();\n\n    }\n\n    /**\n     * The Report object is read-only in Apex. It must be created via Metadata API.\n     * Therefore our test relies on existing data being available to us, unfortunately.\n     * Also, when testing Reports API the test will run with SeeAllData = true, regardless the annotation here.\n     * I include the annotation for clarity.\n     * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_analytics_test_reports.htm\n     */\n    @IsTest( SeeAllData = true )\n    static void test_schedule_report() {\n\n        Report r = [ SELECT Id FROM Report WHERE DeveloperName = 'MA_Test_Account_Report' ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'Report',\n            Source_Report_ID__c = r.Id,\n            Source_Report_Column_Name__c = 'ACCOUNT_ID',\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'ACCOUNT_ID',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        System.schedule( 'Mass Action Job', '0 0 13 * * ?', new MA_MassActionSchedulable( config.Id ) );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionSchedulableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionScheduleUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * Most code coverage comes from MA_JobChangeEventTriggerHandlerTest\n */\npublic inherited sharing class MA_MassActionScheduleUtils {\n\n    public static void unscheduleMassActions( List<ID> configIds ) {\n\n        System.debug( 'MA_MassActionScheduleUtils.unscheduleMassActions: ' + configIds );\n\n        configIds = ( configIds == null ? new List<ID>() : configIds );\n\n        Set<String> jobNames = new Set<String>();\n        for ( ID configId : configIds ) {\n            // Due to oddity with JSON roundtrip serialization of IDs\n            // ending up as 15-char IDs instead of 18-char IDs, then\n            // explicitly converting the value to an ID to get back to 18-char version.\n            // Otherwise, our SOQL query won't find the job names.\n            // https://releasenotes.docs.salesforce.com/en-us/winter16/release-notes/rn_apex_json_ids.htm\n            jobNames.add( 'MA_MassAction_' + ID.valueOf( configId ) );\n        }\n\n        for ( List<CronTrigger> cronTriggers : [\n            SELECT\n                Id, State, CronJobDetail.Name\n            FROM\n                CronTrigger\n            WHERE\n                CronJobDetail.Name IN :jobNames\n        ]) {\n\n            for ( CronTrigger cronTrigger : cronTriggers ) {\n\n                System.debug( 'MA_MassActionScheduleUtils.unscheduleMassActions: Aborting job: ' + JSON.serializePretty( cronTrigger ) );\n                System.abortJob( cronTrigger.Id );\n\n            }\n\n        }\n\n    }\n\n    public static void scheduleMassActions( List<ID> configIds ) {\n\n        System.debug( 'MA_MassActionScheduleUtils.scheduleMassActions: ' + configIds );\n\n        configIds = ( configIds == null ? new List<ID>() : configIds );\n\n        List<Mass_Action_Configuration__c> configs = new List<Mass_Action_Configuration__c>([\n            SELECT\n                Id,\n                Schedule_Cron__c,\n                Schedule_Frequency__c,\n                Schedule_SecondOfMinute__c,\n                Schedule_MinuteOfHour__c,\n                Schedule_HourOfDay__c,\n                Schedule_DayOfMonth__c,\n                Schedule_MonthOfYear__c,\n                Schedule_DayOfWeek__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id IN :configIds\n        ]);\n\n        for ( Mass_Action_Configuration__c config : configs ) {\n\n            String jobName = 'MA_MassAction_' + config.Id;\n            String cron = buildCron( config );\n\n            System.debug( 'MA_MassActionScheduleUtils.scheduleMassActions: Scheduling job: jobName=' + jobName + ', cron=' + cron );\n            ID jobId = System.schedule( jobName, cron, new MA_MassActionSchedulable( config.Id ) );\n            System.debug( 'MA_MassActionScheduleUtils.scheduleMassActions: Scheduled job: ' + jobId );\n\n        }\n\n    }\n\n    public static String buildCron( Mass_Action_Configuration__c config ) {\n\n        System.debug( 'MA_MassActionScheduleUtils.buildCron: ' + config );\n\n        String cron = '';\n\n        if ( config.Schedule_Frequency__c == 'Scheduled' ) {\n\n            cron = String.format(\n                '{0} {1} {2} {3} {4} {5}',\n                new String[] {\n                    config.Schedule_SecondOfMinute__c,\n                    config.Schedule_MinuteOfHour__c,\n                    config.Schedule_HourOfDay__c,\n                    config.Schedule_DayOfMonth__c,\n                    config.Schedule_MonthOfYear__c,\n                    config.Schedule_DayOfWeek__c\n                }\n            );\n\n        } else if ( config.Schedule_Frequency__c == 'Custom' ) {\n\n            cron = config.Schedule_Cron__c;\n\n        }\n\n        System.debug( 'MA_MassActionScheduleUtils.buildCron: cron=' + cron );\n\n        return cron;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionScheduleUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionScheduleUtilsTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MassActionScheduleUtilsTest {\n\n    @IsTest\n    static void test_schedule_jobs() {\n\n        Mass_Action_Configuration__c configA = new Mass_Action_Configuration__c(\n            Name = 'Test Config A',\n            DeveloperName__c = 'Test_Config_A',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'SOQL',\n            Source_List_View_ID__c = 'SELECT Id FROM Account LIMIT 1',\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Scheduled',\n            Schedule_SecondOfMinute__c = '0',\n            Schedule_MinuteOfHour__c = '0',\n            Schedule_HourOfDay__c = '1',\n            Schedule_DayOfMonth__c = '*',\n            Schedule_MonthOfYear__c = '*',\n            Schedule_DayOfWeek__c = '?'\n        );\n\n        Mass_Action_Configuration__c configB = new Mass_Action_Configuration__c(\n            Name = 'Test Config B',\n            DeveloperName__c = 'Test_Config_B',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'SOQL',\n            Source_List_View_ID__c = 'SELECT Id FROM Account LIMIT 1',\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        insert configA;\n        insert configB;\n\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configA.Id) ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configB.Id) ] );\n\n        Test.startTest();\n\n        MA_MassActionScheduleUtils.scheduleMassActions( new List<ID>{ configA.Id, configB.Id } );\n\n        Test.stopTest();\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configA.Id) ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configB.Id) ] );\n\n        CronTrigger triggerA = [ SELECT Id, CronJobDetail.Name, CronExpression FROM CronTrigger WHERE CronJobDetail.Name LIKE :('%' + configA.Id) ];\n        System.assertEquals( MA_MassActionScheduleUtils.buildCron( configA ), triggerA.CronExpression );\n\n        CronTrigger triggerB = [ SELECT Id, CronJobDetail.Name, CronExpression FROM CronTrigger WHERE CronJobDetail.Name LIKE :('%' + configB.Id) ];\n        System.assertEquals( configB.Schedule_Cron__c, triggerB.CronExpression );\n\n    }\n\n    @IsTest\n    static void test_unschedule_jobs() {\n\n        Mass_Action_Configuration__c configA = new Mass_Action_Configuration__c(\n            Name = 'Test Config A',\n            DeveloperName__c = 'Test_Config_A',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'SOQL',\n            Source_List_View_ID__c = 'SELECT Id FROM Account LIMIT 1',\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Scheduled',\n            Schedule_SecondOfMinute__c = '0',\n            Schedule_MinuteOfHour__c = '0',\n            Schedule_HourOfDay__c = '1',\n            Schedule_DayOfMonth__c = '*',\n            Schedule_MonthOfYear__c = '*',\n            Schedule_DayOfWeek__c = '?'\n        );\n\n        Mass_Action_Configuration__c configB = new Mass_Action_Configuration__c(\n            Name = 'Test Config B',\n            DeveloperName__c = 'Test_Config_B',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Source_Type__c = 'SOQL',\n            Source_List_View_ID__c = 'SELECT Id FROM Account LIMIT 1',\n            Target_Type__c = 'Workflow',\n            Target_Action_Name__c = null,\n            Target_SObject_Type__c = 'Account',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        insert configA;\n        insert configB;\n\n        MA_MassActionScheduleUtils.scheduleMassActions( new List<ID>{ configA.Id, configB.Id } );\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configA.Id) ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configB.Id) ] );\n\n        Test.startTest();\n\n        MA_MassActionScheduleUtils.unscheduleMassActions( new List<ID>{ configA.Id, configB.Id } );\n\n        Test.stopTest();\n\n        System.debug( [ SELECT Id, Name FROM CronJobDetail ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configA.Id) ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM CronJobDetail WHERE Name LIKE :('%' + configB.Id) ] );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionScheduleUtilsTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * Most code coverage comes from MA_EditConfigRestControllerTest\n */\npublic inherited sharing class MA_MassActionUtils {\n\n    public static final String ORG_DOMAIN_URL = URL.getOrgDomainUrl().toExternalForm();\n    public static final String REST_API_PATH = '/services/data/v54.0'; // note the 'v' prefix on the version number\n    public static final String SOAP_API_PATH = '/services/Soap/s/54.0'; // note no 'v' prefix on the version number\n\n    public static final String REST_API_SERVICES_URL = ORG_DOMAIN_URL + REST_API_PATH;\n    public static final String SOAP_API_SERVICES_URL = ORG_DOMAIN_URL + SOAP_API_PATH;\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Returns the base URL for use with invoking the Salesforce APIs.\n     *\n     * @param namedCredential\n     *      (optional) Name of a Named Credential to use, without the 'callout:' prefix.\n     *      If blank then the org's domain URL is used instead.\n     *\n     * @return URL for use with Salesforce REST API (e.g. https://yourinstance.my.salesforce.com or callout:YourNamedCredential)\n     *  with the path '/services/data/v54.0' appended to it.\n     */\n    public static String getCalloutRestEndpointURL( String namedCredential ) {\n        String url;\n        if ( String.isBlank( namedCredential ) ) {\n            url = REST_API_SERVICES_URL;\n        } else {\n            url = 'callout:' + namedCredential + REST_API_PATH;\n        }\n        return url;\n    }\n\n    public static String getCalloutSoapEndpointURL( String namedCredential ) {\n        String url;\n        if ( String.isBlank( namedCredential ) ) {\n            url = SOAP_API_SERVICES_URL;\n        } else {\n            url = 'callout:' + namedCredential + SOAP_API_PATH;\n        }\n        return url;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Queries the config record and its related field mappings.\n     * Returns null if no record is found.\n     */\n    public static Mass_Action_Configuration__c getConfiguration( ID recordId ) {\n\n        System.debug( 'MA_MassActionUtils.getConfiguration: recordId=' + recordId );\n\n        Mass_Action_Configuration__c config = null;\n\n        for ( Mass_Action_Configuration__c record : [\n            SELECT\n                Id,\n                OwnerId,\n                Name,\n                DeveloperName__c,\n                Named_Credential__c,\n                Active__c,\n                Batch_Size__c,\n                Description__c,\n                // source\n                Source_Type__c,\n                Source_Report_ID__c,\n                Source_Report_Column_Name__c,\n                Source_List_View_ID__c,\n                Source_SOQL_Query__c,\n                Source_Apex_Class__c,\n                // target\n                Target_Type__c,\n                Target_SObject_Type__c,\n                Target_Action_Name__c,\n                Target_Apex_Script__c,\n                // schedule\n                Schedule_Frequency__c,\n                Schedule_Cron__c,\n                Schedule_SecondOfMinute__c,\n                Schedule_MinuteOfHour__c,\n                Schedule_HourOfDay__c,\n                Schedule_DayOfMonth__c,\n                Schedule_MonthOfYear__c,\n                Schedule_DayOfWeek__c,\n                // system\n                CreatedById,\n                CreatedDate,\n                LastModifiedById,\n                LastModifiedDate,\n                // mappings\n                (\n                    SELECT\n                        Id,\n                        Source_Field_Name__c,\n                        Target_Field_Name__c\n                    FROM\n                        Mass_Action_Mappings__r\n                    FOR REFERENCE\n                )\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id = :recordId\n            FOR VIEW\n        ]) {\n            config = record;\n        }\n\n        return config;\n    }\n\n    /**\n     * This method accepts the JSON serialization of the configuration and field mappings\n     * because when defining the method params as the custom class type was getting internal server error.\n     * I think possibly related to general serialization bugs with Lightning:\n     * https://developer.salesforce.com/forums/?id=906F00000005GiwIAE\n     * https://blog.texei.com/lightning-components-auraenabled-method-parameters-whats-working-and-what-s-not-83c351356104\n     */\n    public static Map<String, Object> saveConfiguration( String wrapperJson, String fieldMappingsJson ) {\n\n        System.debug( 'MA_MassActionUtils.saveConfiguration: wrapperJson=\\n' + wrapperJson );\n        System.debug( 'MA_MassActionUtils.saveConfiguration: fieldMappingsJson=\\n' + fieldMappingsJson );\n\n        Map<String, Object> result = new Map<String, Object>();\n\n        MA_MassActionConfigWrapper wrapper = (MA_MassActionConfigWrapper) JSON.deserializeStrict( wrapperJson, MA_MassActionConfigWrapper.class );\n        Map<String, String> fieldMappings = (Map<String, String>) JSON.deserializeStrict( fieldMappingsJson, Map<String, String>.class );\n\n        System.debug( 'MA_MassActionUtils.saveConfiguration: wrapper=\\n' + wrapper );\n        System.debug( 'MA_MassActionUtils.saveConfiguration: fieldMappings=\\n' + fieldMappings );\n\n        Mass_Action_Configuration__c config = wrapper.toConfiguration();\n        upsert config;\n\n        delete [ SELECT Id FROM Mass_Action_Mapping__c WHERE Mass_Action_Configuration__c = :config.Id ];\n\n        List<Mass_Action_Mapping__c> configMappings = new List<Mass_Action_Mapping__c>();\n        for ( String targetFieldName : fieldMappings.keySet() ) {\n\n            // if a target field is not required for the chosen action\n            // then ignore it if there is no source field selected\n            String sourceFieldName = fieldMappings.get( targetFieldName );\n\n            if ( String.isNotBlank( sourceFieldName ) ) {\n                configMappings.add( new Mass_Action_Mapping__c(\n                    Mass_Action_Configuration__c = config.Id,\n                    Source_Field_Name__c = sourceFieldName,\n                    Target_Field_Name__c = targetFieldName\n                ));\n            }\n\n        }\n\n        insert configMappings;\n\n        result.put( 'success', true );\n        result.put( 'recordId', config.Id );\n\n        return result;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     * or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     */\n    public static MA_ListViewDescribeResult describeListView( String baseURL, ID listViewId ) {\n\n        System.debug( 'MA_MassActionUtils.describeListView' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'listViewId: ' + listViewId );\n\n        List<ListView> listViews = new List<ListView>([ SELECT id, sobjectType FROM ListView WHERE id = :listViewId LIMIT 1 ]);\n        if ( listViews.isEmpty() ) {\n            // provide a more helpful message than the default\n            // System.QueryException: List has no rows for assignment to SObject\n            throw MA_Exceptions.buildException( NoDataFoundException.class, 'No List View found for id: ' + listViewId + '. Ensure the list view exists and is shared to the running user ' + UserInfo.getUserName() );\n        }\n\n        ListView lv = listViews[0];\n\n        String endpoint = String.format(\n            '{0}/sobjects/{1}/listviews/{2}/describe',\n            new String[] { baseURL, lv.sobjectType, lv.id }\n        );\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( endpoint );\n        req.setMethod( 'GET' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'application/json' );\n        req.setHeader( 'Accepts', 'application/json' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n\n        HttpResponse res = sendHttpRequest( req );\n\n        return (MA_ListViewDescribeResult) JSON.deserialize( res.getBody(), MA_ListViewDescribeResult.class );\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Given maps of source data whose keys match Mass_Action_Mapping__c.Source_Field_Name__c then\n     * returns new maps whose keys match Mass_Action_Mapping__c.Target_Field_Name__c and whose values\n     * match the source data. The returned maps will have as many keys as there are mappings.\n     *\n     * When considering a new source for Mass Action Service, then it is the source provider's\n     * responsibility to transform its raw data format into source map format for reuse of this method.\n     * For example, the report source and list view source classes handle their own transformations.\n     */\n    public static List<Map<String, Object>> buildActionInputs( List<Map<String, Object>> sourceRows, List<Mass_Action_Mapping__c> mappings ) {\n\n        System.debug( 'MA_MassActionUtils.buildActionInputs' );\n        System.debug( 'mappings: ' + mappings );\n        System.debug( '----------' );\n\n        List<Map<String, Object>> targetRows = new List<Map<String, Object>>();\n\n        for ( Map<String, Object> sourceRow : sourceRows ) {\n\n            Map<String, Object> sourceRowLowerCaseKeyMap = MA_MapUtils.convertKeysToLowercase( sourceRow );\n\n            Map<String, Object> targetRow = new Map<String, Object>();\n\n            for ( Mass_Action_Mapping__c mapping : mappings ) {\n\n                if ( !sourceRowLowerCaseKeyMap.containsKey( mapping.Source_Field_Name__c.toLowerCase() ) ) {\n                    throw new MA_Exceptions.NoSourceFieldException( sourceRow, mapping.Source_Field_Name__c );\n                }\n\n                targetRow.put( mapping.target_field_name__c, sourceRowLowerCaseKeyMap.get( mapping.Source_Field_Name__c.toLowerCase() ) );\n\n            }\n\n            System.debug( 'sourceRow: ' + sourceRow );\n            System.debug( 'targetRow: ' + targetRow );\n            System.debug( '----------' );\n\n            targetRows.add( targetRow );\n\n        }\n\n        return targetRows;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Designed as a simple way to invoke a configured target action with a given batch of source records.\n     * Based on the config's target action and other properties, the appropriate API call will be invoked.\n     *\n     * Originally designed as an easy way for batch classes to invoke an action from their `execute` methods\n     * with a batch of source records. This keeps logic out of the batch classes for knowing \"how\" to invoke the actions.\n     *\n     * @param config\n     *      Mass Action Configuration record.\n     * @param sourceRowMaps\n     *      Batch of source records to pass as inputs to the target action.\n     */\n    public static void invokeTargetAction( Mass_Action_Configuration__c config, List<Map<String, Object>> sourceRowMaps ) {\n\n        if ( config.Target_Type__c == 'Apex' && String.isNotBlank( config.Target_Apex_Script__c ) ) {\n\n            String baseUrl = MA_MassActionUtils.getCalloutSoapEndpointURL( config.Named_Credential__c );\n            MA_MassActionUtils.invokeExecuteAnonymous( baseUrl, config, sourceRowMaps );\n\n        } else {\n\n            List<Map<String, Object>> targetRowMaps = MA_MassActionUtils.buildActionInputs( sourceRowMaps, config.Mass_Action_Mappings__r );\n\n            String baseUrl = MA_MassActionUtils.getCalloutRestEndpointURL( config.Named_Credential__c );\n            MA_MassActionUtils.invokeAction( baseUrl, config, targetRowMaps );\n\n        }\n\n    }\n\n    /**\n     * Invokes Apex SOAP API via http callout.\n     * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_api.htm\n     */\n    public static void invokeExecuteAnonymous( String baseURL, Mass_Action_Configuration__c config, List<Map<String, Object>> sourceRowMaps ) {\n\n        System.debug( 'MA_MassActionUtils.invokeExecuteAnonymous' );\n        System.debug( 'config: ' + config );\n\n        // Executing an anonymous apex block does not accept other input parameters,\n        // such as variable values to work with as you can do when invoking the Actions API.\n        // Therefore, to provide some semblance of an interface to easily provide data\n        // to the anonymous block while supporting the developers to just write code on-the-fly,\n        // we prepend to the developer's script our own code that inlines the JSON of the source\n        // data then calls an anonymous method named `execute` with a list of maps of source records.\n        // In this manner, the developer's anonymous script simply needs to define a method\n        // `execute( List<Map<String, Object>> sourceRecordsBatch )`\n        // and that is the hook to receive the source records for processing.\n\n        String sourceRowMapsJson = JSON.serialize( sourceRowMaps );\n\n        String apexScript = (\n            ' void mas_initApexBlock() { ' +\n                ' List<Object> untypedRecords = (List<Object>) JSON.deserializeUntyped( \\'' + String.escapeSingleQuotes( sourceRowMapsJson ) + '\\' ); ' +\n                ' List<Map<String, Object>> typedRecords = new List<Map<String, Object>>(); ' +\n                ' for ( Object untypedRecord : untypedRecords ) { ' +\n                    ' typedRecords.add( (Map<String, Object>) untypedRecord ); ' +\n                ' } ' +\n                ' execute( typedRecords ); ' +\n            ' } ' +\n            ' mas_initApexBlock(); ' +\n            config.Target_Apex_Script__c\n        );\n\n        try {\n\n            HttpRequest req = buildExecuteAnonymousHttpRequest( baseUrl, apexScript );\n            HttpResponse res = sendHttpRequest( req );\n\n            MA_AnonymousApexExecuteResult result = parseAnonymousApexHttpResponse( res );\n\n            // if there was an error compiling or executing the script, the http response will still be OK 200\n            // so we need to actually inspect the response body to see if something is wrong\n            if ( result.success == false ) {\n                throw new MA_Exceptions.AnonymousApexException(\n                    req, res, result.compileProblem, result.exceptionMessage, result.exceptionStackTrace\n                );\n            }\n\n        } catch ( MA_Exceptions.InvokeActionException e ) {\n\n            Exception throwable = e;\n\n            try {\n\n                String responseString = e.response.getBody();\n                DOM.Document responseDocument = e.response.getBodyDocument();\n                DOM.XMLNode root = responseDocument.getRootElement();\n\n                if ( responseString.containsIgnoreCase( '<soapenv:Fault>' ) ) {\n\n                    String faultCode = MA_XMLUtils.getChildNodeTextByPath( root, '/Body/Fault/faultcode' );\n                    String faultString = MA_XMLUtils.getChildNodeTextByPath( root, '/Body/Fault/faultstring' );\n\n                    throwable = new MA_Exceptions.AnonymousApexException(\n                        e.request, e.response, null, faultString, faultCode, e\n                    );\n\n                }\n\n            } catch ( Exception ex ) {\n\n                // do nothing\n\n            }\n\n            throw throwable;\n\n        }\n\n    }\n\n    /**\n     * Invokes REST API via http callout.\n     * https://developer.salesforce.com/docs/atlas.en-us.api_action.meta/api_action/actions_intro_invoking.htm\n     */\n    public static void invokeAction( String baseURL, Mass_Action_Configuration__c config, List<Map<String, Object>> targetRowMaps ) {\n\n        System.debug( 'MA_MassActionUtils.invokeAction' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'config: ' + config );\n\n        HttpRequest req = buildInvokeActionHttpRequest( baseURL, config, targetRowMaps );\n        HttpResponse res = sendHttpRequest( req );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Invokes REST API via http callout.\n     * You call this method to get list of object names that can be used with getInvocableActions(..) method.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     */\n    public static List<String> getObjectsWithInvocableActions( String baseURL, String actionType ) {\n\n        System.debug( 'MA_MassActionUtils.getObjectsWithInvocableActions' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'actionType: ' + actionType );\n\n        HttpRequest req = buildInvocableActionsHttpRequest( baseURL, actionType, '' );\n        HttpResponse res = sendHttpRequest( req );\n\n        List<String> objectNames = parseActionObjectsHttpResponse( res );\n\n        return objectNames;\n    }\n\n    /**\n     * Invokes REST API via http callout.\n     * You call this method to get list of available actions for given type and object.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     * @param objectName\n     *      API name of object whose actions to get of the given type (e.g. 'Account', 'Foo__c')\n     */\n    public static List<Map<String, Object>> getInvocableActions( String baseURL, String actionType, String objectName ) {\n\n        System.debug( 'MA_MassActionUtils.getInvocableActions' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'actionType: ' + actionType );\n        System.debug( 'objectName: ' + objectName );\n\n        HttpRequest req = buildInvocableActionsHttpRequest( baseURL, actionType, objectName );\n        HttpResponse res = sendHttpRequest( req );\n\n        List<Map<String, Object>> actions = parseActionsHttpResponse( res );\n\n        return actions;\n    }\n\n    /**\n     * Gets the input variables for the given invocable action.\n     * Use this to know what to prompt user for when binding source fields to target fields.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     * @param actionName\n     *      API Name of the invocable action whose inputs to request.\n     * @param objectName\n     *      API Name of the object whose action to request.\n     */\n    public static List<Map<String, Object>> getInvocableActionInputs( String baseURL, String actionType, String actionName, String objectName ) {\n\n        System.debug( 'MA_MassActionUtils.getInvocableActionInputs' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'actionType: ' + actionType );\n        System.debug( 'actionName: ' + actionName );\n        System.debug( 'objectName: ' + objectName );\n\n        HttpRequest req = buildInvocableActionInputsHttpRequest( baseURL, actionType, actionName, objectName );\n        HttpResponse res = sendHttpRequest( req );\n\n        List<Map<String, Object>> inputs = parseActionInputsHttpResponse( res );\n\n        return inputs;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Creates an HttpRequest with a configured enpoint to invoke the Apex SOAP API\n     * to execute anonymous Apex. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com'),\n     *      with the SOAP API path suffix of '/services/Soap/s/54.0'.\n     * @param apexScript\n     *      The anonymous apex script to execute. This method URL encodes the string.\n     */\n    private static HttpRequest buildExecuteAnonymousHttpRequest( String baseURL, String apexScript ) {\n\n        System.debug( 'MA_MassActionUtils.buildExecuteAnonymousHttpRequest' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'apexScript: ' + apexScript );\n\n        Boolean usesNamedCredential = ( baseURL.startsWithIgnoreCase( 'callout:' ) );\n        String sessionId = ( usesNamedCredential ? '{!$Credential.OAuthToken}' : UserInfo.getSessionId() );\n\n        String envelopeHeader =\n            ' <soapenv:Envelope ' +\n                ' xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" ' +\n                ' xmlns:meta=\"http://soap.sforce.com/2006/04/metadata\" ' +\n                ' xmlns:apex=\"http://soap.sforce.com/2006/08/apex\" ' +\n                ' xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> ';\n\n        String soapHeader =\n            ' <soapenv:Header> ' +\n                ' <apex:SessionHeader> ' +\n                    ' <apex:sessionId>' + sessionId + '</apex:sessionId> ' +\n                ' </apex:SessionHeader> ' +\n            ' </soapenv:Header> ';\n\n        String soapBody =\n            ' <soapenv:Body> ' +\n                ' <apex:executeAnonymous> ' +\n                    ' <apex:String> ' + apexScript.escapeXml() + ' </apex:String> ' +\n                ' </apex:executeAnonymous> ' +\n            ' </soapenv:Body> ';\n\n        String envelopeFooter =\n            ' </soapenv:Envelope> ';\n\n        String soapMessage = (\n            envelopeHeader +\n            soapHeader +\n            soapBody +\n            envelopeFooter\n        );\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( baseURL );\n        req.setMethod( 'POST' );\n        req.setHeader( 'SOAPAction', 'executeAnonymous' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'text/xml' );\n        req.setHeader( 'Accepts', 'text/xml' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n        req.setBody( soapMessage );\n\n        return req;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Creates an HttpRequest with a configured enpoint to invoke the target action\n     * per the configuration. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param config\n     *      Mass Action Configuration record.\n     * @param targetRowMaps\n     *      Field mappings from the data source (e.g. list view or report) and\n     *      inputs to the target action (e.g. quick action, apex, process, etc.).\n     */\n    private static HttpRequest buildInvokeActionHttpRequest( String baseURL, Mass_Action_Configuration__c config, List<Map<String, Object>> targetRowMaps ) {\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( getInvokeActionHttpRequestEndpoint( baseURL, config ) );\n        req.setBody( getInvokeActionHttpRequestBody( config, targetRowMaps ) );\n        req.setMethod( 'POST' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'application/json' );\n        req.setHeader( 'Accepts', 'application/json' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n\n        return req;\n    }\n\n    /**\n     * Creates an endpoint URL to REST API to invoke the target action per the configuration.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param config\n     *      Mass Action Configuration record.\n     */\n    private static String getInvokeActionHttpRequestEndpoint( String baseURL, Mass_Action_Configuration__c config ) {\n\n        String endpoint = null;\n\n        if ( 'Workflow' == config.target_type__c ) {\n\n            endpoint = String.format(\n                '{0}/process/rules',\n                new String[] { baseURL }\n            );\n\n        } else if ( 'Flow' == config.target_type__c ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/flow/{1}',\n                new String[] { baseURL, config.target_action_name__c }\n            );\n\n        } else if ( 'QuickAction' == config.target_type__c ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/quickAction/{1}/{2}',\n                new String[] { baseURL, config.target_sobject_type__c, config.target_action_name__c }\n            );\n\n        } else if ( 'EmailAlert' == config.target_type__c ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/emailAlert/{1}/{2}',\n                new String[] { baseURL, config.target_sobject_type__c, config.target_action_name__c }\n            );\n\n        } else if ( 'Apex' == config.target_type__c ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/apex/{1}',\n                new String[] { baseURL, config.target_action_name__c }\n            );\n\n        }\n\n        return endpoint;\n    }\n\n    private static String getInvokeActionHttpRequestBody( Mass_Action_Configuration__c config, List<Map<String, Object>> targetRowMaps ) {\n\n        Set<String> processRulesAPI = new Set<String> {\n            'Workflow'\n        };\n\n        Set<String> actionsAPI = new Set<String> {\n            'Flow',\n            'QuickAction',\n            'EmailAlert',\n            'Apex'\n        };\n\n        String body = null;\n\n        if ( processRulesAPI.contains( config.target_type__c ) ) {\n\n            body = getInvokeActionHttpRequestBody_ProcessRules( targetRowMaps );\n\n        } else if ( actionsAPI.contains( config.target_type__c ) ) {\n\n            body = getInvokeActionHttpRequestBody_Actions( targetRowMaps );\n\n        }\n\n        return body;\n    }\n\n    /**\n     * Builds up the JSON request body for the REST Process Rules API.\n     * This includes references under '/services/data/<version>/process/rules'\n     * Like Workflow Rules.\n     *\n     * https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_process_rules_trigger.htm\n     */\n    private static String getInvokeActionHttpRequestBody_ProcessRules( List<Map<String, Object>> targetRowMaps ) {\n\n        Set<ID> contextIds = new Set<ID>();\n\n        // In all seriousness, for workflow actions then only\n        // one mapping should exist with target field name of 'ContextId'.\n        // Just in case I ever change that key name then just going to iterate\n        // all keys in the map and add to our set.\n        // But there should only be one key in the map regardless.\n        for ( Map<String, Object> targetRow : targetRowMaps ) {\n            for ( String key : targetRow.keySet() ) {\n                contextIds.add( ID.valueOf( String.valueOf( targetRow.get( key ) ) ) );\n            }\n        }\n\n        Map<String, Object> inputsRequest = new Map<String, Object>{\n            'contextIds' => contextIds\n        };\n\n        return JSON.serializePretty( inputsRequest );\n    }\n\n    /**\n     * Builds up the JSON request body for the REST Actions API.\n     * This includes references under '/services/data/<version>/actions'\n     * like Process Builder, Flows, Quick Actions, Email Alerts, and Invocable Apex.\n     *\n     * https://developer.salesforce.com/docs/atlas.en-us.api_action.meta/api_action/actions_intro_invoking.htm\n     */\n    private static String getInvokeActionHttpRequestBody_Actions( List<Map<String, Object>> targetRowMaps ) {\n\n        Map<String, Object> inputsRequest = new Map<String, Object>{\n            'inputs' => targetRowMaps\n        };\n\n        return JSON.serializePretty( inputsRequest );\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Creates an HttpRequest with a configured enpoint to retrieve invocable actions\n     * for the given object accessible by the REST API. Also sets common headers for\n     * an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     * @param objectName\n     *      API Name of the object whose actions to request.\n     */\n    private static HttpRequest buildInvocableActionsHttpRequest( String baseURL, String actionType, String objectName ) {\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( getInvocableActionsHttpRequestEndpoint( baseURL, actionType, objectName ) );\n        req.setMethod( 'GET' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'application/json' );\n        req.setHeader( 'Accepts', 'application/json' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n\n        return req;\n    }\n\n    /**\n     * Creates an endpoint URL to retrieve invocable actions for the given object\n     * accessible by the REST API. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     * @param objectName\n     *      API Name of the object whose actions to request.\n     */\n    private static String getInvocableActionsHttpRequestEndpoint( String baseURL, String actionType, String objectName ) {\n\n        String endpoint = null;\n\n        if ( 'Flow' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/flow',\n                new String[] { baseURL }\n            );\n\n        } else if ( 'QuickAction' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/quickAction/{1}',\n                new String[] { baseURL, objectName }\n            );\n\n        } else if ( 'EmailAlert' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/emailAlert/{1}',\n                new String[] { baseURL, objectName }\n            );\n\n        } else if ( 'Apex' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/apex',\n                new String[] { baseURL }\n            );\n\n        }\n\n        return endpoint;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Creates an HttpRequest with a configured enpoint to retrieve inputs for an invocable action\n     * for the given object accessible by the REST API. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     * @param actionName\n     *      API Name of the invocable action whose inputs to request.\n     * @param objectName\n     *      API Name of the object whose action to request.\n     */\n    private static HttpRequest buildInvocableActionInputsHttpRequest( String baseURL, String actionType, String actionName, String objectName ) {\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( getInvocableActionInputsHttpRequestEndpoint( baseURL, actionType, actionName, objectName ) );\n        req.setMethod( 'GET' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'application/json' );\n        req.setHeader( 'Accepts', 'application/json' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n\n        return req;\n    }\n\n    /**\n     * Creates an endpoint URL to retrieve inputs for an invocable action\n     * for the given object accessible by the REST API. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param actionType\n     *      Value from picklist Mass_Action_Configuration__c.Target_Type__c (e.g. 'QuickAction', 'EmailAlert')\n     * @param actionName\n     *      API Name of the invocable action whose inputs to request.\n     * @param objectName\n     *      API Name of the object whose action to request.\n     */\n    private static String getInvocableActionInputsHttpRequestEndpoint( String baseURL, String actionType, String actionName, String objectName ) {\n\n        String endpoint = null;\n\n        if ( 'Flow' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/flow/{1}',\n                new String[] { baseURL, actionName }\n            );\n\n        } else if ( 'QuickAction' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/quickAction/{1}/{2}',\n                new String[] { baseURL, objectName, actionName }\n            );\n\n        } else if ( 'EmailAlert' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/emailAlert/{1}/{2}',\n                new String[] { baseURL, objectName, actionName }\n            );\n\n        } else if ( 'Apex' == actionType ) {\n\n            endpoint = String.format(\n                '{0}/actions/custom/apex/{1}',\n                new String[] { baseURL, actionName }\n            );\n\n        }\n\n        return endpoint;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Executes a SOQL query via REST API via http callout.\n     * https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query.htm\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param query\n     *      SOQL query to execute.\n     * @param batchSize\n     *      The preferred max number of records to return at a time.\n     *      Choose a value between 200 and 2,000.\n     *      If there are more records than requested, you'll need to use the nextRecordsUrl to retrieve them.\n     *      https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers_queryoptions.htm\n     */\n    public static MA_SoqlQueryExecuteResult executeSoqlQuery( String baseURL, String query, Integer batchSize ) {\n\n        System.debug( 'MA_MassActionUtils.executeSoqlQuery' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'query: ' + query );\n        System.debug( 'batchSize: ' + batchSize );\n\n        try {\n\n            HttpRequest req = buildExecuteSoqlQueryHttpRequest( baseURL, query, batchSize );\n            HttpResponse res = sendHttpRequest( req );\n\n            return parseSoqlQueryHttpResponse( res );\n\n        } catch ( MA_Exceptions.InvokeActionException e ) {\n\n            Exception throwable = e;\n\n            // extract the soql error message from \"[ { errorCode: xxx, message: yyy } ]\"\n            List<Object> errors = (List<Object>) JSON.deserializeUntyped( e.response.getBody() );\n            for ( Object item : errors ) {\n                Map<String, Object> err = (Map<String, Object>) item;\n                throwable = new MA_Exceptions.SOQLQueryException(\n                    e.request, e.response, query, (String) err.get( 'errorType' ), (String) err.get( 'message' ), e\n                );\n            }\n\n            throw throwable;\n\n        }\n    }\n\n    /**\n     * Creates an HttpRequest with a configured enpoint to execute a SOQL query\n     * against the REST API. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param query\n     *      SOQL query to execute.\n     * @param batchSize\n     *      The preferred max number of records to return at a time.\n     *      Choose a value between 200 and 2,000.\n     *      If there are more records than requested, you'll need to use the nextRecordsUrl to retrieve them.\n     *      https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers_queryoptions.htm\n     */\n    private static HttpRequest buildExecuteSoqlQueryHttpRequest( String baseURL, String query, Integer batchSize ) {\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( getExecuteSoqlQueryHttpRequestEndpoint( baseURL, query ) );\n        req.setMethod( 'GET' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'application/json' );\n        req.setHeader( 'Accepts', 'application/json' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n\n        if ( batchSize != null ) {\n            req.setHeader( 'Sforce-Query-Options', 'batchSize=' + batchSize );\n        }\n\n        return req;\n    }\n\n    /**\n     * Creates an endpoint URL to execute a SOQL query against the REST API.\n     * Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param query\n     *      SOQL query to execute.\n     */\n    private static String getExecuteSoqlQueryHttpRequestEndpoint( String baseURL, String query ) {\n\n        String endpoint = String.format(\n            '{0}/query/?q={1}',\n            new String[] { baseURL, EncodingUtil.urlEncode( query, 'utf-8' ) }\n        );\n\n        return endpoint;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Executes a SOQL query via REST API via http callout.\n     * https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query.htm\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param nextRecordsId\n     *      The last path part in the 'nextRecordsUrl' property from a query response\n     *      that identifies the next page of records to return.\n     * @param batchSize\n     *      The preferred max number of records to return at a time.\n     *      Choose a value between 200 and 2,000.\n     *      If there are more records than requested, you'll need to use the nextRecordsUrl to retrieve them.\n     *      https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers_queryoptions.htm\n     */\n    public static MA_SoqlQueryExecuteResult executeSoqlQueryNextRecords( String baseURL, String nextRecordsId, Integer batchSize ) {\n\n        System.debug( 'MA_MassActionUtils.executeSoqlQueryNextRecords' );\n        System.debug( 'baseURL: ' + baseURL );\n        System.debug( 'nextRecordsId: ' + nextRecordsId );\n        System.debug( 'batchSize: ' + batchSize );\n\n        try {\n\n            HttpRequest req = buildExecuteSoqlQueryNextRecordsHttpRequest( baseURL, nextRecordsId, batchSize );\n            HttpResponse res = sendHttpRequest( req );\n\n            return parseSoqlQueryHttpResponse( res );\n\n        } catch ( MA_Exceptions.InvokeActionException e ) {\n\n            Exception throwable = e;\n\n            // extract the soql error message from \"[ { errorCode: xxx, message: yyy } ]\"\n            List<Object> errors = (List<Object>) JSON.deserializeUntyped( e.response.getBody() );\n            for ( Object item : errors ) {\n                Map<String, Object> err = (Map<String, Object>) item;\n                throwable = new MA_Exceptions.SOQLQueryException(\n                    e.request, e.response, nextRecordsId, (String) err.get( 'errorType' ), (String) err.get( 'message' ), e\n                );\n            }\n\n            throw throwable;\n\n        }\n    }\n\n    /**\n     * Creates an HttpRequest with a configured enpoint to execute a SOQL query\n     * against the REST API. Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param nextRecordsId\n     *      The last path part in the 'nextRecordsUrl' property from a query response\n     *      that identifies the next page of records to return.\n     * @param batchSize\n     *      The preferred max number of records to return at a time.\n     *      Choose a value between 200 and 2,000.\n     *      If there are more records than requested, you'll need to use the nextRecordsUrl to retrieve them.\n     *      https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers_queryoptions.htm\n     */\n    private static HttpRequest buildExecuteSoqlQueryNextRecordsHttpRequest( String baseURL, String nextRecordsId, Integer batchSize ) {\n\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint( getExecuteSoqlQueryNextRecordsHttpRequestEndpoint( baseURL, nextRecordsId ) );\n        req.setMethod( 'GET' );\n        req.setTimeout( 120000 ); // max wait of 2 mins\n        req.setCompressed( true );\n        req.setHeader( 'Content-Type', 'application/json' );\n        req.setHeader( 'Accepts', 'application/json' );\n        req.setHeader( 'Authorization', 'Bearer ' + UserInfo.getSessionId() );\n\n        if ( batchSize != null ) {\n            req.setHeader( 'Sforce-Query-Options', 'batchSize=' + batchSize );\n        }\n\n        return req;\n    }\n\n    /**\n     * Creates an endpoint URL to execute a SOQL query against the REST API.\n     * Also sets common headers for an authorized JSON request.\n     *\n     * @param baseURL\n     *      The 'baseURL' parameter can either be a Named Credential (e.g. 'callout:YourNC'),\n     *      or the org's My Domain URL without any path (e.g. 'https://yourdomain.my.salesforce.com').\n     * @param nextRecordsId\n     *      The last path part in the 'nextRecordsUrl' property from a query response\n     *      that identifies the next page of records to return.\n     */\n    private static String getExecuteSoqlQueryNextRecordsHttpRequestEndpoint( String baseURL, String nextRecordsId ) {\n\n        String endpoint = String.format(\n            '{0}/query/{1}',\n            new String[] { baseURL, EncodingUtil.urlEncode( nextRecordsId, 'utf-8' ) }\n        );\n\n        return endpoint;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * Sends the http request and returns the http response.\n     * Logs the request/response.\n     * Throws exception if status code is not 200 OK.\n     */\n    private static HttpResponse sendHttpRequest( HttpRequest req ) {\n\n        System.debug( req );\n        System.debug( req.getBody() );\n\n        HttpResponse res = new Http().send( req );\n\n        System.debug( res );\n        System.debug( res.getBody() );\n\n        for ( String header : res.getHeaderKeys() ) {\n            System.debug( header + '=' + res.getHeader( header ) );\n        }\n\n        if ( res.getStatusCode() != 200 ) {\n            throw new MA_Exceptions.InvokeActionException( req, res );\n        }\n\n        return res;\n    }\n\n    // ------------------------------------------------------------------------\n\n    /**\n     * JSON deserializes the response.\n     *\n     * Since Apex won't deserialize into a type that uses generic Object data type,\n     * then I'm manually casting the untyped deserialization result to my generic map type.\n     * This way, my Apex class that represents a SOQL query result can generically store\n     * a list of records as objects (not sobjects, because some results may be aggregate results).\n     *\n     * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_json_overview.htm\n     */\n    private static MA_SoqlQueryExecuteResult parseSoqlQueryHttpResponse( HttpResponse res ) {\n\n        Map<String, Object> responseMap = ( Map<String, Object> ) JSON.deserializeUntyped( res.getBody() );\n\n        MA_SoqlQueryExecuteResult result = new MA_SoqlQueryExecuteResult();\n        result.totalSize = (Integer) responseMap.get( 'totalSize' );\n        result.done = (Boolean) responseMap.get( 'done' );\n        result.nextRecordsUrl = (String) responseMap.get( 'nextRecordsUrl' );\n\n        for ( Object item : (List<Object>) responseMap.get( 'records' ) ) {\n            result.records.add( (Map<String, Object>) item );\n        }\n\n        return result;\n    }\n\n    /**\n     * JSON deserializes the response and converts the map of key-value pairs into a list of keys.\n     */\n    private static List<String> parseActionObjectsHttpResponse( HttpResponse res ) {\n\n        List<String> objectNames = new List<String>();\n\n        Map<String, Object> resMap = (Map<String, Object>) JSON.deserializeUntyped( res.getBody() );\n\n        if ( resMap != null ) {\n\n            for ( String objectName : resMap.keySet() ) {\n                objectNames.add( objectName );\n            }\n\n        }\n\n        return objectNames;\n    }\n\n    /**\n     * JSON deserializes the 'actions' property of the response.\n     */\n    private static List<Map<String, Object>> parseActionsHttpResponse( HttpResponse res ) {\n\n        List<Map<String, Object>> actions = new List<Map<String, Object>>();\n\n        Map<String, Object> resMap = (Map<String, Object>) JSON.deserializeUntyped( res.getBody() );\n\n        if ( resMap != null ) {\n\n            List<Object> actionRecords = (List<Object>) resMap.get( 'actions' );\n\n            if ( actionRecords != null ) {\n\n                for ( Object actionRecord : actionRecords ) {\n                    actions.add( (Map<String, Object>) actionRecord );\n                }\n\n            }\n\n        }\n\n        return actions;\n    }\n\n    /**\n     * JSON deserializes the 'inputs' property of the response.\n     */\n    private static List<Map<String, Object>> parseActionInputsHttpResponse( HttpResponse res ) {\n\n        List<Map<String, Object>> inputs = new List<Map<String, Object>>();\n\n        Map<String, Object> resMap = (Map<String, Object>) JSON.deserializeUntyped( res.getBody() );\n\n        if ( resMap != null ) {\n\n            List<Object> inputRecords = (List<Object>) resMap.get( 'inputs' );\n\n            if ( inputRecords != null ) {\n\n                for ( Object inputRecord : inputRecords ) {\n                    inputs.add( (Map<String, Object>) inputRecord );\n                }\n\n            }\n\n        }\n\n        return inputs;\n    }\n\n    /**\n     * XML deserializes the response.\n     * Assumes this is a succcessful response.\n     * A SOAP fault should have been checked prior to calling this method.\n     */\n    private static MA_AnonymousApexExecuteResult parseAnonymousApexHttpResponse( HttpResponse res ) {\n\n        // Parse the SOAP response\n        // https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/sforce_api_calls_executeanonymous_result.htm\n\n        DOM.Document responseDocument = res.getBodyDocument();\n        DOM.XMLNode root = responseDocument.getRootElement();\n\n        MA_AnonymousApexExecuteResult result = new MA_AnonymousApexExecuteResult();\n\n        result.column = Integer.valueOf( MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/column' ) );\n        result.line = Integer.valueOf( MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/line' ) );\n\n        result.compiled = Boolean.valueOf( MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/compiled' ) );\n        result.compileProblem = MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/compileProblem' );\n\n        result.exceptionMessage = MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/exceptionMessage' );\n        result.exceptionStackTrace = MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/exceptionStackTrace' );\n\n        result.success = Boolean.valueOf( MA_XMLUtils.getChildNodeTextByPath( root, 'Body/executeAnonymousResponse/result/success' ) );\n\n        System.debug( 'MA_MassActionUtils.parseAnonymousApexHttpResponse' );\n        System.debug( result );\n\n        return result;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MassActionUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MetadataDeployCallback.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * This class explicitly uses 'without sharing' because it is invoked by the package install handler\n * and it is documented that the use of 'with sharing' by apex classes called by the handler may prevent installation.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_install_handler.htm\n */\npublic without sharing class MA_MetadataDeployCallback implements Metadata.DeployCallback {\n\n    public void handleResult( Metadata.DeployResult result, Metadata.DeployCallbackContext context ) {\n\n        System.debug( 'MA_MetadataDeployCallback.handleResult: ' + context );\n        System.debug( JSON.serializePretty( result ) );\n\n        if ( !result.success ) {\n            throw new MA_Exceptions.MetadataDeployException( result );\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MetadataDeployCallback.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_MetadataDeployCallbackTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_MetadataDeployCallbackTest {\n\n    // https://trailhead.salesforce.com/content/learn/modules/apex_metadata_api/apex_metadata_api_testing\n\n    @IsTest\n    static void test_deploy_success() {\n\n        Metadata.DeployCallbackContext deployContext = new MockMetadataDeployCallbackContext();\n\n        Metadata.DeployResult deployResult = new Metadata.DeployResult();\n        deployResult.success = true;\n\n        Test.startTest();\n\n        Metadata.DeployCallback callback = new MA_MetadataDeployCallback();\n        callback.handleResult( deployResult, deployContext );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_deploy_fail() {\n\n        Metadata.DeployCallbackContext deployContext = new MockMetadataDeployCallbackContext();\n\n        Metadata.DeployResult deployResult = new Metadata.DeployResult();\n        deployResult.success = false;\n        deployResult.errorStatusCode = Metadata.StatusCode.INTERNAL_ERROR;\n        deployResult.errorMessage = 'the error message';\n\n        try {\n\n            Test.startTest();\n\n            Metadata.DeployCallback callback = new MA_MetadataDeployCallback();\n            callback.handleResult( deployResult, deployContext );\n\n            Test.stopTest();\n\n            System.assert( false, 'should have thrown exception' );\n\n        } catch ( MA_Exceptions.MetadataDeployException e ) {\n\n            System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );\n            System.assert( e.getMessage().containsIgnoreCase( String.valueOf( deployResult.errorStatusCode ) ) );\n            System.assert( e.getMessage().containsIgnoreCase( deployResult.errorMessage ) );\n\n        } catch ( Exception e ) {\n\n            System.debug( LoggingLevel.ERROR, e.getMessage() + ' : ' + e.getStackTraceString() );\n            System.assert( false, 'failed for wrong reason' );\n\n        }\n\n    }\n\n    private class MockMetadataDeployCallbackContext extends Metadata.DeployCallbackContext {\n        public override ID getCallbackJobId() {\n            return '0Af00000000000TEST';\n        }\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_MetadataDeployCallbackTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_NamespaceUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * This class explicitly uses 'without sharing' because it is invoked by the package install handler\n * and it is documented that the use of 'with sharing' by apex classes called by the handler may prevent installation.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_install_handler.htm\n */\npublic without sharing class MA_NamespaceUtils {\n\n    // -- private --\n\n    private static final String MY_NAMESPACE = [ SELECT NamespacePrefix FROM ApexClass WHERE Name = 'MA_MassActionUtils' LIMIT 1 ].NamespacePrefix;\n\n    // -- public --\n\n    public static final String NAMESPACE = String.isBlank( MY_NAMESPACE ) ? '' : MY_NAMESPACE;\n    public static final String NAMESPACE_API = String.isBlank( MY_NAMESPACE ) ? '' : MY_NAMESPACE + '__';\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_NamespaceUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportService.cls",
    "content": "/*\n    Copyright (c) 2015 Salesforce.org\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the Salesforce.com Foundation nor the names of\n      its contributors may be used to endorse or promote products derived\n      from this software without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n*/\n/**\n * @author Salesforce.org\n * @group CampaignTools\n * @description A service class that provides methods for interacting with\n * reports via the Analytics API.\n *\n * This class has been modified by Doug Ayers for the purposes of the Mass Action app.\n * Specifically, the ReportRowIdIterableIterator was renamed to ReportRowIterator and was\n * modified to return the full row of data and not just the ID.\n * The IteratorMonotonicIncreasingIdFilter sub-class was removed.\n *\n * https://github.com/SalesforceFoundation/CampaignTools/blob/master/src/classes/ReportService.cls\n */\npublic with sharing class MA_ReportService {\n    /**\n     * @description Retrieve the labels and ids of columns of type ID_TYPE from\n     * the given report.  Returns a Map<String, String> where the column id is\n     * the key and the label is the value.\n     *\n     * @param reportId The id of the report to find columns\n     * @return Map<String, String>\n     */\n    public Map<String, String> getIdColumns(Id reportId) {\n        Reports.ReportExtendedMetadata metadata = Reports.ReportManager.describeReport(reportId).getReportExtendedMetadata();\n        Map<String, Reports.DetailColumn> reportColumns = metadata.getDetailColumnInfo();\n\n        Map<String, String> idColumns = new Map<String, String>();\n\n        for (Reports.DetailColumn column : reportColumns.values()) {\n            if (Reports.ColumnDataType.ID_DATA == column.getDataType()) {\n                idColumns.put(\n                    column.getName(),\n                    column.getLabel()\n                );\n            }\n        }\n\n        return idColumns;\n    }\n\n    /**\n     * @description Runs a report and returns the results.  The given\n     * indexColumn is the name of a column that can be used for sorting the\n     * report for pagination, such that the values in this column can be used\n     * to filter the report to exclude previously processed results.  The given\n     * pageIndex value is an index into the report results corresponding to the\n     * last row processed, and is used to filter out results from the report\n     * run that have already been processed.  This is a technique to work\n     * around the limitation that only the first 2,000 rows of a report's\n     * results can be obtained through the Analytics API at a time.\n     *\n     * @param reportId The id of the report to run\n     * @param indexColumn The name of the column to use for \"indexing\" (i.e., sorting and filtering) the report\n     * @param pageIndex The value to use to determine where ReportResults processing last left off.  If null, the report is processed from the \"beginning\"\n     * @return Reports.ReportResults\n     */\n    @TestVisible\n    private static Reports.ReportResults getReportResults(Id reportId, String indexColumn, String pageIndex) {\n        Reports.ReportMetadata metadata = Reports.ReportManager.describeReport(reportId).getReportMetadata();\n\n        metadata.setReportFormat(Reports.ReportFormat.TABULAR);\n\n        Reports.SortColumn sortColumn = new Reports.SortColumn();\n        sortColumn.setSortColumn(indexColumn);\n        sortColumn.setSortOrder(Reports.ColumnSortOrder.ASCENDING);\n        metadata.setSortBy(new List<Reports.SortColumn>{sortColumn});\n\n        if (null != pageIndex) {\n            List<Reports.ReportFilter> reportFilters = metadata.getReportFilters();\n            reportFilters.add(new Reports.ReportFilter(\n                indexColumn,\n                'greaterThan',\n                pageIndex\n            ));\n            metadata.setReportFilters(reportFilters);\n\n            String booleanFilter = metadata.getReportBooleanFilter();\n            if (String.isNotBlank(booleanFilter)) {\n                metadata.setReportBooleanFilter('(' + booleanFilter + ') AND ' + reportFilters.size());\n            }\n        }\n\n        Reports.ReportResults results = Reports.ReportManager.runReport(\n            reportId,\n            metadata,\n            true\n        );\n\n        return results;\n    }\n\n    /**\n     * @author Salesforce.org\n     * @group CampaignTools\n     * @description A custom Iterator that can be used to iterate over the\n     * unique ids from a given column in a given report.  This class will\n     * iterate over every row in the given report.  To work around a limitation\n     * in the Analytics API that a report run will only return the first 2,000\n     * rows, the column being iterated over is expected to be a filterable and\n     * sortable column.  This requirement comes from the technique of\n     * paginating report results 2,000 records at a time by adding a sort to\n     * the report and then filtering the report to exclude records from\n     * previous \"pages\" of the report.  This will only return unique ids\n     * from the given column, meaning that if a value has already been returned\n     * by this iterator then that value will be skipped next time.\n     */\n    public inherited sharing class ReportRowIterator implements Iterable<Reports.ReportDetailRow>, Iterator<Reports.ReportDetailRow> {\n        /** @description The id of the report to iterate over */\n        @TestVisible\n        private Id reportId;\n\n        /**\n         * @description The name of the column in the report to return values\n         * from and use for indexing\n         */\n        @TestVisible\n        private String columnName;\n\n        /**\n         * @description The numerical index of the column in the report to return values\n         * from and use for indexing\n         */\n        private Integer columnIndex;\n\n        /**\n         * @description All the column names in the report in order of appearance.\n         */\n        private List<String> detailColumnNames;\n\n        /**\n         * @description The id of the last row processed.  This id is\n         * used to filter results to retrieve the next \"page\"\n         */\n        private Id lastRowId;\n\n        /**\n         * @description The data of the last row processed.\n         */\n        private Reports.ReportDetailRow lastRow;\n\n        /**\n         * @description True if the last report run is the last page of\n         * results.  False if there are more pages of data to be retrieved\n         */\n        private Boolean hasAllData;\n\n        /**\n         * @description The Iterator returned by List<Reports.ReportDetailRow>\n         * returned by the ReportResults object.  This keeps track of the\n         * current row being iterated over in the current page of results.\n         */\n        private Iterator<Reports.ReportDetailRow> currentPageRowIterator;\n\n        /**\n         * @description True if the report has been run at least once.  False,\n         * otherwise.\n         */\n        private Boolean hasRunReport = false;\n\n        /**\n         * @description Construct a ReportRowValueIterableIterator for\n         * iterating over the values from the given column name in the given\n         * report\n         *\n         * @param reportId The id of the report to iterate over\n         * @param columnName The name of the column to retrieve values from in the report\n         */\n        public ReportRowIterator(Id reportId, String columnName) {\n            this.reportId = reportId;\n            this.columnName = columnName;\n\n            /*\n            We call getReportResults() in the constructor because if there are\n            going to be any problems running the report this first time, we\n            want the error to hit sooner rather than later.  This early failure\n            is necessary in order to be able to catch the exception within the\n            start() method of the Batchable that consumes this class. If the\n            error only became apparent after calling hasNext() or next() after\n            returning this Iterable from the start() method, then we would not\n            be able to catch that error since those calls happen in a context\n            we do not have control over.\n            */\n\n            Reports.ReportResults results = MA_ReportService.getReportResults(reportId, columnName, null);\n\n            /*\n            Now that we know the report runs successfully, identify the column numerical index\n            among all the columns that the column name resides. We use this information to retrieve\n            this specific column value from each row to track the last row id for sorting and pagination.\n            */\n\n            Reports.ReportMetadata metadata = results.getReportMetadata();\n            List<String> detailColumns = metadata.getDetailColumns();\n            this.detailColumnNames = detailColumns;\n            for (Integer i = 0; i < detailColumns.size(); i++) {\n                if (detailColumns[i] == columnName) {\n                    this.columnIndex = i;\n                }\n            }\n        }\n\n        public Iterator<Reports.ReportDetailRow> iterator() {\n            return new MA_ReportService.ReportRowIterator( this.reportId, this.columnName );\n        }\n\n        /**\n         * @description The list of detail column names in the report.\n         *\n         * @return List\n         */\n        public List<String> getDetailColumnNames() {\n            return this.detailColumnNames.clone();\n        }\n\n        /**\n         * @description Implementation of hasNext() from Iterator interface.\n         * Returns true if there is another row in the report available.\n         *\n         * @return Boolean\n         */\n        public Boolean hasNext() {\n            if (!hasRunReport || (!currentPageRowIterator.hasNext() && !hasAllData)) {\n                runReport();\n            }\n            return currentPageRowIterator.hasNext();\n        }\n\n        /**\n         * @description Implementation of next() from Iterator interface.\n         * Returns the id from the specified column from the next available\n         * report result detail row.\n         *\n         * @return Reports.ReportDetailRow\n         */\n        public Reports.ReportDetailRow next() {\n            if (!hasNext()) {\n                return null;\n            }\n            Reports.ReportDetailRow row = currentPageRowIterator.next();\n            lastRow = row;\n\n            /*\n            Determine the value in the column being used for uniquely sorting\n            and paginating the results. This will be used the next time a 'page'\n            of report records is needed so that only records strictly after this value\n            will be retrieved.\n            */\n            lastRowId = (Id) row.getDataCells().get(this.columnIndex).getValue();\n\n            return lastRow;\n        }\n\n        /**\n         * @description Run the report to retrieve the next page (or the first\n         * page if the report hasn't been run yet), and prepare the class state\n         * for iterating over the new page's result rows.\n         *\n         * @return void\n         */\n        private void runReport() {\n            hasRunReport = true;\n            Reports.ReportResults results = MA_ReportService.getReportResults(\n                reportId,\n                columnName,\n                (String) lastRowId\n            );\n            hasAllData = results.getAllData();\n            Reports.ReportFactWithDetails facts = (Reports.ReportFactWithDetails) results.getFactMap().get('T!T');\n            currentPageRowIterator = facts.getRows().iterator();\n        }\n    }\n}"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportService.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportServiceTest.cls",
    "content": "/*\n    Copyright (c) 2015 Salesforce.org\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the Salesforce.com Foundation nor the names of\n      its contributors may be used to endorse or promote products derived\n      from this software without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n*/\n/**\n * @author Salesforce.org\n * @group CampaignTools\n * @description A service class that provides methods for interacting with\n * reports via the Analytics API.\n *\n * This class has been modified by Doug Ayers for the purposes of the Mass Action app.\n * Test methods have been modified or added and assert based on reports packaged with this app.\n *\n * https://github.com/SalesforceFoundation/CampaignTools/blob/master/src/classes/ReportService_TEST.cls\n */\n@IsTest\nprivate class MA_ReportServiceTest {\n\n    // the test report should filter for accounts whose name starts with this value\n    private static final String ACCOUNT_NAME_PREFIX = 'dca_mass_action: MA Test Account';\n\n    /**\n     * Can't annotate this method with @TestSetup because not allowed\n     * in test classes that use @IsTest( SeeAllData = true ).\n     * Therefore our test methods must call this method explicitly.\n     */\n    static void setup() {\n\n        // get rid of any data that might be in our test report's filters\n        String nameFilter = ACCOUNT_NAME_PREFIX + '%';\n        delete [ SELECT id FROM Account WHERE name LIKE :nameFilter ];\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void testGetIdColumnsReturnsIdColumns() {\n\n        setup();\n\n        Map<String, String> expectedColumns = new Map<String, String>{\n            'ACCOUNT_ID' => Schema.Account.Id.getDescribe().getLabel(),\n            'PARENT_ID'  => Schema.Account.ParentId.getDescribe().getLabel()\n        };\n\n        Report testReport = [\n            SELECT Id\n            FROM Report\n            WHERE DeveloperName = 'MA_Test_Account_Report'\n        ];\n\n        MA_ReportService service = new MA_ReportService();\n\n        Map<String, String> actualColumns = service.getIdColumns( testReport.Id );\n\n        System.assertEquals( expectedColumns, actualColumns );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void testReportIterable() {\n\n        setup();\n\n        Report testReport = [\n            SELECT Id\n            FROM Report\n            WHERE DeveloperName = 'MA_Test_Account_Report'\n        ];\n\n        Test.startTest();\n\n        Iterator<Reports.ReportDetailRow> reportRowIterator = new MA_ReportService.ReportRowIterator(\n            testReport.Id,\n            'ACCOUNT_ID'\n        ).iterator();\n\n        Test.stopTest();\n\n    }\n\n    /**\n     * Due to bug introduced after https://success.salesforce.com/issues_view?Id=a1p3A000000ATHC was fixed,\n     * the Reports.ReportManager.runReport method only sees records that exist in the org before the test runs.\n     * Therefore, we cannot assert that the report sees any data we insert/update/delete in the test itself.\n     */\n    @IsTest( SeeAllData = true )\n    static void testReportIterator() {\n\n        String nameFilter = ACCOUNT_NAME_PREFIX + '%';\n        Set<ID> expectedIds = new Map<ID, Account>([ SELECT Id FROM Account WHERE Name LIKE :nameFilter ]).keySet();\n\n        List<String> expectedColumnNames = new List<String>{ 'ACCOUNT_ID', 'PARENT_ID' };\n\n        Report testReport = [\n            SELECT Id\n            FROM Report\n            WHERE DeveloperName = 'MA_Test_Account_Report'\n        ];\n\n        Test.startTest();\n\n        MA_ReportService.ReportRowIterator reportRowIterator = new MA_ReportService.ReportRowIterator(\n            testReport.Id,\n            'ACCOUNT_ID'\n        );\n\n        Set<Id> actualIds = new Set<Id>();\n\n        while ( reportRowIterator.hasNext() ) {\n            actualIds.add( ( Id ) reportRowIterator.next().getDataCells().get( 0 ).getValue() );\n        }\n\n        Test.stopTest();\n\n        System.assertEquals( expectedIds, actualIds );\n        System.assertEquals( expectedColumnNames, reportRowIterator.getDetailColumnNames() );\n\n    }\n\n    /**\n     * Due to bug introduced after https://success.salesforce.com/issues_view?Id=a1p3A000000ATHC was fixed,\n     * the Reports.ReportManager.runReport method only sees records that exist in the org before the test runs.\n     * Therefore, we cannot assert that the report sees any data we insert/update/delete in the test itself.\n     */\n    /*\n    @IsTest( SeeAllData = true )\n    static void testReportIterator() {\n\n        setup();\n\n        Account acct = new Account(\n            name = ACCOUNT_NAME_PREFIX\n        );\n\n        insert acct;\n\n        Set<Id> expectedIds = new Set<Id>{ acct.id };\n        List<String> expectedColumnNames = new List<String>{ 'ACCOUNT_ID', 'PARENT_ID' };\n\n        Report testReport = [\n            SELECT Id\n            FROM Report\n            WHERE DeveloperName = 'MA_Test_Account_Report'\n        ];\n\n        Test.startTest();\n\n        MA_ReportService.ReportRowIterator reportRowIterator = new MA_ReportService.ReportRowIterator(\n            testReport.Id,\n            'ACCOUNT_ID'\n        );\n\n        Set<Id> actualIds = new Set<Id>();\n\n        while ( reportRowIterator.hasNext() ) {\n            actualIds.add( ( Id ) reportRowIterator.next().getDataCells().get( 0 ).getValue() );\n        }\n\n        Test.stopTest();\n\n        System.assertEquals( expectedIds, actualIds );\n        System.assertEquals( expectedColumnNames, reportRowIterator.getDetailColumnNames() );\n    }\n    */\n\n    /**\n     * Due to bug introduced after https://success.salesforce.com/issues_view?Id=a1p3A000000ATHC was fixed,\n     * the Reports.ReportManager.runReport method only sees records that exist in the org before the test runs.\n     * Therefore, we cannot assert that the report sees any data we insert/update/delete in the test itself.\n     */\n    @IsTest( SeeAllData = true )\n    static void testGetNextPageReportResults() {\n\n        String nameFilter = ACCOUNT_NAME_PREFIX + '%';\n        List<Account> accounts = [ SELECT Id FROM Account WHERE Name LIKE :nameFilter ORDER BY Id ASC ];\n        ID firstAccountId = accounts[0].Id;\n\n        // remove first account; when filter the report we expect all the other ids to be returned\n        accounts.remove( 0 );\n        Set<ID> expectedIds = new Map<ID, Account>( accounts ).keySet();\n\n        Report testReport = [\n            SELECT Id\n            FROM Report\n            WHERE DeveloperName = 'MA_Test_Account_Report'\n        ];\n\n        String columnName = 'ACCOUNT_ID';\n        String pageIndex = firstAccountId; // report should return all rows with Ids after this one\n\n        Test.startTest();\n\n        Reports.ReportResults results = MA_ReportService.getReportResults( testReport.id, columnName, pageIndex );\n        Reports.ReportFactWithDetails facts = ( Reports.ReportFactWithDetails ) results.getFactMap().get( 'T!T' );\n        Iterator<Reports.ReportDetailRow> reportRowIterator = facts.getRows().iterator();\n\n        Set<Id> actualIds = new Set<Id>();\n\n        while ( reportRowIterator.hasNext() ) {\n            actualIds.add( ( Id ) reportRowIterator.next().getDataCells().get( 0 ).getValue() );\n        }\n\n        Test.stopTest();\n\n        System.assertEquals( expectedIds, actualIds );\n\n    }\n\n    /**\n     * Due to bug introduced after https://success.salesforce.com/issues_view?Id=a1p3A000000ATHC was fixed,\n     * the Reports.ReportManager.runReport method only sees records that exist in the org before the test runs.\n     * Therefore, we cannot assert that the report sees any data we insert/update/delete in the test itself.\n     */\n    /*\n    @IsTest( SeeAllData = true )\n    static void testGetNextPageReportResults() {\n\n        setup();\n\n        Account acct1 = new Account(\n            name = ACCOUNT_NAME_PREFIX + '1'\n        );\n\n        Account acct2 = new Account(\n            name = ACCOUNT_NAME_PREFIX + '2'\n        );\n\n        insert new Account[] { acct1, acct2 };\n\n        Set<Id> expectedIds = new Set<Id>{ acct2.id };\n\n        Report testReport = [\n            SELECT Id\n            FROM Report\n            WHERE DeveloperName = 'MA_Test_Account_Report'\n        ];\n\n        String columnName = 'ACCOUNT_ID';\n        String pageIndex = acct1.id; // report should return all rows with Ids after this one\n\n        Test.startTest();\n\n        Reports.ReportResults results = MA_ReportService.getReportResults( testReport.id, columnName, pageIndex );\n        Reports.ReportFactWithDetails facts = ( Reports.ReportFactWithDetails ) results.getFactMap().get( 'T!T' );\n        Iterator<Reports.ReportDetailRow> reportRowIterator = facts.getRows().iterator();\n\n        Set<Id> actualIds = new Set<Id>();\n\n        while ( reportRowIterator.hasNext() ) {\n            actualIds.add( ( Id ) reportRowIterator.next().getDataCells().get( 0 ).getValue() );\n        }\n\n        Test.stopTest();\n\n        System.assertEquals( expectedIds, actualIds );\n\n    }\n    */\n\n}"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportServiceTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportSourceBatchable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_ReportSourceBatchable implements Database.Batchable<Reports.ReportDetailRow>,\n                                                              Database.Stateful,\n                                                              Database.AllowsCallouts,\n                                                              Database.RaisesPlatformEvents {\n\n    private ID configId { get; set; }\n\n    private Mass_Action_Configuration__c config { get; set; }\n\n    private Reports.ReportDescribeResult reportDescribe { get; set; }\n\n    public MA_ReportSourceBatchable( ID configId ) {\n        this.configId = configId;\n    }\n\n    // ------------------------------------------------------------------------\n\n    public Iterable<Reports.ReportDetailRow> start( Database.BatchableContext context ) {\n\n        System.debug( 'MA_ReportSourceBatchable.start: ' + context + ', configId=' + this.configId );\n\n        this.config = MA_MassActionUtils.getConfiguration( this.configId );\n\n        this.reportDescribe = Reports.ReportManager.describeReport( config.Source_Report_ID__c );\n\n        Iterable<Reports.ReportDetailRow> reportIterable = new MA_ReportService.ReportRowIterator( this.config.Source_Report_ID__c, this.config.Source_Report_Column_Name__c );\n\n        MA_MassActionBatchUtils.handleBatchJobStarted( this.configId, context.getJobId() );\n\n        return reportIterable;\n    }\n\n    public void execute( Database.BatchableContext context, List<Reports.ReportDetailRow> reportRows ) {\n\n        System.debug( 'MA_ReportSourceBatchable.execute: ' + context + ', configId=' + this.configId );\n\n        List<Map<String, Object>> sourceRowMaps = convertReportRowsToMaps( reportRows, this.reportDescribe );\n\n        MA_MassActionUtils.invokeTargetAction( this.config, sourceRowMaps );\n\n        MA_MassActionBatchUtils.handleBatchJobExecution( this.configId, context.getJobId(), reportRows.size(), JSON.serializePretty( sourceRowMaps ) );\n\n    }\n\n    public void finish( Database.BatchableContext context ) {\n\n        System.debug( 'MA_ReportSourceBatchable.finish: ' + context + ', configId=' + this.configId );\n\n        MA_MassActionBatchUtils.handleBatchJobFinished( this.configId, context.getJobId() );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    private List<Map<String, Object>> convertReportRowsToMaps( List<Reports.ReportDetailRow> rows, Reports.ReportDescribeResult reportDescribe ) {\n\n        List<Map<String, Object>> maps = new List<Map<String, Object>>();\n\n        for ( Reports.ReportDetailRow row : rows ) {\n            maps.add( convertReportRowToMap( row, reportDescribe ) );\n        }\n\n        return maps;\n    }\n\n    private Map<String, Object> convertReportRowToMap( Reports.ReportDetailRow rowData, Reports.ReportDescribeResult reportDescribe ) {\n\n        Map<String, Object> rowMap = new Map<String, Object>();\n\n        List<String> columnNames = reportDescribe.getReportMetadata().getDetailColumns();\n        Map<String,Reports.DetailColumn> detailColumnsMap = reportDescribe.getReportExtendedMetadata().getDetailColumnInfo();\n        List<Reports.ReportDataCell> dataCells = rowData.getDataCells();\n\n        for ( Integer i = 0; i < columnNames.size(); i++ ) {\n\n            String columnName = columnNames[i];\n            Reports.ReportDataCell dataCell = dataCells[i];\n            Reports.DetailColumn detailColumn = detailColumnsMap.get( columnName );\n\n            Object cellValue = extractCellValue( dataCell.getLabel(), dataCell.getValue(), detailColumn.getDataType() );\n\n            rowMap.put( columnName, cellValue );\n\n        }\n\n        return rowMap;\n    }\n\n    /**\n     * Returns the raw value from the cell based on the column data type\n     * and not simply the localized value displayed to the user.\n     *\n     * For example, consistently return a DateTime object and not\n     * \"January 3rd, 2019\" or \"03/01/2019\" as Strings depending on the user's locale.\n     *\n     * To aid in testability, this method accepts as arguments the simple properties of Reports.ReportDataCell\n     * because that object cannot be mocked or spoofed via JSON deserialization.\n     *\n     * @param cellLabel\n     *      The localized value the user sees in the report\n     * @param cellValue\n     *      The raw value, might be a compound type like Reports.ReportCurrency\n     * @param columnDataType\n     *      Enum of the different data types the column value could represent\n     *\n     * @return The value to use when binding to invocable action inputs,\n     *         which might be the `cellLabel`, `cellValue`, or a property off\n     *         the complex-type `cellValue` like currency amount without the symbol.\n     */\n    @TestVisible\n    private static Object extractCellValue( String cellLabel, Object cellValue, Reports.ColumnDataType columnDataType ) {\n\n        Object extractedValue = null;\n\n            switch on ( columnDataType ) {\n\n                when BOOLEAN_DATA {\n                    // important to grab the value and not the label\n                    // otherwise get the text literal \"true\"/false\n                    // instead of the boolean true/false\n                    // which led to https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/issues/64\n                    extractedValue = cellValue;\n                }\n\n                when DATE_DATA {\n                    // important to grab the value and not the label\n                    // because label will be formatted in running user's locale\n                    // and will fail to map to date inputs on target action\n                    extractedValue = cellValue;\n                }\n\n                when DATETIME_DATA {\n                    // important to grab the value and not the label\n                    // because label will be formatted in running user's locale\n                    // and will fail to map to date inputs on target action\n                    extractedValue = cellValue;\n                }\n\n                when CURRENCY_DATA {\n                    // grab the numerical amount instead\n                    // instead of the label which is text formatted with currency symbol\n                    // this allows the cell value to map to currency inputs on target action\n                    Reports.ReportCurrency currencyData = (Reports.ReportCurrency) cellValue;\n                    if ( currencyData != null ) {\n                        extractedValue = currencyData.getAmount();\n                    }\n                }\n\n                when INT_DATA {\n                    extractedValue = cellValue;\n                }\n\n                when DOUBLE_DATA {\n                    extractedValue = cellValue;\n                }\n\n                when PERCENT_DATA {\n                    extractedValue = cellValue;\n                }\n\n                when else {\n                    // otherwise, use the display label\n                    // this is important for Name field columns\n                    // so you get the record's name and not its id\n                    extractedValue = cellLabel;\n                }\n\n            }\n\n        return extractedValue;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportSourceBatchable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportSourceBatchableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_ReportSourceBatchableTest {\n\n    /**\n     * The Report object is read-only in Apex. It must be created via Metadata API.\n     * Therefore our tests rely on existing data being available to us, unfortunately.\n     * Also, when testing Reports API the test will run with SeeAllData = true, regardless the annotation we use.\n     * I include the annotation with SeeAllData property for clarity.\n     * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_analytics_test_reports.htm\n     */\n\n    /**\n     * Stubs out a simple configuration record with\n     * source properties defined. Test methods should set\n     * the target properties before calling `test_batchable` method.\n     */\n    private static Mass_Action_Configuration__c buildTestConfiguration() {\n\n        Report r = [ SELECT Id FROM Report WHERE DeveloperName = 'MA_Test_Account_Report' ];\n\n        return new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'Report',\n            Source_Report_ID__c = r.Id,\n            Source_Report_Column_Name__c = 'ACCOUNT_ID'\n        );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_Workflow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_Flow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Flow';\n        config.Target_Action_Name__c = 'Test_Flow';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_QuickAction() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'QuickAction';\n        config.Target_Action_Name__c = 'Test_Quick_Action';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_EmailAlert() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'EmailAlert';\n        config.Target_Action_Name__c = 'Test_Email_Alert';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_InvocableApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = 'Test_Apex';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_AnonymousApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = null;\n        config.Target_Apex_Script__c = 'void execute( List<Map<String, Object>> sourceRecordsBatch ) { System.debug( sourceRecordsBatch ); }';\n\n        test_batchable( config );\n\n    }\n\n    static void test_batchable( Mass_Action_Configuration__c config ) {\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'ACCOUNT_ID',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = Database.executeBatch( new MA_ReportSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n        Test.stopTest();\n\n        AsyncApexJob job = MA_MassActionBatchUtils.getJobById( jobId );\n\n        config = [\n            SELECT\n                Id,\n                Last_Run_Completed_Date__c,\n                Last_Run_Completed_With_Errors__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id = :config.Id\n        ];\n\n        System.debug( [ SELECT Id, Message__c FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( job.CompletedDate, config.Last_Run_Completed_Date__c );\n        System.assertEquals( false, config.Last_Run_Completed_With_Errors__c );\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_fail_bad_field_mapping() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_SObject_Type__c = 'Account';\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'NON_EXISTENT_FIELD',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ReportSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.NoSourceFieldException e ) {\n\n            System.assertEquals( configFieldMapping.Source_Field_Name__c, e.sourceFieldName );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_fail_no_report() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Source_Report_ID__c = null;\n        config.Target_Type__c = 'Workflow';\n        config.Target_SObject_Type__c = 'Account';\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ReportSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( NoDataFoundException e ) {\n\n            // because the batchable throws the error in the start method\n            // then we're getting a synchronous exception caught rather than\n            // the job's finish method logging the error asynchronously\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        }\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_fail_bad_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_FAIL'; // callout mock looks for this keyword\n\n        insert config;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ReportSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest( SeeAllData = true )\n    static void test_batchable_fail_soap_fault_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_SOAP_FAULT'; // callout mock looks for this keyword\n\n        insert config;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_ReportSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_extract_cell_value() {\n\n        Test.startTest();\n\n        System.assertEquals( true, MA_ReportSourceBatchable.extractCellValue( 'booleanCell', true, Reports.ColumnDataType.BOOLEAN_DATA ) );\n        System.assertEquals( false, MA_ReportSourceBatchable.extractCellValue( 'booleanCell', false, Reports.ColumnDataType.BOOLEAN_DATA ) );\n        System.assertEquals( 'booleanCell', MA_ReportSourceBatchable.extractCellValue( 'booleanCell', true, Reports.ColumnDataType.STRING_DATA ) );\n\n        System.assertEquals( Date.today(), MA_ReportSourceBatchable.extractCellValue( 'January 3rd, 2019', Date.today(), Reports.ColumnDataType.DATE_DATA ) );\n        System.assertEquals( 'January 3rd, 2019', MA_ReportSourceBatchable.extractCellValue( 'January 3rd, 2019', Date.today(), Reports.ColumnDataType.STRING_DATA ) );\n\n        System.assertEquals( DateTime.now(), MA_ReportSourceBatchable.extractCellValue( 'January 3rd, 2019 4:30 PM', DateTime.now(), Reports.ColumnDataType.DATETIME_DATA ) );\n        System.assertEquals( 'January 3rd, 2019 4:30 PM', MA_ReportSourceBatchable.extractCellValue( 'January 3rd, 2019 4:30 PM', DateTime.now(), Reports.ColumnDataType.STRING_DATA ) );\n\n        Reports.ReportCurrency currencyAmount = (Reports.ReportCurrency) JSON.deserialize( '{ \"currencyCode\" : \"$\", \"amount\" : 12.34 }', Reports.ReportCurrency.class );\n        System.assertEquals( (Decimal) 12.34, MA_ReportSourceBatchable.extractCellValue( '$12.34', currencyAmount, Reports.ColumnDataType.CURRENCY_DATA ) );\n        System.assertEquals( '$12.34', MA_ReportSourceBatchable.extractCellValue( '$12.34', currencyAmount, Reports.ColumnDataType.STRING_DATA ) );\n\n        System.assertEquals( (Integer) 12, MA_ReportSourceBatchable.extractCellValue( '12', 12, Reports.ColumnDataType.INT_DATA ) );\n        System.assertEquals( '12', MA_ReportSourceBatchable.extractCellValue( '12', 12, Reports.ColumnDataType.STRING_DATA ) );\n\n        System.assertEquals( (Double) 12.34, MA_ReportSourceBatchable.extractCellValue( '12.34', 12.34, Reports.ColumnDataType.DOUBLE_DATA ) );\n        System.assertEquals( '12.34', MA_ReportSourceBatchable.extractCellValue( '12.34', 12.34, Reports.ColumnDataType.STRING_DATA ) );\n\n        System.assertEquals( (Double) 0.25, MA_ReportSourceBatchable.extractCellValue( '25%', 0.25, Reports.ColumnDataType.PERCENT_DATA ) );\n        System.assertEquals( '25%', MA_ReportSourceBatchable.extractCellValue( '25%', 0.25, Reports.ColumnDataType.STRING_DATA ) );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_ReportSourceBatchableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigCmpController.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_RunConfigCmpController {\n\n    @AuraEnabled\n    public static Map<String, Object> enqueueAction( ID configId ) {\n\n        Map<String, Object> result = new Map<String, Object>();\n\n        try {\n\n            ID jobId = MA_MassActionBatchUtils.enqueueAction( configId );\n\n            // We don't have lookup fields to AsyncApexJob records,\n            // so standardizing on the 15 character id, least common denominator.\n            // The Apex Jobs page in Setup also only displays the 15 character id.\n            // So giving the user a value that they can immediately copy/paste\n            // to find a job record in Setup or on the Mass Action Log records.\n\n            result.put( 'success', true );\n            result.put( 'jobId', String.valueOf( jobId ).left( 15 ) );\n\n        } catch ( Exception e ) {\n\n            result.put( 'success', false );\n            result.put( 'message', e.getMessage() );\n\n        }\n\n        return result;\n    }\n\n    @AuraEnabled\n    public static MA_MassActionConfigWrapper getConfiguration( ID recordId ) {\n\n        // return json without org's namespace so our code doesn't have to worry about it\n        return new MA_MassActionConfigWrapper( MA_MassActionUtils.getConfiguration( recordId ) );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigCmpController.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigCmpControllerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_RunConfigCmpControllerTest {\n\n    @IsTest\n    static void test_enqueueAction_success() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        Map<String, Object> result = MA_RunConfigCmpController.enqueueAction( config.Id );\n\n        System.assertEquals( true, result.get( 'success' ) );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_enqueueAction_error() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = null, // invalid source type\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Workflow',\n            Target_SObject_Type__c = 'Account'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        Map<String, Object> result = MA_RunConfigCmpController.enqueueAction( config.Id );\n\n        System.assertEquals( false, result.get( 'success' ) );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_getConfiguration() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = '00Bf40000017w5h',\n            Target_Type__c = 'Flow',\n            Target_Action_Name__c = 'Test_Flow',\n            Schedule_Frequency__c = 'Custom',\n            Schedule_Cron__c = '0 0 1 * * ?'\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c fieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'SourceField',\n            Target_Field_Name__c = 'TargetField'\n        );\n\n        insert fieldMapping;\n\n        Test.startTest();\n\n        MA_MassActionConfigWrapper wrapper = MA_RunConfigCmpController.getConfiguration( config.Id );\n\n        System.assertEquals( config.Id, wrapper.recordId );\n        System.assertEquals( config.Name, wrapper.name );\n        System.assertEquals( config.DeveloperName__c, wrapper.developerName );\n        System.assertEquals( config.Description__c, wrapper.description );\n        System.assertEquals( config.Active__c, wrapper.active );\n        System.assertEquals( config.Batch_Size__c, wrapper.batchSize );\n        System.assertEquals( config.Named_Credential__c, wrapper.namedCredential );\n        System.assertEquals( config.Source_Type__c, wrapper.sourceType );\n        System.assertEquals( config.Source_List_View_ID__c, wrapper.sourceListViewID );\n        System.assertEquals( config.Source_Report_ID__c, wrapper.sourceReportID );\n        System.assertEquals( config.Source_Report_Column_Name__c, wrapper.sourceReportColumnName );\n        System.assertEquals( config.Target_Type__c, wrapper.targetType );\n        System.assertEquals( config.Target_SObject_Type__c, wrapper.targetSobjectType );\n        System.assertEquals( config.Target_Action_Name__c, wrapper.targetActionName );\n        System.assertEquals( config.Schedule_Frequency__c, wrapper.scheduleFrequency );\n        System.assertEquals( config.Schedule_Cron__c, wrapper.scheduleCron );\n        System.assertEquals( config.Schedule_SecondOfMinute__c, wrapper.scheduleSecondOfMinute );\n        System.assertEquals( config.Schedule_MinuteOfHour__c, wrapper.scheduleMinuteOfHour );\n        System.assertEquals( config.Schedule_HourOfDay__c, wrapper.scheduleHourOfDay );\n        System.assertEquals( config.Schedule_DayOfMonth__c, wrapper.scheduleDayOfMonth );\n        System.assertEquals( config.Schedule_MonthOfYear__c, wrapper.scheduleMonthOfYear );\n        System.assertEquals( config.Schedule_DayOfWeek__c, wrapper.scheduleDayOfWeek );\n\n        System.assertEquals( 1, wrapper.fieldMappings.size() );\n        System.assertEquals( fieldMapping.Source_Field_Name__c, wrapper.fieldMappings[0].sourceFieldName );\n        System.assertEquals( fieldMapping.Target_Field_Name__c, wrapper.fieldMappings[0].targetFieldName );\n\n        Mass_Action_Configuration__c config2 = wrapper.toConfiguration();\n\n        System.assertEquals( config.Id, config2.Id );\n        System.assertEquals( config.Name, config2.Name );\n        System.assertEquals( config.DeveloperName__c, config2.DeveloperName__c );\n        System.assertEquals( config.Description__c, config2.Description__c );\n        System.assertEquals( config.Active__c, config2.Active__c );\n        System.assertEquals( config.Batch_Size__c, config2.Batch_Size__c );\n        System.assertEquals( config.Named_Credential__c, config2.Named_Credential__c );\n        System.assertEquals( config.Source_Type__c, config2.Source_Type__c );\n        System.assertEquals( config.Source_List_View_ID__c, config2.Source_List_View_ID__c );\n        System.assertEquals( config.Source_Report_ID__c, config2.Source_Report_ID__c );\n        System.assertEquals( config.Source_Report_Column_Name__c, config2.Source_Report_Column_Name__c );\n        System.assertEquals( config.Target_Type__c, config2.Target_Type__c );\n        System.assertEquals( config.Target_SObject_Type__c, config2.Target_SObject_Type__c );\n        System.assertEquals( config.Target_Action_Name__c, config2.Target_Action_Name__c );\n        System.assertEquals( config.Schedule_Frequency__c, config2.Schedule_Frequency__c );\n        System.assertEquals( config.Schedule_Cron__c, config2.Schedule_Cron__c );\n        System.assertEquals( config.Schedule_SecondOfMinute__c, config2.Schedule_SecondOfMinute__c );\n        System.assertEquals( config.Schedule_MinuteOfHour__c, config2.Schedule_MinuteOfHour__c );\n        System.assertEquals( config.Schedule_HourOfDay__c, config2.Schedule_HourOfDay__c );\n        System.assertEquals( config.Schedule_DayOfMonth__c, config2.Schedule_DayOfMonth__c );\n        System.assertEquals( config.Schedule_MonthOfYear__c, config2.Schedule_MonthOfYear__c );\n        System.assertEquals( config.Schedule_DayOfWeek__c, config2.Schedule_DayOfWeek__c );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigCmpControllerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigInvocable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\nglobal with sharing class MA_RunConfigInvocable {\n\n    @InvocableMethod(\n        label = 'MAS: Run Mass Action'\n        description = 'Submits background job to run a Mass Action Configuration.'\n    )\n    global static List<Response> execute( List<Request> requests ) {\n\n        List<Response> responses = new List<Response>();\n\n        Map<ID, Mass_Action_Configuration__c> configsByIdMap = getConfigurationsByIdMap( requests );\n        Map<String, Mass_Action_Configuration__c> configsByUniqueNameMap = getConfigurationsByUniqueNameMap( requests );\n\n        for ( Request req : requests ) {\n\n            System.debug( req );\n\n            Mass_Action_Configuration__c config = null;\n\n            // lookup config by id\n            if ( config == null && String.isNotBlank( req.configId ) ) {\n                config = configsByIdMap.get( req.configId );\n            }\n\n            // lookup config by unique name\n            if ( config == null && String.isNotBlank( req.configUniqueName ) ) {\n                config = configsByUniqueNameMap.get( req.configUniqueName );\n            }\n\n            if ( config == null ) {\n                throw MA_Exceptions.buildException( NoDataFoundException.class, 'No Mass Action Configuration record found for request: ' + req );\n            }\n\n            Response res = new Response();\n            res.jobId = MA_MassActionBatchUtils.enqueueAction( config.Id );\n            responses.add( res );\n\n            System.debug( res );\n\n        }\n\n        return responses;\n    }\n\n    // ------------------------------------------------------------\n\n    private static Map<ID, Mass_Action_Configuration__c> getConfigurationsByIdMap( List<Request> requests ) {\n\n        Set<String> configIds = new Set<String>();\n        for ( Request req : requests ) {\n            if ( String.isNotBlank( req.configId ) ) {\n                configIds.add( req.configId );\n            }\n        }\n\n        Map<ID, Mass_Action_Configuration__c> configMap = new Map<ID, Mass_Action_Configuration__c>([\n            SELECT Id, DeveloperName__c FROM Mass_Action_Configuration__c WHERE Id IN :configIds\n        ]);\n\n        return configMap;\n    }\n\n    private static Map<String, Mass_Action_Configuration__c> getConfigurationsByUniqueNameMap( List<Request> requests ) {\n\n        Set<String> uniqueNames = new Set<String>();\n        for ( Request req : requests ) {\n            if ( String.isNotBlank( req.configUniqueName ) ) {\n                uniqueNames.add( req.configUniqueName );\n            }\n        }\n\n        Map<String, Mass_Action_Configuration__c> configMap = new Map<String, Mass_Action_Configuration__c>();\n        for ( Mass_Action_Configuration__c config : [ SELECT Id, DeveloperName__c FROM Mass_Action_Configuration__c WHERE DeveloperName__c IN :uniqueNames ] ) {\n            configMap.put( config.DeveloperName__c, config );\n        }\n\n        return configMap;\n    }\n\n    // ------------------------------------------------------------\n\n    global inherited sharing class Request {\n\n        @InvocableVariable(\n            label = 'Configuration Unique Name'\n            description = 'The unique name of the Mass Action Configuration to run. Specify this or the ID.'\n            required = false\n        )\n        global String configUniqueName;\n\n        @InvocableVariable(\n            label = 'Configuration ID'\n            description = 'The Salesforce record ID of the Mass Action Configuration to run. Specify this or the Unique Name.'\n            required = false\n        )\n        global ID configId;\n\n    }\n\n    global inherited sharing class Response {\n\n        @InvocableVariable(\n            label = 'Job ID'\n            description = 'The ID of the background apex job processing the Mass Action request.'\n        )\n        global ID jobId;\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigInvocable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigInvocableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_RunConfigInvocableTest {\n\n    @TestSetup\n    static void setup() {\n\n        String objectName = MA_NamespaceUtils.NAMESPACE_API + 'Mass_Action_Configuration__c';\n        ListView lv = [ SELECT Id, Name, DeveloperName, SobjectType FROM ListView WHERE DeveloperName = 'All' AND SobjectType = :objectName AND IsSoqlCompatible = true LIMIT 1 ];\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'ListView',\n            Source_List_View_ID__c = lv.Id,\n            Target_Type__c = 'Apex',\n            Target_Action_Name__c = 'Test_Apex',\n            Target_SObject_Type__c = null\n        );\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n    }\n\n    @IsTest\n    static void test_invocable_by_id() {\n\n        Mass_Action_Configuration__c config = [ SELECT Id FROM Mass_Action_Configuration__c WHERE DeveloperName__c = 'Test_Config' LIMIT 1 ];\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        MA_RunConfigInvocable.Request req = new MA_RunConfigInvocable.Request();\n        req.configId = config.Id;\n\n        List<MA_RunConfigInvocable.Response> responses = MA_RunConfigInvocable.execute( new List<MA_RunConfigInvocable.Request>{ req } );\n\n        System.assertEquals( 1, responses.size() );\n        System.assertEquals( 1, [ SELECT COUNT() FROM AsyncApexJob WHERE Id = :responses[0].jobId ] );\n\n    }\n\n    @IsTest\n    static void test_invocable_by_unique_name() {\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        MA_RunConfigInvocable.Request req = new MA_RunConfigInvocable.Request();\n        req.configUniqueName = 'Test_Config';\n\n        List<MA_RunConfigInvocable.Response> responses = MA_RunConfigInvocable.execute( new List<MA_RunConfigInvocable.Request>{ req } );\n\n        System.assertEquals( 1, responses.size() );\n        System.assertEquals( 1, [ SELECT COUNT() FROM AsyncApexJob WHERE Id = :responses[0].jobId ] );\n\n    }\n\n    @IsTest\n    static void test_invocable_no_data_found() {\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        try {\n\n            MA_RunConfigInvocable.execute( new List<MA_RunConfigInvocable.Request>{ new MA_RunConfigInvocable.Request() } );\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( Exception e ) {\n\n            System.assert( e instanceof System.NoDataFoundException, 'expected NoDataFoundException but got ' + e );\n\n        }\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_RunConfigInvocableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SetConfigUniqueNameBatchable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * Designed for the upgrade to release 1.6 that introduces the Mass_Action_Configuration__c.DeveloperName__c field.\n * Batches over all config records with a blank developer name field and populates one for it based on its name.\n * Automatically retries updating the config record by appending a random suffix to the developer name until generates a unique value.\n *\n * This class explicitly uses 'without sharing' because it is invoked by the package install handler\n * and it is documented that the use of 'with sharing' by apex classes called by the handler may prevent installation.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_install_handler.htm\n */\npublic without sharing class MA_SetConfigUniqueNameBatchable implements Database.Batchable<SObject>,\n                                                                        Database.Stateful,\n                                                                        Database.AllowsCallouts,\n                                                                        Database.RaisesPlatformEvents {\n\n    public Database.QueryLocator start( Database.BatchableContext context ) {\n\n        System.debug( 'MA_SetConfigUniqueNameBatchable.start: ' + context );\n\n        return Database.getQueryLocator([\n            SELECT\n                Id, Name, DeveloperName__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                DeveloperName__c = null\n        ]);\n    }\n\n    public void execute( Database.BatchableContext context, List<Mass_Action_Configuration__c> records ) {\n\n        System.debug( 'MA_SetConfigUniqueNameBatchable.execute: ' + context );\n\n        Boolean hasDuplicateDeveloperNameErrors = false;\n\n        List<Mass_Action_Configuration__c> recordsToUpdate = new List<Mass_Action_Configuration__c>( records );\n\n        for ( Mass_Action_Configuration__c record : recordsToUpdate ) {\n            record.DeveloperName__c = formatNameAsUniqueName( record.Name, false );\n        }\n\n        do {\n\n            List<Database.SaveResult> saveResults = Database.update( recordsToUpdate, false );\n            List<Mass_Action_Configuration__c> recordsToRetry = new List<Mass_Action_Configuration__c>();\n\n            for ( Integer i = 0; i < saveResults.size(); i++ ) {\n\n                Database.SaveResult saveResult = saveResults[i];\n                Mass_Action_Configuration__c record = recordsToUpdate[i];\n\n                if ( !saveResult.isSuccess() ) {\n\n                    Boolean isDuplicateDeveloperNameError = false;\n\n                    System.debug( 'MA_SetConfigUniqueNameBatchable.execute: record failed to update: ' + record );\n\n                    for ( Database.Error err : saveResult.getErrors() ) {\n\n                        System.debug( 'MA_SetConfigUniqueNameBatchable.execute: ' + err );\n\n                        // Bug W-4635920: duplicate value errors are not populating which field in Error.getFields() nor Error.getMessage()\n                        Boolean isDeveloperNameField = true; // assume so until Salesforce fixes the bug\n                        Boolean isDuplicateValue = ( err.getStatusCode() == StatusCode.DUPLICATE_VALUE );\n\n                        isDuplicateDeveloperNameError = ( isDeveloperNameField && isDuplicateValue );\n\n                    }\n\n                    if ( isDuplicateDeveloperNameError ) {\n\n                        // try to make name \"more\" unique with random suffix\n                        record.DeveloperName__c = formatNameAsUniqueName( record.Name, true );\n                        System.debug( 'MA_SetConfigUniqueNameBatchable.execute: duplicate developer name, trying a random value: ' + record );\n\n                        recordsToRetry.add( record );\n\n                        hasDuplicateDeveloperNameErrors = true;\n\n                    }\n\n                    System.debug( 'MA_SetConfigUniqueNameBatchable.execute: isDuplicateDeveloperNameError=' + isDuplicateDeveloperNameError );\n\n                }\n\n            }\n\n            recordsToUpdate = recordsToRetry;\n\n        } while ( hasDuplicateDeveloperNameErrors && recordsToUpdate.size() > 0 );\n\n    }\n\n    public void finish( Database.BatchableContext context ) {\n\n        System.debug( 'MA_SetConfigUniqueNameBatchable.finish: ' + context );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    private String formatNameAsUniqueName( String name, Boolean useRandomSuffix ) {\n\n        String uniqueName = name;\n\n        if ( uniqueName != null ) {\n\n            // trim whitespace\n            uniqueName = uniqueName.trim();\n\n            // replace whitespace with underscore\n            uniqueName = uniqueName.replaceAll( '[ ]+', '_' );\n\n            if ( useRandomSuffix ) {\n\n                String randomSuffix = '_' + MA_StringUtils.getRandomLetters( 4 );\n\n                // ensure room for random suffix\n                uniqueName = uniqueName.left( Mass_Action_Configuration__c.DeveloperName__c.getDescribe().getLength() - randomSuffix.length() );\n\n                // append random suffix\n                uniqueName += randomSuffix;\n\n            }\n\n        }\n\n        return uniqueName;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SetConfigUniqueNameBatchable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SetConfigUniqueNameBatchableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_SetConfigUniqueNameBatchableTest {\n\n    @IsTest\n    private static void test_batch() {\n\n        Mass_Action_Configuration__c c1 = new Mass_Action_Configuration__c(\n            Name = ' Foo Bar '\n        );\n\n        Mass_Action_Configuration__c c2 = new Mass_Action_Configuration__c(\n            Name = 'x'.repeat( Mass_Action_Configuration__c.Name.getDescribe().getLength() )\n        );\n\n        Mass_Action_Configuration__c c3 = new Mass_Action_Configuration__c(\n            Name = 'duplicate'\n        );\n\n        Mass_Action_Configuration__c c4 = new Mass_Action_Configuration__c(\n            Name = 'duplicate'\n        );\n\n        List<Mass_Action_Configuration__c> records = new List<Mass_Action_Configuration__c>{\n            c1, c2, c3, c4\n        };\n\n        insert records;\n\n        System.assertEquals( 4, [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c = null ] );\n\n        Test.startTest();\n\n        Database.executeBatch( new MA_SetConfigUniqueNameBatchable() );\n\n        Test.stopTest();\n\n        System.debug( 'batch updated records:' );\n        for ( Mass_Action_Configuration__c record : [ SELECT Id, Name, DeveloperName__c FROM Mass_Action_Configuration__c ] ) {\n            System.debug( record );\n        }\n\n        System.assertEquals( 4, [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c != null ] );\n        System.assertEquals( 'Foo_Bar', [ SELECT DeveloperName__c FROM Mass_Action_Configuration__c WHERE Id = :c1.Id ].DeveloperName__c );\n        System.assertEquals( c2.Name, [ SELECT DeveloperName__c FROM Mass_Action_Configuration__c WHERE Id = :c2.Id ].DeveloperName__c );\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c = 'duplicate' ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c LIKE 'duplicate_%' ] );\n\n    }\n\n    @IsTest\n    static void test_batch_200() {\n\n        List<Mass_Action_Configuration__c> records = new List<Mass_Action_Configuration__c>();\n\n        for ( Integer i = 0; i < 200; i++ ) {\n            records.add( new Mass_Action_Configuration__c(\n                Name = 'duplicate'\n            ));\n        }\n\n        insert records;\n\n        System.assertEquals( records.size(), [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE Name = 'duplicate' ] );\n        System.assertEquals( records.size(), [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c = null ] );\n\n        Test.startTest();\n\n        // should generate new unique names for 199 of the 200 records\n        Database.executeBatch( new MA_SetConfigUniqueNameBatchable() );\n\n        Test.stopTest();\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c = 'duplicate' ] );\n        System.assertEquals( records.size() - 1, [ SELECT COUNT() FROM Mass_Action_Configuration__c WHERE DeveloperName__c LIKE 'duplicate_%' ] );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SetConfigUniqueNameBatchableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SetupAuthWizardPageController.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_SetupAuthWizardPageController {\n\n    public final String orgDomainURL {\n        get {\n            return URL.getOrgDomainUrl().toExternalForm();\n        }\n    }\n\n    public final String myDomain {\n        get { return this.orgDomainURL.substringBetween( 'https://', '.my.salesforce.com' ); }\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SetupAuthWizardPageController.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SetupAuthWizardPageControllerTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_SetupAuthWizardPageControllerTest {\n\n    @IsTest\n    static void test_controller() {\n\n        Test.setCurrentPage( Page.MA_SetupAuthWizardPage );\n\n        Test.startTest();\n\n        MA_SetupAuthWizardPageController controller = new MA_SetupAuthWizardPageController();\n\n        System.assertEquals( URL.getOrgDomainUrl().toExternalForm(), controller.orgDomainURL );\n        System.assertEquals( URL.getOrgDomainUrl().toExternalForm().substringBetween( 'https://', '.my.salesforce.com' ), controller.myDomain );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SetupAuthWizardPageControllerTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlQueryExecuteResult.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/*\n * Represents some parts of a JSON response from SOQL Query REST API.\n * \"/services/data/<version>/query/?q=<soql>\"\n */\npublic inherited sharing class MA_SoqlQueryExecuteResult {\n\n    public Integer totalSize { get; set; }\n\n    public Boolean done { get; set; }\n\n    public String nextRecordsUrl { get; set; }\n\n    public List<Map<String, Object>> records { get; set; }\n\n    public MA_SoqlQueryExecuteResult() {\n        this.totalSize = 0;\n        this.done = false;\n        this.nextRecordsUrl = null;\n        this.records = new List<Map<String, Object>>();\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlQueryExecuteResult.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlQueryExecuteResultTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_SoqlQueryExecuteResultTest {\n\n    @IsTest\n    static void test_object() {\n\n        Test.startTest();\n\n        MA_SoqlQueryExecuteResult result = new MA_SoqlQueryExecuteResult();\n        result.totalSize = 1;\n        result.done = true;\n        result.nextRecordsUrl = 'https://nextRecordsUrl';\n        result.records = new List<Map<String, Object>>{\n            new Map<String, Object>{\n                'attributes' => new Map<String, Object>{\n                    'type' => 'Account'\n                },\n                'Name' => 'Test Account'\n            }\n        };\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlQueryExecuteResultTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceBatchable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_SoqlSourceBatchable implements Database.Batchable<SObject>,\n                                                            Database.Stateful,\n                                                            Database.AllowsCallouts,\n                                                            Database.RaisesPlatformEvents {\n\n    private ID configId { get; set; }\n\n    private Mass_Action_Configuration__c config { get; set; }\n\n    public MA_SoqlSourceBatchable( ID configId ) {\n        this.configId = configId;\n    }\n\n    // ------------------------------------------------------------------------\n\n    public Database.QueryLocator start( Database.BatchableContext context ) {\n\n        System.debug( 'MA_SoqlSourceBatchable.start: ' + context + ', configId=' + this.configId );\n\n        this.config = MA_MassActionUtils.getConfiguration( this.configId );\n\n        Database.QueryLocator queryLocator = Database.getQueryLocator( this.config.Source_SOQL_Query__c );\n\n        MA_MassActionBatchUtils.handleBatchJobStarted( this.configId, context.getJobId() );\n\n        return queryLocator;\n    }\n\n    public void execute( Database.BatchableContext context, List<SObject> records ) {\n\n        System.debug( 'MA_SoqlSourceBatchable.execute: ' + context + ', configId=' + this.configId );\n\n        List<Map<String, Object>> sourceRowMaps = convertRecordsToMaps( records );\n\n        MA_MassActionUtils.invokeTargetAction( this.config, sourceRowMaps );\n\n        MA_MassActionBatchUtils.handleBatchJobExecution( this.configId, context.getJobId(), records.size(), JSON.serializePretty( records ) );\n\n    }\n\n    public void finish( Database.BatchableContext context ) {\n\n        System.debug( 'MA_SoqlSourceBatchable.finish: ' + context + ', configId=' + this.configId );\n\n        MA_MassActionBatchUtils.handleBatchJobFinished( this.configId, context.getJobId() );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    private List<Map<String, Object>> convertRecordsToMaps( List<SObject> records ) {\n\n        List<Map<String, Object>> maps = new List<Map<String, Object>>();\n\n        Map<String, SObjectField> fieldsMap = records.getSObjectType().getDescribe().fields.getMap();\n\n        for ( SObject record : records ) {\n            maps.add( convertRecordToMap( record, fieldsMap ) );\n        }\n\n        return maps;\n    }\n\n    private Map<String, Object> convertRecordToMap( SObject record, Map<String, SObjectField> fieldsMap ) {\n\n        Map<String, Object> recordMap = new Map<String, Object>();\n\n        for ( String fieldName : fieldsMap.keySet() ) {\n            // As of Winter '19, Apex does not provide a way to\n            // inspect a SOQL query to know which fields were queried.\n            // We can get a map of populated field values, but that map only\n            // has entries for fields from the query that were non-null.\n            // If the configuration record's field mappings reference a field\n            // whose value is null in the query result, the map we return\n            // would be lacking that map key and our validation would throw an\n            // exception. Therefore, as a workaround, we iterate all the fields\n            // from the sobject describe and attempt to grab the value from the queried record.\n            DescribeFieldResult fieldDesc = fieldsMap.get( fieldName ).getDescribe();\n            recordMap.put( fieldDesc.getName(), null );\n        }\n\n        recordMap.putAll( MA_MapUtils.visitFieldPaths( record ) );\n\n        return recordMap;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceBatchable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceBatchableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_SoqlSourceBatchableTest {\n\n    /**\n     * Stubs out a simple configuration record with\n     * source properties defined. Test methods should set\n     * the target properties before calling `test_batchable` method.\n     */\n    private static Mass_Action_Configuration__c buildTestConfiguration() {\n\n        return new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Active__c = true,\n            Batch_Size__c = 200,\n            Source_Type__c = 'SOQL',\n            Source_SOQL_Query__c = 'SELECT Id, Name FROM Account LIMIT 10'\n        );\n\n    }\n\n    @IsTest\n    static void test_batchable_Workflow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_Flow() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Flow';\n        config.Target_Action_Name__c = 'Test_Flow';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_QuickAction() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'QuickAction';\n        config.Target_Action_Name__c = 'Test_Quick_Action';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_EmailAlert() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'EmailAlert';\n        config.Target_Action_Name__c = 'Test_Email_Alert';\n        config.Target_SObject_Type__c = 'Account';\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_InvocableApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = 'Test_Apex';\n        config.Target_SObject_Type__c = null;\n\n        test_batchable( config );\n\n    }\n\n    @IsTest\n    static void test_batchable_AnonymousApex() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Action_Name__c = null;\n        config.Target_SObject_Type__c = null;\n        config.Target_Apex_Script__c = 'void execute( List<Map<String, Object>> sourceRecordsBatch ) { System.debug( sourceRecordsBatch ); }';\n\n        test_batchable( config );\n\n    }\n\n    static void test_batchable( Mass_Action_Configuration__c config ) {\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'Id',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        ID jobId = Database.executeBatch( new MA_SoqlSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n        Test.stopTest();\n\n        AsyncApexJob job = MA_MassActionBatchUtils.getJobById( jobId );\n\n        config = [\n            SELECT\n                Id,\n                Last_Run_Completed_Date__c,\n                Last_Run_Completed_With_Errors__c\n            FROM\n                Mass_Action_Configuration__c\n            WHERE\n                Id = :config.Id\n        ];\n\n        System.debug( [ SELECT Id, Message__c FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Mass_Action_Configuration__c = :config.Id ] );\n        System.assertEquals( job.CompletedDate, config.Last_Run_Completed_Date__c );\n        System.assertEquals( false, config.Last_Run_Completed_With_Errors__c );\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_bad_field_mapping() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Workflow';\n        config.Target_SObject_Type__c = 'Account';\n\n        insert config;\n\n        Mass_Action_Mapping__c configFieldMapping = new Mass_Action_Mapping__c(\n            Mass_Action_Configuration__c = config.Id,\n            Source_Field_Name__c = 'NON_EXISTENT_FIELD',\n            Target_Field_Name__c = 'ContextId'\n        );\n\n        insert configFieldMapping;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_SoqlSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.NoSourceFieldException e ) {\n\n            System.assertEquals( configFieldMapping.Source_Field_Name__c, e.sourceFieldName );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_bad_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_FAIL'; // callout mock looks for this keyword\n\n        insert config;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_SoqlSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n    @IsTest\n    static void test_batchable_fail_soap_fault_apex_script() {\n\n        Mass_Action_Configuration__c config = buildTestConfiguration();\n        config.Target_Type__c = 'Apex';\n        config.Target_Apex_Script__c = 'TEST_SOAP_FAULT'; // callout mock looks for this keyword\n\n        insert config;\n\n        Account acct = new Account(\n            Name = 'Test Account'\n        );\n\n        insert acct;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        try {\n\n            Test.startTest();\n\n            Database.executeBatch( new MA_SoqlSourceBatchable( config.Id ), config.Batch_Size__c.intValue() );\n\n            // Async code completes once the test stops,\n            // and any exceptions that occurred will be thrown.\n            // To avoid the test failing because of that,\n            // we have a try..catch block. An event will\n            // still be raised that the batch job failed.\n            Test.stopTest();\n\n            System.assert( false, 'should have failed' );\n\n        } catch ( MA_Exceptions.AnonymousApexException e ) {\n\n            System.assert( true );\n\n        } catch ( Exception e ) {\n\n            System.assert( false, 'failed for wrong exception' );\n\n        } finally {\n\n            Test.getEventBus().deliver();\n\n        }\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceBatchableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceIterable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\npublic with sharing class MA_SoqlSourceIterable implements Iterator<Map<String, Object>>, Iterable<Map<String, Object>> {\n\n    private Mass_Action_Configuration__c config { get; set; }\n\n    private Boolean hasRunQuery { get ;set; }\n\n    private Boolean hasAllData { get; set; }\n\n    private String nextRecordsURL { get; set; }\n\n    private Iterator<Map<String, Object>> currentPageIterator { get; set; }\n\n    // Not to be confused with Batch Apex batch size, this is the value\n    // used in the 'Sforce-Query-Options' header with REST API to chunk\n    // up the amount of query records returned. This value is between 200 to 2,000.\n    // https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers_queryoptions.htm\n    private Integer queryOptionsBatchSize { get; set; }\n\n    public MA_SoqlSourceIterable( ID configId ) {\n\n        System.debug( 'MA_SoqlSourceIterable: configId=' + configId );\n\n        this.config = MA_MassActionUtils.getConfiguration( configId );\n        this.hasRunQuery = false;\n        this.hasAllData = false;\n\n    }\n\n    public MA_SoqlSourceIterable( ID configId, Integer queryOptionsBatchSize ) {\n        this( configId );\n        this.queryOptionsBatchSize = queryOptionsBatchSize;\n    }\n\n    // ------------------------------------------------------------------------\n\n    public Map<String, Object> next() {\n\n        System.debug( 'MA_SoqlSourceIterable.next' );\n\n        Map<String, Object> record = null;\n\n        if ( hasNext() ) {\n            record = this.currentPageIterator.next();\n        }\n\n        return record;\n    }\n\n    public Boolean hasNext() {\n\n        System.debug( 'MA_SoqlSourceIterable.hasNext' );\n\n        if ( !this.hasRunQuery || ( !this.currentPageIterator.hasNext() && !this.hasAllData ) ) {\n            runQuery();\n        }\n\n        return this.currentPageIterator.hasNext();\n    }\n\n    // ------------------------------------------------------------------------\n\n    private void runQuery() {\n\n        System.debug( 'MA_SoqlSourceIterable.runQuery' );\n\n        String baseURL = MA_MassActionUtils.getCalloutRestEndpointURL( this.config.Named_Credential__c );\n\n        MA_SoqlQueryExecuteResult queryResult = new MA_SoqlQueryExecuteResult();\n\n        if ( String.isEmpty( this.nextRecordsURL ) ) {\n            queryResult = MA_MassActionUtils.executeSoqlQuery( baseURL, this.config.Source_SOQL_Query__c, this.queryOptionsBatchSize );\n        } else {\n            String nextRecordsId = this.nextRecordsURL.substringAfterLast( '/' );\n            queryResult = MA_MassActionUtils.executeSoqlQueryNextRecords( baseURL, nextRecordsId, this.queryOptionsBatchSize );\n        }\n\n        this.hasRunQuery = true;\n        this.hasAllData = queryResult.done;\n        this.nextRecordsURL = queryResult.nextRecordsUrl;\n        this.currentPageIterator = queryResult.records.iterator();\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    public Iterator<Map<String, Object>> iterator() {\n\n        System.debug( 'MA_SoqlSourceIterable.iterator' );\n\n        return new MA_SoqlSourceIterable( this.config.Id, this.queryOptionsBatchSize );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceIterable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceIterableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_SoqlSourceIterableTest {\n\n    @IsTest\n    static void test_iterable() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'SOQL',\n            Source_SOQL_Query__c = 'SELECT Id, Name FROM Account',\n            Target_Type__c = 'Flow',\n            Target_Action_Name__c = 'Test_Flow',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Test.startTest();\n\n        // Test Single Http Call\n\n        Integer totalSize = 0;\n\n        MA_SoqlSourceIterable iterable = new MA_SoqlSourceIterable( config.Id );\n\n        while ( iterable.hasNext() ) {\n\n            Map<String, Object> record = iterable.next();\n            System.debug( JSON.serializePretty( record ) );\n\n            totalSize++;\n\n            switch on ( totalSize ) {\n                when 1 {\n                    System.assertEquals( 'Test Account 1', record.get( 'Name' ) );\n                }\n                when 2 {\n                    System.assertEquals( 'Test Account 2', record.get( 'Name' ) );\n                }\n            }\n\n        }\n\n        System.assertEquals( 1, totalSize );\n\n        // Test Multiple Http Calls\n\n        totalSize = 0;\n\n        iterable = new MA_SoqlSourceIterable( config.Id, 200 );\n\n        while ( iterable.hasNext() ) {\n\n            Map<String, Object> record = iterable.next();\n            System.debug( JSON.serializePretty( record ) );\n\n            totalSize++;\n\n            switch on ( totalSize ) {\n                when 1 {\n                    System.assertEquals( 'Test Account 1', record.get( 'Name' ) );\n                }\n                when 2 {\n                    System.assertEquals( 'Test Account 2', record.get( 'Name' ) );\n                }\n            }\n\n        }\n\n        System.assertEquals( 2, totalSize );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_iterator() {\n\n        Test.startTest();\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config',\n            Active__c = false,\n            Batch_Size__c = 200,\n            Named_Credential__c = 'Mass_Action_Test_Named_Credential',\n            Source_Type__c = 'SOQL',\n            Source_SOQL_Query__c = 'SELECT Id, Name FROM Account',\n            Target_Type__c = 'Flow',\n            Target_Action_Name__c = 'Test_Flow',\n            Schedule_Frequency__c = 'Manual'\n        );\n\n        insert config;\n\n        Test.setMock( HttpCalloutMock.class, new MA_HttpCalloutMock() );\n\n        Iterable<Map<String, Object>> iterable = (Iterable<Map<String, Object>>) new MA_SoqlSourceIterable( config.Id );\n        Iterator<Map<String, Object>> iterator = iterable.iterator();\n\n        String iterableJSON = JSON.serialize( iterable );\n        String iteratorJSON = JSON.serialize( iterator );\n\n        System.debug( 'iterableJSON=' + iterableJSON );\n        System.debug( 'iteratorJSON=' + iteratorJSON );\n\n        System.assertEquals( iterableJSON, iteratorJSON );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_SoqlSourceIterableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_StringUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * First try to use a method on the Apex String class before resorting to this class.\n * Inspired by https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html\n */\npublic inherited sharing class MA_StringUtils {\n\n    public static String defaultIfBlank( String str, String defaultStr ) {\n        return ( String.isNotBlank( str ) ? str : defaultStr );\n    }\n\n    /**\n     * Returns a random string of uppercase letters with the given length.\n     * Originally designed for auto-generating unique names for configuration\n     * records when subscribers upgraded to the version that introduced the unique name field.\n     */\n    public static String getRandomLetters( Integer length ) {\n\n        final String[] LETTERS = 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z'.split(',');\n\n        String text = '';\n\n        for ( Integer i = 0; i < length; i++ ) {\n            Integer index = Math.mod( Math.abs( Crypto.getRandomInteger() ), LETTERS.size() );\n            text += LETTERS[index];\n        }\n\n        return text;\n    }\n\n    /**\n     * Returns an abbreviated string value no longer than max allowable length for the field.\n     * If string value is empty or null then returns an empty string.\n     * @see String.abbreviate\n     */\n    public static String abbreviateWithinFieldLength( String value, SObjectField field ) {\n        return abbreviate( value, field.getDescribe().getLength() );\n    }\n\n    /**\n     * Returns an abbreviated string value no longer than `maxWidth`.\n     * If string value is empty or null then returns empty string.\n     * @see String.abbreviate\n     */\n    public static String abbreviate( String value, Integer maxWidth ) {\n        return ( String.isBlank( value ) ? '' : value.abbreviate( maxWidth ) );\n    }\n\n    /**\n     * Determines if the input matches the regular expression.\n     * @see Matcher.matches\n     */\n    public static Boolean matches( String input, String regex ) {\n        Pattern p = Pattern.compile( regex );\n        Matcher m = p.matcher( input );\n        return m.matches();\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_StringUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_StringUtilsTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_StringUtilsTest {\n\n    @IsTest\n    static void givenBlankStringThenReturnsDefaultString() {\n\n        String defaultStr = 'DEFAULT';\n\n        Test.startTest();\n\n        System.assertEquals( defaultStr, MA_StringUtils.defaultIfBlank( null, defaultStr ) );\n        System.assertEquals( defaultStr, MA_StringUtils.defaultIfBlank( '', defaultStr ) );\n        System.assertEquals( defaultStr, MA_StringUtils.defaultIfBlank( ' ', defaultStr ) );\n        System.assertEquals( defaultStr, MA_StringUtils.defaultIfBlank( '\\t', defaultStr ) );\n        System.assertEquals( defaultStr, MA_StringUtils.defaultIfBlank( '\\n', defaultStr ) );\n        System.assertEquals( defaultStr, MA_StringUtils.defaultIfBlank( '\\r', defaultStr ) );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void givenNonBlankStringThenReturnsString() {\n\n        String defaultStr = 'DEFAULT';\n\n        Test.startTest();\n\n        System.assertEquals( 'text', MA_StringUtils.defaultIfBlank( 'text', defaultStr ) );\n        System.assertEquals( ' text ', MA_StringUtils.defaultIfBlank( ' text ', defaultStr ) );\n        System.assertEquals( ' 1 2 3 ', MA_StringUtils.defaultIfBlank( ' 1 2 3 ', defaultStr ) );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_get_random_letters() {\n\n        Test.startTest();\n\n        String str1 = MA_StringUtils.getRandomLetters( 200 );\n        System.assertEquals( 200, str1.length() );\n        System.assertEquals( true, str1.isAlpha() );\n\n        String str2 = MA_StringUtils.getRandomLetters( 0 );\n        System.assertEquals( 0, str2.length() );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void test_abbreviateWithinFieldLength() {\n\n        Integer messageLength = Mass_Action_Log__c.Message__c.getDescribe().getLength();\n\n        String shortMessage = ''.leftPad( messageLength - 10, 'x' );\n        String longMessage = ''.leftPad( messageLength + 10, 'x' );\n        String emptyMessage = '';\n        String nullMessage = null;\n\n        Test.startTest();\n\n        String abbrShortMessage = MA_StringUtils.abbreviateWithinFieldLength( shortMessage, Mass_Action_Log__c.Message__c );\n        String abbrLongMessage = MA_StringUtils.abbreviateWithinFieldLength( longMessage, Mass_Action_Log__c.Message__c );\n        String abbrEmptyMessage = MA_StringUtils.abbreviateWithinFieldLength( emptyMessage, Mass_Action_Log__c.Message__c );\n        String abbrNullMessage = MA_StringUtils.abbreviateWithinFieldLength( nullMessage, Mass_Action_Log__c.Message__c );\n\n        Test.stopTest();\n\n        System.assertEquals( messageLength - 10, abbrShortMessage.length() );\n        System.assert( !abbrShortMessage.endsWith( '...' ) );\n\n        System.assertEquals( messageLength, abbrLongMessage.length() );\n        System.assert( abbrLongMessage.endsWith( '...' ) );\n\n        System.assertEquals( 0, abbrEmptyMessage.length() );\n        System.assertEquals( '', abbrEmptyMessage );\n\n        System.assertEquals( 0, abbrNullMessage.length() );\n        System.assertEquals( '', abbrNullMessage );\n\n    }\n\n    @IsTest\n    static void test_abbreviate() {\n\n        Integer messageLength = 50;\n\n        String shortMessage = ''.leftPad( messageLength - 10, 'x' );\n        String longMessage = ''.leftPad( messageLength + 10, 'x' );\n        String emptyMessage = '';\n        String nullMessage = null;\n\n        Test.startTest();\n\n        String abbrShortMessage = MA_StringUtils.abbreviate( shortMessage, messageLength );\n        String abbrLongMessage = MA_StringUtils.abbreviate( longMessage, messageLength );\n        String abbrEmptyMessage = MA_StringUtils.abbreviate( emptyMessage, messageLength );\n        String abbrNullMessage = MA_StringUtils.abbreviate( nullMessage, messageLength );\n\n        Test.stopTest();\n\n        System.assertEquals( messageLength - 10, abbrShortMessage.length() );\n        System.assert( !abbrShortMessage.endsWith( '...' ) );\n\n        System.assertEquals( messageLength, abbrLongMessage.length() );\n        System.assert( abbrLongMessage.endsWith( '...' ) );\n\n        System.assertEquals( 0, abbrEmptyMessage.length() );\n        System.assertEquals( '', abbrEmptyMessage );\n\n        System.assertEquals( 0, abbrNullMessage.length() );\n        System.assertEquals( '', abbrNullMessage );\n\n    }\n\n    @IsTest\n    static void test_matches() {\n\n        Test.startTest();\n\n        String regex = 'Hello, [a-zA-Z]+';\n\n        System.assertEquals( true, MA_StringUtils.matches( 'Hello, Salesforce', regex ) );\n        System.assertEquals( false, MA_StringUtils.matches( 'Hello, 123', regex ) );\n        System.assertEquals( false, MA_StringUtils.matches( 'nope', regex ) );\n\n        Test.stopTest();\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_StringUtilsTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradeMassActionLogsBatchable.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * Designed for the upgrade to release 2.3 that introduces the record types to Mass_Action_Log__c object.\n * Batches over all log records with a blank record type and assigns the \"Child_Log\" record type to it.\n * For each unique combination of configuration id and job id of existing logs for a configuration,\n * creates a new parent log record and links the child log records to it.\n *\n * This class explicitly uses 'without sharing' because it is invoked by the package install handler\n * and it is documented that the use of 'with sharing' by apex classes called by the handler may prevent installation.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_install_handler.htm\n */\npublic without sharing class MA_UpgradeMassActionLogsBatchable implements Database.Batchable<SObject>,\n                                                                          Database.Stateful,\n                                                                          Database.AllowsCallouts,\n                                                                          Database.RaisesPlatformEvents {\n\n    public Database.QueryLocator start( Database.BatchableContext context ) {\n\n        System.debug( 'MA_UpgradeMassActionLogsBatchable.start: ' + context );\n\n        return Database.getQueryLocator([\n            SELECT\n                Id, RecordTypeId, Mass_Action_Configuration__c, Parent_Log__c,\n                Job_ID__c, Message_Type__c, Timestamp__c, CreatedDate\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                RecordTypeId = null\n                AND\n                Job_ID__c != null\n            ORDER BY\n                Mass_Action_Configuration__c ASC,\n                Job_ID__c ASC,\n                CreatedDate ASC,\n                Id ASC\n        ]);\n    }\n\n    public void execute( Database.BatchableContext context, List<Mass_Action_Log__c> logs ) {\n\n        System.debug( 'MA_UpgradeMassActionLogsBatchable.execute: ' + context );\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Map<ID, AsyncApexJob> jobsMap = new Map<ID, AsyncApexJob>();\n        Map<String, Mass_Action_Log__c> parentLogsMap = new Map<String, Mass_Action_Log__c>();\n        Map<String, Mass_Action_Log__c> parentLogsToInsertMap = new Map<String, Mass_Action_Log__c>();\n        List<Mass_Action_Log__c> childLogsToUpdate = new List<Mass_Action_Log__c>();\n\n        // create filter criteria when searching for\n        // existing parent logs; we only want parent logs\n        // pertinent to these config and job ids\n        Set<ID> configIds18 = new Set<ID>();\n        Set<ID> jobIds18 = new Set<ID>();\n        Set<String> jobIds15 = new Set<String>();\n\n        for ( Mass_Action_Log__c log : logs ) {\n\n            if ( String.isNotBlank( log.Mass_Action_Configuration__c ) ) {\n                configIds18.add( log.Mass_Action_Configuration__c );\n            }\n\n            if ( String.isNotBlank( log.Job_ID__c ) ) {\n                jobIds15.add( log.Job_ID__c.left( 15 ) );\n                jobIds18.add( ID.valueOf( log.Job_ID__c ) );\n            }\n\n        }\n\n        // get jobs to populate data on parent logs\n        jobsMap = MA_MassActionBatchUtils.getJobsByJobIdMap( jobIds18 );\n\n        // get any existing parent logs from prior batch executions\n        parentLogsMap = getParentLogsMap( configIds18, jobIds15 );\n\n        // determine any parent logs that need to be created\n        for ( Mass_Action_Log__c log : logs ) {\n\n            String key = computeKey( log.Mass_Action_Configuration__c, log.Job_ID__c );\n            Mass_Action_Log__c parentLog = parentLogsMap.get( key );\n            AsyncApexJob job = jobsMap.get( ID.valueOf( log.Job_ID__c ) );\n\n            if ( parentLog == null ) {\n\n                parentLog = new Mass_Action_Log__c(\n                    RecordTypeId = logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId(),\n                    Mass_Action_Configuration__c = log.Mass_Action_Configuration__c,\n                    Job_ID__c = log.Job_ID__c,\n                    Message_Type__c = 'Informational',\n                    Message__c = 'Batch job information',\n                    Timestamp__c = String.valueOf( log.CreatedDate.getTime() ),\n                    Total_Batches__c = 0,\n                    Processed_Batches__c = 0,\n                    Failed_Batches__c = 0\n                );\n\n                // very old jobs may have been deleted and no longer exist\n                // so if not, just skip this part\n                if ( job != null ) {\n\n                    String messageType = 'Error';\n\n                    String message = 'Batch job ' + (\n                        ( job.Status == 'Completed' ) ? 'completed with errors' :\n                        String.isBlank( job.Status ) ? 'information' :\n                        job.Status.toLowerCase()\n                    );\n\n                    parentLog.Message_Type__c = messageType;\n                    parentLog.Message__c = message;\n                    parentLog.Submitted_Date__c = job.CreatedDate;\n                    parentLog.Total_Batches__c = job.TotalJobItems;\n                    parentLog.Processed_Batches__c = job.JobItemsProcessed;\n\n                    // See comment further down where we increment failed batches\n                    //parentLog.Failed_Batches__c = job.NumberOfErrors;\n\n                } else {\n\n                    // For old logs, the AsyncApexJob record may\n                    // no longer exist or have been purged already.\n                    // If we the job record doesn't exist then we can't\n                    // reliably determine the job's submitted date or\n                    // how many total batches were processed.\n                    // Let's add a message to that effect so the user\n                    // understands why their parent log isn't complete.\n                    parentLog.Message__c = 'Batch job information incomplete';\n                    parentLog.Long_Message__c = (\n                        'Do not be alarmed, this is an informational message only.' +\n                        '\\n\\n' +\n                        'During the Mass Action Scheduler package upgrade to create parent logs, ' +\n                        'we could not find a batch job for id \"7071h00000ehRQZ\". ' +\n                        'The AsyncApexJob record from the Apex Jobs page in Setup may have already been purged from the system. ' +\n                        'Therefore, the \"Submitted Date\", \"Total Batches\", and \"Processed Batches\" field values on this log record ' +\n                        'may not be accurate because we did not find an AsyncApexJob record to copy the values from.' +\n                        '\\n\\n' +\n                        'Tip: You can safely delete Mass Action Log records anytime after the batch job has completed. ' +\n                        'They exist to help you troubleshoot errors and track job progress.'\n                    );\n\n                }\n\n                // add yet to be saved log to map to avoid\n                // re-processing this key and so ensuring\n                // the first parent log's timestamp should\n                // be the earliest date of the earliest\n                // child log for this map key\n                parentLogsMap.put( key, parentLog );\n\n                // add yet to be saved log to map that will saved\n                parentLogsToInsertMap.put( key, parentLog );\n\n            }\n\n        }\n\n        // create new parent logs\n        insert parentLogsToInsertMap.values();\n\n        // requery parent logs\n        parentLogsMap = getParentLogsMap( configIds18, jobIds15 );\n\n        // assign parent logs to child logs\n        for ( Mass_Action_Log__c log : logs ) {\n\n            String key = computeKey( log.Mass_Action_Configuration__c, log.Job_ID__c );\n            Mass_Action_Log__c parentLog = parentLogsMap.get( key );\n\n            if ( parentLog != null ) {\n                childLogsToUpdate.add( new Mass_Action_Log__c(\n                    Id = log.Id,\n                    Parent_Log__c = parentLog.Id,\n                    RecordTypeId = logRecordTypeInfosMap.get( 'Child_Log' ).getRecordTypeId(),\n                    Message_Type__c = 'Error',\n                    Timestamp__c = String.valueOf( log.CreatedDate.getTime() )\n                ));\n            }\n\n        }\n\n        // update child logs\n        update childLogsToUpdate;\n\n        // In prior versions, only batch job errors were\n        // logged, but to do I used try/catch in the start/execute/finish\n        // methods and inserted log records right then.\n        // This let us log the errors, but the batch job considered\n        // all executions were successful -- no number of errors.\n        // For this data migration, assume any log record means an error.\n        // We will set the number of errors equal to number of log records we find.\n        for ( List<AggregateResult> results : [\n            SELECT\n                Mass_Action_Configuration__c configId,\n                Job_ID__c jobId,\n                Parent_Log__c parentLogId,\n                COUNT( Id ) logCount\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                Parent_Log__c IN :parentLogsMap.values()\n                AND\n                RecordTypeId = :logRecordTypeInfosMap.get( 'Child_Log' ).getRecordTypeId()\n            GROUP BY\n                Mass_Action_Configuration__c,\n                Job_ID__c,\n                Parent_Log__c\n        ]) {\n            for ( AggregateResult result : results ) {\n\n                System.debug( result );\n\n                ID configId = (ID) result.get( 'configId' );\n                ID jobId = (ID) result.get( 'jobId' );\n                ID parentLogId = (ID) result.get( 'parentLogId' );\n                Integer logCount = (Integer) result.get( 'logCount' );\n\n                String key = computeKey( configId, jobId );\n                Mass_Action_Log__c parentLog = parentLogsMap.get( key );\n                parentLog.Failed_Batches__c = logCount;\n\n            }\n        }\n\n        update parentLogsMap.values();\n\n    }\n\n    public void finish( Database.BatchableContext context ) {\n\n        System.debug( 'MA_UpgradeMassActionLogsBatchable.finish: ' + context );\n\n    }\n\n    // ------------------------------------------------------------------------\n\n    private String computeKey( String configId, String jobId ) {\n        return ( configId.left( 18 ) + '#' + jobId.left( 15 ) );\n    }\n\n    private Map<String, Mass_Action_Log__c> getParentLogsMap( Set<ID> configIds18, Set<String> jobIds15 ) {\n\n        Map<String,RecordTypeInfo> logRecordTypeInfosMap = Mass_Action_Log__c.SObjectType.getDescribe().getRecordTypeInfosByDeveloperName();\n\n        Map<String, Mass_Action_Log__c> parentLogsMap = new Map<String, Mass_Action_Log__c>();\n\n        for ( Mass_Action_Log__c parentLog : [\n            SELECT\n                Id, Mass_Action_Configuration__c, Job_ID__c,\n                Total_Batches__c, Processed_Batches__c, Failed_Batches__c\n            FROM\n                Mass_Action_Log__c\n            WHERE\n                RecordTypeId = :logRecordTypeInfosMap.get( 'Parent_Log' ).getRecordTypeId()\n                AND\n                Mass_Action_Configuration__c IN :configIds18\n                AND\n                Job_ID__c IN :jobIds15\n        ]) {\n            String key = computeKey( parentLog.Mass_Action_Configuration__c, parentLog.Job_ID__c );\n            parentLogsMap.put( key, parentLog );\n        }\n\n        return parentLogsMap;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradeMassActionLogsBatchable.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradeMassActionLogsBatchableTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_UpgradeMassActionLogsBatchableTest {\n\n    @IsTest\n    static void test_non_existant_job() {\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        Mass_Action_Log__c log = new Mass_Action_Log__c(\n            Mass_Action_Configuration__c = config.Id,\n            Message__c = 'the error message',\n            Job_ID__c = '707f400NOTEXIST'\n        );\n\n        insert log;\n\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Parent_Log' ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Child_Log' ] );\n\n        Test.startTest();\n\n        Database.executeBatch( new MA_UpgradeMassActionLogsBatchable() );\n\n        Test.stopTest();\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Parent_Log' ] );\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Child_Log' ] );\n\n        Mass_Action_Log__c parentLog = [\n            SELECT Id, Message__c, Message_Type__c, Submitted_Date__c, Total_Batches__c, Processed_Batches__c, Failed_Batches__c\n            FROM Mass_Action_Log__c\n            WHERE RecordType.DeveloperName = 'Parent_Log' AND Job_ID__c = :String.valueOf( log.Job_ID__c ).left( 15 )\n        ];\n\n        System.assertEquals( 1, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Parent_Log__c = :parentLog.Id ] );\n\n        System.assertEquals( 'Informational', parentLog.Message_Type__c );\n        System.assertEquals( 'Batch job information incomplete', parentLog.Message__c );\n        System.assertEquals( null, parentLog.Submitted_Date__c );\n        System.assertEquals( 0, parentLog.Total_Batches__c );\n        System.assertEquals( 0, parentLog.Processed_Batches__c );\n        System.assertEquals( 1, parentLog.Failed_Batches__c, 'should match number of child logs that were converted' );\n\n    }\n\n    @IsTest\n    static void test_batch_200() {\n\n        AsyncApexJob job1 = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.ABORTED_JOB_ID );\n        AsyncApexJob job2 = MA_AsyncApexJobMock.getJobById( MA_AsyncApexJobMock.COMPLETED_WITH_ERRORS_JOB_ID );\n\n        Mass_Action_Configuration__c config = new Mass_Action_Configuration__c(\n            Name = 'Test Config',\n            DeveloperName__c = 'Test_Config'\n        );\n\n        insert config;\n\n        List<Mass_Action_Log__c> logs = new List<Mass_Action_Log__c>();\n\n        for ( Integer i = 0; i < 200; i++ ) {\n            logs.add( new Mass_Action_Log__c(\n                Mass_Action_Configuration__c = config.Id,\n                Message__c = 'Error ' + String.valueOf( i ).leftPad( 3, '0' ),\n                Job_ID__c = ( i < 100 ? job1.Id : job2.Id )\n            ));\n        }\n\n        insert logs;\n\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Parent_Log' ] );\n        System.assertEquals( 0, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Child_Log' ] );\n\n        Test.startTest();\n\n        Database.executeBatch( new MA_UpgradeMassActionLogsBatchable() );\n\n        Test.stopTest();\n\n        System.assertEquals( 2, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Parent_Log' ] );\n        System.assertEquals( 200, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE RecordType.DeveloperName = 'Child_Log' ] );\n\n        Mass_Action_Log__c parentLog1 = [\n            SELECT Id, Message__c, Message_Type__c, Submitted_Date__c, Total_Batches__c, Processed_Batches__c, Failed_Batches__c\n            FROM Mass_Action_Log__c\n            WHERE RecordType.DeveloperName = 'Parent_Log' AND Job_ID__c = :String.valueOf( job1.Id ).left( 15 )\n        ];\n\n        Mass_Action_Log__c parentLog2 = [\n            SELECT Id, Message__c, Message_Type__c, Submitted_Date__c, Total_Batches__c, Processed_Batches__c, Failed_Batches__c\n            FROM Mass_Action_Log__c\n            WHERE RecordType.DeveloperName = 'Parent_Log' AND Job_ID__c = :String.valueOf( job2.Id ).left( 15 )\n        ];\n\n        System.assertEquals( 100, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Parent_Log__c = :parentLog1.Id ] );\n        System.assertEquals( 100, [ SELECT COUNT() FROM Mass_Action_Log__c WHERE Parent_Log__c = :parentLog2.Id ] );\n\n        System.assertEquals( 'Error', parentLog1.Message_Type__c );\n        System.assertEquals( 'Batch job aborted', parentLog1.Message__c );\n        System.assertEquals( true, job1.CreatedDate.isSameDay( parentLog1.Submitted_Date__c ) );\n        System.assertEquals( job1.TotalJobItems, parentLog1.Total_Batches__c );\n        System.assertEquals( job1.JobItemsProcessed, parentLog1.Processed_Batches__c );\n        System.assertEquals( 100, parentLog1.Failed_Batches__c, 'should match number of child logs that were converted' );\n\n        System.assertEquals( 'Error', parentLog2.Message_Type__c );\n        System.assertEquals( 'Batch job completed with errors', parentLog2.Message__c );\n        System.assertEquals( true, job2.CreatedDate.isSameDay( parentLog2.Submitted_Date__c ) );\n        System.assertEquals( job2.TotalJobItems, parentLog2.Total_Batches__c );\n        System.assertEquals( job2.JobItemsProcessed, parentLog2.Processed_Batches__c );\n        System.assertEquals( 100, parentLog2.Failed_Batches__c, 'should match number of child logs that were converted' );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradeMassActionLogsBatchableTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradePageLayoutsService.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * Designed to upgrade the Mass Action Configuration page layout to include new\n * actions, fields, and related lists introduced in new package versions.\n *\n * This class uses the Apex Metadata API, and when deployed as a managed package\n * requires the Apex Setting \"Deploy Metadata from Non-Certified Package Versions via Apex\" enabled\n * because this app is not offered through the AppExchange.\n *\n * If you do not want to enable the setting for automatic page layout updates,\n * you can install the code from source from the project repository.\n *\n * This class explicitly uses 'without sharing' because it is invoked by the package install handler\n * and it is documented that the use of 'with sharing' by apex classes called by the handler may prevent installation.\n * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_install_handler.htm\n */\npublic without sharing class MA_UpgradePageLayoutsService {\n\n    /**\n     * Updates page layouts bundled with the Mass Action Scheduler managed package,\n     * such as ensure action buttons are on the layout and related lists are configured.\n     *\n     * Returns the enqueued metadata deployment id.\n     */\n    public ID upgrade() {\n\n        System.debug( 'MA_UpgradePageLayoutsService.upgrade' );\n\n        Metadata.DeployContainer container = buildMetadataDeployContainer();\n        Metadata.DeployCallback callback = new MA_MetadataDeployCallback();\n\n        ID deploymentId = ( Test.isRunningTest() ? '0Af00000000000TEST' : Metadata.Operations.enqueueDeployment( container, callback ) );\n\n        System.debug( 'MA_UpgradePageLayoutsService.upgrade: deploymentId=' + deploymentId );\n\n        return deploymentId;\n    }\n\n    /**\n     * Builds a metadata deploy container to include any page layout\n     * changes to make in this package upgrade.\n     *\n     * For easier testability, this exists as its own method.\n     */\n    @TestVisible\n    private Metadata.DeployContainer buildMetadataDeployContainer() {\n\n        Metadata.DeployContainer container = new Metadata.DeployContainer();\n\n        List<Metadata.Metadata> metadataToDeploy = new List<Metadata.Metadata>();\n        metadataToDeploy.addAll( update_MassActionConfiguration_PageLayouts() );\n\n        for ( Metadata.Metadata md : metadataToDeploy ) {\n            container.addMetadata( md );\n        }\n\n        return container;\n    }\n\n    // ------------------------------------------------------------------------\n\n    private List<Metadata.Metadata> update_MassActionConfiguration_PageLayouts() {\n\n        String namespace = MA_NamespaceUtils.NAMESPACE_API;\n\n        List<Metadata.Metadata> layouts = Metadata.Operations.retrieve(\n            Metadata.MetadataType.Layout,\n            new List<String>{\n                String.format(\n                    '{0}Mass_Action_Configuration__c-{0}Mass Action Configuration Layout',\n                    new Object[] { namespace }\n                )\n            }\n        );\n\n        System.debug( 'MA_UpgradePageLayoutsService.update_MassActionConfiguration_PageLayouts: current page layouts:' );\n        System.debug( JSON.serializePretty( layouts ) );\n\n        Metadata.Layout layout = (Metadata.Layout) layouts[0];\n\n        update_MassActionConfigurationLayout_PlatformActionItems( layout );\n        update_MassActionConfigurationLayout_RelatedLists( layout );\n\n        System.debug( 'MA_UpgradePageLayoutsService.update_MassActionConfiguration_PageLayouts: updated page layouts:' );\n        System.debug( JSON.serializePretty( layouts ) );\n\n        return layouts;\n    }\n\n    /**\n     * Ensures our \"Run_via_Flow\" and \"Quick_Edit\" action items are on the page layout.\n     * Switches out the original \"Run\" action item with the newer \"Run_via_Flow\" action item.\n     */\n    private void update_MassActionConfigurationLayout_PlatformActionItems( Metadata.Layout layout ) {\n\n        // This may or may not be blank depending on if the code is\n        // part of the managed package or not\n        String namespace = MA_NamespaceUtils.NAMESPACE_API;\n\n        // Pattern to identify action items part of the MAS codebase.\n        // Note the `?` to indicate the namespace may or may not exist\n        // in the platform actions names, which is part of the problem\n        // when upgrading and the actions disappearing from page layouts\n        // as the namespace might not exist in the name and so when\n        // admins would save the page layout then the actions would drop off\n        // and have to be readded manually in the Page Layout Editor.\n        // This upgrade code handles that by ensuring the appropriate names are assigned.\n        String runActionItemRegex = '(?i)(dca_mass_action__)?Mass_Action_Configuration__c\\\\.(dca_mass_action__)?(Run|Run_via_Flow)';\n        String quickEditActionItemRegex = '(?i)(dca_mass_action__)?Mass_Action_Configuration__c\\\\.(dca_mass_action__)?Quick_Edit';\n\n        List<Metadata.PlatformActionListItem> platformActionListItemsToKeep = new List<Metadata.PlatformActionListItem>();\n\n        for ( Metadata.PlatformActionListItem platformActionListItem : layout.platformActionList.platformActionListItems ) {\n\n            Boolean matchesRunActionItem = MA_StringUtils.matches( platformActionListItem.actionName, runActionItemRegex );\n            Boolean matchesQuickEditActionItem = MA_StringUtils.matches( platformActionListItem.actionName, quickEditActionItemRegex );\n\n            if ( !matchesRunActionItem && !matchesQuickEditActionItem ) {\n                platformActionListItemsToKeep.add( platformActionListItem );\n            }\n\n        }\n\n        // -----------------------------------------------------------\n\n        Metadata.PlatformActionListItem runActionItem = new Metadata.PlatformActionListItem();\n        runActionItem.actionType = Metadata.PlatformActionTypeEnum.QuickAction;\n        runActionItem.actionName = String.format(\n            '{0}Mass_Action_Configuration__c.{0}Run_via_Flow',\n            new Object[] { namespace }\n        );\n\n        platformActionListItemsToKeep.add( runActionItem );\n\n        // -----------------------------------------------------------\n\n        Metadata.PlatformActionListItem quickEditActionItem = new Metadata.PlatformActionListItem();\n        quickEditActionItem.actionType = Metadata.PlatformActionTypeEnum.QuickAction;\n        quickEditActionItem.actionName = String.format(\n            '{0}Mass_Action_Configuration__c.{0}Quick_Edit',\n            new Object[] { namespace }\n        );\n\n        platformActionListItemsToKeep.add( quickEditActionItem );\n\n        // -----------------------------------------------------------\n\n        // Sort the action items.\n        // Our Run and Quick Edit actions will be the first two.\n        Integer sortIndex = 2;\n        for ( Metadata.PlatformActionListItem platformActionListItem : platformActionListItemsToKeep ) {\n            if ( platformActionListItem == runActionItem ) {\n                platformActionListItem.sortOrder = 0;\n            } else if ( platformActionListItem == quickEditActionItem ) {\n                platformActionListItem.sortOrder = 1;\n            } else {\n                platformActionListItem.sortOrder = sortIndex++;\n            }\n        }\n\n        // -----------------------------------------------------------\n\n        layout.platformActionList.platformActionListItems = platformActionListItemsToKeep;\n\n    }\n\n    private void update_MassActionConfigurationLayout_RelatedLists( Metadata.Layout layout ) {\n\n        // This may or may not be blank depending on if the code is\n        // part of the managed package or not\n        String namespace = MA_NamespaceUtils.NAMESPACE_API;\n\n        // Pattern to identify related lists part of the MAS codebase.\n        // Note the `?` to indicate the namespace may or may not exist.\n        // This upgrade code handles that by ensuring the appropriate names are assigned.\n        String fieldMappingsListRegex = '(?i)(dca_mass_action__)?Mass_Action_Mapping__c\\\\.(dca_mass_action__)?Mass_Action_Configuration__c';\n        String parentLogsListRegex = '(?i)(dca_mass_action__)?Mass_Action_Log__c\\\\.(dca_mass_action__)?Parent_Log_Configuration__c';\n        String allLogsListRegex = '(?i)(dca_mass_action__)?Mass_Action_Log__c\\\\.(dca_mass_action__)?Mass_Action_Configuration__c';\n\n        // existing related lists to keep on page layout\n        List<Metadata.RelatedListItem> relatedListItemsToKeep = new List<Metadata.RelatedListItem>();\n\n        // exclude any of our related lists while preserving ones the subscriber org has added\n        for ( Metadata.RelatedListItem relatedListItem : layout.relatedLists ) {\n\n            Boolean matchesFieldMappingList = MA_StringUtils.matches( relatedListItem.relatedList, fieldMappingsListRegex );\n            Boolean matchesParentLogsList = MA_StringUtils.matches( relatedListItem.relatedList, parentLogsListRegex );\n            Boolean matchesAllLogsList = MA_StringUtils.matches( relatedListItem.relatedList, allLogsListRegex );\n\n            if ( !matchesFieldMappingList && !matchesParentLogsList && !matchesAllLogsList ) {\n                relatedListItemsToKeep.add( relatedListItem );\n            }\n\n        }\n\n        // -----------------------------------------------------------\n\n        Metadata.RelatedListItem fieldMappingRelatedListItem = new Metadata.RelatedListItem();\n\n        fieldMappingRelatedListItem.relatedList = String.format(\n            '{0}Mass_Action_Mapping__c.{0}Mass_Action_Configuration__c',\n            new Object[] { namespace }\n        );\n\n        fieldMappingRelatedListItem.fields = new String[] {\n            'NAME',\n            String.format(\n                '{0}Source_Field_Name__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Target_Field_Name__c',\n                new Object[] { namespace }\n            )\n        };\n\n        fieldMappingRelatedListItem.sortField = String.format(\n            '{0}Source_Field_Name__c',\n            new Object[] { namespace }\n        );\n        fieldMappingRelatedListItem.sortOrder = Metadata.SortOrder.Asc_x;\n\n        // -----------------------------------------------------------\n\n        Metadata.RelatedListItem parentLogsRelatedListItem = new Metadata.RelatedListItem();\n\n        parentLogsRelatedListItem.relatedList = String.format(\n            '{0}Mass_Action_Log__c.{0}Parent_Log_Configuration__c',\n            new Object[] { namespace }\n        );\n\n        parentLogsRelatedListItem.fields = new String[] {\n            'NAME',\n            String.format(\n                '{0}Job_ID__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Message__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Batch_Success_Rate__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Total_Batches__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Processed_Batches__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Failed_Batches__c',\n                new Object[] { namespace }\n            ),\n            String.format(\n                '{0}Timestamp__c',\n                new Object[] { namespace }\n            )\n        };\n\n        parentLogsRelatedListItem.sortField = String.format(\n            '{0}Timestamp__c',\n            new Object[] { namespace }\n        );\n        parentLogsRelatedListItem.sortOrder = Metadata.SortOrder.Desc_x;\n\n        // -----------------------------------------------------------\n\n        // add related lists in the order we want them\n        List<Metadata.RelatedListItem> relatedListItemsToAdd = new List<Metadata.RelatedListItem>();\n        relatedListItemsToAdd.add( fieldMappingRelatedListItem );\n        relatedListItemsToAdd.add( parentLogsRelatedListItem );\n        relatedListItemsToAdd.addAll( relatedListItemsToKeep );\n\n        layout.relatedLists = relatedListItemsToAdd;\n\n    }\n\n    // ------------------------------------------------------------------------\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradePageLayoutsService.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradePageLayoutsServiceTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_UpgradePageLayoutsServiceTest {\n\n    // https://trailhead.salesforce.com/content/learn/modules/apex_metadata_api/apex_metadata_api_testing\n\n    @IsTest\n    static void test_upgrade() {\n\n        Test.startTest();\n\n        MA_UpgradePageLayoutsService service = new MA_UpgradePageLayoutsService();\n\n        ID deploymentId = service.upgrade();\n\n        Test.stopTest();\n\n        // can't actually do a deployment in a test,\n        // so assert we got back our mock deploy id\n        System.assertEquals( '0Af00000000000TEST', deploymentId );\n\n    }\n\n    @IsTest\n    static void test_buildMetadataDeployContainer() {\n\n        String namespace = MA_NamespaceUtils.NAMESPACE_API;\n\n        String MassActionConfigurationPageLayoutName = String.format(\n            '{0}Mass_Action_Configuration__c-{0}Mass Action Configuration Layout',\n            new Object[] { namespace }\n        );\n\n        Test.startTest();\n\n        MA_UpgradePageLayoutsService service = new MA_UpgradePageLayoutsService();\n\n        Metadata.DeployContainer container = service.buildMetadataDeployContainer();\n\n        Test.stopTest();\n\n        System.debug( JSON.serializePretty( container ) );\n\n        Boolean foundMassActionConfigurationPageLayout = false;\n\n        for ( Metadata.Metadata md : container.getMetadata() ) {\n            if ( md.fullName == MassActionConfigurationPageLayoutName ) {\n                foundMassActionConfigurationPageLayout = true;\n                validateMassActionConfigurationPageLayout( (Metadata.Layout) md );\n            }\n        }\n\n        System.assertEquals( true, foundMassActionConfigurationPageLayout, 'did not find Mass Action Configuration page layout' );\n\n    }\n\n    private static void validateMassActionConfigurationPageLayout( Metadata.Layout layout ) {\n\n        String namespace = MA_NamespaceUtils.NAMESPACE_API;\n\n        String runActionListItemName = String.format( '{0}Mass_Action_Configuration__c.{0}Run', new Object[] { namespace } );\n        String runFlowActionListItemName = String.format( '{0}Mass_Action_Configuration__c.{0}Run_via_Flow', new Object[] { namespace } );\n        String quickEditActionListItemName = String.format( '{0}Mass_Action_Configuration__c.{0}Quick_Edit', new Object[] { namespace } );\n\n        Boolean foundRunFlowActionListItem = false;\n        Boolean foundQuickEditActionListItem = false;\n\n        System.assert( layout.platformActionList.platformActionListItems.size() >= 2, 'missing action list items' );\n\n        for ( Metadata.PlatformActionListItem action : layout.platformActionList.platformActionListItems ) {\n            if ( action.actionName == runActionListItemName ) {\n                System.assert( false, 'found ' + action.actionName + ' action list item, but it should have been removed' );\n            } else if ( action.actionName == runFlowActionListItemName ) {\n                foundRunFlowActionListItem = true;\n                System.assertEquals( 0, action.sortOrder );\n            } else if ( action.actionName == quickEditActionListItemName ) {\n                foundQuickEditActionListItem = true;\n                System.assertEquals( 1, action.sortOrder );\n            }\n        }\n\n        System.assertEquals( true, foundRunFlowActionListItem, 'did not find Run Flow action list item' );\n        System.assertEquals( true, foundQuickEditActionListItem, 'did not find Quick Edit action list item' );\n\n        // -----------------------------------------------------------\n\n        String fieldMappingsListName = String.format( '{0}Mass_Action_Mapping__c.{0}Mass_Action_Configuration__c', new Object[] { namespace } );\n        String parentLogsListName = String.format( '{0}Mass_Action_Log__c.{0}Parent_Log_Configuration__c', new Object[] { namespace } );\n        String allLogsListName = String.format( '{0}Mass_Action_Log__c.{0}Mass_Action_Configuration__c', new Object[] { namespace } );\n\n        Boolean foundFieldMappingsList = false;\n        Boolean foundParentLogsList = false;\n\n        System.assert( layout.relatedLists.size() >= 2, 'missing related lists' );\n\n        for ( Metadata.RelatedListItem relatedListItem : layout.relatedLists ) {\n            if ( relatedListItem.relatedList == allLogsListName ) {\n                System.assert( false, 'found ' + relatedListItem.relatedList + ' related list, but it should have been removed' );\n            } else if ( relatedListItem.relatedList == fieldMappingsListName ) {\n                foundFieldMappingsList = true;\n            } else if ( relatedListItem.relatedList == parentLogsListName ) {\n                foundParentLogsList = true;\n            }\n        }\n\n        System.assertEquals( true, foundFieldMappingsList, 'did not find Field Mappings related list' );\n        System.assertEquals( true, foundParentLogsList, 'did not find Parent Logs related list' );\n\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_UpgradePageLayoutsServiceTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_XMLUtils.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n/**\n * First try to use a method on the DOM.XMLNode class before resorting to this class.\n */\npublic inherited sharing class MA_XMLUtils {\n\n    /**\n     * Convenience method that returns the node text from the found\n     * child node. If no such child node exists, returns null.\n     */\n    public static String getChildNodeTextByPath( DOM.XMLNode root, String path ) {\n        DOM.XMLNode child = getChildNodeByPath( root, path );\n        return ( child != null ? child.getText() : null );\n    }\n\n    /**\n     * Iterates child nodes to find and return the node whose name matches\n     * the names in the given path.\n     *\n     * @param root\n     *      XML node to begin the search.\n     * @param path\n     *      Path of child node names separated by slash (/), relative to the root node.\n     */\n    public static DOM.XMLNode getChildNodeByPath( DOM.XMLNode root, String path ) {\n\n        DOM.XMLNode child = null;\n\n        if ( root != null && String.isNotBlank( path ) ) {\n\n            if ( path.startsWith( '/' ) ) {\n                path = path.substringAfter( '/' );\n            }\n\n            String[] names = path.split( '/' );\n            child = root;\n\n            for ( String name : names ) {\n\n                DOM.XMLNode foundNode = null;\n\n                for ( DOM.XMLNode childNode : child.getChildElements() ) {\n\n                    if ( String.isNotBlank( childNode.getName() ) && childNode.getName().equalsIgnoreCase( name ) ) {\n                        foundNode = childNode;\n                        break;\n                    }\n\n                }\n\n                child = foundNode;\n\n                if ( foundNode == null ) {\n                    // didn't find child node, exit\n                    break;\n                }\n\n            }\n\n        }\n\n        return child;\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_XMLUtils.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/classes/MA_XMLUtilsTest.cls",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\n@IsTest\nprivate class MA_XMLUtilsTest {\n\n    @IsTest\n    static void givenNullRootThenReturnNull() {\n\n        DOM.Document doc = new DOM.Document();\n        doc.load( getSoapFaultResponse( 'test error message' ) );\n\n        Test.startTest();\n\n        DOM.XmlNode child = MA_XMLUtils.getChildNodeByPath( null, '/Body/Fault/faultcode' );\n        System.assertEquals( null, child );\n\n        String faultString = MA_XMLUtils.getChildNodeTextByPath( null, '/Body/Fault/faultstring' );\n        System.assertEquals( null, faultString );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void givenEmptyPathThenReturnNull() {\n\n        DOM.Document doc = new DOM.Document();\n        doc.load( getSoapFaultResponse( 'test error message' ) );\n\n        Test.startTest();\n\n        DOM.XmlNode child = MA_XMLUtils.getChildNodeByPath( doc.getRootElement(), '' );\n        System.assertEquals( null, child );\n\n        String faultString = MA_XMLUtils.getChildNodeTextByPath( doc.getRootElement(), null );\n        System.assertEquals( null, faultString );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void givenInvalidPathThenReturnNull() {\n\n        DOM.Document doc = new DOM.Document();\n        doc.load( getSoapFaultResponse( 'test error message' ) );\n\n        Test.startTest();\n\n        DOM.XmlNode child = MA_XMLUtils.getChildNodeByPath( doc.getRootElement(), '/Body/Fault/notFound' );\n        System.assertEquals( null, child );\n\n        String faultString = MA_XMLUtils.getChildNodeTextByPath( doc.getRootElement(), '/Body/Fault/notFound' );\n        System.assertEquals( null, faultString );\n\n        Test.stopTest();\n\n    }\n\n    @IsTest\n    static void givenValidPathThenReturnChild() {\n\n        DOM.Document doc = new DOM.Document();\n        doc.load( getSoapFaultResponse( 'test error message' ) );\n\n        Test.startTest();\n\n        DOM.XmlNode child = MA_XMLUtils.getChildNodeByPath( doc.getRootElement(), '/Body/Fault/faultcode' );\n        System.assertEquals( 'soapenv:Client', child.getText() );\n\n        String faultString = MA_XMLUtils.getChildNodeTextByPath( doc.getRootElement(), '/Body/Fault/faultstring' );\n        System.assertEquals( 'test error message', faultString );\n\n        Test.stopTest();\n\n    }\n\n    private static String getSoapFaultResponse( String faultString ) {\n        return (\n            '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' +\n            '<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">' +\n                '<soapenv:Body>' +\n                    '<soapenv:Fault>' +\n                        '<faultcode>soapenv:Client</faultcode>' +\n                        '<faultstring>' + faultString + '</faultstring>' +\n                    '</soapenv:Fault>' +\n                '</soapenv:Body>' +\n            '</soapenv:Envelope>'\n        );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/classes/MA_XMLUtilsTest.cls-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexClass xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexClass>\n"
  },
  {
    "path": "force-app/main/default/contentassets/maslogominimal.asset-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ContentAsset xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <isVisibleByExternalUsers>false</isVisibleByExternalUsers>\n    <language>en_US</language>\n    <masterLabel>maslogominimal</masterLabel>\n    <relationships>\n        <organization>\n            <access>VIEWER</access>\n        </organization>\n    </relationships>\n    <versions>\n        <version>\n            <number>1</number>\n            <pathOnClient>mas-logo-minimal.png</pathOnClient>\n        </version>\n    </versions>\n</ContentAsset>\n"
  },
  {
    "path": "force-app/main/default/flexipages/Mass_Action_Configuration_Record_Page.flexipage-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FlexiPage xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>collapsed</name>\n                    <value>false</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>numVisibleActions</name>\n                    <value>10</value>\n                </componentInstanceProperties>\n                <componentName>force:highlightsPanel</componentName>\n                <identifier>force_highlightsPanel</identifier>\n            </componentInstance>\n        </itemInstances>\n        <mode>Replace</mode>\n        <name>header</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>decorate</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>richTextValue</name>\n                    <value>&lt;span style=&quot;font-size:14px;&quot;&gt;&lt;span style=&quot;color:#B22222;&quot;&gt;&amp;nbsp; &amp;nbsp;Please use the&amp;nbsp;&lt;b&gt;Configure&lt;/b&gt;&amp;nbsp;tab to edit this record. Editing the record directly may cause errors or inability to run the configuration.&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:richText</componentName>\n                <identifier>flexipage_richText</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>relatedListComponentOverride</name>\n                    <value>ADVGRID</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>rowsToDisplay</name>\n                    <value>10</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>showActionBar</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentName>force:relatedListContainer</componentName>\n                <identifier>force_relatedListContainer</identifier>\n            </componentInstance>\n        </itemInstances>\n        <mode>Replace</mode>\n        <name>relatedTabContent</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>decorate</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>richTextValue</name>\n                    <value>&lt;div&gt;&lt;span style=&quot;font-size:14px;&quot;&gt;&lt;span style=&quot;color:#B22222;&quot;&gt;&amp;nbsp; &amp;nbsp;Please use the&amp;nbsp;&lt;b&gt;Configure&lt;/b&gt;&amp;nbsp;tab to edit this record. Editing the record directly may cause errors or inability to run the configuration.&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:richText</componentName>\n                <identifier>flexipage_richText2</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentName>force:detailPanel</componentName>\n                <identifier>force_detailPanel</identifier>\n            </componentInstance>\n        </itemInstances>\n        <mode>Replace</mode>\n        <name>detailTabContent</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentName>MA_EditConfigCmp</componentName>\n                <identifier>MA_EditConfigCmp</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>facet-2e32b50e-63c7-4cd4-8055-2ddfd1fb5aa2</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>relatedTabContent</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.relatedLists</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>relatedListsTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>active</name>\n                    <value>false</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>detailTabContent</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.detail</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>detailTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>active</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>facet-2e32b50e-63c7-4cd4-8055-2ddfd1fb5aa2</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Configure</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>customTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <mode>Replace</mode>\n        <name>maintabs</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>tabs</name>\n                    <value>maintabs</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tabset</componentName>\n                <identifier>flexipage_tabset</identifier>\n            </componentInstance>\n        </itemInstances>\n        <mode>Replace</mode>\n        <name>main</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>parentFieldApiName</name>\n                    <value>Mass_Action_Configuration__c.Id</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>relatedListApiName</name>\n                    <value>Mass_Action_Logs__r</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>relatedListComponentOverride</name>\n                    <value>ADVGRID</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>rowsToDisplay</name>\n                    <value>10</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>showActionBar</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentName>force:relatedListSingleContainer</componentName>\n                <identifier>force_relatedListSingleContainer</identifier>\n            </componentInstance>\n        </itemInstances>\n        <mode>Replace</mode>\n        <name>sidebar</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <masterLabel>Mass Action Configuration Record Page</masterLabel>\n    <parentFlexiPage>flexipage__default_rec_L</parentFlexiPage>\n    <sobjectType>Mass_Action_Configuration__c</sobjectType>\n    <template>\n        <name>flexipage:recordHomeTemplateDesktop</name>\n    </template>\n    <type>RecordPage</type>\n</FlexiPage>\n"
  },
  {
    "path": "force-app/main/default/flexipages/Mass_Action_Configuration_Record_Page_One_Column.flexipage-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FlexiPage xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>collapsed</name>\n                    <value>false</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>numVisibleActions</name>\n                    <value>3</value>\n                </componentInstanceProperties>\n                <componentName>force:highlightsPanel</componentName>\n                <identifier>force_highlightsPanel</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>header</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>decorate</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>richTextValue</name>\n                    <value>&lt;span style=&quot;color:#B22222;&quot;&gt;&lt;span style=&quot;font-size:14px;&quot;&gt;&amp;nbsp; &amp;nbsp; Please use the&amp;nbsp;&lt;b&gt;Configure&lt;/b&gt;&amp;nbsp;tab to edit this record. Editing the record directly may cause errors or inability to run the configuration.&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:richText</componentName>\n                <identifier>flexipage_richText</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>relatedListComponentOverride</name>\n                    <value>ADVGRID</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>rowsToDisplay</name>\n                    <value>10</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>showActionBar</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentName>force:relatedListContainer</componentName>\n                <identifier>force_relatedListContainer</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-d5b3947c-84c6-4271-8519-f0b60f6c7e42</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>decorate</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>richTextValue</name>\n                    <value>&lt;span style=&quot;color:#B22222;&quot;&gt;&lt;span style=&quot;font-size:14px;&quot;&gt;&amp;nbsp; &amp;nbsp; Please use the&amp;nbsp;&lt;b&gt;Configure&lt;/b&gt;&amp;nbsp;tab to edit this record. Editing the record directly may cause errors or inability to run the configuration.&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:richText</componentName>\n                <identifier>flexipage_richText2</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentName>force:detailPanel</componentName>\n                <identifier>force_detailPanel</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-1d7982e7-d8ee-454b-bb5a-768f3d0fdde3</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentName>MA_CheckForPackageUpdatesCmp</componentName>\n                <identifier>MA_CheckForPackageUpdatesCmp</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentName>MA_EditConfigCmp</componentName>\n                <identifier>MA_EditConfigCmp</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-a94fecbe-793f-4a27-bcbc-219b6ce5051b</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>parentFieldApiName</name>\n                    <value>Mass_Action_Configuration__c.Id</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>relatedListApiName</name>\n                    <value>Mass_Action_Parent_Logs__r</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>relatedListComponentOverride</name>\n                    <value>ADVGRID</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>rowsToDisplay</name>\n                    <value>10</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>showActionBar</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentName>force:relatedListSingleContainer</componentName>\n                <identifier>force_relatedListSingleContainer</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-iv1g6tv58r</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>active</name>\n                    <value>false</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>Facet-d5b3947c-84c6-4271-8519-f0b60f6c7e42</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.relatedLists</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>relatedListsTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>Facet-1d7982e7-d8ee-454b-bb5a-768f3d0fdde3</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.detail</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>detailTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>active</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>Facet-a94fecbe-793f-4a27-bcbc-219b6ce5051b</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Configure</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>customTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>Facet-iv1g6tv58r</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Logs</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>customTab2</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-c9680872-f740-4e9a-b886-fb55d50aa5c2</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>tabs</name>\n                    <value>Facet-c9680872-f740-4e9a-b886-fb55d50aa5c2</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tabset</componentName>\n                <identifier>flexipage_tabset</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentName>MA_DevelopedByCmp</componentName>\n                <identifier>MA_DevelopedByCmp</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>main</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <masterLabel>Mass Action Configuration Record Page - One Column</masterLabel>\n    <sobjectType>Mass_Action_Configuration__c</sobjectType>\n    <template>\n        <name>flexipage:recordHomeSingleColTemplateDesktop</name>\n    </template>\n    <type>RecordPage</type>\n</FlexiPage>\n"
  },
  {
    "path": "force-app/main/default/flexipages/Mass_Action_Log_Record_Page.flexipage-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FlexiPage xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>collapsed</name>\n                    <value>false</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>numVisibleActions</name>\n                    <value>3</value>\n                </componentInstanceProperties>\n                <componentName>force:highlightsPanel</componentName>\n                <identifier>force_highlightsPanel</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>header</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>relatedListComponentOverride</name>\n                    <value>ADVGRID</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>rowsToDisplay</name>\n                    <value>10</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>showActionBar</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentName>force:relatedListContainer</componentName>\n                <identifier>force_relatedListContainer</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-86a5136e-eab3-45a5-bc19-9e4674fb6ce8</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentName>force:detailPanel</componentName>\n                <identifier>force_detailPanel</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>detailTabContent</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>active</name>\n                    <value>true</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>Facet-86a5136e-eab3-45a5-bc19-9e4674fb6ce8</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.relatedLists</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>relatedListsTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>active</name>\n                    <value>false</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>detailTabContent</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.detail</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>detailTab</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>maintabs</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentName>force:detailPanel</componentName>\n                <identifier>force_detailPanel2</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-b4ad3ac9-e977-48e4-a8b1-99b112545a63</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>body</name>\n                    <value>Facet-b4ad3ac9-e977-48e4-a8b1-99b112545a63</value>\n                </componentInstanceProperties>\n                <componentInstanceProperties>\n                    <name>title</name>\n                    <value>Standard.Tab.detail</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tab</componentName>\n                <identifier>detailTab2</identifier>\n            </componentInstance>\n        </itemInstances>\n        <name>Facet-ca95ac52-a6b4-4cd4-bcf7-a602f68d6fca</name>\n        <type>Facet</type>\n    </flexiPageRegions>\n    <flexiPageRegions>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>tabs</name>\n                    <value>maintabs</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tabset</componentName>\n                <identifier>flexipage_tabset</identifier>\n                <visibilityRule>\n                    <criteria>\n                        <leftValue>{!Record.RecordType.DeveloperName}</leftValue>\n                        <operator>EQUAL</operator>\n                        <rightValue>Parent_Log</rightValue>\n                    </criteria>\n                </visibilityRule>\n            </componentInstance>\n        </itemInstances>\n        <itemInstances>\n            <componentInstance>\n                <componentInstanceProperties>\n                    <name>tabs</name>\n                    <value>Facet-ca95ac52-a6b4-4cd4-bcf7-a602f68d6fca</value>\n                </componentInstanceProperties>\n                <componentName>flexipage:tabset</componentName>\n                <identifier>flexipage_tabset2</identifier>\n                <visibilityRule>\n                    <criteria>\n                        <leftValue>{!Record.RecordType.DeveloperName}</leftValue>\n                        <operator>NE</operator>\n                        <rightValue>Parent_Log</rightValue>\n                    </criteria>\n                </visibilityRule>\n            </componentInstance>\n        </itemInstances>\n        <name>main</name>\n        <type>Region</type>\n    </flexiPageRegions>\n    <masterLabel>Mass Action Log Record Page</masterLabel>\n    <sobjectType>Mass_Action_Log__c</sobjectType>\n    <template>\n        <name>flexipage:recordHomeSingleColTemplateDesktop</name>\n    </template>\n    <type>RecordPage</type>\n</FlexiPage>\n"
  },
  {
    "path": "force-app/main/default/flows/MAS_Batch_Apex_Error_Event.flow-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Flow xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionCalls>\n        <name>eventContextErrorEmail</name>\n        <label>Context Error Email</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <actionName>emailSimple</actionName>\n        <actionType>emailSimple</actionType>\n        <inputParameters>\n            <name>emailSubject</name>\n            <value>\n                <stringValue>Salesforce MAS: Batch Apex Error Event process didn&#39;t start: No matching records found</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>emailBody</name>\n            <value>\n                <elementReference>noRecordsFoundTextTemplate</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>emailAddresses</name>\n            <value>\n                <stringValue>douglascayers+massactionscheduler@gmail.com</stringValue>\n            </value>\n        </inputParameters>\n    </actionCalls>\n    <actionCalls>\n        <name>eventContextMoreEmail</name>\n        <label>Context Error Email</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <actionName>emailSimple</actionName>\n        <actionType>emailSimple</actionType>\n        <inputParameters>\n            <name>emailSubject</name>\n            <value>\n                <stringValue>Salesforce MAS: Batch Apex Error Event process didn&#39;t start: Multiple matching records found</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>emailBody</name>\n            <value>\n                <elementReference>multipleRecordsFoundTextTemplate</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>emailAddresses</name>\n            <value>\n                <stringValue>douglascayers+massactionscheduler@gmail.com</stringValue>\n            </value>\n        </inputParameters>\n    </actionCalls>\n    <actionCalls>\n        <processMetadataValues>\n            <name>apexSelection</name>\n            <value>\n                <stringValue>MAS: Batch Apex Error Event Handler</stringValue>\n            </value>\n        </processMetadataValues>\n        <name>myRule_1_A1</name>\n        <label>Handle Batch Apex Error Event</label>\n        <locationX>100</locationX>\n        <locationY>200</locationY>\n        <actionName>MA_BatchApexErrorEventInvocable</actionName>\n        <actionType>apex</actionType>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Request ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>requestId</name>\n            <value>\n                <elementReference>myVariable_myEvent.RequestId</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Stack Trace</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>stackTrace</name>\n            <value>\n                <elementReference>myVariable_myEvent.StackTrace</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>DateTime</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Created Date</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>createdDate</name>\n            <value>\n                <elementReference>myVariable_myEvent.CreatedDate</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Created By ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>createdById</name>\n            <value>\n                <elementReference>myVariable_myEvent.CreatedById</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Replay ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>replayId</name>\n            <value>\n                <elementReference>myVariable_myEvent.ReplayId</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Async Apex Job ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>asyncApexJobId</name>\n            <value>\n                <elementReference>myVariable_myEvent.AsyncApexJobId</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Phase</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>phase</name>\n            <value>\n                <elementReference>myVariable_myEvent.Phase</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Message</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>message</name>\n            <value>\n                <elementReference>myVariable_myEvent.Message</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Exception Type</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>exceptionType</name>\n            <value>\n                <elementReference>myVariable_myEvent.ExceptionType</elementReference>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>Job Scope</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>0.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>jobScope</name>\n            <value>\n                <elementReference>myVariable_myEvent.JobScope</elementReference>\n            </value>\n        </inputParameters>\n    </actionCalls>\n    <assignments>\n        <name>RecordCountAssignment</name>\n        <label>RecordCountAssignment</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <assignmentItems>\n            <assignToReference>myVariable_event_record_count</assignToReference>\n            <operator>Add</operator>\n            <value>\n                <numberValue>1.0</numberValue>\n            </value>\n        </assignmentItems>\n        <assignmentItems>\n            <assignToReference>myVariable_event_context</assignToReference>\n            <operator>Assign</operator>\n            <value>\n                <elementReference>myVariable_event_current_record</elementReference>\n            </value>\n        </assignmentItems>\n        <connector>\n            <targetReference>eventContextCheckLoop</targetReference>\n        </connector>\n    </assignments>\n    <decisions>\n        <name>eventContextCheckDecision</name>\n        <label>ContextCheckDecision</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <defaultConnector>\n            <targetReference>myDecision</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>default</defaultConnectorLabel>\n        <rules>\n            <name>eventContextCheckRule</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>myVariable_event_record_count</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <numberValue>0.0</numberValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>eventContextErrorEmail</targetReference>\n            </connector>\n            <label>Context Check Decision - Is Zero</label>\n        </rules>\n        <rules>\n            <name>eventContextGtOneCheckRule</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>myVariable_event_record_count</leftValueReference>\n                <operator>GreaterThan</operator>\n                <rightValue>\n                    <numberValue>1.0</numberValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>eventContextMoreEmail</targetReference>\n            </connector>\n            <label>Context Check Decision - Greater than One</label>\n        </rules>\n    </decisions>\n    <decisions>\n        <processMetadataValues>\n            <name>index</name>\n            <value>\n                <numberValue>0.0</numberValue>\n            </value>\n        </processMetadataValues>\n        <name>myDecision</name>\n        <label>myDecision</label>\n        <locationX>50</locationX>\n        <locationY>0</locationY>\n        <defaultConnectorLabel>default</defaultConnectorLabel>\n        <rules>\n            <name>myRule_1</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>formula_myRule_1</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <booleanValue>true</booleanValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>myRule_1_A1</targetReference>\n            </connector>\n            <label>Always</label>\n        </rules>\n    </decisions>\n    <description>Subscribes to error events of batch Apex jobs to create Mass Action Logs.</description>\n    <formulas>\n        <name>formula_myRule_1</name>\n        <dataType>Boolean</dataType>\n        <expression>true</expression>\n    </formulas>\n    <formulas>\n        <name>OrganizationName</name>\n        <dataType>String</dataType>\n        <expression>{!$Organization.Name}</expression>\n    </formulas>\n    <interviewLabel>MAS_Batch_Apex_Error_Event-1_InterviewLabel</interviewLabel>\n    <label>MAS: Batch Apex Error Event</label>\n    <loops>\n        <name>eventContextCheckLoop</name>\n        <label>ContextCheckLoop</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <assignNextValueToReference>myVariable_event_current_record</assignNextValueToReference>\n        <collectionReference>myVariable_event_context_collection</collectionReference>\n        <iterationOrder>Asc</iterationOrder>\n        <nextValueConnector>\n            <targetReference>RecordCountAssignment</targetReference>\n        </nextValueConnector>\n        <noMoreValuesConnector>\n            <targetReference>eventContextCheckDecision</targetReference>\n        </noMoreValuesConnector>\n    </loops>\n    <processMetadataValues>\n        <name>EventType</name>\n        <value>\n            <stringValue>BatchApexErrorEvent</stringValue>\n        </value>\n    </processMetadataValues>\n    <processMetadataValues>\n        <name>ObjectType</name>\n        <value>\n            <stringValue>User</stringValue>\n        </value>\n    </processMetadataValues>\n    <processType>CustomEvent</processType>\n    <recordLookups>\n        <name>myEventContextRecordLookup</name>\n        <label>myEventContextRecordLookup</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>\n        <connector>\n            <targetReference>eventContextCheckLoop</targetReference>\n        </connector>\n        <filters>\n            <processMetadataValues>\n                <name>implicit</name>\n                <value>\n                    <booleanValue>false</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>inputDataType</name>\n                <value>\n                    <stringValue>ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>User ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideReferenceTo</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideType</name>\n                <value>\n                    <stringValue>ID</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>operatorDataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>Event</stringValue>\n                </value>\n            </processMetadataValues>\n            <field>Id</field>\n            <operator>EqualTo</operator>\n            <value>\n                <elementReference>myVariable_myEvent.CreatedById</elementReference>\n            </value>\n        </filters>\n        <object>User</object>\n        <outputReference>myVariable_event_context_collection</outputReference>\n    </recordLookups>\n    <startElementReference>myEventContextRecordLookup</startElementReference>\n    <status>Active</status>\n    <textTemplates>\n        <description>text template for when multiple records are records found</description>\n        <name>multipleRecordsFoundTextTemplate</name>\n        <text>Hello {!OrganizationName} Admin, \n\nThe MAS: Batch Apex Error Event process is configured to start when a Batch Apex Error Platform Event platform event message occurs. A Batch Apex Error Platform Event message occurred, but the process didn&#39;t start because multiple records in your org match the values specified in the process&#39;s Object node.\n\nHere are the values from the Batch Apex Error Platform Event message.\nCreated By ID: {!myVariable_myEvent.CreatedById}\n\nTo fix this issue, adjust the matching filters in the process&#39;s Object node.\n\nThank you, \nSalesforce Process Automation</text>\n    </textTemplates>\n    <textTemplates>\n        <description>text template for no records found</description>\n        <name>noRecordsFoundTextTemplate</name>\n        <text>Hello {!OrganizationName} Admin, \n\nThe MAS: Batch Apex Error Event process is configured to start when a Batch Apex Error Platform Event platform event message occurs. A Batch Apex Error Platform Event message occurred, but the process didn&#39;t start because no records in your org match the values specified in the process&#39;s Object node.\n\nHere are the values from the Batch Apex Error Platform Event message.\nCreated By ID: {!myVariable_myEvent.CreatedById}\n\nTo fix this issue, adjust the matching filters in the process&#39;s Object node.\n\nThank you, \nSalesforce Process Automation</text>\n    </textTemplates>\n    <variables>\n        <name>myVariable_event_context</name>\n        <dataType>SObject</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>true</isOutput>\n        <objectType>User</objectType>\n    </variables>\n    <variables>\n        <name>myVariable_event_context_collection</name>\n        <dataType>SObject</dataType>\n        <isCollection>true</isCollection>\n        <isInput>true</isInput>\n        <isOutput>true</isOutput>\n        <objectType>User</objectType>\n    </variables>\n    <variables>\n        <name>myVariable_event_current_record</name>\n        <dataType>SObject</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>true</isOutput>\n        <objectType>User</objectType>\n    </variables>\n    <variables>\n        <name>myVariable_event_record_count</name>\n        <dataType>Number</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>true</isOutput>\n        <scale>2</scale>\n        <value>\n            <numberValue>0.0</numberValue>\n        </value>\n    </variables>\n    <variables>\n        <name>myVariable_myEvent</name>\n        <dataType>SObject</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>false</isOutput>\n        <objectType>BatchApexErrorEvent</objectType>\n    </variables>\n</Flow>\n"
  },
  {
    "path": "force-app/main/default/flows/MAS_Mass_Action_Configuration.flow-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Flow xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionCalls>\n        <processMetadataValues>\n            <name>customNotifTypeName</name>\n            <value>\n                <stringValue>Mass_Action_Notification</stringValue>\n            </value>\n        </processMetadataValues>\n        <processMetadataValues>\n            <name>recipientCategory</name>\n            <value>\n                <stringValue>owner</stringValue>\n            </value>\n        </processMetadataValues>\n        <processMetadataValues>\n            <name>recipientType</name>\n            <value>\n                <stringValue>reference</stringValue>\n            </value>\n        </processMetadataValues>\n        <name>myRule_1_A1</name>\n        <label>Send Notification</label>\n        <locationX>100</locationX>\n        <locationY>200</locationY>\n        <actionName>customNotificationAction</actionName>\n        <actionType>customNotificationAction</actionType>\n        <inputParameters>\n            <name>customNotifTypeId</name>\n            <value>\n                <stringValue>000000000000000</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>customNotifTypeName</name>\n            <value>\n                <stringValue>Mass_Action_Notification</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>title</name>\n            <value>\n                <stringValue>{!myVariable_current.Name}</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>body</name>\n            <value>\n                <stringValue>✅ Mass Action Scheduler completed.</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>targetId</name>\n            <value>\n                <stringValue>{!myVariable_current.Id}</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>recipientIds</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>500.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>recipientIds</name>\n            <value>\n                <elementReference>myCollection_myRule_1_A1recipientIds</elementReference>\n            </value>\n        </inputParameters>\n    </actionCalls>\n    <actionCalls>\n        <processMetadataValues>\n            <name>customNotifTypeName</name>\n            <value>\n                <stringValue>Mass_Action_Notification</stringValue>\n            </value>\n        </processMetadataValues>\n        <processMetadataValues>\n            <name>recipientCategory</name>\n            <value>\n                <stringValue>owner</stringValue>\n            </value>\n        </processMetadataValues>\n        <processMetadataValues>\n            <name>recipientType</name>\n            <value>\n                <stringValue>reference</stringValue>\n            </value>\n        </processMetadataValues>\n        <name>myRule_4_A1</name>\n        <label>Send Notification</label>\n        <locationX>400</locationX>\n        <locationY>200</locationY>\n        <actionName>customNotificationAction</actionName>\n        <actionType>customNotificationAction</actionType>\n        <inputParameters>\n            <name>customNotifTypeId</name>\n            <value>\n                <stringValue>000000000000000</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>customNotifTypeName</name>\n            <value>\n                <stringValue>Mass_Action_Notification</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>title</name>\n            <value>\n                <stringValue>{!myVariable_current.Name}</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>body</name>\n            <value>\n                <stringValue>🚫 Mass Action Scheduler completed with errors.</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <name>targetId</name>\n            <value>\n                <stringValue>{!myVariable_current.Id}</stringValue>\n            </value>\n        </inputParameters>\n        <inputParameters>\n            <processMetadataValues>\n                <name>dataType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>isRequired</name>\n                <value>\n                    <booleanValue>true</booleanValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>leftHandSideLabel</name>\n                <value>\n                    <stringValue>recipientIds</stringValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>maxOccurs</name>\n                <value>\n                    <numberValue>500.0</numberValue>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>objectType</name>\n                <value>\n                    <stringValue/>\n                </value>\n            </processMetadataValues>\n            <processMetadataValues>\n                <name>rightHandSideType</name>\n                <value>\n                    <stringValue>String</stringValue>\n                </value>\n            </processMetadataValues>\n            <name>recipientIds</name>\n            <value>\n                <elementReference>myCollection_myRule_4_A1recipientIds</elementReference>\n            </value>\n        </inputParameters>\n    </actionCalls>\n    <assignments>\n        <name>myAssignment_myRule_1_A1</name>\n        <label>myAssignment_myRule_1_A1</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <assignmentItems>\n            <assignToReference>myCollection_myRule_1_A1recipientIds</assignToReference>\n            <operator>Add</operator>\n            <value>\n                <elementReference>myVariable_current.OwnerId</elementReference>\n            </value>\n        </assignmentItems>\n        <connector>\n            <targetReference>myRule_1_A1</targetReference>\n        </connector>\n    </assignments>\n    <assignments>\n        <name>myAssignment_myRule_4_A1</name>\n        <label>myAssignment_myRule_4_A1</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <assignmentItems>\n            <assignToReference>myCollection_myRule_4_A1recipientIds</assignToReference>\n            <operator>Add</operator>\n            <value>\n                <elementReference>myVariable_current.OwnerId</elementReference>\n            </value>\n        </assignmentItems>\n        <connector>\n            <targetReference>myRule_4_A1</targetReference>\n        </connector>\n    </assignments>\n    <decisions>\n        <name>isChangedDecision2_myRule_1_dca_mass_action_Last_Run_Completed_Date_c</name>\n        <label>isChangedDecision2_myRule_1_dca_mass_action_Last_Run_Completed_Date_c</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <defaultConnector>\n            <targetReference>isChangedDecision5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>default</defaultConnectorLabel>\n        <rules>\n            <name>isChangedRule_2_myRule_1_dca_mass_action_Last_Run_Completed_Date_c</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>myVariable_old</leftValueReference>\n                <operator>IsNull</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <conditions>\n                <leftValueReference>myVariable_old.Last_Run_Completed_Date__c</leftValueReference>\n                <operator>NotEqualTo</operator>\n                <rightValue>\n                    <elementReference>myVariable_current.Last_Run_Completed_Date__c</elementReference>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>isChangedDecision5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</targetReference>\n            </connector>\n            <label>isChangedRule_2_myRule_1_dca_mass_action_Last_Run_Completed_Date_c</label>\n        </rules>\n    </decisions>\n    <decisions>\n        <name>isChangedDecision5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</name>\n        <label>isChangedDecision5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</label>\n        <locationX>0</locationX>\n        <locationY>0</locationY>\n        <defaultConnector>\n            <targetReference>myDecision</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>default</defaultConnectorLabel>\n        <rules>\n            <name>isChangedRule_5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>myVariable_old</leftValueReference>\n                <operator>IsNull</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <conditions>\n                <leftValueReference>myVariable_old.Last_Run_Completed_Date__c</leftValueReference>\n                <operator>NotEqualTo</operator>\n                <rightValue>\n                    <elementReference>myVariable_current.Last_Run_Completed_Date__c</elementReference>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>myDecision</targetReference>\n            </connector>\n            <label>isChangedRule_5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</label>\n        </rules>\n    </decisions>\n    <decisions>\n        <processMetadataValues>\n            <name>index</name>\n            <value>\n                <numberValue>0.0</numberValue>\n            </value>\n        </processMetadataValues>\n        <name>myDecision</name>\n        <label>myDecision</label>\n        <locationX>50</locationX>\n        <locationY>0</locationY>\n        <defaultConnector>\n            <targetReference>myDecision3</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>default</defaultConnectorLabel>\n        <rules>\n            <name>myRule_1</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <processMetadataValues>\n                    <name>inputDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>leftHandSideType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>operatorDataType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>rightHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <leftValueReference>myVariable_current.Last_Run_Completed_Date__c</leftValueReference>\n                <operator>IsNull</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <conditions>\n                <processMetadataValues>\n                    <name>inputDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>leftHandSideType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>operatorDataType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>rightHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <leftValueReference>isChangedRule_2_myRule_1_dca_mass_action_Last_Run_Completed_Date_c</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <booleanValue>true</booleanValue>\n                </rightValue>\n            </conditions>\n            <conditions>\n                <processMetadataValues>\n                    <name>inputDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>leftHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>operatorDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>rightHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <leftValueReference>myVariable_current.Last_Run_Completed_With_Errors__c</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>myAssignment_myRule_1_A1</targetReference>\n            </connector>\n            <label>Batch Job Completed (success)</label>\n        </rules>\n    </decisions>\n    <decisions>\n        <processMetadataValues>\n            <name>index</name>\n            <value>\n                <numberValue>1.0</numberValue>\n            </value>\n        </processMetadataValues>\n        <name>myDecision3</name>\n        <label>myDecision3</label>\n        <locationX>50</locationX>\n        <locationY>0</locationY>\n        <defaultConnectorLabel>default</defaultConnectorLabel>\n        <rules>\n            <name>myRule_4</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <processMetadataValues>\n                    <name>inputDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>leftHandSideType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>operatorDataType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>rightHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <leftValueReference>myVariable_current.Last_Run_Completed_Date__c</leftValueReference>\n                <operator>IsNull</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <conditions>\n                <processMetadataValues>\n                    <name>inputDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>leftHandSideType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>operatorDataType</name>\n                    <value>\n                        <stringValue>DateTime</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>rightHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <leftValueReference>isChangedRule_5_myRule_4_dca_mass_action_Last_Run_Completed_Date_c</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <booleanValue>true</booleanValue>\n                </rightValue>\n            </conditions>\n            <conditions>\n                <processMetadataValues>\n                    <name>inputDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>leftHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>operatorDataType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <processMetadataValues>\n                    <name>rightHandSideType</name>\n                    <value>\n                        <stringValue>Boolean</stringValue>\n                    </value>\n                </processMetadataValues>\n                <leftValueReference>myVariable_current.Last_Run_Completed_With_Errors__c</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <booleanValue>true</booleanValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>myAssignment_myRule_4_A1</targetReference>\n            </connector>\n            <label>Batch Job Completed (errors)</label>\n        </rules>\n    </decisions>\n    <description>Automates user notifications when a configuration run completes.</description>\n    <interviewLabel>MAS_Mass_Action_Configuration-1_InterviewLabel</interviewLabel>\n    <label>MAS: Mass Action Configuration</label>\n    <processMetadataValues>\n        <name>ObjectType</name>\n        <value>\n            <stringValue>Mass_Action_Configuration__c</stringValue>\n        </value>\n    </processMetadataValues>\n    <processMetadataValues>\n        <name>ObjectVariable</name>\n        <value>\n            <elementReference>myVariable_current</elementReference>\n        </value>\n    </processMetadataValues>\n    <processMetadataValues>\n        <name>OldObjectVariable</name>\n        <value>\n            <elementReference>myVariable_old</elementReference>\n        </value>\n    </processMetadataValues>\n    <processMetadataValues>\n        <name>TriggerType</name>\n        <value>\n            <stringValue>onAllChanges</stringValue>\n        </value>\n    </processMetadataValues>\n    <processType>Workflow</processType>\n    <startElementReference>isChangedDecision2_myRule_1_dca_mass_action_Last_Run_Completed_Date_c</startElementReference>\n    <status>Active</status>\n    <variables>\n        <name>myCollection_myRule_1_A1recipientIds</name>\n        <dataType>String</dataType>\n        <isCollection>true</isCollection>\n        <isInput>false</isInput>\n        <isOutput>false</isOutput>\n    </variables>\n    <variables>\n        <name>myCollection_myRule_4_A1recipientIds</name>\n        <dataType>String</dataType>\n        <isCollection>true</isCollection>\n        <isInput>false</isInput>\n        <isOutput>false</isOutput>\n    </variables>\n    <variables>\n        <name>myVariable_current</name>\n        <dataType>SObject</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>true</isOutput>\n        <objectType>Mass_Action_Configuration__c</objectType>\n    </variables>\n    <variables>\n        <name>myVariable_old</name>\n        <dataType>SObject</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>false</isOutput>\n        <objectType>Mass_Action_Configuration__c</objectType>\n    </variables>\n</Flow>\n"
  },
  {
    "path": "force-app/main/default/flows/MAS_Run_Mass_Action_Flow.flow-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Flow xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionCalls>\n        <description>Runs a Mass Action Configuration record now, despite it&#39;s normal schedule.</description>\n        <name>Run_Mass_Action</name>\n        <label>Run Mass Action</label>\n        <locationX>1114</locationX>\n        <locationY>59</locationY>\n        <actionName>MA_RunConfigInvocable</actionName>\n        <actionType>apex</actionType>\n        <connector>\n            <targetReference>Set_Stage_3</targetReference>\n        </connector>\n        <inputParameters>\n            <name>configUniqueName</name>\n            <value>\n                <elementReference>varConfigRecord.DeveloperName__c</elementReference>\n            </value>\n        </inputParameters>\n        <outputParameters>\n            <assignToReference>varJobId</assignToReference>\n            <name>jobId</name>\n        </outputParameters>\n    </actionCalls>\n    <assignments>\n        <description>The stages are visualized by a path component on each screen.</description>\n        <name>Set_Stage_1</name>\n        <label>Set Stage 1</label>\n        <locationX>591</locationX>\n        <locationY>58</locationY>\n        <assignmentItems>\n            <assignToReference>$Flow.CurrentStage</assignToReference>\n            <operator>Assign</operator>\n            <value>\n                <elementReference>Stage_01_Choose_Action</elementReference>\n            </value>\n        </assignmentItems>\n        <connector>\n            <targetReference>ChooseActionScreen</targetReference>\n        </connector>\n    </assignments>\n    <assignments>\n        <description>The stages are visualized by a path component on each screen.</description>\n        <name>Set_Stage_2</name>\n        <label>Set Stage 2</label>\n        <locationX>773</locationX>\n        <locationY>282</locationY>\n        <assignmentItems>\n            <assignToReference>$Flow.CurrentStage</assignToReference>\n            <operator>Assign</operator>\n            <value>\n                <elementReference>Stage_02_Confirm_Action</elementReference>\n            </value>\n        </assignmentItems>\n        <connector>\n            <targetReference>ConfirmActionScreen</targetReference>\n        </connector>\n    </assignments>\n    <assignments>\n        <description>The stages are visualized by a path component on each screen.</description>\n        <name>Set_Stage_3</name>\n        <label>Set Stage 3</label>\n        <locationX>1259</locationX>\n        <locationY>59</locationY>\n        <assignmentItems>\n            <assignToReference>$Flow.CurrentStage</assignToReference>\n            <operator>Assign</operator>\n            <value>\n                <elementReference>Stage_03_Summary</elementReference>\n            </value>\n        </assignmentItems>\n        <connector>\n            <targetReference>ReviewActionScreen</targetReference>\n        </connector>\n    </assignments>\n    <choices>\n        <description>On the Choose Action screen, this is the default choice listed to prompt user to make a selection.</description>\n        <name>Choice_ChooseActionPlaceholder</name>\n        <choiceText>Choose a Mass Action Configuration</choiceText>\n        <dataType>String</dataType>\n    </choices>\n    <choices>\n        <description>On the Confirm Action screen, this choice indicates the user wants to be routed back to choose a different configuration.</description>\n        <name>Choice_ConfirmActionChange</name>\n        <choiceText>Choose a different configuration</choiceText>\n        <dataType>String</dataType>\n        <value>\n            <stringValue>ChooseNewConfigurationToRun</stringValue>\n        </value>\n    </choices>\n    <choices>\n        <description>On the Confirm Action screen, this choice indicates the user wants to run the selected configuration.</description>\n        <name>Choice_ConfirmActionRun</name>\n        <choiceText>{!varConfigRecord.Name}</choiceText>\n        <dataType>String</dataType>\n        <value>\n            <elementReference>varConfigRecord.DeveloperName__c</elementReference>\n        </value>\n    </choices>\n    <decisions>\n        <description>Determines if the `recordId` input variable was provided or not. If yes, go to the Confirm Action screen, otherwise go to the Choose Action screen.</description>\n        <name>Decision_Have_Record_Id</name>\n        <label>Have Record Id?</label>\n        <locationX>236</locationX>\n        <locationY>52</locationY>\n        <defaultConnector>\n            <targetReference>Set_Stage_1</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>No</defaultConnectorLabel>\n        <rules>\n            <name>Decision_Have_Record_Id_Yes</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>recordId</leftValueReference>\n                <operator>IsNull</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>Get_Config_Record_By_Id</targetReference>\n            </connector>\n            <label>Yes</label>\n        </rules>\n    </decisions>\n    <decisions>\n        <description>Route to next step based on user&#39;s choice on the Confirm Action screen: run the selected configuration or choose a different one.</description>\n        <name>Decision_Run_Config</name>\n        <label>Run Config?</label>\n        <locationX>928</locationX>\n        <locationY>59</locationY>\n        <defaultConnector>\n            <targetReference>Set_Stage_1</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>No</defaultConnectorLabel>\n        <rules>\n            <name>Decision_Run_Config_Yes</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>ConfirmActionOption</leftValueReference>\n                <operator>EqualTo</operator>\n                <rightValue>\n                    <elementReference>Choice_ConfirmActionRun</elementReference>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>Run_Mass_Action</targetReference>\n            </connector>\n            <label>Yes</label>\n        </rules>\n    </decisions>\n    <decisions>\n        <description>Prevent moving to next screen if the user did not make a valid selection.</description>\n        <name>Decision_Validate_Choice</name>\n        <label>Validate Choice</label>\n        <locationX>581</locationX>\n        <locationY>285</locationY>\n        <defaultConnector>\n            <targetReference>Set_Stage_1</targetReference>\n        </defaultConnector>\n        <defaultConnectorLabel>Invalid</defaultConnectorLabel>\n        <rules>\n            <name>Decision_Validate_Choice_Valid</name>\n            <conditionLogic>and</conditionLogic>\n            <conditions>\n                <leftValueReference>varConfigRecord</leftValueReference>\n                <operator>IsNull</operator>\n                <rightValue>\n                    <booleanValue>false</booleanValue>\n                </rightValue>\n            </conditions>\n            <connector>\n                <targetReference>Set_Stage_2</targetReference>\n            </connector>\n            <label>Valid</label>\n        </rules>\n    </decisions>\n    <description>Prompts user to choose an active Mass Action Configuration to run. Upon user confirmation, the flow submits the configuration and displays the batch job id.</description>\n    <dynamicChoiceSets>\n        <description>List of active Mass Action Configuration records the user may choose to run. Note that when a user makes a selection, we set the `recordId` input variable. This allows the flow to navigate to the beginning again and start as if it had been given a selection so that we can reuse the &quot;Get By Id&quot; action without duplicating logic or needing an extra Assignment step.</description>\n        <name>varConfigRecordChoices</name>\n        <dataType>String</dataType>\n        <displayField>Name</displayField>\n        <filters>\n            <field>Active__c</field>\n            <operator>EqualTo</operator>\n            <value>\n                <booleanValue>true</booleanValue>\n            </value>\n        </filters>\n        <object>Mass_Action_Configuration__c</object>\n        <outputAssignments>\n            <assignToReference>recordId</assignToReference>\n            <field>Id</field>\n        </outputAssignments>\n        <sortField>Name</sortField>\n        <sortOrder>Asc</sortOrder>\n        <valueField>Id</valueField>\n    </dynamicChoiceSets>\n    <formulas>\n        <description>Mass Action Scheduler app standardizes on showing users the 15 character batch job id. This makes it easy to copy/paste the value to cross reference on the Apex Jobs page in Setup and the Mass Action Log records.</description>\n        <name>varJobId15</name>\n        <dataType>String</dataType>\n        <expression>LEFT({!varJobId}, 15)</expression>\n    </formulas>\n    <interviewLabel>MAS: Run Mass Action Flow {!$Flow.CurrentDateTime}</interviewLabel>\n    <isTemplate>true</isTemplate>\n    <label>MAS: Run Mass Action Flow</label>\n    <processMetadataValues>\n        <name>BuilderType</name>\n        <value>\n            <stringValue>LightningFlowBuilder</stringValue>\n        </value>\n    </processMetadataValues>\n    <processMetadataValues>\n        <name>OriginBuilderType</name>\n        <value>\n            <stringValue>LightningFlowBuilder</stringValue>\n        </value>\n    </processMetadataValues>\n    <processType>Flow</processType>\n    <recordLookups>\n        <description>Query the configuration record identified by the `recordId` input variable. If found, we will use it as the default choice for which configuration to run.</description>\n        <name>Get_Config_Record_By_Id</name>\n        <label>Get By Id</label>\n        <locationX>244</locationX>\n        <locationY>284</locationY>\n        <assignNullValuesIfNoRecordsFound>true</assignNullValuesIfNoRecordsFound>\n        <connector>\n            <targetReference>Decision_Validate_Choice</targetReference>\n        </connector>\n        <filters>\n            <field>Active__c</field>\n            <operator>EqualTo</operator>\n            <value>\n                <booleanValue>true</booleanValue>\n            </value>\n        </filters>\n        <filters>\n            <field>Id</field>\n            <operator>EqualTo</operator>\n            <value>\n                <elementReference>recordId</elementReference>\n            </value>\n        </filters>\n        <object>Mass_Action_Configuration__c</object>\n        <outputReference>varConfigRecord</outputReference>\n        <queriedFields>Id</queriedFields>\n        <queriedFields>Name</queriedFields>\n        <queriedFields>DeveloperName__c</queriedFields>\n        <sortField>Id</sortField>\n        <sortOrder>Asc</sortOrder>\n    </recordLookups>\n    <screens>\n        <description>Prompt user to choose an active Mass Action Configuration record to run.</description>\n        <name>ChooseActionScreen</name>\n        <label>Choose Action</label>\n        <locationX>422</locationX>\n        <locationY>128</locationY>\n        <allowBack>false</allowBack>\n        <allowFinish>true</allowFinish>\n        <allowPause>false</allowPause>\n        <connector>\n            <targetReference>Decision_Have_Record_Id</targetReference>\n        </connector>\n        <fields>\n            <name>ChooseActionPath</name>\n            <extensionName>c:MA_FlowStagePathCmp</extensionName>\n            <fieldType>ComponentInstance</fieldType>\n            <inputParameters>\n                <name>currentStage</name>\n                <value>\n                    <elementReference>$Flow.CurrentStage</elementReference>\n                </value>\n            </inputParameters>\n            <inputParameters>\n                <name>stages</name>\n                <value>\n                    <elementReference>$Flow.ActiveStages</elementReference>\n                </value>\n            </inputParameters>\n            <isRequired>true</isRequired>\n        </fields>\n        <fields>\n            <name>ChooseActionConfigId</name>\n            <choiceReferences>Choice_ChooseActionPlaceholder</choiceReferences>\n            <choiceReferences>varConfigRecordChoices</choiceReferences>\n            <dataType>String</dataType>\n            <defaultSelectedChoiceReference>Choice_ChooseActionPlaceholder</defaultSelectedChoiceReference>\n            <fieldText>Mass Action Configuration</fieldText>\n            <fieldType>DropdownBox</fieldType>\n            <isRequired>true</isRequired>\n        </fields>\n        <fields>\n            <name>ChooseActionNote</name>\n            <fieldText>&lt;p&gt;Only active configurations are available to run.&lt;/p&gt;</fieldText>\n            <fieldType>DisplayText</fieldType>\n        </fields>\n        <showFooter>true</showFooter>\n        <showHeader>false</showHeader>\n    </screens>\n    <screens>\n        <description>Provide user an opportunity to confirm the action to run.</description>\n        <name>ConfirmActionScreen</name>\n        <label>Confirm Action</label>\n        <locationX>936</locationX>\n        <locationY>282</locationY>\n        <allowBack>false</allowBack>\n        <allowFinish>true</allowFinish>\n        <allowPause>false</allowPause>\n        <connector>\n            <targetReference>Decision_Run_Config</targetReference>\n        </connector>\n        <fields>\n            <name>ConfirmActionPath</name>\n            <extensionName>c:MA_FlowStagePathCmp</extensionName>\n            <fieldType>ComponentInstance</fieldType>\n            <inputParameters>\n                <name>currentStage</name>\n                <value>\n                    <elementReference>$Flow.CurrentStage</elementReference>\n                </value>\n            </inputParameters>\n            <inputParameters>\n                <name>stages</name>\n                <value>\n                    <elementReference>$Flow.ActiveStages</elementReference>\n                </value>\n            </inputParameters>\n            <isRequired>true</isRequired>\n        </fields>\n        <fields>\n            <name>ConfirmActionOption</name>\n            <choiceReferences>Choice_ConfirmActionRun</choiceReferences>\n            <choiceReferences>Choice_ConfirmActionChange</choiceReferences>\n            <dataType>String</dataType>\n            <defaultSelectedChoiceReference>Choice_ConfirmActionRun</defaultSelectedChoiceReference>\n            <fieldText>Confirm Action</fieldText>\n            <fieldType>RadioButtons</fieldType>\n            <isRequired>true</isRequired>\n        </fields>\n        <showFooter>true</showFooter>\n        <showHeader>false</showHeader>\n    </screens>\n    <screens>\n        <description>Show user the batch job id that was submitted. They can use it to look up job details and log records to track progress.</description>\n        <name>ReviewActionScreen</name>\n        <label>Review Action</label>\n        <locationX>1395</locationX>\n        <locationY>59</locationY>\n        <allowBack>false</allowBack>\n        <allowFinish>true</allowFinish>\n        <allowPause>false</allowPause>\n        <fields>\n            <name>ReviewActionPath</name>\n            <extensionName>c:MA_FlowStagePathCmp</extensionName>\n            <fieldType>ComponentInstance</fieldType>\n            <inputParameters>\n                <name>currentStage</name>\n                <value>\n                    <elementReference>$Flow.CurrentStage</elementReference>\n                </value>\n            </inputParameters>\n            <inputParameters>\n                <name>stages</name>\n                <value>\n                    <elementReference>$Flow.ActiveStages</elementReference>\n                </value>\n            </inputParameters>\n            <isRequired>true</isRequired>\n        </fields>\n        <fields>\n            <name>ReviewActionNote</name>\n            <fieldText>&lt;p&gt;&lt;b style=&quot;font-size: 14px;&quot;&gt;Mass Action Configuration&lt;/b&gt;&lt;/p&gt;&lt;p&gt;{!varConfigRecord.Name}&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;b style=&quot;font-size: 14px;&quot;&gt;Batch Job Submitted&lt;/b&gt;&lt;/p&gt;&lt;p&gt;{!varJobId15}&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;Review the related Mass Action Logs for progress updates and any error messages.&lt;/p&gt;</fieldText>\n            <fieldType>DisplayText</fieldType>\n        </fields>\n        <showFooter>true</showFooter>\n        <showHeader>false</showHeader>\n    </screens>\n    <stages>\n        <name>Stage_01_Choose_Action</name>\n        <isActive>true</isActive>\n        <label>Choose Action</label>\n        <stageOrder>1</stageOrder>\n    </stages>\n    <stages>\n        <name>Stage_02_Confirm_Action</name>\n        <isActive>true</isActive>\n        <label>Confirm Action</label>\n        <stageOrder>2</stageOrder>\n    </stages>\n    <stages>\n        <name>Stage_03_Summary</name>\n        <isActive>true</isActive>\n        <label>Summary</label>\n        <stageOrder>3</stageOrder>\n    </stages>\n    <startElementReference>Decision_Have_Record_Id</startElementReference>\n    <status>Active</status>\n    <variables>\n        <description>The id of the Mass Action Configuration record where the flow was launched by a quick action on the record page. If your flow has a Text input variable called `recordId`, the quick action passes the record&#39;s ID into that variable at runtime. If not, it doesn&#39;t and the flow tries to run anyway. This is how we can pre-select the configuration record in the flow.</description>\n        <name>recordId</name>\n        <dataType>String</dataType>\n        <isCollection>false</isCollection>\n        <isInput>true</isInput>\n        <isOutput>false</isOutput>\n    </variables>\n    <variables>\n        <description>The currently selected Mass Action Configuration record to run.</description>\n        <name>varConfigRecord</name>\n        <dataType>SObject</dataType>\n        <isCollection>false</isCollection>\n        <isInput>false</isInput>\n        <isOutput>false</isOutput>\n        <objectType>Mass_Action_Configuration__c</objectType>\n    </variables>\n    <variables>\n        <description>The batch id after submitting the selected Mass Action Configuration record.</description>\n        <name>varJobId</name>\n        <dataType>String</dataType>\n        <isCollection>false</isCollection>\n        <isInput>false</isInput>\n        <isOutput>true</isOutput>\n    </variables>\n</Flow>\n"
  },
  {
    "path": "force-app/main/default/layouts/Mass_Action_Configuration__c-Mass Action Configuration Layout.layout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Layout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <excludeButtons>ChangeOwnerOne</excludeButtons>\n    <excludeButtons>ChangeRecordType</excludeButtons>\n    <excludeButtons>Clone</excludeButtons>\n    <excludeButtons>Share</excludeButtons>\n    <excludeButtons>Submit</excludeButtons>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Name</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>DeveloperName__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Named_Credential__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>OwnerId</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Active__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Batch_Size__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>false</editHeading>\n        <label>Description Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Description__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Last Job Run Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Last_Run_Completed_Date__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Last_Run_Completed_With_Errors__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Source Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Source_Type__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Source_Report_ID__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Source_Report_Column_Name__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Source_List_View_ID__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Source_SOQL_Query__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Source_Apex_Class__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Target Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Target_Type__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Target_SObject_Type__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Target_Action_Name__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Target_Apex_Script__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Schedule Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_Frequency__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_SecondOfMinute__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_MinuteOfHour__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_HourOfDay__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_DayOfMonth__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_MonthOfYear__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_DayOfWeek__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Edit</behavior>\n                <field>Schedule_Cron__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>System Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>CreatedById</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>LastModifiedById</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Custom Links</label>\n        <layoutColumns/>\n        <layoutColumns/>\n        <layoutColumns/>\n        <style>CustomLinks</style>\n    </layoutSections>\n    <miniLayout>\n        <fields>Name</fields>\n        <fields>Source_Type__c</fields>\n        <fields>Target_Type__c</fields>\n        <fields>Active__c</fields>\n    </miniLayout>\n    <platformActionList>\n        <actionListContext>Record</actionListContext>\n        <platformActionListItems>\n            <actionName>FeedItem.TextPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>0</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.ContentPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>1</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.LinkPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>2</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Mass_Action_Configuration__c.Run_via_Flow</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>3</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Mass_Action_Configuration__c.Quick_Edit</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>4</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Delete</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>5</sortOrder>\n        </platformActionListItems>\n    </platformActionList>\n    <quickActionList>\n        <quickActionListItems>\n            <quickActionName>FeedItem.TextPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.ContentPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.LinkPost</quickActionName>\n        </quickActionListItems>\n    </quickActionList>\n    <relatedLists>\n        <fields>NAME</fields>\n        <fields>Source_Field_Name__c</fields>\n        <fields>Target_Field_Name__c</fields>\n        <relatedList>Mass_Action_Mapping__c.Mass_Action_Configuration__c</relatedList>\n        <sortField>Source_Field_Name__c</sortField>\n        <sortOrder>Asc</sortOrder>\n    </relatedLists>\n    <relatedLists>\n        <fields>NAME</fields>\n        <fields>Job_ID__c</fields>\n        <fields>Message__c</fields>\n        <fields>Batch_Success_Rate__c</fields>\n        <fields>Total_Batches__c</fields>\n        <fields>Processed_Batches__c</fields>\n        <fields>Failed_Batches__c</fields>\n        <fields>Timestamp__c</fields>\n        <relatedList>Mass_Action_Log__c.Parent_Log_Configuration__c</relatedList>\n        <sortField>Timestamp__c</sortField>\n        <sortOrder>Desc</sortOrder>\n    </relatedLists>\n    <showEmailCheckbox>false</showEmailCheckbox>\n    <showHighlightsPanel>false</showHighlightsPanel>\n    <showInteractionLogPanel>false</showInteractionLogPanel>\n    <showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>\n    <showSubmitAndAttachButton>false</showSubmitAndAttachButton>\n    <summaryLayout>\n        <masterLabel>00hf4000000jcti</masterLabel>\n        <sizeX>4</sizeX>\n        <sizeY>0</sizeY>\n        <summaryLayoutStyle>Default</summaryLayoutStyle>\n    </summaryLayout>\n</Layout>\n"
  },
  {
    "path": "force-app/main/default/layouts/Mass_Action_Log__c-Mass Action Child Log Layout.layout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Layout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <excludeButtons>Submit</excludeButtons>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Mass_Action_Configuration__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Message_Type__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Job_ID__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Parent_Log__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Message Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Message__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Long_Message__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Job_Scope__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>System Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>CreatedById</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Timestamp__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>LastModifiedById</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Custom Links</label>\n        <layoutColumns/>\n        <layoutColumns/>\n        <layoutColumns/>\n        <style>CustomLinks</style>\n    </layoutSections>\n    <miniLayout>\n        <fields>Mass_Action_Configuration__c</fields>\n        <fields>Job_ID__c</fields>\n        <fields>Message_Type__c</fields>\n        <fields>Message__c</fields>\n    </miniLayout>\n    <platformActionList>\n        <actionListContext>Record</actionListContext>\n        <platformActionListItems>\n            <actionName>FeedItem.TextPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>0</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.ContentPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>1</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.LinkPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>2</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Edit</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>3</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Delete</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>4</sortOrder>\n        </platformActionListItems>\n    </platformActionList>\n    <quickActionList>\n        <quickActionListItems>\n            <quickActionName>FeedItem.TextPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.ContentPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.LinkPost</quickActionName>\n        </quickActionListItems>\n    </quickActionList>\n    <showEmailCheckbox>false</showEmailCheckbox>\n    <showHighlightsPanel>false</showHighlightsPanel>\n    <showInteractionLogPanel>false</showInteractionLogPanel>\n    <showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>\n    <showSubmitAndAttachButton>false</showSubmitAndAttachButton>\n    <summaryLayout>\n        <masterLabel>00hf4000004tdCv</masterLabel>\n        <sizeX>4</sizeX>\n        <sizeY>0</sizeY>\n        <summaryLayoutStyle>Default</summaryLayoutStyle>\n    </summaryLayout>\n</Layout>\n"
  },
  {
    "path": "force-app/main/default/layouts/Mass_Action_Log__c-Mass Action Log Layout.layout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Layout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <excludeButtons>Submit</excludeButtons>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Mass_Action_Configuration__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Message_Type__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Job_ID__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>RecordTypeId</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Message Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Message__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Long_Message__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Job_Scope__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>System Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>CreatedById</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Timestamp__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>LastModifiedById</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Custom Links</label>\n        <layoutColumns/>\n        <layoutColumns/>\n        <layoutColumns/>\n        <style>CustomLinks</style>\n    </layoutSections>\n    <miniLayout>\n        <fields>Mass_Action_Configuration__c</fields>\n        <fields>Job_ID__c</fields>\n        <fields>Message_Type__c</fields>\n        <fields>Message__c</fields>\n    </miniLayout>\n    <platformActionList>\n        <actionListContext>Record</actionListContext>\n        <platformActionListItems>\n            <actionName>FeedItem.TextPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>0</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.ContentPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>1</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.LinkPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>2</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Edit</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>3</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Delete</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>4</sortOrder>\n        </platformActionListItems>\n    </platformActionList>\n    <quickActionList>\n        <quickActionListItems>\n            <quickActionName>FeedItem.TextPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.ContentPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.LinkPost</quickActionName>\n        </quickActionListItems>\n    </quickActionList>\n    <relatedLists>\n        <fields>NAME</fields>\n        <fields>Message_Type__c</fields>\n        <fields>Message__c</fields>\n        <fields>Long_Message__c</fields>\n        <fields>Timestamp__c</fields>\n        <fields>CREATED_DATE</fields>\n        <relatedList>Mass_Action_Log__c.Parent_Log__c</relatedList>\n        <sortField>Timestamp__c</sortField>\n        <sortOrder>Desc</sortOrder>\n    </relatedLists>\n    <showEmailCheckbox>false</showEmailCheckbox>\n    <showHighlightsPanel>false</showHighlightsPanel>\n    <showInteractionLogPanel>false</showInteractionLogPanel>\n    <showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>\n    <showSubmitAndAttachButton>false</showSubmitAndAttachButton>\n    <summaryLayout>\n        <masterLabel>00hf4000000MOYT</masterLabel>\n        <sizeX>4</sizeX>\n        <sizeY>0</sizeY>\n        <summaryLayoutStyle>Default</summaryLayoutStyle>\n    </summaryLayout>\n</Layout>\n"
  },
  {
    "path": "force-app/main/default/layouts/Mass_Action_Log__c-Mass Action Parent Log Layout.layout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Layout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <excludeButtons>Submit</excludeButtons>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Mass_Action_Configuration__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Message_Type__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Job_ID__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>RecordTypeId</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Batch Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Batch_Success_Rate__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Total_Batches__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Processed_Batches__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Failed_Batches__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsLeftToRight</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Message Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Message__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Long_Message__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Job_Scope__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>OneColumn</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>System Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>CreatedById</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Timestamp__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>LastModifiedById</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>Submitted_Date__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Custom Links</label>\n        <layoutColumns/>\n        <layoutColumns/>\n        <layoutColumns/>\n        <style>CustomLinks</style>\n    </layoutSections>\n    <platformActionList>\n        <actionListContext>Record</actionListContext>\n        <platformActionListItems>\n            <actionName>FeedItem.TextPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>0</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.ContentPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>1</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>FeedItem.LinkPost</actionName>\n            <actionType>QuickAction</actionType>\n            <sortOrder>2</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Edit</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>3</sortOrder>\n        </platformActionListItems>\n        <platformActionListItems>\n            <actionName>Delete</actionName>\n            <actionType>StandardButton</actionType>\n            <sortOrder>4</sortOrder>\n        </platformActionListItems>\n    </platformActionList>\n    <quickActionList>\n        <quickActionListItems>\n            <quickActionName>FeedItem.TextPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.ContentPost</quickActionName>\n        </quickActionListItems>\n        <quickActionListItems>\n            <quickActionName>FeedItem.LinkPost</quickActionName>\n        </quickActionListItems>\n    </quickActionList>\n    <relatedLists>\n        <fields>NAME</fields>\n        <fields>Message_Type__c</fields>\n        <fields>Message__c</fields>\n        <fields>Long_Message__c</fields>\n        <fields>Timestamp__c</fields>\n        <fields>CREATED_DATE</fields>\n        <relatedList>Mass_Action_Log__c.Parent_Log__c</relatedList>\n        <sortField>Timestamp__c</sortField>\n        <sortOrder>Desc</sortOrder>\n    </relatedLists>\n    <showEmailCheckbox>false</showEmailCheckbox>\n    <showHighlightsPanel>false</showHighlightsPanel>\n    <showInteractionLogPanel>false</showInteractionLogPanel>\n    <showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>\n    <showSubmitAndAttachButton>false</showSubmitAndAttachButton>\n    <summaryLayout>\n        <masterLabel>00hf4000004tdNA</masterLabel>\n        <sizeX>4</sizeX>\n        <sizeY>0</sizeY>\n        <summaryLayoutStyle>Default</summaryLayoutStyle>\n    </summaryLayout>\n</Layout>\n"
  },
  {
    "path": "force-app/main/default/layouts/Mass_Action_Mapping__c-Mass Action Mapping Layout.layout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Layout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <excludeButtons>Submit</excludeButtons>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Mass_Action_Configuration__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Source_Field_Name__c</field>\n            </layoutItems>\n            <layoutItems>\n                <behavior>Required</behavior>\n                <field>Target_Field_Name__c</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns/>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>false</customLabel>\n        <detailHeading>true</detailHeading>\n        <editHeading>true</editHeading>\n        <label>System Information</label>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>CreatedById</field>\n            </layoutItems>\n        </layoutColumns>\n        <layoutColumns>\n            <layoutItems>\n                <behavior>Readonly</behavior>\n                <field>LastModifiedById</field>\n            </layoutItems>\n        </layoutColumns>\n        <style>TwoColumnsTopToBottom</style>\n    </layoutSections>\n    <layoutSections>\n        <customLabel>true</customLabel>\n        <detailHeading>false</detailHeading>\n        <editHeading>true</editHeading>\n        <label>Custom Links</label>\n        <layoutColumns/>\n        <layoutColumns/>\n        <layoutColumns/>\n        <style>CustomLinks</style>\n    </layoutSections>\n    <miniLayout>\n        <fields>Mass_Action_Configuration__c</fields>\n        <fields>Source_Field_Name__c</fields>\n        <fields>Target_Field_Name__c</fields>\n    </miniLayout>\n    <showEmailCheckbox>false</showEmailCheckbox>\n    <showHighlightsPanel>false</showHighlightsPanel>\n    <showInteractionLogPanel>false</showInteractionLogPanel>\n    <showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>\n    <showSubmitAndAttachButton>false</showSubmitAndAttachButton>\n    <summaryLayout>\n        <masterLabel>00hf4000000jdT7</masterLabel>\n        <sizeX>4</sizeX>\n        <sizeY>0</sizeY>\n        <summaryLayoutStyle>Default</summaryLayoutStyle>\n    </summaryLayout>\n</Layout>\n"
  },
  {
    "path": "force-app/main/default/namedCredentials/Mass_Action_Test_Named_Credential.namedCredential-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<NamedCredential xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <allowMergeFieldsInBody>false</allowMergeFieldsInBody>\n    <allowMergeFieldsInHeader>false</allowMergeFieldsInHeader>\n    <endpoint>https://dca-mass-action-dev-ed.test.my.salesforce.com</endpoint>\n    <generateAuthorizationHeader>false</generateAuthorizationHeader>\n    <label>Mass Action Test Named Credential (Do Not Use)</label>\n    <principalType>Anonymous</principalType>\n    <protocol>NoAuthentication</protocol>\n</NamedCredential>\n"
  },
  {
    "path": "force-app/main/default/notificationtypes/Mass_Action_Notification.notiftype-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomNotificationType xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <customNotifTypeName>Mass Action Notification</customNotifTypeName>\n    <desktop>true</desktop>\n    <masterLabel>Mass Action Notification</masterLabel>\n    <mobile>true</mobile>\n</CustomNotificationType>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/Mass_Action_Batch_Apex_Status_Event__e.object-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <deploymentStatus>Deployed</deploymentStatus>\n    <description>Used by Mass Action Scheduler app to track status change events and errors as its batch jobs execute. These results appear as Mass Action Logs on Mass Action Configuration records.</description>\n    <eventType>HighVolume</eventType>\n    <label>Mass Action Batch Apex Status Event</label>\n    <pluralLabel>Mass Action Batch Apex Status Events</pluralLabel>\n    <publishBehavior>PublishImmediately</publishBehavior>\n</CustomObject>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Job_ID__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Job_ID__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Job ID field on Mass Action Log object.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Job ID</label>\n    <length>255</length>\n    <required>false</required>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Job_Scope__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Job_Scope__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Message Type field on Mass Action Log object.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Job Scope</label>\n    <length>131000</length>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Long_Message__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Long_Message__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Long Message field on Mass Action Log object.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Long Message</label>\n    <length>131000</length>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Message_Type__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Message_Type__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Message Type field on Mass Action Log object.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Message Type</label>\n    <length>255</length>\n    <required>false</required>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Message__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Message__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Message field on Mass Action Log object.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Message</label>\n    <length>255</length>\n    <required>false</required>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Phase__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Phase__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Mirror of the the Phase field on BatchApexErrorEvent. Indicates what phase of a batch job this event occurred, such as start, execute, or finish.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Phase</label>\n    <length>255</length>\n    <required>false</required>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Batch_Apex_Status_Event__e/fields/Timestamp__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Timestamp__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Timestamp field on the Mass Action Log object. Platform Events are processed asynchronously. The timestamp field represents the original date/time the cause of this event occurred. The value is displayed as a number to provide a way to sort log records in near their actual chronological order despite when the log records were eventually inserted.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Timestamp</label>\n    <length>255</length>\n    <required>false</required>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/Mass_Action_Configuration__c.object-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <content>MA_EditConfigCmp</content>\n        <formFactor>Large</formFactor>\n        <skipRecordTypeSelect>false</skipRecordTypeSelect>\n        <type>LightningComponent</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <content>MA_EditConfigCmp</content>\n        <formFactor>Large</formFactor>\n        <skipRecordTypeSelect>false</skipRecordTypeSelect>\n        <type>LightningComponent</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <allowInChatterGroups>true</allowInChatterGroups>\n    <compactLayoutAssignment>Default_Compact_Layout</compactLayoutAssignment>\n    <deploymentStatus>Deployed</deploymentStatus>\n    <deprecated>false</deprecated>\n    <description>A configuration of inputs (reports, list views, queries) and actions (process builder, flows, apex) that can be scheduled.\nhttps://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/</description>\n    <enableActivities>true</enableActivities>\n    <enableBulkApi>true</enableBulkApi>\n    <enableFeeds>false</enableFeeds>\n    <enableHistory>true</enableHistory>\n    <enableLicensing>false</enableLicensing>\n    <enableReports>true</enableReports>\n    <enableSearch>true</enableSearch>\n    <enableSharing>true</enableSharing>\n    <enableStreamingApi>true</enableStreamingApi>\n    <label>Mass Action Configuration</label>\n    <nameField>\n        <label>Mass Action Configuration Name</label>\n        <trackHistory>false</trackHistory>\n        <type>Text</type>\n    </nameField>\n    <pluralLabel>Mass Action Configurations</pluralLabel>\n    <searchLayouts>\n        <customTabListAdditionalFields>Active__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Schedule_Frequency__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Source_Type__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Target_Type__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Target_Action_Name__c</customTabListAdditionalFields>\n        <excludedStandardButtons>ChangeOwner</excludedStandardButtons>\n        <excludedStandardButtons>Accept</excludedStandardButtons>\n        <lookupDialogsAdditionalFields>Active__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Schedule_Frequency__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Source_Type__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Target_Type__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Target_Action_Name__c</lookupDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Active__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Schedule_Frequency__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Source_Type__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Target_Type__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Target_Action_Name__c</lookupPhoneDialogsAdditionalFields>\n        <searchResultsAdditionalFields>Active__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Schedule_Frequency__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Source_Type__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Target_Type__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Target_Action_Name__c</searchResultsAdditionalFields>\n    </searchLayouts>\n    <sharingModel>ReadWrite</sharingModel>\n    <visibility>Public</visibility>\n</CustomObject>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/compactLayouts/Default_Compact_Layout.compactLayout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CompactLayout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Default_Compact_Layout</fullName>\n    <fields>Name</fields>\n    <fields>Active__c</fields>\n    <fields>Schedule_Frequency__c</fields>\n    <fields>Source_Type__c</fields>\n    <fields>Target_Type__c</fields>\n    <fields>Target_Action_Name__c</fields>\n    <fields>Last_Run_Completed_Date__c</fields>\n    <label>Default Compact Layout</label>\n</CompactLayout>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Active__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Active__c</fullName>\n    <defaultValue>true</defaultValue>\n    <deprecated>false</deprecated>\n    <description>If active then action can be ran and scheduled. Inactive actions will not run and have their scheduled job aborted.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>If active then action can be ran and scheduled. Inactive actions will not run and have their scheduled job aborted.</inlineHelpText>\n    <label>Active</label>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Checkbox</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Batch_Size__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Batch_Size__c</fullName>\n    <deprecated>false</deprecated>\n    <description>The number of source records to run through the target action at a time. Correlates to the apex batch job size. Can be between 1 and 200. Same concept as Data Loader&#39;s batch size.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>The number of source records to run through the target action at a time. Correlates to the apex batch job size. Can be between 1 and 200. Same concept as Data Loader&#39;s batch size.</inlineHelpText>\n    <label>Batch Size</label>\n    <precision>18</precision>\n    <required>false</required>\n    <scale>0</scale>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Number</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Description__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Description__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Help yourself and others know why and what this configuration is for by adding a description. You&#39;ll thank yourself later =)</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Help yourself and others know why and what this configuration is for by adding a description. You&#39;ll thank yourself later =)</inlineHelpText>\n    <label>Description</label>\n    <length>32000</length>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/DeveloperName__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>DeveloperName__c</fullName>\n    <caseSensitive>false</caseSensitive>\n    <deprecated>false</deprecated>\n    <description>A unique name to reference this record by without knowing its ID. This is particularly useful when invoking a configuration on-demand from Process Builder or Flow.</description>\n    <externalId>true</externalId>\n    <inlineHelpText>A unique name to reference this record by without knowing its ID.</inlineHelpText>\n    <label>Mass Action Configuration Unique Name</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>true</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Last_Run_Completed_Date__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Last_Run_Completed_Date__c</fullName>\n    <deprecated>false</deprecated>\n    <description>When the last run of this configuration completed. It is updated when the batch job finishes. Use this field to control when you chain other configurations together. For example, Process Builder may monitor when this field value changes and if the unique name is &quot;Config1&quot; then can decide to automatically run &quot;Config2&quot; to ensure &quot;Config2&quot; only runs after &quot;Config1&quot; completes.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>When the last run of this configuration completed. It is updated when the batch job finishes. Use this field to control when you chain other configurations together. For example, to ensure &quot;Config2&quot; only runs after &quot;Config1&quot; completes.</inlineHelpText>\n    <label>Last Run Completed Date</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>DateTime</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Last_Run_Completed_With_Errors__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Last_Run_Completed_With_Errors__c</fullName>\n    <defaultValue>false</defaultValue>\n    <deprecated>false</deprecated>\n    <description>Indicates if the last run of this configuration completed with errors. It is updated when the batch job finishes. This field is checked if the last run of this configuration created log records reporting any errors, otherwise it is unchecked. Use this field with the Last Run Completed Date in Process Builder to control when to automatically run other configurations conditionally upon a configuration completing successfully or not. For example, run &quot;Config2&quot; only if &quot;Config1&quot; completed without errors.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Indicates if the last run of this configuration completed with errors. It is updated when the batch job finishes. This field is checked if the last run of this configuration created log records reporting any errors, otherwise it is unchecked.</inlineHelpText>\n    <label>Last Run Completed With Errors</label>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Checkbox</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Named_Credential__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Named_Credential__c</fullName>\n    <deprecated>false</deprecated>\n    <description>The Named Credential that provides authentication to Salesforce REST API when invoking target actions. This will be the running user for the record updates.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>By default, the user who schedules the mass actions is the running user for record updates. You may optionally choose a Named Credential to specify the running user instead.</inlineHelpText>\n    <label>Named Credential</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_Cron__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_Cron__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Schedule Cron Expression https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Specify your own cron expression to schedule this action. See &quot;Apex Scheduler&quot; in the Salesforce Apex Developer Guide for full details on supported format.</inlineHelpText>\n    <label>Schedule Cron</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_DayOfMonth__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_DayOfMonth__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Day of Month component of cron schedule expression. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose which days of the month this action will run.</inlineHelpText>\n    <label>Schedule Day</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_DayOfWeek__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_DayOfWeek__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Weekday component of cron schedule expression. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose which days of the week this action will run.</inlineHelpText>\n    <label>Schedule Weekday</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_Frequency__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_Frequency__c</fullName>\n    <deprecated>false</deprecated>\n    <description>On Demand = not scheduled\nScheduled = user scheduled via simple options\nCustom = user provided own cron expression</description>\n    <externalId>false</externalId>\n    <inlineHelpText>How often will this action run?</inlineHelpText>\n    <label>Schedule Frequency</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Picklist</type>\n    <valueSet>\n        <restricted>true</restricted>\n        <valueSetDefinition>\n            <sorted>false</sorted>\n            <value>\n                <fullName>Manual</fullName>\n                <default>true</default>\n                <label>On Demand</label>\n            </value>\n            <value>\n                <fullName>Scheduled</fullName>\n                <default>false</default>\n                <label>Scheduled</label>\n            </value>\n            <value>\n                <fullName>Custom</fullName>\n                <default>false</default>\n                <label>Custom</label>\n            </value>\n        </valueSetDefinition>\n    </valueSet>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_HourOfDay__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_HourOfDay__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Hour of Day component of cron schedule expression. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose which hours of the day this action will run. Salesforce uses the time zone of the user who schedules the job</inlineHelpText>\n    <label>Schedule Hour</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_MinuteOfHour__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_MinuteOfHour__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Minute component of cron schedule expression. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose which minutes of the hour this action will run.</inlineHelpText>\n    <label>Schedule Minute</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_MonthOfYear__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_MonthOfYear__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Month of Year component of cron schedule expression. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose which months of the year this action will run.</inlineHelpText>\n    <label>Schedule Month</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Schedule_SecondOfMinute__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Schedule_SecondOfMinute__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Second component of cron schedule expression. https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose which seconds of the minute this action will run.</inlineHelpText>\n    <label>Schedule Second</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Source_Apex_Class__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_Apex_Class__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Name (including namespace if applicable) of an Apex class that implements Iterable&lt;Map&lt;String, Object&gt;&gt;. The returned iterator produces the source records to process. This also is a way, other than External Objects, to process data retrieved from HTTP callouts to external web services. You could query an external system to learn the Salesforce record IDs to apply updates to.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Name (including namespace if applicable) of an Apex class that implements Iterable&lt;Map&lt;String, Object&gt;&gt;. The returned iterator produces the source records to process. The source data, for example, could come from HTTP callouts to external web services.</inlineHelpText>\n    <label>Source Apex Class</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Source_List_View_ID__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_List_View_ID__c</fullName>\n    <deprecated>false</deprecated>\n    <description>List View that provides the source records. Applicable when Source Type is List View.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose a list view that identifies the records to process.</inlineHelpText>\n    <label>Source List View ID</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Source_Report_Column_Name__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_Report_Column_Name__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Report column name that holds unique record values for sorting and paginating. Needed for workaround with Reports API to process more than 2,000 rows. Applicable when Source Type is Report.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Choose a column that uniquely identifies each record in the report. For example, &quot;Account ID&quot;. Uniqueness ensures predictable sorting and pagination to avoid processing a record multiple times.</inlineHelpText>\n    <label>Source Report Column Name</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Source_Report_ID__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_Report_ID__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Report that provides the source records. Applicable when Source Type is Report.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Due to an API limitation, reports with more than 10,000 records may fail to process. For larger data sets, use list views instead which support millions of records.</inlineHelpText>\n    <label>Source Report ID</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Source_SOQL_Query__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_SOQL_Query__c</fullName>\n    <deprecated>false</deprecated>\n    <description>SOQL query that provides the source records. Applicable when Source Type is SOQL. Max SOQL query length limit: https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_soslsoql.htm</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Enter SOQL query that identifies the records to process. Use aliases with Aggregate functions (COUNT, SUM, MIN, MAX, AVG, etc.) to make them available in the Field Mappings step.</inlineHelpText>\n    <label>Source SOQL Query</label>\n    <length>20000</length>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Source_Type__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_Type__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Where source records come from to perform actions on, like reports or list views.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Where source records come from to perform actions on, like reports or list views.</inlineHelpText>\n    <label>Source Type</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Picklist</type>\n    <valueSet>\n        <restricted>true</restricted>\n        <valueSetDefinition>\n            <sorted>false</sorted>\n            <value>\n                <fullName>Report</fullName>\n                <default>false</default>\n                <label>Report</label>\n            </value>\n            <value>\n                <fullName>ListView</fullName>\n                <default>false</default>\n                <label>List View</label>\n            </value>\n            <value>\n                <fullName>SOQL</fullName>\n                <default>false</default>\n                <label>SOQL</label>\n            </value>\n            <value>\n                <fullName>Apex</fullName>\n                <default>false</default>\n                <label>Apex</label>\n            </value>\n        </valueSetDefinition>\n    </valueSet>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Target_Action_Name__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Target_Action_Name__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Name of the action to process the source records (e.g. Process Builder, Flow, Invocable Apex class, Quick Action, Email Alert, etc). Should be blank for when Target Type is Workflow Rules.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Name of the action to process the source records (e.g. Process Builder, Flow, Invocable Apex class, Quick Action, Email Alert, etc). Should be blank for when Target Type is Workflow Rules.</inlineHelpText>\n    <label>Target Action Name</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Target_Apex_Script__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Target_Apex_Script__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Anonymous Apex script to execute. Your script must include a method definition for `void execute( List&lt;Map&lt;String, Object&gt;&gt; sourceRecordsBatch )`, which will be passed the current batch of source records. Your script is invoked once per batch just like the `execute` method of a Batchable class. Unlike a Batchable class, no state is preserved within the script between executions.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Anonymous Apex script to execute. Your script must include a method definition for `void execute( List&lt;Map&lt;String, Object&gt;&gt; sourceRecordsBatch )`, which will be passed the current batch of source records. No script state is preserved between executions.</inlineHelpText>\n    <label>Target Apex Script</label>\n    <length>131000</length>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Target_SObject_Type__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Target_SObject_Type__c</fullName>\n    <deprecated>false</deprecated>\n    <externalId>false</externalId>\n    <label>Target SObject Type</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/fields/Target_Type__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Target_Type__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Type of action to perform on the source records.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Type of action to perform on the source records.</inlineHelpText>\n    <label>Target Type</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Picklist</type>\n    <valueSet>\n        <restricted>true</restricted>\n        <valueSetDefinition>\n            <sorted>false</sorted>\n            <value>\n                <fullName>Flow</fullName>\n                <default>false</default>\n                <label>Process Builder &amp; Flows</label>\n            </value>\n            <value>\n                <fullName>Workflow</fullName>\n                <default>false</default>\n                <label>Workflow Rules</label>\n            </value>\n            <value>\n                <fullName>QuickAction</fullName>\n                <default>false</default>\n                <label>Quick Actions</label>\n            </value>\n            <value>\n                <fullName>EmailAlert</fullName>\n                <default>false</default>\n                <label>Email Alerts</label>\n            </value>\n            <value>\n                <fullName>Apex</fullName>\n                <default>false</default>\n                <label>Apex</label>\n            </value>\n        </valueSetDefinition>\n    </valueSet>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Configuration__c/listViews/All.listView-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ListView xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>All</fullName>\n    <columns>NAME</columns>\n    <columns>Active__c</columns>\n    <columns>Schedule_Frequency__c</columns>\n    <columns>Source_Type__c</columns>\n    <columns>Target_Type__c</columns>\n    <columns>Target_Action_Name__c</columns>\n    <columns>Last_Run_Completed_Date__c</columns>\n    <filterScope>Everything</filterScope>\n    <label>All</label>\n</ListView>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Job_Change_Event__e/Mass_Action_Job_Change_Event__e.object-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <deploymentStatus>Deployed</deploymentStatus>\n    <description>As a workaround to known issue https://success.salesforce.com/issues_view?id=a1p30000000SyhIAAS, this platform event allows apex jobs (CronTrigger) to be scheduled and aborted from Apex REST execution context by moving the logic to another asynchronous execution context.</description>\n    <eventType>StandardVolume</eventType>\n    <label>Mass Action Job Change Event</label>\n    <pluralLabel>Mass Action Job Change Events</pluralLabel>\n    <publishBehavior>PublishAfterCommit</publishBehavior>\n</CustomObject>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Job_Change_Event__e/fields/Payload__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Payload__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Serialized JSON payload that conforms to the MA_JobChangeEvent apex class.</description>\n    <externalId>false</externalId>\n    <isFilteringDisabled>false</isFilteringDisabled>\n    <isNameField>false</isNameField>\n    <isSortingDisabled>false</isSortingDisabled>\n    <label>Payload</label>\n    <length>131072</length>\n    <type>LongTextArea</type>\n    <visibleLines>10</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/Mass_Action_Log__c.object-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <allowInChatterGroups>true</allowInChatterGroups>\n    <compactLayoutAssignment>Default_Compact_Layout</compactLayoutAssignment>\n    <deploymentStatus>Deployed</deploymentStatus>\n    <deprecated>false</deprecated>\n    <description>Information about Mass Action batch job executions. You can safely delete these records after their related batch job has finished.\nhttps://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/</description>\n    <enableActivities>true</enableActivities>\n    <enableBulkApi>true</enableBulkApi>\n    <enableFeeds>false</enableFeeds>\n    <enableHistory>true</enableHistory>\n    <enableLicensing>false</enableLicensing>\n    <enableReports>true</enableReports>\n    <enableSearch>true</enableSearch>\n    <enableSharing>true</enableSharing>\n    <enableStreamingApi>true</enableStreamingApi>\n    <label>Mass Action Log</label>\n    <nameField>\n        <displayFormat>MAL-{000000}</displayFormat>\n        <label>Mass Action Log Number</label>\n        <trackHistory>false</trackHistory>\n        <type>AutoNumber</type>\n    </nameField>\n    <pluralLabel>Mass Action Logs</pluralLabel>\n    <recordTypeTrackHistory>false</recordTypeTrackHistory>\n    <searchLayouts>\n        <customTabListAdditionalFields>Mass_Action_Configuration__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Job_ID__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Message_Type__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Message__c</customTabListAdditionalFields>\n        <customTabListAdditionalFields>RECORDTYPE</customTabListAdditionalFields>\n        <customTabListAdditionalFields>Timestamp__c</customTabListAdditionalFields>\n        <lookupDialogsAdditionalFields>Mass_Action_Configuration__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Job_ID__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Message_Type__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Message__c</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>RECORDTYPE</lookupDialogsAdditionalFields>\n        <lookupDialogsAdditionalFields>Timestamp__c</lookupDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Mass_Action_Configuration__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Job_ID__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Message_Type__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Message__c</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>RECORDTYPE</lookupPhoneDialogsAdditionalFields>\n        <lookupPhoneDialogsAdditionalFields>Timestamp__c</lookupPhoneDialogsAdditionalFields>\n        <searchResultsAdditionalFields>Mass_Action_Configuration__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Job_ID__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Message_Type__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Message__c</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>RECORDTYPE</searchResultsAdditionalFields>\n        <searchResultsAdditionalFields>Timestamp__c</searchResultsAdditionalFields>\n    </searchLayouts>\n    <sharingModel>ControlledByParent</sharingModel>\n    <visibility>Public</visibility>\n</CustomObject>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/compactLayouts/Child_Log_Compact_Layout.compactLayout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CompactLayout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Child_Log_Compact_Layout</fullName>\n    <fields>Name</fields>\n    <fields>Mass_Action_Configuration__c</fields>\n    <fields>Job_ID__c</fields>\n    <fields>Message_Type__c</fields>\n    <fields>Parent_Log__c</fields>\n    <label>Child Log Compact Layout</label>\n</CompactLayout>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/compactLayouts/Default_Compact_Layout.compactLayout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CompactLayout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Default_Compact_Layout</fullName>\n    <fields>Name</fields>\n    <fields>Mass_Action_Configuration__c</fields>\n    <fields>Job_ID__c</fields>\n    <fields>Message_Type__c</fields>\n    <fields>RecordTypeId</fields>\n    <label>Default Compact Layout</label>\n</CompactLayout>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/compactLayouts/Parent_Log_Compact_Layout.compactLayout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CompactLayout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Parent_Log_Compact_Layout</fullName>\n    <fields>Name</fields>\n    <fields>Mass_Action_Configuration__c</fields>\n    <fields>Job_ID__c</fields>\n    <fields>Batch_Success_Rate__c</fields>\n    <fields>Total_Batches__c</fields>\n    <fields>Processed_Batches__c</fields>\n    <fields>Failed_Batches__c</fields>\n    <label>Parent Log Compact Layout</label>\n</CompactLayout>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Batch_Success_Percentage__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Batch_Success_Percentage__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Calculates the success percentage of the batch job&#39;s executions.</description>\n    <externalId>false</externalId>\n    <formula>IF(\n  Processed_Batches__c &gt; 0,\n  MAX( 0, Processed_Batches__c - Failed_Batches__c ) / Processed_Batches__c,\n  0\n)</formula>\n    <formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs>\n    <inlineHelpText>Calculates the success percentage of the batch job&#39;s executions.</inlineHelpText>\n    <label>Batch Success %</label>\n    <precision>18</precision>\n    <required>false</required>\n    <scale>0</scale>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Percent</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Batch_Success_Rate__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Batch_Success_Rate__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Visualizes the batch success percentage in color. Uses https://shields.io to generage the image in real-time.</description>\n    <externalId>false</externalId>\n    <formula>IMAGE(\n  &#39;https://img.shields.io/static/v1.svg?label=&amp;message=&#39; &amp;\n  TEXT( ROUND( Batch_Success_Percentage__c * 100, 0 ) )  &amp; &#39;%&#39; &amp;\n  &#39;&amp;color=&#39; &amp;\n  IF( Batch_Success_Percentage__c &gt;= 0.90, &#39;4CC620&#39;, /* brightgreen */\n    IF( Batch_Success_Percentage__c &gt;= 0.80, &#39;4bca81&#39;, /* green */\n      IF( Batch_Success_Percentage__c &gt;= 0.50, &#39;ffb75d&#39;, /* orange */\n        &#39;d4504c&#39; /* red */\n      )\n    )\n  ),\n  TEXT( ROUND( Batch_Success_Percentage__c * 100, 0 ) ) &amp; &#39;%&#39;\n)</formula>\n    <formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs>\n    <inlineHelpText>Visualizes the batch success percentage in color.</inlineHelpText>\n    <label>Batch Success Rate</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Failed_Batches__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Failed_Batches__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Total number of batches with a failure. A batch is considered transactional, so any unhandled exceptions constitute an entire failure of the batch. Pairs to the Number of Errors field on the AsyncApexJob object.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Total number of batches with a failure. A batch is considered transactional, so any unhandled exceptions constitute an entire failure of the batch.</inlineHelpText>\n    <label>Failed Batches</label>\n    <precision>18</precision>\n    <required>false</required>\n    <scale>0</scale>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Number</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Job_ID__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Job_ID__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Apex Batch Job ID. Since we can&#39;t have lookup fields to AsyncApexJob records, please standardize on the 15 character id, least common denominator for our use cases. SOQL WHERE filters will fail if stored value and filter value are not same length. Set as external id just so it&#39;s indexed. Don&#39;t UPSERT by this field value.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Apex Batch Job ID. You can also monitor job status on the Apex Jobs page in Setup.</inlineHelpText>\n    <label>Job ID</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Job_Scope__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Job_Scope__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Job Scope from BatchApexErrorEvent. The Record IDs that are in scope if the event was fired from the execute() method of a batch job. If the batch job uses custom iterators instead of sObjects, JobScope is the toString() representation of the iterable objects.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>The Record IDs that are in scope if the event was fired from the execute() method of a batch job. If the batch job uses custom iterators instead of sObjects, JobScope is the toString() representation of the iterable objects.</inlineHelpText>\n    <label>Job Scope</label>\n    <length>131000</length>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Long_Message__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Long_Message__c</fullName>\n    <deprecated>false</deprecated>\n    <description>The full error message, particularly if more than 255 characters.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>The full error message, particularly if more than 255 characters.</inlineHelpText>\n    <label>Long Message</label>\n    <length>131000</length>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>LongTextArea</type>\n    <visibleLines>5</visibleLines>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Mass_Action_Configuration__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Mass_Action_Configuration__c</fullName>\n    <deprecated>false</deprecated>\n    <externalId>false</externalId>\n    <label>Mass Action Configuration</label>\n    <referenceTo>Mass_Action_Configuration__c</referenceTo>\n    <relationshipLabel>All Mass Action Logs</relationshipLabel>\n    <relationshipName>Mass_Action_Logs</relationshipName>\n    <relationshipOrder>0</relationshipOrder>\n    <reparentableMasterDetail>false</reparentableMasterDetail>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>MasterDetail</type>\n    <writeRequiresMasterRead>true</writeRequiresMasterRead>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Message_Type__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Message_Type__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Is this message just informational, a success event, or an error event.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Is this message just informational, a success event, or an error event.</inlineHelpText>\n    <label>Message Type</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Picklist</type>\n    <valueSet>\n        <valueSetDefinition>\n            <sorted>false</sorted>\n            <value>\n                <fullName>Informational</fullName>\n                <default>true</default>\n                <label>ℹ️ Informational</label>\n            </value>\n            <value>\n                <fullName>Success</fullName>\n                <default>false</default>\n                <label>✅ Success</label>\n            </value>\n            <value>\n                <fullName>Error</fullName>\n                <default>false</default>\n                <label>🚫 Error</label>\n            </value>\n        </valueSetDefinition>\n    </valueSet>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Message__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Message__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Apex Job extended status with details about any errors.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Apex Job extended status with details about any errors.</inlineHelpText>\n    <label>Message</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>TextArea</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Parent_Log_Configuration__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Parent_Log_Configuration__c</fullName>\n    <deleteConstraint>SetNull</deleteConstraint>\n    <deprecated>false</deprecated>\n    <description>Populated only when the log record type is &quot;Parent Log&quot;, otherwise it is null. This allows us to have a filtered related list of parent logs on Mass Action Configuration page layout. https://douglascayers.com/2015/11/18/salesforce-filter-related-lists-without-code/</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Populated only when the log record type is &quot;Parent Log&quot;, otherwise it is null.</inlineHelpText>\n    <label>Parent Log Configuration</label>\n    <referenceTo>Mass_Action_Configuration__c</referenceTo>\n    <relationshipLabel>Mass Action Logs</relationshipLabel>\n    <relationshipName>Mass_Action_Parent_Logs</relationshipName>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Lookup</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Parent_Log__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Parent_Log__c</fullName>\n    <deleteConstraint>SetNull</deleteConstraint>\n    <deprecated>false</deprecated>\n    <description>Child logs capture details for discrete events during the lifecycle of a batch job. When the job started, success or failure of its executions, and when the job finished. Parent logs groups these child logs together for a given batch job id, and reflect the overall job status.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Child logs capture details for discrete events during the lifecycle of a batch job. Parent logs groups these child logs together for a given batch job id.</inlineHelpText>\n    <label>Parent Log</label>\n    <referenceTo>Mass_Action_Log__c</referenceTo>\n    <relationshipLabel>Related Logs</relationshipLabel>\n    <relationshipName>Mass_Action_Logs</relationshipName>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Lookup</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Processed_Batches__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Processed_Batches__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Total number of batches processed successfully. Each batch contains a set of records. Pairs to the Job Items Processed field on the AsyncApexJob object.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Total number of batches processed successfully. Each batch contains a set of records.</inlineHelpText>\n    <label>Processed Batches</label>\n    <precision>18</precision>\n    <required>false</required>\n    <scale>0</scale>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Number</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Submitted_Date__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Submitted_Date__c</fullName>\n    <deprecated>false</deprecated>\n    <description>When the Apex Job was submitted. Pairs to the Created Date field on the AsyncApexJob object.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>When the Apex Job was submitted.</inlineHelpText>\n    <label>Submitted Date</label>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>DateTime</type>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Timestamp__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Timestamp__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Pairs to the Timestamp field on the Mass Action Batch Apex Status Event object. Platform Events are processed asynchronously. The timestamp field represents the original date/time the cause of this event occurred. The value is displayed as a number to provide a way to sort log records in near their actual chronological order despite when the log records were eventually inserted.</description>\n    <externalId>false</externalId>\n    <label>Timestamp</label>\n    <length>255</length>\n    <required>false</required>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/fields/Total_Batches__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Total_Batches__c</fullName>\n    <deprecated>false</deprecated>\n    <description>Total number of batches processed. Each batch contains a set of records. Pairs to the Total Job Items field on the AsyncApexJob object.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>Total number of batches processed. Each batch contains a set of records.</inlineHelpText>\n    <label>Total Batches</label>\n    <precision>18</precision>\n    <required>false</required>\n    <scale>0</scale>\n    <trackHistory>false</trackHistory>\n    <trackTrending>false</trackTrending>\n    <type>Number</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/listViews/All.listView-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ListView xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>All</fullName>\n    <columns>NAME</columns>\n    <columns>Mass_Action_Configuration__c</columns>\n    <columns>Job_ID__c</columns>\n    <columns>RECORDTYPE</columns>\n    <columns>Message_Type__c</columns>\n    <columns>Message__c</columns>\n    <columns>CREATED_DATE</columns>\n    <filterScope>Everything</filterScope>\n    <label>All Logs</label>\n</ListView>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/listViews/All_Parent_Logs.listView-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ListView xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>All_Parent_Logs</fullName>\n    <columns>NAME</columns>\n    <columns>Mass_Action_Configuration__c</columns>\n    <columns>Job_ID__c</columns>\n    <columns>Message_Type__c</columns>\n    <columns>Message__c</columns>\n    <columns>Batch_Success_Rate__c</columns>\n    <columns>Total_Batches__c</columns>\n    <columns>Failed_Batches__c</columns>\n    <columns>Processed_Batches__c</columns>\n    <columns>CREATED_DATE</columns>\n    <filterScope>Everything</filterScope>\n    <filters>\n        <field>RECORDTYPE</field>\n        <operation>equals</operation>\n        <value>Mass_Action_Log__c.Parent_Log</value>\n    </filters>\n    <label>All Parent Logs</label>\n</ListView>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/recordTypes/Child_Log.recordType-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<RecordType xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Child_Log</fullName>\n    <active>true</active>\n    <compactLayoutAssignment>Child_Log_Compact_Layout</compactLayoutAssignment>\n    <description>Represents informational, success, and error messages of a batch job run for a configuration.</description>\n    <label>Child Log</label>\n    <picklistValues>\n        <picklist>Message_Type__c</picklist>\n        <values>\n            <fullName>Error</fullName>\n            <default>false</default>\n        </values>\n        <values>\n            <fullName>Informational</fullName>\n            <default>true</default>\n        </values>\n        <values>\n            <fullName>Success</fullName>\n            <default>false</default>\n        </values>\n    </picklistValues>\n</RecordType>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Log__c/recordTypes/Parent_Log.recordType-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<RecordType xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Parent_Log</fullName>\n    <active>true</active>\n    <compactLayoutAssignment>Parent_Log_Compact_Layout</compactLayoutAssignment>\n    <description>Exactly one parent log should exist per batch job id for a configuration.</description>\n    <label>Parent Log</label>\n    <picklistValues>\n        <picklist>Message_Type__c</picklist>\n        <values>\n            <fullName>Error</fullName>\n            <default>false</default>\n        </values>\n        <values>\n            <fullName>Informational</fullName>\n            <default>true</default>\n        </values>\n        <values>\n            <fullName>Success</fullName>\n            <default>false</default>\n        </values>\n    </picklistValues>\n</RecordType>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Mapping__c/Mass_Action_Mapping__c.object-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomObject xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Accept</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>CancelEdit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Clone</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Delete</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Edit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>List</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>New</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>SaveEdit</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>Tab</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <formFactor>Large</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <actionOverrides>\n        <actionName>View</actionName>\n        <formFactor>Small</formFactor>\n        <type>Default</type>\n    </actionOverrides>\n    <allowInChatterGroups>false</allowInChatterGroups>\n    <compactLayoutAssignment>Default_Compact_Layout</compactLayoutAssignment>\n    <deploymentStatus>Deployed</deploymentStatus>\n    <deprecated>false</deprecated>\n    <description>Defines field mappings between sources and targets.\nhttps://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/</description>\n    <enableActivities>false</enableActivities>\n    <enableBulkApi>true</enableBulkApi>\n    <enableFeeds>false</enableFeeds>\n    <enableHistory>false</enableHistory>\n    <enableLicensing>false</enableLicensing>\n    <enableReports>true</enableReports>\n    <enableSearch>false</enableSearch>\n    <enableSharing>true</enableSharing>\n    <enableStreamingApi>true</enableStreamingApi>\n    <label>Mass Action Mapping</label>\n    <nameField>\n        <displayFormat>MAM-{000000}</displayFormat>\n        <label>Mass Action Mapping Number</label>\n        <type>AutoNumber</type>\n    </nameField>\n    <pluralLabel>Mass Action Mappings</pluralLabel>\n    <searchLayouts/>\n    <sharingModel>ControlledByParent</sharingModel>\n    <visibility>Public</visibility>\n</CustomObject>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Mapping__c/compactLayouts/Default_Compact_Layout.compactLayout-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CompactLayout xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Default_Compact_Layout</fullName>\n    <fields>Name</fields>\n    <fields>Mass_Action_Configuration__c</fields>\n    <fields>Source_Field_Name__c</fields>\n    <fields>Target_Field_Name__c</fields>\n    <label>Default Compact Layout</label>\n</CompactLayout>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Mapping__c/fields/Mass_Action_Configuration__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Mass_Action_Configuration__c</fullName>\n    <deprecated>false</deprecated>\n    <externalId>false</externalId>\n    <label>Mass Action Configuration</label>\n    <referenceTo>Mass_Action_Configuration__c</referenceTo>\n    <relationshipLabel>Mass Action Mappings</relationshipLabel>\n    <relationshipName>Mass_Action_Mappings</relationshipName>\n    <relationshipOrder>0</relationshipOrder>\n    <reparentableMasterDetail>false</reparentableMasterDetail>\n    <trackTrending>false</trackTrending>\n    <type>MasterDetail</type>\n    <writeRequiresMasterRead>false</writeRequiresMasterRead>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Mapping__c/fields/Source_Field_Name__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Source_Field_Name__c</fullName>\n    <deprecated>false</deprecated>\n    <description>API name of the source record to map to the target field. For example, the unique column name in a report or list view.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>API name of the source record to map to the target field. For example, the unique column name in a report or list view.</inlineHelpText>\n    <label>Source Field Name</label>\n    <length>255</length>\n    <required>true</required>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/objects/Mass_Action_Mapping__c/fields/Target_Field_Name__c.field-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomField xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <fullName>Target_Field_Name__c</fullName>\n    <deprecated>false</deprecated>\n    <description>API name of the target parameter to map to the source field. For example, the parameter name to a Flow.</description>\n    <externalId>false</externalId>\n    <inlineHelpText>API name of the target parameter to map to the source field. For example, the parameter name to a Flow.</inlineHelpText>\n    <label>Target Field Name</label>\n    <length>255</length>\n    <required>true</required>\n    <trackTrending>false</trackTrending>\n    <type>Text</type>\n    <unique>false</unique>\n</CustomField>\n"
  },
  {
    "path": "force-app/main/default/pages/LC_APIPage.page",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n -->\n<!--\n    For performance, turn off as much of the normal Salesforce page content.\n -->\n<apex:page applyHtmlTag=\"false\"\n           applyBodyTag=\"false\"\n           showHeader=\"false\"\n           showChat=\"false\"\n           standardStylesheets=\"false\"\n           sideBar=\"false\"\n           docType=\"html-5.0\">\n\n<html>\n\n    <head>\n        <apex:includeScript value=\"{!$Resource.penpal}\"/>\n        <apex:includeScript value=\"{!$Resource.jsforce}\"/>\n    </head>\n\n    <body>\n\n        <script>\n\n            const jsforceConn = new jsforce.Connection({\n                accessToken: '{!$Api.Session_Id}',\n                version: '54.0'\n            });\n\n            const penpalConn = Penpal.connectToParent({\n                methods: {\n                    restRequest,\n                    fetchRequest\n                }\n            });\n\n            /**\n             * Makes a Salesforce REST API request and returns a promise that resolves to the response.\n             * See the LC_API.cmp for documentation on usage.\n             */\n            function restRequest( request ) {\n                return new Promise( function( resolve, reject ) {\n                    jsforceConn.request( request ).then( function( response ) {\n                        resolve({\n                            success: true,\n                            data: response\n                        });\n                    }).catch( function( err ) {\n                        // Have to resolve because if reject\n                        // then whole post message operation fails,\n                        // so wrapping our response with our own\n                        // success flag to denote if any errors.\n                        resolve( formatError( err ) );\n                    });\n                });\n            };\n\n            /**\n             * Makes a JavaScript Fetch request and returns a promise that resolves to the response.\n             * See the LC_API.cmp for documentation on usage.\n             */\n            function fetchRequest( request ) {\n                return new Promise( function( resolve, reject ) {\n                    fetch( request.url, request.options ).then( function( response ) {\n                        if ( response.ok ) {\n                            // Although the Fetch's Response has a .json() method,\n                            // the response body might not conform to JSON and would error.\n                            // Instead, we read the response as text and then use our\n                            // utility `getAsJsonOrText` to convert it to JSON if appropriate.\n                            response.text().then( function( responseText ) {\n                                resolve({\n                                    success: true,\n                                    data: getAsJsonOrText( responseText )\n                                });\n                            });\n                        } else {\n                            resolve({\n                                success: false,\n                                data: response.statusText\n                            });\n                        }\n                    }).catch( function( err ) {\n                        // Have to resolve because if reject\n                        // then whole post message operation fails,\n                        // so wrapping our response with our own\n                        // success flag to denote if any errors.\n                        resolve( formatError( err ) );\n                    });\n                });\n            };\n\n            /**\n             * Formats the error object into our common data structure\n             * for communicating to the Penpal parent.\n             *\n             * @param error\n             *      JavaScript error object obtained from a promise catch method.\n             * @returns { { data: any, success: boolean } }\n             */\n            function formatError( error ) {\n                // If the server's response body was JSON but the status code\n                // indicated an error, the response body is treated\n                // as a string and set to Error.message property.\n                // To propogate the original JSON payload as JSON then\n                // we try to parse it as JSON. If the parse fails then\n                // we just resolve with the Error.message string anyways.\n                return ({\n                    success: false,\n                    data: getAsJsonOrText( error.message ) // postMessage cannot deserialize the Error object, so pick off the message\n                });\n            }\n\n            /**\n             * If content can be parsed by `JSON.parse` then the json is returned,\n             * otherwise, the content as-is is returned instead.\n             */\n            function getAsJsonOrText( content ) {\n                try {\n                    return JSON.parse( content );\n                } catch ( e ) {\n                    return content;\n                }\n            }\n\n        </script>\n\n    </body>\n\n</html>\n\n</apex:page>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/pages/LC_APIPage.page-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexPage xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <availableInTouch>true</availableInTouch>\n    <confirmationTokenRequired>false</confirmationTokenRequired>\n    <label>LC_APIPage</label>\n</ApexPage>\n"
  },
  {
    "path": "force-app/main/default/pages/LC_VisualforceDomainPage.page",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/douglascayers/sfdx-lightning-api-component\nLicense: BSD 3-Clause License\n -->\n<!--\n    For performance, turn off as much of the normal Salesforce page content.\n -->\n<apex:page controller=\"LC_VisualforceDomainController\"\n           contentType=\"text/plain\"\n           showHeader=\"false\"\n           showChat=\"false\"\n           sideBar=\"false\"\n           applyHtmlTag=\"false\"\n           applyBodyTag=\"false\">{!domainURL}</apex:page>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/pages/LC_VisualforceDomainPage.page-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexPage xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <availableInTouch>true</availableInTouch>\n    <confirmationTokenRequired>false</confirmationTokenRequired>\n    <label>LC_VisualforceDomainPage</label>\n</ApexPage>\n"
  },
  {
    "path": "force-app/main/default/pages/MA_SetupAuthWizardPage.page",
    "content": "<!--\nAuthor: Doug Ayers\nWebsite: https://douglascayers.com\nGitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\nLicense: BSD 3-Clause License\n -->\n<apex:page controller=\"MA_SetupAuthWizardPageController\">\n\n    <apex:slds />\n\n    <apex:includeScript value=\"{!URLFOR($Resource.jsforce)}\"/>\n    <apex:includeScript value=\"{!URLFOR($Resource.jquery)}\"/>\n    <script>$j = jQuery.noConflict();</script>\n\n    <div class=\"slds-scope\">\n\n        <apex:form id=\"theForm\" styleClass=\"slds-p-around_large\">\n\n            <apex:pageMessages />\n\n            <div id=\"spinner\" class=\"slds-hide\">\n                <div class=\"slds-spinner_container\" style=\"position:fixed\">\n                    <div role=\"status\" class=\"slds-spinner slds-spinner_medium slds-spinner_brand\">\n                        <span class=\"slds-assistive-text\">Loading</span>\n                        <div class=\"slds-spinner__dot-a\"></div>\n                        <div class=\"slds-spinner__dot-b\"></div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"slds-page-header slds-m-bottom_large\">\n                <div class=\"slds-grid\">\n                    <div class=\"slds-col slds-has-flexi-truncate\">\n                        <div class=\"slds-media slds-no-space slds-grow\">\n                            <div class=\"slds-media__body\">\n                                <nav>\n                                    <ol class=\"slds-breadcrumb slds-line-height_reset\">\n                                        <li class=\"slds-breadcrumb__item\">\n                                            <span>Mass Action Scheduler</span>\n                                        </li>\n                                    </ol>\n                                </nav>\n                                <h1 class=\"slds-page-header__title slds-m-right_small slds-align-middle slds-truncate\">\n                                    Authentication Setup Wizard\n                                </h1>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"slds-col slds-no-flex slds-grid slds-align-top\">\n                        <div class=\"slds-button-group\" role=\"group\">\n                            <!--<apex:commandButton value=\" Create Metadata \" onclick=\"createMetadata(); return false;\" styleClass=\"slds-button slds-button_neutral\"/>-->\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"slds-card slds-p-around_card-wrapper-spacing\">\n                <div class=\"slds-grid\">\n                    <div class=\"slds-col slds-shrink-none\">\n\n                        <apex:image value=\"{!URLFOR($Resource.MA_SalesforceSecurityLogo)}\"/>\n\n                    </div>\n                    <div class=\"slds-col slds-m-horizontal_large slds-p-top_small\">\n\n                        <div class=\"slds-text-heading_medium\">1. Usage</div>\n                        <p class=\"slds-p-bottom_medium\">\n                            Mass Action Scheduler uses the <a href=\"https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_what_is_rest_api.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Salesforce REST API</a>\n                            to provide you a robust configuration wizard as well as\n                            to invoke your Flows, Processes, Quick Actions, Apex, and Workflow Rules per your defined schedules.\n                        </p>\n\n                        <div class=\"slds-text-heading_medium\">2. Security Requirements</div>\n                        <p class=\"slds-p-bottom_medium\">\n                            For security purposes, Salesforce requires Lightning Components to\n                            <a href=\"https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_understanding_authentication.htm\" target=\"_blank\" rel=\"noopener noreferrer\">authenticate</a> to the Salesforce REST API\n                            through <a href=\"https://help.salesforce.com/articleView?id=remoteaccess_authenticate.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">OAuth</a>\n                            via <a href=\"https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/apex_api_calls.htm\" target=\"_blank\" rel=\"noopener noreferrer\">Apex</a>.\n                            As a Salesforce Admin, you satisfy these requirements by declaratively creating a\n                            <a href=\"https://help.salesforce.com/articleView?id=connected_app_overview.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">Connected App</a>,\n                            <a href=\"https://help.salesforce.com/articleView?id=sso_provider_sfdc.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">Auth. Provider</a>, and\n                            <a href=\"https://help.salesforce.com/articleView?id=named_credentials_about.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">Named Credential</a>.\n                            These metadata components also ensure that custom apps, like Mass Action Scheduler, never actually receive or know your Salesforce password\n                            and that you have explicitly authorized the app to perform Salesforce operations on your behalf. For example, to run a flow at 5am while you are sleeping 🙂\n                        </p>\n\n                        <div class=\"slds-text-heading_medium\">3a. Manual Setup</div>\n                        <p class=\"slds-p-bottom_medium\">\n                            The manual setup of the Connected App, Auth. Provider, and Named Credential is several clicks and copying and pasting very long and specific values between forms.\n                            This is the primary complaint and barrier to adoption of the Mass Action Scheduler app.\n                            Therefore, the automated setup option is recommended and provided as a convenience.\n                            However, if desired, you can create these items manually by following the instructions on the <a href=\"https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler/wiki/Specify-the-Running-User-via-Named-Credentials\">project wiki page</a>.\n                        </p>\n\n                        <div class=\"slds-text-heading_medium\">3b. Automated Setup</div>\n                        <p class=\"slds-p-bottom_medium\">\n                            This setup wizard will automatically configure the\n                            <a href=\"https://help.salesforce.com/articleView?id=connected_app_overview.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">Connected App</a>,\n                            <a href=\"https://help.salesforce.com/articleView?id=sso_provider_sfdc.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">Auth. Provider</a>, and\n                            <a href=\"https://help.salesforce.com/articleView?id=named_credentials_about.htm&type=5\" target=\"_blank\" rel=\"noopener noreferrer\">Named Credential</a>\n                            metadata required for Mass Action Scheduler to access the Salesforce REST API.\n                            The metadata will be created with the names <b>Mass_Action</b>.\n                        </p>\n\n                        <p class=\"slds-p-bottom_medium\">\n                            <apex:commandButton value=\" Create Connected App, Auth. Provider, and Named Credential \" onclick=\"createMetadata(); return false;\" styleClass=\"slds-button slds-button_brand\"/>\n                        </p>\n\n                        <p class=\"slds-p-bottom_medium\">\n\n                            <div id=\"message-template\" class=\"slds-hide\">\n                                <div class=\"slds-notify_container slds-is-relative\">\n                                    <div class=\"slds-notify slds-notify_toast slds-theme_error slds-theme_alert-texture\" role=\"alert\">\n                                        <span class=\"slds-assistive-text\">error</span>\n                                        <div class=\"slds-notify__content\">\n                                            <h2 class=\"slds-text-heading_small \"><span class=\"message-content\">test</span></h2>\n                                        </div>\n                                        <button class=\"slds-button slds-notify__close slds-button_icon-inverse\" title=\"Close\" onclick=\"clearMessages(); return false;\">\n                                            X\n                                            <span class=\"slds-assistive-text\">Close</span>\n                                        </button>\n                                    </div>\n                                </div>\n                            </div>\n\n                            <div id=\"messages\"><!-- populated by javascript --></div>\n\n                        </p>\n\n                        <div class=\"slds-text-heading_medium\">4. Post Setup</div>\n                        <p class=\"slds-p-bottom_medium\">\n                            <ol class=\"slds-list_ordered\" style=\"list-style-type: lower-alpha;\">\n                                <li class=\"slds-var-m-vertical_small\">\n                                    <b>Wait 10 minutes</b> for the Connected App to become available to the Salesforce login servers, otherwise you will get error <span class=\"slds-text-color_error\">invalid_client_id</span> in step 4b.\n                                </li>\n                                <li class=\"slds-var-m-vertical_small\">\n                                    In Setup, go to the <a href=\"/lightning/setup/NamedCredential/home\" target=\"_blank\" rel=\"noopener noreferrer\">Named Credential</a> record,\n                                    click <b>Edit</b>, ensure the <b>Start Authentication Flow on Save</b> checkbox is selected, then click <b>Save</b>.\n                                </li>\n                                <li class=\"slds-var-m-vertical_small\">\n                                    Salesforce will prompt you to log in with the user credentials you want Mass Action Scheduler app to use.\n                                    On the login page, click <b>Use Custom Domain</b> and enter <span id=\"post-setup-custom-domain\">your org's My Domain</span>.\n                                </li>\n                                <li class=\"slds-var-m-vertical_small\">\n                                    Upon logging in Salesforce will prompt you to authorize Mass Action Scheduler app to perform requests on your behalf.\n                                    At no time will Mass Action Scheduler app be provided your <i>actual</i> Salesforce password, which is a purpose of these security requirements.\n                                </li>\n                            </ol>\n                            Once you have done this final step, then you are ready to create your own <a href=\"{!URLFOR( $Action.Mass_Action_Configuration__c.New )}\">Mass Action Configurations</a> to\n                            declaratively schedule Process Builder, Flows, Quick Actions, Email Alerts, Workflow Rules, and Apex to process records from Reports and List Views.\n                        </p>\n\n                        <hr/>\n\n                        <div class=\"slds-text-heading_medium\">Troubleshooting Automated Setup Errors</div>\n                        <p class=\"slds-p-bottom_medium\">\n\n                            <div class=\"slds-text-heading_small slds-text-color_error\">error: duplicate value found</div>\n                            <p class=\"slds-p-bottom_small\">\n                                This error means a Connected App or Named Credential already exists with the unique name <b>Mass_Action</b>.\n                                This may occur if you have already created the metadata manually or have already used the automated setup.\n                            </p>\n\n                            <div class=\"slds-text-heading_small slds-text-color_error\">error=This URL Suffix already exists or has been previously used</div>\n                            <p class=\"slds-p-bottom_small\">\n                                This error means an Auth. Provider already exists with the unique name <b>Mass_Action</b>.\n                                This may occur if you have already created the metadata manually or have already used the automated setup.\n                            </p>\n\n                            <div class=\"slds-text-heading_small slds-text-color_error\">error=invalid_client_id</div>\n                            <p class=\"slds-p-bottom_small\">\n                                This error can occur when you save the newly created Named Credential to complete the authentication flow\n                                and Salesforce has not completed syncing the changes to the login servers.\n                                Wait 10 minutes then try again. If the issue continues, then delete and re-create the\n                                Connected App, Auth. Provider, and Named Credential.\n                            </p>\n\n                            <div class=\"slds-text-heading_small slds-text-color_error\">Problem Logging In: No CSRF cookie</div>\n                            <p class=\"slds-p-bottom_small\">\n                                In step 4c, when you re-save the Named Credential to provide your credentials, you might get an error\n                                on the first attempt about <b>CSRF: No CSRF cookie</b>. Make sure you enter your Custom Domain on the\n                                Salesforce login page. Re-navigate back to the Named Credential in Setup menu and try again.\n                            </p>\n\n                        </p>\n\n                    </div>\n                </div>\n            </div>\n\n        </apex:form>\n\n    </div>\n\n    <script>\n\n        var conn = new jsforce.Connection({\n            accessToken : '{!$Api.Session_Id}',\n            version : '54.0'\n        });\n\n        // When creating a connected app, the consumer key and secret must be plain text.\n        // http://releasenotes.docs.salesforce.com/en-us/spring19/release-notes/rn_identity_client_secret_resize.htm\n        const consumerKey = getRandomLetters( 85 );\n        const consumerSecret = getRandomString( 64, true, false, true, false );\n\n        function createMetadata() {\n\n            $j( '#spinner' ).removeClass( 'slds-hide' );\n            clearMessages();\n\n            Promise.resolve()\n                .then( function() {\n\n                    let label = 'Mass Action';\n                    let fullName = 'Mass_Action';\n                    let orgDomainURL = '{!orgDomainURL}';\n                    let myDomain = '{!myDomain}';\n\n                    // update instructions with exact domain the user should enter to remove guesswork\n                    $j( '#post-setup-custom-domain' ).html( `<code>${myDomain}</code>` );\n\n                    return conn.metadata.create( 'ConnectedApp', buildConnectedApp( label, fullName, orgDomainURL, consumerKey, consumerSecret ) )\n                        .then( function( result ) {\n                            validateMetadataSaveResult( 'ConnectedApp', result );\n                            showMessage( 'Connected App created with name \"' + fullName + '\"', 'SUCCESS' );\n                            return conn.metadata.create( 'AuthProvider', buildAuthProvider( label, fullName, orgDomainURL, consumerKey, consumerSecret ) );\n                        })\n                        .then( function( result ) {\n                            validateMetadataSaveResult( 'AuthProvider', result );\n                            showMessage( 'Auth. Provider created with URL Suffix \"' + fullName + '\"', 'SUCCESS' );\n                            return conn.metadata.create( 'NamedCredential', buildNamedCredential( label, fullName, orgDomainURL ) );\n                        })\n                        .then( function( result ) {\n                            validateMetadataSaveResult( 'NamedCredential', result );\n                            showMessage( 'Named Credential created with name \"' + fullName + '\"', 'SUCCESS' );\n                            return conn.query( 'SELECT Id FROM NamedCredential WHERE DeveloperName = \\'' + fullName + '\\' LIMIT 1' );\n                        })\n                        .then( function( result ) {\n                            console.log( result );\n                            showMessage( 'Wait <b>10 minutes</b> then complete authentication flow by <a href=\"/lightning/setup/NamedCredential/page?address=%2F' + result.records[0].Id + '%2Fe\" target=\"_blank\" rel=\"noopener noreferrer\">re-saving the Named Credential</a>', 'WARNING' );\n                        });\n\n                })\n                .catch( function( err ) {\n                    console.error( err );\n                    showMessage( err.message, 'ERROR' );\n                })\n                .then( function() {\n                    $j( '#spinner' ).addClass( 'slds-hide' );\n                });\n        }\n\n        function buildConnectedApp( label, fullName, orgDomainURL, consumerKey, consumerSecret ) {\n            return {\n                fullName : fullName,\n                label : label,\n                description : 'Auto-generated for Mass Action Scheduler using the app\\'s Authentication Setup Wizard.',\n                contactEmail : '{!$User.Email}',\n                oauthConfig : {\n                    callbackUrl : orgDomainURL + '/services/authcallback/' + fullName,\n                    consumerKey : consumerKey,\n                    consumerSecret : consumerSecret,\n                    scopes : [\n                        'Full',\n                        'RefreshToken'\n                    ]\n                }\n            };\n        }\n\n        function buildAuthProvider( label, fullName, orgDomainURL, consumerKey, consumerSecret ) {\n            return {\n                fullName : fullName,\n                friendlyName : label,\n                includeOrgIdInIdentifier : true,\n                providerType : 'Salesforce',\n                consumerKey : consumerKey,\n                consumerSecret : consumerSecret\n            };\n        }\n\n        function buildNamedCredential( label, fullName, orgDomainURL ) {\n            return {\n                fullName : fullName,\n                label : label,\n                authProvider : fullName,\n                endpoint : orgDomainURL,\n                oauthScope : 'full refresh_token',\n                principalType : 'NamedUser',\n                protocol : 'Oauth',\n                allowMergeFieldsInHeader : true,\n                allowMergeFieldsInBody : true\n            };\n        }\n\n        /**\n         * Validates the metadata save result.\n         * If success is false, then throws error.\n         *\n         * @param type the metadata type (e.g. NamedCredential, CustomObject)\n         * @param result the save result\n         */\n        function validateMetadataSaveResult( type, result ) {\n            console.log( 'validating metadata save result: type=' + type + ', fullName=' + result.fullName );\n            console.log( result );\n            if ( !result.success ) {\n                var message = 'type=' + type + ', name=' + result.fullName + ', error=' + result.errors.message;\n                throw new Error( message );\n            }\n        }\n\n        /**\n         * Shows a dismissable message notification at top of page.\n         *\n         * @param message text to display\n         * @param severity SUCCESS, ERROR\n         */\n        function showMessage( message, severity ) {\n\n            var newMessage = $j( '#message-template' ).children().clone();\n\n            $j( newMessage ).find( 'div[role=\"alert\"]' )\n                .removeClass( 'slds-theme_error' )\n                .removeClass( 'slds-theme_success' )\n                .addClass( 'slds-theme_' + severity.toLowerCase() );\n\n            $j( newMessage ).removeClass( 'slds-hide' );\n\n            $j( newMessage ).find( '.message-content' ).html( message );\n            $j( newMessage ).find( '.slds-assistive-text' ).text( severity );\n\n            $j( '#messages' ).append( newMessage );\n\n        }\n\n        function clearMessages() {\n            $j( '#messages' ).empty();\n        }\n\n        // ----------------------------------------------------------\n\n        function getRandomLetters( num ) {\n            return getRandomString( num, true, true, false, false );\n        }\n\n        function getRandomNumbers( num ) {\n            return getRandomString( num, false, false, true, false );\n        }\n\n        /**\n         * Generates a random string.\n         *\n         * @param num number of characters to generate\n         * @param includeUpperCase A-Z\n         * @param includeLowerCase a-z\n         * @param includeDigits 0-9\n         * @param includeSymbols !@#$%^&*()\n         * @returns {string}\n         */\n        function getRandomString( num, includeUpperCase, includeLowerCase, includeDigits, includeSymbols ) {\n\n            var CHARS = '';\n            if ( includeUpperCase ) {\n                CHARS += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n            }\n            if ( includeLowerCase ) {\n                CHARS += 'abcdefghijklmnopqrstuvwxyz';\n            }\n            if ( includeDigits ) {\n                CHARS += '0123456789';\n            }\n            if ( includeSymbols ) {\n                CHARS += '!@#$%^&*()';\n            }\n\n            var randomNumbers = new Uint32Array( num );\n            window.crypto.getRandomValues( randomNumbers ); // fills array with random values\n\n            var text = '';\n            randomNumbers.forEach( function( number ) {\n                var idx = ( number % CHARS.length );\n                text += CHARS.substring( idx, idx + 1 );\n            });\n\n            return text;\n        }\n\n    </script>\n\n</apex:page>\n<!--\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n-->"
  },
  {
    "path": "force-app/main/default/pages/MA_SetupAuthWizardPage.page-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexPage xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <availableInTouch>true</availableInTouch>\n    <confirmationTokenRequired>false</confirmationTokenRequired>\n    <label>MA_SetupAuthWizardPage</label>\n</ApexPage>\n"
  },
  {
    "path": "force-app/main/default/permissionsets/Mass_Action_Admin.permissionset-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<PermissionSet xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <applicationVisibilities>\n        <application>Mass_Action_Scheduler</application>\n        <visible>true</visible>\n    </applicationVisibilities>\n    <applicationVisibilities>\n        <application>Mass_Action_Scheduler_Lightning</application>\n        <visible>true</visible>\n    </applicationVisibilities>\n    <classAccesses>\n        <apexClass>LC_URLController</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>LC_URLControllerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>LC_VisualforceDomainController</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>LC_VisualforceDomainControllerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_AnonymousApexExecuteResult</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_AsyncApexJobMock</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_BatchApexErrorEventInvocable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_BatchApexErrorEventInvocableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_BatchApexStatusEventTriggerHandler</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_BatchApexStatusEventTriggerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_EditConfigCmpController</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_EditConfigCmpControllerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_EditConfigRestController</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_EditConfigRestControllerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_Exceptions</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ExceptionsTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_HttpCalloutMock</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_InstallHandler</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_InstallHandlerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_IterableSourceBatchable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_IterableSourceBatchableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_JobChangeEvent</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_JobChangeEventTriggerHandler</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_JobChangeEventTriggerHandlerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ListViewDescribeResult</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ListViewDescribeResultTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ListViewSourceBatchable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ListViewSourceBatchableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MapUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MapUtilsTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionBatchEnqueuer</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionBatchUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionBatchUtilsTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionConfigTriggerHandler</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionConfigTriggerHandlerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionConfigWrapper</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionLogTriggerHandler</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionLogTriggerHandlerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionSchedulable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionSchedulableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionScheduleUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionScheduleUtilsTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MassActionUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MetadataDeployCallback</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_MetadataDeployCallbackTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_NamespaceUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ReportService</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ReportServiceTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ReportSourceBatchable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_ReportSourceBatchableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_RunConfigCmpController</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_RunConfigCmpControllerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_RunConfigInvocable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_RunConfigInvocableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SetConfigUniqueNameBatchable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SetConfigUniqueNameBatchableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SetupAuthWizardPageController</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SetupAuthWizardPageControllerTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SoqlQueryExecuteResult</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SoqlQueryExecuteResultTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SoqlSourceBatchable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SoqlSourceBatchableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SoqlSourceIterable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_SoqlSourceIterableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_StringUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_StringUtilsTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_UpgradeMassActionLogsBatchable</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_UpgradeMassActionLogsBatchableTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_UpgradePageLayoutsService</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_UpgradePageLayoutsServiceTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_XMLUtils</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <classAccesses>\n        <apexClass>MA_XMLUtilsTest</apexClass>\n        <enabled>true</enabled>\n    </classAccesses>\n    <description>Grants user access to Mass Action Configurations.</description>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Active__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Batch_Size__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Description__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.DeveloperName__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Last_Run_Completed_Date__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Last_Run_Completed_With_Errors__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Named_Credential__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_Cron__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_DayOfMonth__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_DayOfWeek__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_Frequency__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_HourOfDay__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_MinuteOfHour__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_MonthOfYear__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Schedule_SecondOfMinute__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Source_Apex_Class__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Source_List_View_ID__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Source_Report_Column_Name__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Source_Report_ID__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Source_SOQL_Query__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Source_Type__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Target_Action_Name__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Target_Apex_Script__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Target_SObject_Type__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Configuration__c.Target_Type__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>false</editable>\n        <field>Mass_Action_Log__c.Batch_Success_Percentage__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>false</editable>\n        <field>Mass_Action_Log__c.Batch_Success_Rate__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Failed_Batches__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Job_ID__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Job_Scope__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Long_Message__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Message_Type__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Message__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Parent_Log_Configuration__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Parent_Log__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Processed_Batches__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Submitted_Date__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Timestamp__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <fieldPermissions>\n        <editable>true</editable>\n        <field>Mass_Action_Log__c.Total_Batches__c</field>\n        <readable>true</readable>\n    </fieldPermissions>\n    <hasActivationRequired>false</hasActivationRequired>\n    <label>Mass Action Admin</label>\n    <objectPermissions>\n        <allowCreate>true</allowCreate>\n        <allowDelete>false</allowDelete>\n        <allowEdit>false</allowEdit>\n        <allowRead>true</allowRead>\n        <modifyAllRecords>false</modifyAllRecords>\n        <object>Mass_Action_Batch_Apex_Status_Event__e</object>\n        <viewAllRecords>false</viewAllRecords>\n    </objectPermissions>\n    <objectPermissions>\n        <allowCreate>true</allowCreate>\n        <allowDelete>true</allowDelete>\n        <allowEdit>true</allowEdit>\n        <allowRead>true</allowRead>\n        <modifyAllRecords>true</modifyAllRecords>\n        <object>Mass_Action_Configuration__c</object>\n        <viewAllRecords>true</viewAllRecords>\n    </objectPermissions>\n    <objectPermissions>\n        <allowCreate>true</allowCreate>\n        <allowDelete>false</allowDelete>\n        <allowEdit>false</allowEdit>\n        <allowRead>true</allowRead>\n        <modifyAllRecords>false</modifyAllRecords>\n        <object>Mass_Action_Job_Change_Event__e</object>\n        <viewAllRecords>false</viewAllRecords>\n    </objectPermissions>\n    <objectPermissions>\n        <allowCreate>true</allowCreate>\n        <allowDelete>true</allowDelete>\n        <allowEdit>true</allowEdit>\n        <allowRead>true</allowRead>\n        <modifyAllRecords>true</modifyAllRecords>\n        <object>Mass_Action_Log__c</object>\n        <viewAllRecords>true</viewAllRecords>\n    </objectPermissions>\n    <objectPermissions>\n        <allowCreate>true</allowCreate>\n        <allowDelete>true</allowDelete>\n        <allowEdit>true</allowEdit>\n        <allowRead>true</allowRead>\n        <modifyAllRecords>true</modifyAllRecords>\n        <object>Mass_Action_Mapping__c</object>\n        <viewAllRecords>true</viewAllRecords>\n    </objectPermissions>\n    <pageAccesses>\n        <apexPage>LC_APIPage</apexPage>\n        <enabled>true</enabled>\n    </pageAccesses>\n    <pageAccesses>\n        <apexPage>LC_VisualforceDomainPage</apexPage>\n        <enabled>true</enabled>\n    </pageAccesses>\n    <pageAccesses>\n        <apexPage>MA_SetupAuthWizardPage</apexPage>\n        <enabled>true</enabled>\n    </pageAccesses>\n    <recordTypeVisibilities>\n        <recordType>Mass_Action_Log__c.Child_Log</recordType>\n        <visible>true</visible>\n    </recordTypeVisibilities>\n    <recordTypeVisibilities>\n        <recordType>Mass_Action_Log__c.Parent_Log</recordType>\n        <visible>true</visible>\n    </recordTypeVisibilities>\n    <tabSettings>\n        <tab>MA_SetupAuthWizardPageTab</tab>\n        <visibility>Visible</visibility>\n    </tabSettings>\n    <tabSettings>\n        <tab>Mass_Action_Configuration__c</tab>\n        <visibility>Visible</visibility>\n    </tabSettings>\n    <tabSettings>\n        <tab>Mass_Action_Log__c</tab>\n        <visibility>Visible</visibility>\n    </tabSettings>\n</PermissionSet>\n"
  },
  {
    "path": "force-app/main/default/quickActions/Mass_Action_Configuration__c.Quick_Edit.quickAction-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<QuickAction xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <description>Toggle the configuration being active/inactive and batch size.</description>\n    <label>Quick Edit</label>\n    <optionsCreateFeedItem>false</optionsCreateFeedItem>\n    <quickActionLayout>\n        <layoutSectionStyle>TwoColumnsLeftToRight</layoutSectionStyle>\n        <quickActionLayoutColumns>\n            <quickActionLayoutItems>\n                <emptySpace>false</emptySpace>\n                <field>Name</field>\n                <uiBehavior>Required</uiBehavior>\n            </quickActionLayoutItems>\n            <quickActionLayoutItems>\n                <emptySpace>false</emptySpace>\n                <field>DeveloperName__c</field>\n                <uiBehavior>Required</uiBehavior>\n            </quickActionLayoutItems>\n            <quickActionLayoutItems>\n                <emptySpace>false</emptySpace>\n                <field>Batch_Size__c</field>\n                <uiBehavior>Required</uiBehavior>\n            </quickActionLayoutItems>\n            <quickActionLayoutItems>\n                <emptySpace>false</emptySpace>\n                <field>Active__c</field>\n                <uiBehavior>Edit</uiBehavior>\n            </quickActionLayoutItems>\n            <quickActionLayoutItems>\n                <emptySpace>false</emptySpace>\n                <field>Description__c</field>\n                <uiBehavior>Edit</uiBehavior>\n            </quickActionLayoutItems>\n        </quickActionLayoutColumns>\n        <quickActionLayoutColumns/>\n    </quickActionLayout>\n    <type>Update</type>\n</QuickAction>\n"
  },
  {
    "path": "force-app/main/default/quickActions/Mass_Action_Configuration__c.Run.quickAction-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<QuickAction xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <description>(deprecated) Runs the Mass Action now.</description>\n    <height>250</height>\n    <label>Run</label>\n    <lightningComponent>MA_RunConfigCmp</lightningComponent>\n    <optionsCreateFeedItem>false</optionsCreateFeedItem>\n    <type>LightningComponent</type>\n    <width>-100</width>\n</QuickAction>\n"
  },
  {
    "path": "force-app/main/default/quickActions/Mass_Action_Configuration__c.Run_via_Flow.quickAction-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<QuickAction xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <description>(recommended) The flow prompts the user to choose an active configuration to run. Upon user confirmation, submits the batch job. Same concept as &quot;Run Flow&quot; action, but this one remains in page layouts after package upgrades.</description>\n    <flowDefinition>MAS_Run_Mass_Action_Flow</flowDefinition>\n    <label>Run</label>\n    <optionsCreateFeedItem>false</optionsCreateFeedItem>\n    <type>Flow</type>\n</QuickAction>\n"
  },
  {
    "path": "force-app/main/default/reports/Mass_Action_Test_Reports/MA_Test_Account_Report.report-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Report xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <columns>\n        <field>ACCOUNT_ID</field>\n    </columns>\n    <columns>\n        <field>PARENT_ID</field>\n    </columns>\n    <description>For report automation solutions by Doug Ayers (https://douglascayers.com)</description>\n    <filter>\n        <criteriaItems>\n            <column>ACCOUNT.NAME</column>\n            <isUnlocked>true</isUnlocked>\n            <operator>startsWith</operator>\n            <value>dca_mass_action: MA Test Account</value>\n        </criteriaItems>\n    </filter>\n    <format>Tabular</format>\n    <name>MA Test Account Report</name>\n    <params>\n        <name>co</name>\n        <value>1</value>\n    </params>\n    <reportType>AccountList</reportType>\n    <scope>organization</scope>\n    <showDetails>true</showDetails>\n    <showGrandTotal>true</showGrandTotal>\n    <showSubTotals>true</showSubTotals>\n    <sortColumn>ACCOUNT_ID</sortColumn>\n    <sortOrder>Asc</sortOrder>\n    <timeFrameFilter>\n        <dateColumn>CREATED_DATE</dateColumn>\n        <interval>INTERVAL_CUSTOM</interval>\n    </timeFrameFilter>\n</Report>\n"
  },
  {
    "path": "force-app/main/default/reports/Mass_Action_Test_Reports.reportFolder-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ReportFolder xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <folderShares>\n        <accessLevel>View</accessLevel>\n        <sharedTo>AllInternalUsers</sharedTo>\n        <sharedToType>Organization</sharedToType>\n    </folderShares>\n    <name>Mass Action Test Reports</name>\n</ReportFolder>\n"
  },
  {
    "path": "force-app/main/default/staticresources/MA_SalesforceSecurityLogo.resource-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<StaticResource xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <cacheControl>Private</cacheControl>\n    <contentType>image/png</contentType>\n    <description>Salesforce cloud logo with the word &quot;Security&quot; underneath.</description>\n</StaticResource>\n"
  },
  {
    "path": "force-app/main/default/staticresources/jquery.js",
    "content": "/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(e,t){\"use strict\";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return\"function\"==typeof t&&\"number\"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement(\"script\");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?l[c.call(e)]||\"object\":typeof e}var b=\"3.3.1\",w=function(e,t){return new w.fn.init(e,t)},T=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;w.fn=w.prototype={jquery:\"3.3.1\",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:\"jQuery\"+(\"3.3.1\"+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==c.call(e))&&(!(t=i(e))||\"function\"==typeof(n=f.call(t,\"constructor\")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(T,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,\"string\"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),\"function\"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){l[\"[object \"+t+\"]\"]=t.toLowerCase()});function C(e){var t=!!e&&\"length\"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b=\"sizzle\"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",R=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",I=\"\\\\[\"+M+\"*(\"+R+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+R+\"))|)\"+M+\"*\\\\]\",W=\":(\"+R+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+I+\")*)|.*)\\\\)|)\",$=new RegExp(M+\"+\",\"g\"),B=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),F=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),_=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),z=new RegExp(\"=\"+M+\"*([^\\\\]'\\\"]*?)\"+M+\"*\\\\]\",\"g\"),X=new RegExp(W),U=new RegExp(\"^\"+R+\"$\"),V={ID:new RegExp(\"^#(\"+R+\")\"),CLASS:new RegExp(\"^\\\\.(\"+R+\")\"),TAG:new RegExp(\"^(\"+R+\"|[*])\"),ATTR:new RegExp(\"^\"+I),PSEUDO:new RegExp(\"^\"+W),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+P+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\\d$/i,Q=/^[^{]+\\{\\s*\\[native \\w/,J=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,K=/[+~]/,Z=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+M+\"?|(\"+M+\")|.)\",\"ig\"),ee=function(e,t,n){var r=\"0x\"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ne=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&(\"form\"in e||\"label\"in e)},{dir:\"parentNode\",next:\"legend\"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],\"string\"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+\" \"]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if(\"object\"!==t.nodeName.toLowerCase()){(c=t.getAttribute(\"id\"))?c=c.replace(te,ne):t.setAttribute(\"id\",c=b),s=(h=a(e)).length;while(s--)h[s]=\"#\"+c+\" \"+ve(h[s]);v=h.join(\",\"),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute(\"id\")}}}return u(e.replace(B,\"$1\"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+\" \")>r.cacheLength&&delete t[e.shift()],t[n+\" \"]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split(\"|\"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return\"input\"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return(\"input\"===n||\"button\"===n)&&t.type===e}}function de(e){return function(t){return\"form\"in t?t.parentNode&&!1===t.disabled?\"label\"in t?\"label\"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:\"label\"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&\"HTML\"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener(\"unload\",re,!1):i.attachEvent&&i.attachEvent(\"onunload\",re)),n.attributes=ue(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute(\"id\")===t}},r.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return n&&n.value===t}},r.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML=\"<a id='\"+b+\"'></a><select id='\"+b+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&y.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||y.push(\"\\\\[\"+M+\"*(?:value|\"+P+\")\"),e.querySelectorAll(\"[id~=\"+b+\"-]\").length||y.push(\"~=\"),e.querySelectorAll(\":checked\").length||y.push(\":checked\"),e.querySelectorAll(\"a#\"+b+\"+*\").length||y.push(\".#.+[+~]\")}),ue(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=d.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&y.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&y.push(\":enabled\",\":disabled\"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&y.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),y.push(\",.*:\")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,\"*\"),m.call(e,\"[s!='']:x\"),v.push(\"!=\",W)}),y=y.length&&new RegExp(y.join(\"|\")),v=v.length&&new RegExp(v.join(\"|\")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,\"='$1']\"),n.matchesSelector&&g&&!S[t+\" \"]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+\"\").replace(te,ne)},oe.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n=\"\",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||\"\").replace(Z,ee),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&E(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?\"!=\"===t:!t||(i+=\"\",\"=\"===t?i===n:\"!=\"===t?i!==n:\"^=\"===t?n&&0===i.indexOf(n):\"*=\"===t?n&&i.indexOf(n)>-1:\"$=\"===t?n&&i.slice(-n.length)===n:\"~=\"===t?(\" \"+i.replace($,\" \")+\" \").indexOf(n)>-1:\"|=\"===t&&(i===n||i.slice(0,n.length+1)===n+\"-\"))}},CHILD:function(e,t,n,r,i){var o=\"nth\"!==e.slice(0,3),a=\"last\"!==e.slice(-4),s=\"of-type\"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?\"nextSibling\":\"previousSibling\",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g=\"only\"===e&&!h&&\"nextSibling\"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error(\"unsupported pseudo: \"+e);return i[b]?i(t):i.length>1?(n=[e,e,\"\",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,\"$1\"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||\"\")||oe.error(\"unsupported lang: \"+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute(\"xml:lang\")||t.getAttribute(\"lang\"))return(n=n.toLowerCase())===e||0===n.indexOf(e+\"-\")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:he(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:he(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=r.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})r.pseudos[t]=fe(t);for(t in{submit:!0,reset:!0})r.pseudos[t]=pe(t);function ye(){}ye.prototype=r.filters=r.pseudos,r.setFilters=new ye,a=oe.tokenize=function(e,t){var n,i,o,a,s,u,l,c=k[e+\" \"];if(c)return t?0:c.slice(0);s=e,u=[],l=r.preFilter;while(s){n&&!(i=F.exec(s))||(i&&(s=s.slice(i[0].length)||s),u.push(o=[])),n=!1,(i=_.exec(s))&&(n=i.shift(),o.push({value:n,type:i[0].replace(B,\" \")}),s=s.slice(n.length));for(a in r.filter)!(i=V[a].exec(s))||l[a]&&!(i=l[a](i))||(n=i.shift(),o.push({value:n,type:a,matches:i}),s=s.slice(n.length));if(!n)break}return t?s.length:s?oe.error(e):k(e,u).slice(0)};function ve(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function me(e,t,n){var r=t.dir,i=t.next,o=i||r,a=n&&\"parentNode\"===o,s=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||a)return e(t,n,i);return!1}:function(t,n,u){var l,c,f,p=[T,s];if(u){while(t=t[r])if((1===t.nodeType||a)&&e(t,n,u))return!0}else while(t=t[r])if(1===t.nodeType||a)if(f=t[b]||(t[b]={}),c=f[t.uniqueID]||(f[t.uniqueID]={}),i&&i===t.nodeName.toLowerCase())t=t[r]||t;else{if((l=c[o])&&l[0]===T&&l[1]===s)return p[2]=l[2];if(c[o]=p,p[2]=e(t,n,u))return!0}return!1}}function xe(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r<i;r++)oe(e,t[r],n);return n}function we(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Te(e,t,n,r,i,o){return r&&!r[b]&&(r=Te(r)),i&&!i[b]&&(i=Te(i,o)),se(function(o,a,s,u){var l,c,f,p=[],d=[],h=a.length,g=o||be(t||\"*\",s.nodeType?[s]:s,[]),y=!e||!o&&t?g:we(g,p,e,s,u),v=n?i||(o?e:h||r)?[]:a:y;if(n&&n(y,v,s,u),r){l=we(v,d),r(l,[],s,u),c=l.length;while(c--)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f))}if(o){if(i||e){if(i){l=[],c=v.length;while(c--)(f=v[c])&&l.push(y[c]=f);i(null,v=[],l,u)}c=v.length;while(c--)(f=v[c])&&(l=i?O(o,f):p[c])>-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[\" \"],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u<o;u++)if(n=r.relative[e[u].type])p=[me(xe(p),n)];else{if((n=r.filter[e[u].type].apply(null,e[u].matches))[b]){for(i=++u;i<o;i++)if(r.relative[e[i].type])break;return Te(u>1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:\" \"===e[u-2].type?\"*\":\"\"})).replace(B,\"$1\"),n,u<i&&Ce(e.slice(u,i)),i<o&&Ce(e=e.slice(i)),i<o&&ve(e))}p.push(n)}return xe(p)}function Ee(e,t){var n=t.length>0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m=\"0\",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG(\"*\",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+\" \"];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p=\"function\"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&\"ID\"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split(\"\").sort(D).join(\"\")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement(\"fieldset\"))}),ue(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||le(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||le(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute(\"disabled\")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[\":\"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):\"string\"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t<r;t++)if(w.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)w.find(e,i[t],n);return r>1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,\"string\"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,\"string\"==typeof e){if(!(i=\"<\"===e[0]&&\">\"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(w.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&w(e);if(!D.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,\"parentNode\")},parentsUntil:function(e,t,n){return k(e,\"parentNode\",n)},next:function(e){return P(e,\"nextSibling\")},prev:function(e){return P(e,\"previousSibling\")},nextAll:function(e){return k(e,\"nextSibling\")},prevAll:function(e){return k(e,\"previousSibling\")},nextUntil:function(e,t,n){return k(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return k(e,\"previousSibling\",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,\"iframe\")?e.contentDocument:(N(e,\"template\")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return\"Until\"!==e.slice(-5)&&(r=n),r&&\"string\"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\\x20\\t\\r\\n\\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e=\"string\"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s<o.length)!1===o[s].apply(n[0],n[1])&&e.stopOnFalse&&(s=o.length,n=!1)}e.memory||(n=!1),t=!1,i&&(o=n?[]:\"\")},l={add:function(){return o&&(n&&!t&&(s=o.length-1,a.push(n)),function t(n){w.each(n,function(n,r){g(r)?e.unique&&l.has(r)||o.push(r):r&&r.length&&\"string\"!==x(r)&&t(r)})}(arguments),n&&!t&&u()),this},remove:function(){return w.each(arguments,function(e,t){var n;while((n=w.inArray(t,o,n))>-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n=\"\",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=\"\"),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[[\"notify\",\"progress\",w.Callbacks(\"memory\"),w.Callbacks(\"memory\"),2],[\"resolve\",\"done\",w.Callbacks(\"once memory\"),w.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",w.Callbacks(\"once memory\"),w.Callbacks(\"once memory\"),1,\"rejected\"]],r=\"pending\",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},\"catch\":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+\"With\"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t<o)){if((e=r.apply(s,u))===n.promise())throw new TypeError(\"Thenable self-resolution\");l=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,g(l)?i?l.call(e,a(o,n,I,i),a(o,n,W,i)):(o++,l.call(e,a(o,n,I,i),a(o,n,W,i),a(o,n,I,n.notifyWith))):(r!==I&&(s=void 0,u=[e]),(i||n.resolveWith)(s,u))}},c=i?l:function(){try{l()}catch(e){w.Deferred.exceptionHook&&w.Deferred.exceptionHook(e,c.stackTrace),t+1>=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+\"With\"](this===o?void 0:this,arguments),this},o[t[0]+\"With\"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),\"pending\"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn(\"jQuery.Deferred exception: \"+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener(\"DOMContentLoaded\",_),e.removeEventListener(\"load\",_),w.ready()}\"complete\"===r.readyState||\"loading\"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener(\"DOMContentLoaded\",_),e.addEventListener(\"load\",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},X=/^-ms-/,U=/-([a-z])/g;function V(e,t){return t.toUpperCase()}function G(e){return e.replace(X,\"ms-\").replace(U,V)}var Y=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Q(){this.expando=w.expando+Q.uid++}Q.uid=1,Q.prototype={cache:function(e){var t=e[this.expando];return t||(t={},Y(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[G(t)]=n;else for(r in t)i[G(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][G(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(G):(t=G(t))in r?[t]:t.match(M)||[]).length;while(n--)delete r[t[n]]}(void 0===t||w.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!w.isEmptyObject(t)}};var J=new Q,K=new Q,Z=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,ee=/[A-Z]/g;function te(e){return\"true\"===e||\"false\"!==e&&(\"null\"===e?null:e===+e+\"\"?+e:Z.test(e)?JSON.parse(e):e)}function ne(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(ee,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=te(n)}catch(e){}K.set(e,t,n)}else n=void 0;return n}w.extend({hasData:function(e){return K.hasData(e)||J.hasData(e)},data:function(e,t,n){return K.access(e,t,n)},removeData:function(e,t){K.remove(e,t)},_data:function(e,t,n){return J.access(e,t,n)},_removeData:function(e,t){J.remove(e,t)}}),w.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=K.get(o),1===o.nodeType&&!J.get(o,\"hasDataAttrs\"))){n=a.length;while(n--)a[n]&&0===(r=a[n].name).indexOf(\"data-\")&&(r=G(r.slice(5)),ne(o,r,i[r]));J.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof e?this.each(function(){K.set(this,e)}):z(this,function(t){var n;if(o&&void 0===t){if(void 0!==(n=K.get(o,e)))return n;if(void 0!==(n=ne(o,e)))return n}else this.each(function(){K.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks(\"once memory\").add(function(){J.remove(e,[t+\"queue\",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return\"string\"!=typeof e&&(t=e,e=\"fx\",n--),arguments.length<n?w.queue(this[0],e):void 0===t?this:this.each(function(){var n=w.queue(this,e,t);w._queueHooks(this,e),\"fx\"===e&&\"inprogress\"!==n[0]&&w.dequeue(this,e)})},dequeue:function(e){return this.each(function(){w.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=w.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=J.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var re=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ie=new RegExp(\"^(?:([+-])=|)(\"+re+\")([a-z%]*)$\",\"i\"),oe=[\"Top\",\"Right\",\"Bottom\",\"Left\"],ae=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&w.contains(e.ownerDocument,e)&&\"none\"===w.css(e,\"display\")},se=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i};function ue(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return w.css(e,t,\"\")},u=s(),l=n&&n[3]||(w.cssNumber[t]?\"\":\"px\"),c=(w.cssNumber[t]||\"px\"!==l&&+u)&&ie.exec(w.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)w.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,w.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var le={};function ce(e){var t,n=e.ownerDocument,r=e.nodeName,i=le[r];return i||(t=n.body.appendChild(n.createElement(r)),i=w.css(t,\"display\"),t.parentNode.removeChild(t),\"none\"===i&&(i=\"block\"),le[r]=i,i)}function fe(e,t){for(var n,r,i=[],o=0,a=e.length;o<a;o++)(r=e[o]).style&&(n=r.style.display,t?(\"none\"===n&&(i[o]=J.get(r,\"display\")||null,i[o]||(r.style.display=\"\")),\"\"===r.style.display&&ae(r)&&(i[o]=ce(r))):\"none\"!==n&&(i[o]=\"none\",J.set(r,\"display\",n)));for(o=0;o<a;o++)null!=i[o]&&(e[o].style.display=i[o]);return e}w.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?w(this).show():w(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]+)/i,he=/^$|^module$|\\/(?:java|ecma)script/i,ge={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n<r;n++)J.set(e[n],\"globalEval\",!t||J.get(t[n],\"globalEval\"))}var me=/<|&#?\\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===x(o))w.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+w.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;w.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&w.inArray(o,r)>-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),\"script\"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement(\"div\")),t=r.createElement(\"input\");t.setAttribute(\"type\",\"radio\"),t.setAttribute(\"checked\",\"checked\"),t.setAttribute(\"name\",\"t\"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML=\"<textarea>x</textarea>\",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){\"string\"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return\"undefined\"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||\"\").match(M)||[\"\"]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||\"\").match(M)||[\"\"]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||\"\").split(\".\").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,\"handle events\")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,\"events\")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n<arguments.length;n++)u[n]=arguments[n];if(t.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,t)){s=w.event.handlers.call(this,t,l),n=0;while((o=s[n++])&&!t.isPropagationStopped()){t.currentTarget=o.elem,r=0;while((a=o.handlers[r++])&&!t.isImmediatePropagationStopped())t.rnamespace&&!t.rnamespace.test(a.namespace)||(t.handleObj=a,t.data=a.data,void 0!==(i=((w.event.special[a.origType]||{}).handle||a.handler).apply(o.elem,u))&&!1===(t.result=i)&&(t.preventDefault(),t.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,t),t.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&e.button>=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?w(i,this).index(l)>-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(e,t){Object.defineProperty(w.Event.prototype,e,{enumerable:!0,configurable:!0,get:g(t)?function(){if(this.originalEvent)return t(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[e]},set:function(t){Object.defineProperty(this,e,{enumerable:!0,configurable:!0,writable:!0,value:t})}})},fix:function(e){return e[w.expando]?e:new w.Event(e)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==Se()&&this.focus)return this.focus(),!1},delegateType:\"focusin\"},blur:{trigger:function(){if(this===Se()&&this.blur)return this.blur(),!1},delegateType:\"focusout\"},click:{trigger:function(){if(\"checkbox\"===this.type&&this.click&&N(this,\"input\"))return this.click(),!1},_default:function(e){return N(e.target,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},w.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},w.Event=function(e,t){if(!(this instanceof w.Event))return new w.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ee:ke,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&w.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[w.expando]=!0},w.Event.prototype={constructor:w.Event,isDefaultPrevented:ke,isPropagationStopped:ke,isImmediatePropagationStopped:ke,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ee,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ee,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ee,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},w.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&we.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Te.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},w.event.addProp),w.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,t){w.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return i&&(i===r||w.contains(r,i))||(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),w.fn.extend({on:function(e,t,n,r){return De(this,e,t,n,r)},one:function(e,t,n,r){return De(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,w(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=ke),this.each(function(){w.event.remove(this,e,n,t)})}});var Ne=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,Ae=/<script|<style|<link/i,je=/checked\\s*(?:[^=]|=\\s*.checked.)/i,qe=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Le(e,t){return N(e,\"table\")&&N(11!==t.nodeType?t:t.firstChild,\"tr\")?w(e).children(\"tbody\")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function Oe(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n<r;n++)w.event.add(t,i,l[i][n])}K.hasData(e)&&(s=K.access(e),u=w.extend({},s),K.set(t,u))}}function Me(e,t){var n=t.nodeName.toLowerCase();\"input\"===n&&pe.test(e.type)?t.checked=e.checked:\"input\"!==n&&\"textarea\"!==n||(t.defaultValue=e.defaultValue)}function Re(e,t,n,r){t=a.apply([],t);var i,o,s,u,l,c,f=0,p=e.length,d=p-1,y=t[0],v=g(y);if(v||p>1&&\"string\"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,\"script\"),He)).length;f<p;f++)l=i,f!==d&&(l=w.clone(l,!0,!0),u&&w.merge(s,ye(l,\"script\"))),n.call(e[f],l,f);if(u)for(c=s[s.length-1].ownerDocument,w.map(s,Oe),f=0;f<u;f++)l=s[f],he.test(l.type||\"\")&&!J.access(l,\"globalEval\")&&w.contains(c,l)&&(l.src&&\"module\"!==(l.type||\"\").toLowerCase()?w._evalUrl&&w._evalUrl(l.src):m(l.textContent.replace(qe,\"\"),c,l))}return e}function Ie(e,t,n){for(var r,i=t?w.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||w.cleanData(ye(r)),r.parentNode&&(n&&w.contains(r.ownerDocument,r)&&ve(ye(r,\"script\")),r.parentNode.removeChild(r));return e}w.extend({htmlPrefilter:function(e){return e.replace(Ne,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r<i;r++)Me(o[r],a[r]);if(t)if(n)for(o=o||ye(e),a=a||ye(s),r=0,i=o.length;r<i;r++)Pe(o[r],a[r]);else Pe(e,s);return(a=ye(s,\"script\")).length>0&&ve(a,!u&&ye(e,\"script\")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(w.cleanData(ye(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=[];return Re(this,arguments,function(t){var n=this.parentNode;w.inArray(this,e)<0&&(w.cleanData(ye(this)),n&&n.replaceChild(t,this))},e)}}),w.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,t){w.fn[e]=function(e){for(var n,r=[],i=w(e),o=i.length-1,a=0;a<=o;a++)n=a===o?this:this.clone(!0),w(i[a])[t](n),s.apply(r,n.get());return this.pushStack(r)}});var We=new RegExp(\"^(\"+re+\")(?!px)[a-z%]+$\",\"i\"),$e=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},Be=new RegExp(oe.join(\"|\"),\"i\");!function(){function t(){if(c){l.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",c.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",be.appendChild(l).appendChild(c);var t=e.getComputedStyle(c);i=\"1%\"!==t.top,u=12===n(t.marginLeft),c.style.right=\"60%\",s=36===n(t.right),o=36===n(t.width),c.style.position=\"absolute\",a=36===c.offsetWidth||\"absolute\",be.removeChild(l),c=null}}function n(e){return Math.round(parseFloat(e))}var i,o,a,s,u,l=r.createElement(\"div\"),c=r.createElement(\"div\");c.style&&(c.style.backgroundClip=\"content-box\",c.cloneNode(!0).style.backgroundClip=\"\",h.clearCloneStyle=\"content-box\"===c.style.backgroundClip,w.extend(h,{boxSizingReliable:function(){return t(),o},pixelBoxStyles:function(){return t(),s},pixelPosition:function(){return t(),i},reliableMarginLeft:function(){return t(),u},scrollboxSize:function(){return t(),a}}))}();function Fe(e,t,n){var r,i,o,a,s=e.style;return(n=n||$e(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||w.contains(e.ownerDocument,e)||(a=w.style(e,t)),!h.pixelBoxStyles()&&We.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function _e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}var ze=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ue={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ve={letterSpacing:\"0\",fontWeight:\"400\"},Ge=[\"Webkit\",\"Moz\",\"ms\"],Ye=r.createElement(\"div\").style;function Qe(e){if(e in Ye)return e;var t=e[0].toUpperCase()+e.slice(1),n=Ge.length;while(n--)if((e=Ge[n]+t)in Ye)return e}function Je(e){var t=w.cssProps[e];return t||(t=w.cssProps[e]=Qe(e)||e),t}function Ke(e,t,n){var r=ie.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function Ze(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=w.css(e,n+oe[a],!0,i)),r?(\"content\"===n&&(u-=w.css(e,\"padding\"+oe[a],!0,i)),\"margin\"!==n&&(u-=w.css(e,\"border\"+oe[a]+\"Width\",!0,i))):(u+=w.css(e,\"padding\"+oe[a],!0,i),\"padding\"!==n?u+=w.css(e,\"border\"+oe[a]+\"Width\",!0,i):s+=w.css(e,\"border\"+oe[a]+\"Width\",!0,i));return!r&&o>=0&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o=\"border-box\"===w.css(e,\"boxSizing\",!1,r),a=o;if(We.test(i)){if(!n)return i;i=\"auto\"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),(\"auto\"===i||!parseFloat(i)&&\"inline\"===w.css(e,\"display\",!1,r))&&(i=e[\"offset\"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?\"border\":\"content\"),a,r,i)+\"px\"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o=\"number\"),null!=n&&n===n&&(\"number\"===o&&(n+=i&&i[3]||(w.cssNumber[s]?\"\":\"px\")),h.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),\"normal\"===i&&t in Ve&&(i=Ve[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each([\"height\",\"width\"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a=\"border-box\"===w.css(e,\"boxSizing\",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,\"border\",!1,o)-.5)),s&&(i=ie.exec(n))&&\"px\"!==(i[3]||\"px\")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,\"marginLeft\"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),w.each({margin:\"\",padding:\"\",border:\"Width\"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o=\"string\"==typeof n?n.split(\" \"):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},\"margin\"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a<i;a++)o[t[a]]=w.css(e,t[a],!1,r);return o}return void 0!==n?w.style(e,t,n):w.css(e,t)},e,t,arguments.length>1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?\"\":\"px\")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=oe[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ct(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),y=J.get(e,\"fxshow\");n.queue||(null==(a=w._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,w.queue(e,\"fx\").length||a.empty.fire()})}));for(r in t)if(i=t[r],it.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!y||void 0===y[r])continue;g=!0}d[r]=y&&y[r]||w.style(e,r)}if((u=!w.isEmptyObject(t))||!w.isEmptyObject(d)){f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=y&&y.display)&&(l=J.get(e,\"display\")),\"none\"===(c=w.css(e,\"display\"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=w.css(e,\"display\"),fe([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===w.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1;for(r in d)u||(y?\"hidden\"in y&&(g=y.hidden):y=J.access(e,\"fxshow\",{display:l}),o&&(y.hidden=!g),g&&fe([e],!0),p.done(function(){g||fe([e]),J.remove(e,\"fxshow\");for(r in d)w.style(e,r,d[r])})),u=lt(g?y[r]:0,r,p),r in y||(y[r]=u.start,g&&(u.end=u.start,u.start=0))}}function ft(e,t){var n,r,i,o,a;for(n in e)if(r=G(n),i=t[r],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=w.cssHooks[r])&&\"expand\"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function pt(e,t,n){var r,i,o=0,a=pt.prefilters.length,s=w.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=nt||st(),n=Math.max(0,l.startTime+l.duration-t),r=1-(n/l.duration||0),o=0,a=l.tweens.length;o<a;o++)l.tweens[o].run(r);return s.notifyWith(e,[l,r,n]),r<1&&a?n:(a||s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:w.extend({},t),opts:w.extend(!0,{specialEasing:{},easing:w.easing._default},n),originalProperties:t,originalOptions:n,startTime:nt||st(),duration:n.duration,tweens:[],createTween:function(t,n){var r=w.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?(s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l,t])):s.rejectWith(e,[l,t]),this}}),c=l.props;for(ft(c,l.opts.specialEasing);o<a;o++)if(r=pt.prefilters[o].call(l,e,c,l.opts))return g(r.stop)&&(w._queueHooks(l.elem,l.opts.queue).stop=r.stop.bind(r)),r;return w.map(c,lt,l),g(l.opts.start)&&l.opts.start.call(e,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),w.fx.timer(w.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l}w.Animation=w.extend(pt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return ue(n.elem,e,ie.exec(t),n),n}]},tweener:function(e,t){g(e)?(t=e,e=[\"*\"]):e=e.match(M);for(var n,r=0,i=e.length;r<i;r++)n=e[r],pt.tweeners[n]=pt.tweeners[n]||[],pt.tweeners[n].unshift(t)},prefilters:[ct],prefilter:function(e,t){t?pt.prefilters.unshift(e):pt.prefilters.push(e)}}),w.speed=function(e,t,n){var r=e&&\"object\"==typeof e?w.extend({},e):{complete:n||!n&&t||g(e)&&e,duration:e,easing:n&&t||t&&!g(t)&&t};return w.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in w.fx.speeds?r.duration=w.fx.speeds[r.duration]:r.duration=w.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){g(r.old)&&r.old.call(this),r.queue&&w.dequeue(this,r.queue)},r},w.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=w.isEmptyObject(e),o=w.speed(t,n,r),a=function(){var t=pt(this,w.extend({},e),o);(i||J.get(this,\"finish\"))&&t.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return\"string\"!=typeof e&&(n=t,t=e,e=void 0),t&&!1!==e&&this.queue(e||\"fx\",[]),this.each(function(){var t=!0,i=null!=e&&e+\"queueHooks\",o=w.timers,a=J.get(this);if(i)a[i]&&a[i].stop&&r(a[i]);else for(i in a)a[i]&&a[i].stop&&ot.test(i)&&r(a[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||w.dequeue(this,e)})},finish:function(e){return!1!==e&&(e=e||\"fx\"),this.each(function(){var t,n=J.get(this),r=n[e+\"queue\"],i=n[e+\"queueHooks\"],o=w.timers,a=r?r.length:0;for(n.finish=!0,w.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),w.each([\"toggle\",\"show\",\"hide\"],function(e,t){var n=w.fn[t];w.fn[t]=function(e,r,i){return null==e||\"boolean\"==typeof e?n.apply(this,arguments):this.animate(ut(t,!0),e,r,i)}}),w.each({slideDown:ut(\"show\"),slideUp:ut(\"hide\"),slideToggle:ut(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,t){w.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),w.timers=[],w.fx.tick=function(){var e,t=0,n=w.timers;for(nt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||w.fx.stop(),nt=void 0},w.fx.timer=function(e){w.timers.push(e),w.fx.start()},w.fx.interval=13,w.fx.start=function(){rt||(rt=!0,at())},w.fx.stop=function(){rt=null},w.fx.speeds={slow:600,fast:200,_default:400},w.fn.delay=function(t,n){return t=w.fx?w.fx.speeds[t]||t:t,n=n||\"fx\",this.queue(n,function(n,r){var i=e.setTimeout(n,t);r.stop=function(){e.clearTimeout(i)}})},function(){var e=r.createElement(\"input\"),t=r.createElement(\"select\").appendChild(r.createElement(\"option\"));e.type=\"checkbox\",h.checkOn=\"\"!==e.value,h.optSelected=t.selected,(e=r.createElement(\"input\")).value=\"t\",e.type=\"radio\",h.radioValue=\"t\"===e.value}();var dt,ht=w.expr.attrHandle;w.fn.extend({attr:function(e,t){return z(this,w.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&\"radio\"===t&&N(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,\"tabindex\");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(\" \")}function mt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function xt(e){return Array.isArray(e)?e:\"string\"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&\" \"+vt(i)+\" \"){a=0;while(o=t[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=vt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&\" \"+vt(i)+\" \"){a=0;while(o=t[a++])while(r.indexOf(\" \"+o+\" \")>-1)r=r.replace(\" \"+o+\" \",\" \");i!==(s=vt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(e,t){var n=typeof e,r=\"string\"===n||Array.isArray(e);return\"boolean\"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&\"boolean\"!==n||((t=mt(this))&&J.set(this,\"__className__\",t),this.setAttribute&&this.setAttribute(\"class\",t||!1===e?\"\":J.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&(\" \"+vt(mt(n))+\" \").indexOf(t)>-1)return!0;return!1}});var bt=/\\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i=\"\":\"number\"==typeof i?i+=\"\":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?\"\":e+\"\"})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&\"set\"in t&&void 0!==t.set(this,i,\"value\")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&\"get\"in t&&void 0!==(n=t.get(i,\"value\"))?n:\"string\"==typeof(n=i.value)?n.replace(bt,\"\"):null==n?\"\":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,\"value\");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!N(n.parentNode,\"optgroup\"))){if(t=w(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=w.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=w.inArray(w.valHooks.option.get(r),o)>-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each([\"radio\",\"checkbox\"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),h.focusin=\"onfocusin\"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,\"type\")?t.type:t,x=f.call(t,\"namespace\")?t.namespace.split(\".\"):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(\".\")>-1&&(m=(x=m.split(\".\")).shift(),x.sort()),c=m.indexOf(\":\")<0&&\"on\"+m,t=t[w.expando]?t:new w.Event(m,\"object\"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join(\".\"),t.rnamespace=t.namespace?new RegExp(\"(^|\\\\.)\"+x.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,\"events\")||{})[t.type]&&J.get(s,\"handle\"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\\?/;w.parseXML=function(t){var n;if(!t||\"string\"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,\"text/xml\")}catch(e){n=void 0}return n&&!n.getElementsByTagName(\"parsererror\").length||w.error(\"Invalid XML: \"+t),n};var St=/\\[\\]$/,Dt=/\\r?\\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+\"[\"+(\"object\"==typeof i&&null!=i?t:\"\")+\"]\",i,n,r)});else if(n||\"object\"!==x(t))r(e,t);else for(i in t)jt(e+\"[\"+i+\"]\",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join(\"&\")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,\"elements\");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(\":disabled\")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,\"\\r\\n\")}}):{name:t.name,value:n.replace(Dt,\"\\r\\n\")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\\/\\//,It={},Wt={},$t=\"*/\".concat(\"*\"),Bt=r.createElement(\"a\");Bt.href=Ct.href;function Ft(e){return function(t,n){\"string\"!=typeof t&&(n=t,t=\"*\");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])\"+\"===r[0]?(r=r.slice(1)||\"*\",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return\"string\"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i[\"*\"]&&a(\"*\")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:\"GET\",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":$t,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){\"object\"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks(\"once memory\"),x=h.statusCode||{},b={},T={},C=\"canceled\",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+\"\").replace(Rt,Ct.protocol+\"//\"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||\"*\").toLowerCase().match(M)||[\"\"],null==h.crossDomain){l=r.createElement(\"a\");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+\"//\"+Bt.host!=l.protocol+\"//\"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&\"string\"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger(\"ajaxStart\"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,\"\"),h.hasContent?h.data&&h.processData&&0===(h.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(h.data=h.data.replace(qt,\"+\")):(d=h.url.slice(o.length),h.data&&(h.processData||\"string\"==typeof h.data)&&(o+=(kt.test(o)?\"&\":\"?\")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,\"$1\"),d=(kt.test(o)?\"&\":\"?\")+\"_=\"+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader(\"If-Modified-Since\",w.lastModified[o]),w.etag[o]&&E.setRequestHeader(\"If-None-Match\",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader(\"Content-Type\",h.contentType),E.setRequestHeader(\"Accept\",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+(\"*\"!==h.dataTypes[0]?\", \"+$t+\"; q=0.01\":\"\"):h.accepts[\"*\"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C=\"abort\",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger(\"ajaxSend\",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort(\"timeout\")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,\"No Transport\");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||\"\",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader(\"Last-Modified\"))&&(w.lastModified[o]=T),(T=E.getResponseHeader(\"etag\"))&&(w.etag[o]=T)),204===t||\"HEAD\"===h.type?C=\"nocontent\":304===t?C=\"notmodified\":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C=\"error\",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+\"\",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?\"ajaxSuccess\":\"ajaxError\",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger(\"ajaxComplete\",[E,h]),--w.active||w.event.trigger(\"ajaxStop\")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,\"json\")},getScript:function(e,t){return w.get(e,void 0,t,\"script\")}}),w.each([\"get\",\"post\"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,\"throws\":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&\"withCredentials\"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i[\"X-Requested-With\"]||(i[\"X-Requested-With\"]=\"XMLHttpRequest\");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,\"abort\"===e?s.abort():\"error\"===e?\"number\"!=typeof s.status?o(0,\"error\"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,\"text\"!==(s.responseType||\"text\")||\"string\"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n(\"error\"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n(\"abort\");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),w.ajaxTransport(\"script\",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(\"<script>\").prop({charset:e.scriptCharset,src:e.url}).on(\"load error\",n=function(e){t.remove(),n=null,e&&o(\"error\"===e.type?404:200,e.type)}),r.head.appendChild(t[0])},abort:function(){n&&n()}}}});var Yt=[],Qt=/(=)\\?(?=&|$)|\\?\\?/;w.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Yt.pop()||w.expando+\"_\"+Et++;return this[e]=!0,e}}),w.ajaxPrefilter(\"json jsonp\",function(t,n,r){var i,o,a,s=!1!==t.jsonp&&(Qt.test(t.url)?\"url\":\"string\"==typeof t.data&&0===(t.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Qt.test(t.data)&&\"data\");if(s||\"jsonp\"===t.dataTypes[0])return i=t.jsonpCallback=g(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(Qt,\"$1\"+i):!1!==t.jsonp&&(t.url+=(kt.test(t.url)?\"&\":\"?\")+t.jsonp+\"=\"+i),t.converters[\"script json\"]=function(){return a||w.error(i+\" was not called\"),a[0]},t.dataTypes[0]=\"json\",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?w(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,Yt.push(i)),a&&g(o)&&o(a[0]),a=o=void 0}),\"script\"}),h.createHTMLDocument=function(){var e=r.implementation.createHTMLDocument(\"\").body;return e.innerHTML=\"<form></form><form></form>\",2===e.childNodes.length}(),w.parseHTML=function(e,t,n){if(\"string\"!=typeof e)return[];\"boolean\"==typeof t&&(n=t,t=!1);var i,o,a;return t||(h.createHTMLDocument?((i=(t=r.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=r.location.href,t.head.appendChild(i)):t=r),o=A.exec(e),a=!n&&[],o?[t.createElement(o[1])]:(o=xe([e],t,a),a&&a.length&&w(a).remove(),w.merge([],o.childNodes))},w.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return s>-1&&(r=vt(e.slice(s)),e=e.slice(0,s)),g(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),a.length>0&&w.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?w(\"<div>\").append(w.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},w.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){w.fn[t]=function(e){return this.on(t,e)}}),w.expr.pseudos.animated=function(e){return w.grep(w.timers,function(t){return e===t.elem}).length},w.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=w.css(e,\"position\"),f=w(e),p={};\"static\"===c&&(e.style.position=\"relative\"),s=f.offset(),o=w.css(e,\"top\"),u=w.css(e,\"left\"),(l=(\"absolute\"===c||\"fixed\"===c)&&(o+u).indexOf(\"auto\")>-1)?(a=(r=f.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),g(t)&&(t=t.call(e,n,w.extend({},s))),null!=t.top&&(p.top=t.top-s.top+a),null!=t.left&&(p.left=t.left-s.left+i),\"using\"in t?t.using.call(e,p):f.css(p)}},w.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){w.offset.setOffset(this,e,t)});var t,n,r=this[0];if(r)return r.getClientRects().length?(t=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:t.top+n.pageYOffset,left:t.left+n.pageXOffset}):{top:0,left:0}},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===w.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===w.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=w(e).offset()).top+=w.css(e,\"borderTopWidth\",!0),i.left+=w.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-w.css(r,\"marginTop\",!0),left:t.left-i.left-w.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===w.css(e,\"position\"))e=e.offsetParent;return e||be})}}),w.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(e,t){var n=\"pageYOffset\"===t;w.fn[e]=function(r){return z(this,function(e,r,i){var o;if(y(e)?o=e:9===e.nodeType&&(o=e.defaultView),void 0===i)return o?o[t]:e[r];o?o.scrollTo(n?o.pageXOffset:i,n?i:o.pageYOffset):e[r]=i},e,r,arguments.length)}}),w.each([\"top\",\"left\"],function(e,t){w.cssHooks[t]=_e(h.pixelPosition,function(e,n){if(n)return n=Fe(e,t),We.test(n)?w(e).position()[t]+\"px\":n})}),w.each({Height:\"height\",Width:\"width\"},function(e,t){w.each({padding:\"inner\"+e,content:t,\"\":\"outer\"+e},function(n,r){w.fn[r]=function(i,o){var a=arguments.length&&(n||\"boolean\"!=typeof i),s=n||(!0===i||!0===o?\"margin\":\"border\");return z(this,function(t,n,i){var o;return y(t)?0===r.indexOf(\"outer\")?t[\"inner\"+e]:t.document.documentElement[\"client\"+e]:9===t.nodeType?(o=t.documentElement,Math.max(t.body[\"scroll\"+e],o[\"scroll\"+e],t.body[\"offset\"+e],o[\"offset\"+e],o[\"client\"+e])):void 0===i?w.css(t,n,s):w.style(t,n,i,s)},t,a?i:void 0,a)}})}),w.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),w.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=N,w.isFunction=g,w.isWindow=y,w.camelCase=G,w.type=x,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return w});var Jt=e.jQuery,Kt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=Kt),t&&e.jQuery===w&&(e.jQuery=Jt),w},t||(e.jQuery=e.$=w),w});"
  },
  {
    "path": "force-app/main/default/staticresources/jquery.resource-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<StaticResource xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <cacheControl>Public</cacheControl>\n    <contentType>application/javascript</contentType>\n    <description>v3.3.1\nhttps://code.jquery.com/</description>\n</StaticResource>\n"
  },
  {
    "path": "force-app/main/default/staticresources/jsforce.js",
    "content": "!function(t){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=t();else if(\"function\"==typeof define&&define.amd)define([],t);else{var e;e=\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:this,e.jsforce=t()}}(function(){var t;return function(){function t(e,n,r){function i(s,a){if(!n[s]){if(!e[s]){var u=\"function\"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error(\"Cannot find module '\"+s+\"'\");throw c.code=\"MODULE_NOT_FOUND\",c}var l=n[s]={exports:{}};e[s][0].call(l.exports,function(t){var n=e[s][1][t];return i(n||t)},l,l.exports,t,e,n,r)}return n[s].exports}for(var o=\"function\"==typeof require&&require,s=0;s<r.length;s++)i(r[s]);return i}return t}()({1:[function(t,e,n){\"use strict\";var r=t(\"../core\");r.browser=t(\"./client\"),t(\"../api\"),e.exports=r},{\"../api\":8,\"../core\":20,\"./client\":15}],2:[function(t,e,n){\"use strict\";e.exports=\"1.9.1\"},{}],3:[function(t,e,n){\"use strict\";e.exports={inherits:t(\"inherits\"),util:t(\"util\"),events:t(\"events\"),\"lodash/core\":t(\"lodash/core\"),\"readable-stream\":t(\"readable-stream\"),multistream:t(\"multistream\"),\"./VERSION\":t(\"./VERSION\"),\"./cache\":t(\"./cache\"),\"./connection\":t(\"./connection\"),\"./core\":t(\"./core\"),\"./csv\":t(\"./csv\"),\"./date\":t(\"./date\"),\"./http-api\":t(\"./http-api\"),\"./logger\":t(\"./logger\"),\"./oauth2\":t(\"./oauth2\"),\"./process\":t(\"./process\"),\"./promise\":t(\"./promise\"),\"./query\":t(\"./query\"),\"./quick-action\":t(\"./quick-action\"),\"./record-stream\":t(\"./record-stream\"),\"./record\":t(\"./record\"),\"./soap\":t(\"./soap\"),\"./sobject\":t(\"./sobject\"),\"./soql-builder\":t(\"./soql-builder\"),\"./transport\":t(\"./transport\")}},{\"./VERSION\":2,\"./cache\":18,\"./connection\":19,\"./core\":20,\"./csv\":21,\"./date\":22,\"./http-api\":23,\"./logger\":24,\"./oauth2\":25,\"./process\":26,\"./promise\":27,\"./query\":28,\"./quick-action\":29,\"./record\":31,\"./record-stream\":30,\"./soap\":33,\"./sobject\":34,\"./soql-builder\":35,\"./transport\":36,events:47,inherits:84,\"lodash/core\":88,multistream:89,\"readable-stream\":107,util:117}],4:[function(t,e,n){\"use strict\";var r=t(\"lodash/core\"),i=t(\"../core\"),o=(t(\"../promise\"),function(t,e){this._report=t,this._conn=t._conn,this.id=e});o.prototype.retrieve=function(t){var e=this._conn,n=this._report,r=[e._baseUrl(),\"analytics\",\"reports\",n.id,\"instances\",this.id].join(\"/\");return e.request(r).thenCall(t)};var s=function(t,e){this._conn=t,this.id=e};s.prototype.describe=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"reports\",this.id,\"describe\"].join(\"/\");return this._conn.request(e).thenCall(t)},s.prototype[\"delete\"]=s.prototype.del=s.prototype.destroy=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"reports\",this.id].join(\"/\");return this._conn.request({method:\"DELETE\",url:e}).thenCall(t)},s.prototype.clone=function(t,e){var n=[this._conn._baseUrl(),\"analytics\",\"reports\"].join(\"/\");n+=\"?cloneId=\"+this.id;var r={reportMetadata:{name:t}},i={method:\"POST\",url:n,headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(r)};return this._conn.request(i).thenCall(e)},s.prototype.explain=function(t){var e=\"/query/?explain=\"+this.id;return this._conn.request(e).thenCall(t)},s.prototype.run=s.prototype.exec=s.prototype.execute=function(t,e){t=t||{},r.isFunction(t)&&(e=t,t={});var n=[this._conn._baseUrl(),\"analytics\",\"reports\",this.id].join(\"/\");n+=\"?includeDetails=\"+(t.details?\"true\":\"false\");var i={method:t.metadata?\"POST\":\"GET\",url:n};return t.metadata&&(i.headers={\"Content-Type\":\"application/json\"},i.body=JSON.stringify(t.metadata)),this._conn.request(i).thenCall(e)},s.prototype.executeAsync=function(t,e){t=t||{},r.isFunction(t)&&(e=t,t={});var n=[this._conn._baseUrl(),\"analytics\",\"reports\",this.id,\"instances\"].join(\"/\");t.details&&(n+=\"?includeDetails=true\");var i={method:\"POST\",url:n,body:\"\"};return t.metadata&&(i.headers={\"Content-Type\":\"application/json\"},i.body=JSON.stringify(t.metadata)),this._conn.request(i).thenCall(e)},s.prototype.instance=function(t){return new o(this,t)},s.prototype.instances=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"reports\",this.id,\"instances\"].join(\"/\");return this._conn.request(e).thenCall(t)};var a=function(t,e){this._conn=t,this.id=e};a.prototype.describe=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"dashboards\",this.id,\"describe\"].join(\"/\");return this._conn.request(e).thenCall(t)},a.prototype.components=function(t,e){var n=[this._conn._baseUrl(),\"analytics\",\"dashboards\",this.id].join(\"/\"),i={};r.isFunction(t)?e=t:r.isArray(t)?i.componentIds=t:r.isString(t)&&(i.componentIds=[t]);var o={method:\"POST\",url:n,headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(i)};return this._conn.request(o).thenCall(e)},a.prototype.status=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"dashboards\",this.id,\"status\"].join(\"/\");return this._conn.request(e).thenCall(t)},a.prototype.refresh=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"dashboards\",this.id].join(\"/\"),n={method:\"PUT\",url:e,body:\"\"};return this._conn.request(n).thenCall(t)},a.prototype.clone=function(t,e,n){var i=[this._conn._baseUrl(),\"analytics\",\"dashboards\"].join(\"/\");i+=\"?cloneId=\"+this.id;var o={};r.isObject(t)?(o=t,n=e):(o.name=t,o.folderId=e);var s={method:\"POST\",url:i,headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(o)};return this._conn.request(s).thenCall(n)},a.prototype[\"delete\"]=a.prototype.del=a.prototype.destroy=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"dashboards\",this.id].join(\"/\");return this._conn.request({method:\"DELETE\",url:e}).thenCall(t)};var u=function(t){this._conn=t};u.prototype.report=function(t){return new s(this._conn,t)},u.prototype.reports=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"reports\"].join(\"/\");return this._conn.request(e).thenCall(t)},u.prototype.dashboard=function(t){return new a(this._conn,t)},u.prototype.dashboards=function(t){var e=[this._conn._baseUrl(),\"analytics\",\"dashboards\"].join(\"/\");return this._conn.request(e).thenCall(t)},i.on(\"connection:new\",function(t){t.analytics=new u(t)}),e.exports=u},{\"../core\":20,\"../promise\":27,\"lodash/core\":88}],5:[function(t,e,n){\"use strict\";var r=t(\"../core\"),i=function(t){this._conn=t};i.prototype._baseUrl=function(){return this._conn.instanceUrl+\"/services/apexrest\"},i.prototype._createRequestParams=function(t,e,n,r){var i={method:t,url:this._baseUrl()+e},o={};return r&&\"object\"==typeof r.headers&&(o=r.headers),/^(GET|DELETE)$/i.test(t)||(o[\"Content-Type\"]=\"application/json\"),i.headers=o,n&&(i.body=JSON.stringify(n)),i},i.prototype.get=function(t,e,n){return\"function\"==typeof e&&(n=e,e=void 0),this._conn.request(this._createRequestParams(\"GET\",t,void 0,e)).thenCall(n)},i.prototype.post=function(t,e,n,r){\"function\"==typeof e&&(r=e,e=void 0,n=void 0),\"function\"==typeof n&&(r=n,n=void 0);var i=this._createRequestParams(\"POST\",t,e,n);return this._conn.request(i).thenCall(r)},i.prototype.put=function(t,e,n,r){\"function\"==typeof e&&(r=e,e=void 0,n=void 0),\"function\"==typeof n&&(r=n,n=void 0);var i=this._createRequestParams(\"PUT\",t,e,n);return this._conn.request(i).thenCall(r)},i.prototype.patch=function(t,e,n,r){\"function\"==typeof e&&(r=e,e=void 0,n=void 0),\"function\"==typeof n&&(r=n,n=void 0);var i=this._createRequestParams(\"PATCH\",t,e,n);return this._conn.request(i).thenCall(r)},i.prototype.del=i.prototype[\"delete\"]=function(t,e,n){return\"function\"==typeof e&&(n=e,e=void 0),this._conn.request(this._createRequestParams(\"DELETE\",t,void 0,e)).thenCall(n)},r.on(\"connection:new\",function(t){t.apex=new i(t)}),e.exports=i},{\"../core\":20}],6:[function(t,e,n){(function(n){\"use strict\";var r=t(\"inherits\"),i=t(\"readable-stream\"),o=i.Duplex,s=t(\"events\"),a=t(\"lodash/core\"),u=t(\"multistream\"),c=t(\"../core\"),l=t(\"../record-stream\"),h=t(\"../promise\"),p=t(\"../http-api\"),f=function(t,e,n,r,i){this._bulk=t,this.type=e,this.operation=n,this.options=r||{},this.id=i,this.state=this.id?\"Open\":\"Unknown\",this._batches={}};r(f,s.EventEmitter),f.prototype.info=function(t){return this._jobInfo||(this._jobInfo=this.check()),this._jobInfo.thenCall(t)},f.prototype.open=function(t){var e=this,n=this._bulk;n._logger;if(!this._jobInfo){var r=this.operation.toLowerCase();\"harddelete\"===r&&(r=\"hardDelete\");var i=['<?xml version=\"1.0\" encoding=\"UTF-8\"?>','<jobInfo  xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">',\"<operation>\"+r+\"</operation>\",\"<object>\"+this.type+\"</object>\",this.options.extIdField?\"<externalIdFieldName>\"+this.options.extIdField+\"</externalIdFieldName>\":\"\",this.options.concurrencyMode?\"<concurrencyMode>\"+this.options.concurrencyMode+\"</concurrencyMode>\":\"\",this.options.assignmentRuleId?\"<assignmentRuleId>\"+this.options.assignmentRuleId+\"</assignmentRuleId>\":\"\",\"<contentType>CSV</contentType>\",\"</jobInfo>\"].join(\"\");this._jobInfo=n._request({method:\"POST\",path:\"/job\",body:i,headers:{\"Content-Type\":\"application/xml; charset=utf-8\"},responseType:\"application/xml\"}).then(function(t){return e.emit(\"open\",t.jobInfo),e.id=t.jobInfo.id,e.state=t.jobInfo.state,t.jobInfo},function(t){throw e.emit(\"error\",t),t})}return this._jobInfo.thenCall(t)},f.prototype.createBatch=function(){var t=new d(this),e=this;return t.on(\"queue\",function(){e._batches[t.id]=t}),t},f.prototype.batch=function(t){var e=this._batches[t];return e||(e=new d(this,t),this._batches[t]=e),e},f.prototype.check=function(t){var e=this,n=this._bulk,r=n._logger;return this._jobInfo=this._waitAssign().then(function(){return n._request({method:\"GET\",path:\"/job/\"+e.id,responseType:\"application/xml\"})}).then(function(t){return r.debug(t.jobInfo),e.id=t.jobInfo.id,e.type=t.jobInfo.object,e.operation=t.jobInfo.operation,e.state=t.jobInfo.state,t.jobInfo}),this._jobInfo.thenCall(t)},f.prototype._waitAssign=function(t){return(this.id?h.resolve({id:this.id}):this.open()).thenCall(t)},f.prototype.list=function(t){var e=this,n=this._bulk,r=n._logger;return this._waitAssign().then(function(){return n._request({method:\"GET\",path:\"/job/\"+e.id+\"/batch\",responseType:\"application/xml\"})}).then(function(t){r.debug(t.batchInfoList.batchInfo);var e=t.batchInfoList;return e=a.isArray(e.batchInfo)?e.batchInfo:[e.batchInfo]}).thenCall(t)},f.prototype.close=function(){var t=this;return this._changeState(\"Closed\").then(function(e){return t.id=null,t.emit(\"close\",e),e},function(e){throw t.emit(\"error\",e),e})},f.prototype.abort=function(){var t=this;return this._changeState(\"Aborted\").then(function(e){return t.id=null,t.emit(\"abort\",e),e},function(e){throw t.emit(\"error\",e),e})},f.prototype._changeState=function(t,e){var n=this,r=this._bulk,i=r._logger;return this._jobInfo=this._waitAssign().then(function(){var e=['<?xml version=\"1.0\" encoding=\"UTF-8\"?>','<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">',\"<state>\"+t+\"</state>\",\"</jobInfo>\"].join(\"\");return r._request({method:\"POST\",path:\"/job/\"+n.id,body:e,headers:{\"Content-Type\":\"application/xml; charset=utf-8\"},responseType:\"application/xml\"})}).then(function(t){return i.debug(t.jobInfo),n.state=t.jobInfo.state,t.jobInfo}),this._jobInfo.thenCall(e)};var d=function(t,e){d.super_.call(this,{objectMode:!0}),this.job=t,this.id=e,this._bulk=t._bulk,this._deferred=h.defer(),this._setupDataStreams()};r(d,i.Writable),d.prototype._setupDataStreams=function(){var t=this,e={nullValue:\"#N/A\"};this._uploadStream=new l.Serializable,this._uploadDataStream=this._uploadStream.stream(\"csv\",e),this._downloadStream=new l.Parsable,this._downloadDataStream=this._downloadStream.stream(\"csv\",e),this.on(\"finish\",function(){t._uploadStream.end()}),this._uploadDataStream.once(\"readable\",function(){t.job.open().then(function(){t._uploadDataStream.pipe(t._createRequestStream())})});var n=this._dataStream=new o;n._write=function(e,n,r){t._uploadDataStream.write(e,n,r)},n.on(\"finish\",function(){t._uploadDataStream.end()}),this._downloadDataStream.on(\"readable\",function(){n.read(0)}),this._downloadDataStream.on(\"end\",function(){n.push(null)}),n._read=function(e){for(var r;null!==(r=t._downloadDataStream.read());)n.push(r)}},d.prototype._createRequestStream=function(){var t=this,e=t._bulk,n=e._logger;return e._request({method:\"POST\",path:\"/job/\"+t.job.id+\"/batch\",headers:{\"Content-Type\":\"text/csv\"},responseType:\"application/xml\"},function(e,r){e?t.emit(\"error\",e):(n.debug(r.batchInfo),t.id=r.batchInfo.id,t.emit(\"queue\",r.batchInfo))}).stream()},d.prototype._write=function(t,e,n){t=a.clone(t),\"insert\"===this.job.operation?delete t.Id:\"delete\"===this.job.operation&&(t={Id:t.Id}),delete t.type,delete t.attributes,this._uploadStream.write(t,e,n)},d.prototype.stream=function(){return this._dataStream},d.prototype.run=d.prototype.exec=d.prototype.execute=function(t,e){var n=this;if(\"function\"==typeof t&&(e=t,t=null),this._result)throw new Error(\"Batch already executed.\");var r=h.defer();if(this._result=r.promise,this._result.then(function(t){n._deferred.resolve(t)},function(t){n._deferred.reject(t)}),this.once(\"response\",function(t){r.resolve(t)}),this.once(\"error\",function(t){r.reject(t)}),a.isObject(t)&&a.isFunction(t.pipe))t.pipe(this._dataStream);else{var i;a.isArray(t)?(a.forEach(t,function(t){Object.keys(t).forEach(function(e){\"boolean\"==typeof t[e]&&(t[e]=String(t[e]))}),n.write(t)}),n.end()):a.isString(t)&&(i=t,this._dataStream.write(i,\"utf8\"),this._dataStream.end())}return this.thenCall(e)},d.prototype.then=function(t,e,n){return this._deferred.promise.then(t,e,n)},d.prototype.thenCall=function(t){return a.isFunction(t)&&this.then(function(e){n.nextTick(function(){t(null,e)})},function(e){n.nextTick(function(){t(e)})}),this},d.prototype.check=function(t){var e=this._bulk,n=e._logger,r=this.job.id,i=this.id;if(!r||!i)throw new Error(\"Batch not started.\");return e._request({method:\"GET\",path:\"/job/\"+r+\"/batch/\"+i,responseType:\"application/xml\"}).then(function(t){return n.debug(t.batchInfo),t.batchInfo}).thenCall(t)},d.prototype.poll=function(t,e){var n=this,r=this.job.id,i=this.id;if(!r||!i)throw new Error(\"Batch not started.\");var o=(new Date).getTime(),s=function(){var a=(new Date).getTime();if(o+e<a){var u=new Error(\"Polling time out. Job Id = \"+r+\" , batch Id = \"+i);return u.name=\"PollingTimeout\",u.jobId=r,u.batchId=i,void n.emit(\"error\",u)}n.check(function(e,r){e?n.emit(\"error\",e):\"Failed\"===r.state?parseInt(r.numberRecordsProcessed,10)>0?n.retrieve():n.emit(\"error\",new Error(r.stateMessage)):\"Completed\"===r.state?n.retrieve():(n.emit(\"progress\",r),setTimeout(s,t))})};setTimeout(s,t)},d.prototype.retrieve=function(t){var e=this,n=this._bulk,r=this.job.id,i=this.job,o=this.id;if(!r||!o)throw new Error(\"Batch not started.\");return i.info().then(function(t){return n._request({method:\"GET\",path:\"/job/\"+r+\"/batch/\"+o+\"/result\"})}).then(function(t){var s;if(\"query\"===i.operation){n._conn,t[\"result-list\"].result;s=t[\"result-list\"].result,s=a.map(a.isArray(s)?s:[s],function(t){return{id:t,batchId:o,jobId:r}})}else s=a.map(t,function(t){return{id:t.Id||null,success:\"true\"===t.Success,errors:t.Error?[t.Error]:[]}});return e.emit(\"response\",s),s}).fail(function(t){throw e.emit(\"error\",t),t}).thenCall(t)},d.prototype.result=function(t){var e=this.job.id,n=this.id;if(!e||!n)throw new Error(\"Batch not started.\");var r=new l.Parsable,i=r.stream(\"csv\");this._bulk._request({method:\"GET\",path:\"/job/\"+e+\"/batch/\"+n+\"/result/\"+t,responseType:\"application/octet-stream\"}).stream().pipe(i);return r};var y=function(){y.super_.apply(this,arguments)};r(y,p),y.prototype.beforeSend=function(t){t.headers=t.headers||{},t.headers[\"X-SFDC-SESSION\"]=this._conn.accessToken},y.prototype.isSessionExpired=function(t){return 400===t.statusCode&&/<exceptionCode>InvalidSessionId<\\/exceptionCode>/.test(t.body)},y.prototype.hasErrorInResponseBody=function(t){return!!t.error},y.prototype.parseError=function(t){return{errorCode:t.error.exceptionCode,message:t.error.exceptionMessage}};var m=function(t){this._conn=t,this._logger=t._logger};m.prototype.pollInterval=1e3,m.prototype.pollTimeout=1e4,m.prototype._request=function(t,e){var n=this._conn;t=a.clone(t);var r=[n.instanceUrl,\"services/async\",n.version].join(\"/\");t.url=r+t.path;var i={responseType:t.responseType};return delete t.path,delete t.responseType,new y(this._conn,i).request(t).thenCall(e)},m.prototype.load=function(t,e,n,r,i){var o=this;if(!t||!e)throw new Error(\"Insufficient arguments. At least, 'type' and 'operation' are required.\");a.isObject(n)&&n.constructor===Object||(i=r,r=n,n=null);var s=this.createJob(t,e,n);s.once(\"error\",function(t){u&&u.emit(\"error\",t)});var u=s.createBatch(),c=function(){u=null,s.close()},l=function(t){\"PollingTimeout\"!==t.name&&c()};return u.on(\"response\",c),u.on(\"error\",l),u.on(\"queue\",function(){u.poll(o.pollInterval,o.pollTimeout)}),u.execute(r,i)},m.prototype.query=function(t){var e=t.replace(/\\([\\s\\S]+\\)/g,\"\").match(/FROM\\s+(\\w+)/i);if(!e)throw new Error(\"No sobject type found in query, maybe caused by invalid SOQL.\");var n=e[1],r=this,i=new l.Parsable,o=i.stream(\"csv\");return this.load(n,\"query\",t).then(function(t){var e=t.map(function(t){return r.job(t.jobId).batch(t.batchId).result(t.id).stream()});u(e).pipe(o)}).fail(function(t){i.emit(\"error\",t)}),i},m.prototype.createJob=function(t,e,n){return new f(this,t,e,n)},m.prototype.job=function(t){return new f(this,null,null,null,t)},c.on(\"connection:new\",function(t){t.bulk=new m(t)}),e.exports=m}).call(this,t(\"_process\"))},{\"../core\":20,\"../http-api\":23,\"../promise\":27,\"../record-stream\":30,_process:91,events:47,inherits:84,\"lodash/core\":88,multistream:89,\"readable-stream\":107}],7:[function(t,e,n){\"use strict\";var r=t(\"inherits\"),i=t(\"lodash/core\"),o=t(\"../core\"),s=t(\"../promise\"),a=e.exports=function(t){this._conn=t};a.prototype._request=function(t,e){return/^(put|post|patch)$/i.test(t.method)&&i.isObject(t.body)&&(t.headers={\"Content-Type\":\"application/json\"},t.body=JSON.stringify(t.body)),t.url=this._normalizeUrl(t.url),this._conn.request(t,e)},a.prototype._normalizeUrl=function(t){return 0===t.indexOf(\"/chatter/\")||0===t.indexOf(\"/connect/\")?\"/services/data/v\"+this._conn.version+t:/^\\/v[\\d]+\\.[\\d]+\\//.test(t)?\"/services/data\"+t:0!==t.indexOf(\"/services/\")&&\"/\"===t[0]?\"/services/data/v\"+this._conn.version+\"/chatter\"+t:t},a.prototype.request=function(t,e){return new u(this,t).thenCall(e)},a.prototype.resource=function(t,e){return new c(this,t,e)},a.prototype.batch=function(t,e){var n=[],r=[];i.forEach(t,function(t){var e=s.defer();t._promise=e.promise,n.push(t.batchParams()),r.push(e)});var o={method:\"POST\",url:this._normalizeUrl(\"/connect/batch\"),body:{batchRequests:n}};return this.request(o).then(function(t){return i.forEach(t.results,function(t,e){var n=r[e];t.statusCode>=400?n.reject(t.result):n.resolve(t.result)}),t}).thenCall(e)};var u=function(t,e){this._chatter=t,this._params=e,this._promise=null};u.prototype.batchParams=function(){var t=this._params,e={method:t.method,url:this._chatter._normalizeUrl(t.url)};return this._params.body&&(e.richInput=this._params.body),e},u.prototype.promise=function(){return this._promise||this._chatter._request(this._params)},u.prototype.stream=function(){return this._chatter._request(this._params).stream()},u.prototype.then=function(t,e){return this.promise().then(t,e)},u.prototype.thenCall=function(t){return i.isFunction(t)?this.promise().thenCall(t):this};var c=function(t,e,n){if(n){var r=i.map(i.keys(n),function(t){return t+\"=\"+encodeURIComponent(n[t])}).join(\"&\");e+=(e.indexOf(\"?\")>0?\"&\":\"?\")+r}c.super_.call(this,t,{method:\"GET\",url:e}),this._url=e};r(c,u),c.prototype.create=function(t,e){return this._chatter.request({method:\"POST\",url:this._url,body:t}).thenCall(e)},c.prototype.retrieve=function(t){return this.thenCall(t)},c.prototype.update=function(t,e){return this._chatter.request({method:\"POST\",url:this._url,body:t}).thenCall(e)},c.prototype.del=c.prototype[\"delete\"]=function(t){return this._chatter.request({method:\"DELETE\",url:this._url}).thenCall(t)},o.on(\"connection:new\",function(t){t.chatter=new a(t)})},{\"../core\":20,\"../promise\":27,inherits:84,\"lodash/core\":88}],8:[function(t,e,n){t(\"./analytics\"),t(\"./apex\"),t(\"./bulk\"),t(\"./chatter\"),t(\"./metadata\"),t(\"./soap\"),t(\"./streaming\"),t(\"./tooling\")},{\"./analytics\":4,\"./apex\":5,\"./bulk\":6,\"./chatter\":7,\"./metadata\":9,\"./soap\":10,\"./streaming\":12,\"./tooling\":13}],9:[function(t,e,n){(function(n,r){\"use strict\";function i(t){var e=l.clone(t);return e.success=\"true\"===e.success,e}function o(t){var e=i(t);return e.created=\"true\"===e.created,e}function s(t){var e=l.clone(t);return delete e.$,e}var a=t(\"inherits\"),u=t(\"events\"),c=t(\"readable-stream\"),l=t(\"lodash/core\"),h=t(\"../core\"),p=t(\"../promise\"),f=t(\"../soap\"),d=e.exports=function(t){this._conn=t};d.prototype.pollInterval=1e3,d.prototype.pollTimeout=1e4,d.prototype._invoke=function(t,e,n){var r=new f(this._conn,{xmlns:\"http://soap.sforce.com/2006/04/metadata\",endpointUrl:this._conn.instanceUrl+\"/services/Soap/m/\"+this._conn.version});return r.invoke(t,e).then(function(t){return t.result}).thenCall(n)},d.prototype.createAsync=function(t,e,n){if(Number(this._conn.version)>30)throw new Error(\"Async metadata CRUD calls are not supported on ver 31.0 or later.\");var r=function(e){return e[\"@xsi:type\"]=t,e},i=l.isArray(e);e=i?l.map(e,r):r(e);var o=this._invoke(\"create\",{metadata:e});return new y(this,o,i).thenCall(n)},d.prototype.createSync=d.prototype.create=function(t,e,n){var r=function(e){return e[\"@xsi:type\"]=t,e},o=l.isArray(e);return e=o?l.map(e,r):r(e),this._invoke(\"createMetadata\",{metadata:e}).then(function(t){return l.isArray(t)?l.map(t,i):i(t)}).thenCall(n)},d.prototype.readSync=d.prototype.read=function(t,e,n){return this._invoke(\"readMetadata\",{type:t,fullNames:e}).then(function(t){return l.isArray(t.records)?l.map(t.records,s):s(t.records)}).thenCall(n)},d.prototype.updateAsync=function(t,e,n){if(Number(this._conn.version)>30)throw new Error(\"Async metadata CRUD calls are not supported on ver 31.0 or later.\");var r=function(e){return e.metadata[\"@xsi:type\"]=t,e},i=l.isArray(e);e=i?l.map(e,r):r(e);var o=this._invoke(\"update\",{updateMetadata:e});return new y(this,o,i).thenCall(n)},d.prototype.updateSync=d.prototype.update=function(t,e,n){var r=function(e){return e[\"@xsi:type\"]=t,e},o=l.isArray(e);return e=o?l.map(e,r):r(e),this._invoke(\"updateMetadata\",{metadata:e}).then(function(t){return l.isArray(t)?l.map(t,i):i(t)}).thenCall(n)},d.prototype.upsertSync=d.prototype.upsert=function(t,e,n){var r=function(e){return e[\"@xsi:type\"]=t,e},i=l.isArray(e);return e=i?l.map(e,r):r(e),this._invoke(\"upsertMetadata\",{metadata:e}).then(function(t){return l.isArray(t)?l.map(t,o):o(t)}).thenCall(n)},d.prototype.deleteAsync=function(t,e,n){if(Number(this._conn.version)>30)throw new Error(\"Async metadata CRUD calls are not supported on ver 31.0 or later.\");var r=function(e){return l.isString(e)&&(e={fullName:e}),e[\"@xsi:type\"]=t,e},i=l.isArray(e);e=i?l.map(e,r):r(e);var o=this._invoke(\"delete\",{metadata:e});return new y(this,o,i).thenCall(n)},d.prototype.del=d.prototype.deleteSync=d.prototype[\"delete\"]=function(t,e,n){return this._invoke(\"deleteMetadata\",{type:t,fullNames:e}).then(function(t){return l.isArray(t)?l.map(t,i):i(t)}).thenCall(n)},d.prototype.rename=function(t,e,n,r){return this._invoke(\"renameMetadata\",{type:t,oldFullName:e,newFullName:n}).then(function(t){return i(t)}).thenCall(r)},d.prototype.checkStatus=function(t,e){var n=l.isArray(t),r=this._invoke(\"checkStatus\",{asyncProcessId:t});return new y(this,r,n).thenCall(e)},d.prototype.describe=function(t,e){return l.isString(t)||(e=t,t=this._conn.version),this._invoke(\"describeMetadata\",{asOfVersion:t}).then(function(t){return t.metadataObjects=l.isArray(t.metadataObjects)?t.metadataObjects:[t.metadataObjects],t.metadataObjects=l.map(t.metadataObjects,function(t){return t.childXmlNames&&(t.childXmlNames=l.isArray(t.childXmlNames)?t.childXmlNames:[t.childXmlNames]),t.inFolder=\"true\"===t.inFolder,t.metaFile=\"true\"===t.metaFile,t}),t.partialSaveAllowed=\"true\"===t.partialSaveAllowed,t.testRequired=\"true\"===t.testRequired,t}).thenCall(e)},d.prototype.list=function(t,e,n){return l.isString(e)||(n=e,e=this._conn.version),l.isArray(t)||(t=[t]),this._invoke(\"listMetadata\",{queries:t,asOfVersion:e},n)},d.prototype.retrieve=function(t,e){var n=this._invoke(\"retrieve\",{request:t});return new m(this,n).thenCall(e)},d.prototype.checkRetrieveStatus=function(t,e){return this._invoke(\"checkRetrieveStatus\",{asyncProcessId:t},e)},d.prototype.deploy=function(t,e,n){e&&!l.isFunction(e)||(n=e,e={});var i=p.defer();if(l.isObject(t)&&l.isFunction(t.pipe)){var o=[];t.on(\"data\",function(t){o.push(t)}),t.on(\"end\",function(){i.resolve(r.concat(o).toString(\"base64\"))})}else if(t instanceof r)i.resolve(t.toString(\"base64\"));else{if(!(t instanceof String||\"string\"==typeof t))throw\"Unexpected zipInput type\";i.resolve(t)}var s=this,a=i.promise.then(function(t){return s._invoke(\"deploy\",{ZipFile:t,DeployOptions:e},n)});return new _(this,a).thenCall(n)},d.prototype.checkDeployStatus=function(t,e,n){return l.isObject(e)||l.isBoolean(e)?e=!!e:(n=e,e=!1),this._invoke(\"checkDeployStatus\",{asyncProcessId:t,includeDetails:e}).then(function(t){return t.done=\"true\"===t.done,t.success=\"true\"===t.success,t.checkOnly=\"true\"===t.checkOnly,t.runTestsEnabled=\"true\"===t.runTestsEnabled,t.ignoreWarnings&&(t.ignoreWarnings=\"true\"===t.ignoreWarnings),t.rollbackOnError&&(t.rollbackOnError=\"true\"===t.rollbackOnError),t.numberComponentErrors=Number(t.numberComponentErrors),t.numberComponentsDeployed=Number(t.numberComponentsDeployed),t.numberComponentsTotal=Number(t.numberComponentsTotal),t.numberTestErrors=Number(t.numberTestErrors),t.numberTestsCompleted=Number(t.numberTestsCompleted),t.numberTestsTotal=Number(t.numberTestsTotal),t}).thenCall(n)};var y=function(t,e,n){this._meta=t,this._results=e,this._isArray=n};a(y,u.EventEmitter),y.prototype.then=function(t,e){var n=this;return this._results.then(function(e){var r=function(t){return t.$&&\"true\"===t.$[\"xsi:nil\"]?null:(t.done=\"true\"===t.done,t)};return e=l.isArray(e)?l.map(e,r):r(e),n._isArray&&!l.isArray(e)&&(e=[e]),t(e)},e)},y.prototype.thenCall=function(t){return l.isFunction(t)?this.then(function(e){n.nextTick(function(){t(null,e)})},function(e){n.nextTick(function(){t(e)})}):this},y.prototype.check=function(t){var e=this,n=this._meta;return this.then(function(t){var r=l.isArray(t)?l.map(t,function(t){return t.id}):t.id;return e._ids=r,n.checkStatus(r)}).thenCall(t)},y.prototype.poll=function(t,e){var n=this,r=(new Date).getTime(),i=function(){var o=(new Date).getTime();if(r+e<o){var s=\"Polling time out.\";return n._ids&&(s+=\" Process Id = \"+n._ids),void n.emit(\"error\",new Error(s))}n.check().then(function(e){for(var r=!0,o=l.isArray(e)?e:[e],s=0,a=o.length;s<a;s++){var u=o[s];u&&!u.done&&(n.emit(\"progress\",u),r=!1)}r?n.emit(\"complete\",e):setTimeout(i,t)},function(t){n.emit(\"error\",t)})};setTimeout(i,t)},y.prototype.complete=function(t){var e=p.defer();this.on(\"complete\",function(t){e.resolve(t)}),this.on(\"error\",function(t){e.reject(t)});var n=this._meta;return this.poll(n.pollInterval,n.pollTimeout),e.promise.thenCall(t)};var m=function(t,e){m.super_.call(this,t,e)};a(m,y),m.prototype.complete=function(t){var e=this._meta;return m.super_.prototype.complete.call(this).then(function(t){return e.checkRetrieveStatus(t.id)}).thenCall(t)},m.prototype.stream=function(){var t=this,e=new c.Readable,n=!1;return e._read=function(){n||(n=!0,t.complete(function(t,n){t?e.emit(\"error\",t):(e.push(new r(n.zipFile,\"base64\")),e.push(null))}))},e};var _=function(t,e){_.super_.call(this,t,e)};a(_,y),_.prototype.complete=function(t,e){l.isFunction(t)&&(e=t,t=!1);var n=this._meta;return _.super_.prototype.complete.call(this).then(function(e){return n.checkDeployStatus(e.id,t)}).thenCall(e)},h.on(\"connection:new\",function(t){t.metadata=new d(t)})}).call(this,t(\"_process\"),t(\"buffer\").Buffer)},{\"../core\":20,\"../promise\":27,\"../soap\":33,_process:91,buffer:41,events:47,inherits:84,\"lodash/core\":88,\"readable-stream\":107}],10:[function(t,e,n){\"use strict\";var r=t(\"lodash/core\"),i=t(\"../core\"),o=t(\"../soap\"),s=e.exports=function(t){this._conn=t};s.prototype._invoke=function(t,e,n,r){var i=new o(this._conn,{xmlns:\"urn:partner.soap.sforce.com\",endpointUrl:this._conn.instanceUrl+\"/services/Soap/u/\"+this._conn.version});return i.invoke(t,e,{result:n}).then(function(t){return t.result}).thenCall(r)};var a={};s.prototype.convertLead=function(t,e){var n=r.isArray(t)?[a.LeadConvertResult]:a.LeadConvertResult;return this._invoke(\"convertLead\",{leadConverts:t},n,e)},a.LeadConvertResult={success:\"boolean\",errors:[],leadId:\"string\",accountId:\"string\",contactId:\"string\",opportunityId:\"string\"},s.prototype.merge=function(t,e){var n=r.isArray(t)?[a.MergeResult]:a.MergeResult;return this._invoke(\"merge\",{mergeRequests:t},n,e)},a.MergeResult={success:\"boolean\",errors:[],id:\"string\",mergedRecordIds:[\"string\"],updatedRelatedIds:[\"string\"]},s.prototype.emptyRecycleBin=function(t,e){return this._invoke(\"emptyRecycleBin\",{ids:t},[a.EmptyRecycleBinResult],e)},a.EmptyRecycleBinResult={id:\"string\",success:\"boolean\",errors:[]},s.prototype.describeTabs=function(t){return this._invoke(\"describeTabs\",{},[a.DescribeTabSetResult],t)},a.DescribeTabSetResult={label:\"string\",logoUrl:\"string\",namespace:\"string\",selected:\"boolean\",tabs:[{colors:[{theme:\"string\",color:\"string\",context:\"string\"}],iconUrl:\"string\",icons:[{theme:\"string\",height:\"number\",width:\"number\",url:\"string\",contentType:\"string\"}],label:\"string\",custom:\"boolean\",miniIconUrl:\"string\",name:\"string\",sobjectName:\"string\",url:\"string\"}]},s.prototype.getServerTimestamp=function(t){return this._invoke(\"getServerTimestamp\",{},a.GetServerTimestampResult,t)},a.GetServerTimestampResult={timestamp:\"string\"},s.prototype.getUserInfo=function(t){return this._invoke(\"getUserInfo\",{},a.GetUserInfoResult,t)},a.GetUserInfoResult={accessibilityMode:\"boolean\",currencySymbol:\"string\",orgAttachmentFileSizeLimit:\"number\",orgDefaultCurrencyIsoCode:\"string\",orgDisallowHtmlAttachments:\"boolean\",orgHasPersonAccounts:\"boolean\",organizationId:\"string\",organizationMultiCurrency:\"boolean\",organizationName:\"string\",profileId:\"string\",roleId:\"string\",sessionSecondsValid:\"number\",userDefaultCurrencyIsoCode:\"string\",userEmail:\"string\",userFullName:\"string\",userId:\"string\",userLanguage:\"string\",userLocale:\"string\",userName:\"string\",userTimeZone:\"string\",userType:\"string\",userUiSkin:\"string\"},s.prototype.setPassword=function(t,e,n){return this._invoke(\"setPassword\",{userId:t,password:e},n)},s.prototype.resetPassword=function(t,e){return this._invoke(\"resetPassword\",{userId:t},e)},s.prototype.create=function(t,e){var n=r.isArray(t)?[a.SaveResult]:a.SaveResult,i={\"@xmlns\":\"urn:partner.soap.sforce.com\",\"@xmlns:ns1\":\"sobject.partner.soap.sforce.com\",\"ns1:sObjects\":t};return this._invoke(\"create\",i,n,e)},s.prototype.update=function(t,e){var n=r.isArray(t)?[a.SaveResult]:a.SaveResult,i={\"@xmlns\":\"urn:partner.soap.sforce.com\",\"@xmlns:ns1\":\"sobject.partner.soap.sforce.com\",\"ns1:sObjects\":t};return this._invoke(\"update\",i,n,e)},a.SaveResult={success:\"boolean\",errors:[],id:\"string\"},s.prototype.upsert=function(t,e,n){var i=r.isArray(e)?[a.UpsertResult]:a.UpsertResult,o={\"@xmlns\":\"urn:partner.soap.sforce.com\",\"@xmlns:ns1\":\"sobject.partner.soap.sforce.com\",\"ns1:externalIDFieldName\":t,\"ns1:sObjects\":e};return this._invoke(\"upsert\",o,i,n)},a.UpsertResult={created:\"boolean\",success:\"boolean\",errors:[],id:\"string\"},s.prototype[\"delete\"]=function(t,e){var n=r.isArray(t)?[a.DeleteResult]:a.DeleteResult,i={\"@xmlns\":\"urn:partner.soap.sforce.com\",\"@xmlns:ns1\":\"sobject.partner.soap.sforce.com\",\"ns1:ids\":t};return this._invoke(\"delete\",i,n,e)},a.DeleteResult={success:\"boolean\",errors:[],id:\"string\"},i.on(\"connection:new\",function(t){t.soap=new s(t)}),e.exports=s},{\"../core\":20,\"../soap\":33,\"lodash/core\":88}],11:[function(t,e,n){var r={};r.AuthFailure=function(t){this.incoming=function(e,n){\"/meta/connect\"!==e.channel&&\"/meta/handshake\"!==e.channel||!e.advice||\"none\"!=e.advice.reconnect?n(e):t(e)}},r.Replay=function(t,e){var n=\"replay\",r=null!=e,i=e,o=t;this.setExtensionEnabled=function(t){r=t},this.setReplay=function(t){\ni=parseInt(t,10)},this.setChannel=function(t){o=t},this.incoming=function(t,e){\"/meta/handshake\"===t.channel?t.ext&&1==t.ext[n]&&(r=!0):t.channel===o&&t.data&&t.data.event&&t.data.event.replayId&&(i=t.data.event.replayId),e(t)},this.outgoing=function(t,e){if(\"/meta/subscribe\"===t.channel&&t.subscription===o&&r){t.ext||(t.ext={});var s={};s[o]=i,t.ext[n]=s}e(t)}},e.exports=r},{}],12:[function(t,e,n){\"use strict\";var r=t(\"events\"),i=t(\"inherits\"),o=t(\"lodash/core\"),s=t(\"faye\"),a=t(\"./streaming-extension\"),u=t(\"../core\"),c=function(t,e){this._streaming=t,this.name=e};c.prototype.subscribe=function(t){return this._streaming.subscribe(this.name,t)},c.prototype.unsubscribe=function(t){return this._streaming.unsubscribe(this.name,t),this};var l=function(t,e){this._streaming=t,this._name=e};l.prototype.subscribe=function(t){return this._streaming.subscribe(this._name,t)},l.prototype.unsubscribe=function(t){return this._streaming.unsubscribe(this._name,t),this},l.prototype.push=function(t,e){var n=o.isArray(t);t=n?t:[t];var r=this._streaming._conn;return this._id||(this._id=r.sobject(\"StreamingChannel\").findOne({Name:this._name},\"Id\").then(function(t){return t.Id})),this._id.then(function(e){var n=\"/sobjects/StreamingChannel/\"+e+\"/push\";return r.requestPost(n,{pushEvents:t})}).then(function(t){return n?t:t[0]}).thenCall(e)};var h=function(t){this._conn=t};i(h,r.EventEmitter),h.prototype._createClient=function(t,e){var n=\"string\"==typeof t&&0===t.indexOf(\"/u/\"),r=[this._conn.instanceUrl,\"cometd\"+(n===!0&&\"36.0\"===this._conn.version?\"/replay\":\"\"),this._conn.version].join(\"/\"),i=new s.Client(r,{});return i.setHeader(\"Authorization\",\"OAuth \"+this._conn.accessToken),e instanceof Array&&e.forEach(function(t){i.addExtension(t)}),i._dispatcher.getConnectionTypes().indexOf(\"callback-polling\")===-1&&(i._dispatcher.selectTransport(\"long-polling\"),i._dispatcher._transport.batching=!1),i},h.prototype._getFayeClient=function(t){var e=0===t.indexOf(\"/u/\"),n=e?\"generic\":\"pushTopic\";return this._fayeClients&&this._fayeClients[n]||(this._fayeClients=this._fayeClients||{},this._fayeClients[n]=this._createClient(t)),this._fayeClients[n]},h.prototype.topic=function(t){this._topics=this._topics||{};var e=this._topics[t]=this._topics[t]||new c(this,t);return e},h.prototype.channel=function(t){return new l(this,t)},h.prototype.subscribe=function(t,e){var n=0===t.indexOf(\"/\")?t:\"/topic/\"+t,r=this._getFayeClient(n);return r.subscribe(n,e)},h.prototype.unsubscribe=function(t,e){var n=0===t.indexOf(\"/\")?t:\"/topic/\"+t,r=this._getFayeClient(n);return r.unsubscribe(n,e),this},h.prototype.createClient=function(t){return this._createClient(null,t)},u.on(\"connection:new\",function(t){t.streaming=new h(t)}),u.StreamingExtension=a,e.exports=h},{\"../core\":20,\"./streaming-extension\":11,events:47,faye:48,inherits:84,\"lodash/core\":88}],13:[function(t,e,n){\"use strict\";var r=t(\"../core\"),i=t(\"lodash/core\"),o=t(\"../cache\"),s=function(t){this._conn=t,this._logger=t._logger;var e=[\"query\",\"queryMore\",\"_toRecordResult\",\"create\",\"_createSingle\",\"_createParallel\",\"_createMany\",\"insert\",\"retrieve\",\"_retrieveSingle\",\"_retrieveParallel\",\"_retrieveMany\",\"update\",\"_updateSingle\",\"_updateParallel\",\"_updateMany\",\"upsert\",\"del\",\"delete\",\"destroy\",\"_destroySingle\",\"_destroyParallel\",\"_destroyMany\",\"describe\",\"describeGlobal\",\"sobject\"];e.forEach(function(e){this[e]=t.constructor.prototype[e]},this),this.cache=new o;var n={key:function(t){return t?\"describe.\"+t:\"describe\"}};this.describe$=this.cache.makeCacheable(this.describe,this,n),this.describe=this.cache.makeResponseCacheable(this.describe,this,n),this.describeSObject$=this.describe$,this.describeSObject=this.describe,n={key:\"describeGlobal\"},this.describeGlobal$=this.cache.makeCacheable(this.describeGlobal,this,n),this.describeGlobal=this.cache.makeResponseCacheable(this.describeGlobal,this,n),this.initialize()};s.prototype.initialize=function(){this.sobjects={},this.cache.clear(),this.cache.get(\"describeGlobal\").removeAllListeners(\"value\"),this.cache.get(\"describeGlobal\").on(\"value\",i.bind(function(t){if(t.result){var e=i.map(t.result.sobjects,function(t){return t.name});e.forEach(this.sobject,this)}},this))},s.prototype._baseUrl=function(){return this._conn._baseUrl()+\"/tooling\"},s.prototype._supports=function(t){return\"sobject-collection\"!==t&&this._conn._supports.apply(this._conn,arguments)},s.prototype.request=function(){return this._conn.request.apply(this._conn,arguments)},s.prototype.executeAnonymous=function(t,e){var n=this._baseUrl()+\"/executeAnonymous?anonymousBody=\"+encodeURIComponent(t);return this.request(n).thenCall(e)},s.prototype.runTestsAsynchronous=function(t,e){var n=this._baseUrl()+\"/runTestsAsynchronous/\";return this._conn.requestPost(n,{classids:t.join(\",\")},void 0,e)},s.prototype.runTestsSynchronous=function(t,e){var n=this._baseUrl()+\"/runTestsSynchronous/\";return this._conn.requestPost(n,{classnames:t.join(\",\")},void 0,e)},s.prototype.completions=function(t,e){i.isString(t)||(e=t,t=\"apex\");var n=this._baseUrl()+\"/completions?type=\"+encodeURIComponent(t);return this.request(n).thenCall(e)},r.on(\"connection:new\",function(t){t.tooling=new s(t)}),e.exports=s},{\"../cache\":18,\"../core\":20,\"lodash/core\":88}],14:[function(t,e,n){\"use strict\";function r(t){var e={};return t.split(/\\n/).forEach(function(t){var n=t.split(/\\s*:\\s*/),r=n[0].toLowerCase(),i=n[1];e[r]=i}),e}var i=t(\"readable-stream\").Duplex,o=t(\"lodash/core\");e.exports={supported:\"object\"==typeof Sfdc&&\"undefined\"!=typeof Sfdc.canvas,createRequest:function(t){return function(e,n){function s(i){var s={client:t.client,method:e.method,data:i};if(e.headers){s.headers={};for(var c in e.headers)\"content-type\"===c.toLowerCase()?s.contentType=e.headers[c]:s.headers[c]=e.headers[c]}s.success=function(t){var e=r(t.responseHeaders),i=t.payload;o.isString(i)||(i=JSON.stringify(i)),a={statusCode:t.status,headers:e,body:i},n&&n(null,a,a.body),u.end()},s.failure=function(t){n&&n(t)},Sfdc.canvas.client.ajax(e.url,s)}var a,u=new i;u._read=function(t){a&&u.push(a.body)};var c=[],l=!1;return u._write=function(t,e,n){c.push(t.toString(e)),n()},u.on(\"finish\",function(){l||(s(c.join(\"\")),l=!0)}),!e.body&&\"\"!==e.body&&/^(put|post|patch)$/i.test(e.method)||(s(e.body),l=!0),u}}}},{\"lodash/core\":88,\"readable-stream\":107}],15:[function(t,e,n){\"use strict\";function r(t,e,n){var r=screen.width/2-e/2,i=screen.height/2-n/2;return window.open(t,null,\"location=yes,toolbar=no,status=no,menubar=no,width=\"+e+\",height=\"+n+\",top=\"+i+\",left=\"+r)}function i(){var t=o(),e=localStorage.getItem(\"jsforce_state\");if(t&&e&&t.body.state===e){localStorage.removeItem(\"jsforce_state\");var n=e.split(\".\"),r=n[0],i=n[1],s=new f(r);return t.success?(s._storeTokens(t.body),location.hash=\"\"):s._storeError(t.body),\"popup\"===i&&window.close(),!0}}function o(){var t;if(window.location.hash){if(t=u.parse(window.location.hash.substring(1)),t.access_token)return{success:!0,body:t}}else if(window.location.search&&(t=u.parse(window.location.search.substring(1)),t.error))return{success:!1,body:t}}var s=t(\"events\"),a=t(\"inherits\"),u=t(\"querystring\"),c=t(\"lodash/core\"),l=t(\"../connection\"),h=t(\"../oauth2\"),p=0,f=function(t){this._prefix=t||\"jsforce\"+p++,this.connection=null};a(f,s.EventEmitter),f.prototype.init=function(t){if(!i()){this.config=t,this.connection=new l(t);var e=this._getTokens();if(e){this.connection.initialize(e);var n=this;setTimeout(function(){n.emit(\"connect\",n.connection)},10)}}},f.prototype.login=function(t,e){c.isFunction(t)&&(e=t,t={}),t=t||{},e=e||function(){},c.extend(t,this.config);this._prompt(t,e)},f.prototype._prompt=function(t,e){var n=this,i=new h(t),o=Math.random().toString(36).substring(2),s=[this._prefix,\"popup\",o].join(\".\");localStorage.setItem(\"jsforce_state\",s);var a=i.getAuthorizationUrl({response_type:\"token\",scope:t.scope,state:s}),u=t.size||{},c=r(a,u.width||912,u.height||513);if(!c)return s=[this._prefix,\"redirect\",o].join(\".\"),localStorage.setItem(\"jsforce_state\",s),a=i.getAuthorizationUrl({response_type:\"token\",scope:t.scope,state:s}),void(location.href=a);n._removeTokens();var l=setInterval(function(){try{if(!c||c.closed){clearInterval(l);var t=n._getTokens();if(t)n.connection.initialize(t),n.emit(\"connect\",n.connection),e(null,{status:\"connect\"});else{var r=n._getError();r?e(new Error(r.error+\": \"+r.error_description)):e(null,{status:\"cancel\"})}}}catch(i){}},1e3)},f.prototype.isLoggedIn=function(){return!(!this.connection||!this.connection.accessToken)},f.prototype.logout=function(){this.connection.logout(),this._removeTokens(),this.emit(\"disconnect\")},f.prototype._getTokens=function(){var t=new RegExp(\"(^|;\\\\s*)\"+this._prefix+\"_loggedin=true(;|$)\");if(document.cookie.match(t)){var e=Number(localStorage.getItem(this._prefix+\"_issued_at\"));if(Date.now()<e+72e5){var n,r=localStorage.getItem(this._prefix+\"_id\");if(r){var i=r.split(\"/\");n={id:i.pop(),organizationId:i.pop(),url:r}}return{accessToken:localStorage.getItem(this._prefix+\"_access_token\"),instanceUrl:localStorage.getItem(this._prefix+\"_instance_url\"),userInfo:n}}}return null},f.prototype._storeTokens=function(t){localStorage.setItem(this._prefix+\"_access_token\",t.access_token),localStorage.setItem(this._prefix+\"_instance_url\",t.instance_url),localStorage.setItem(this._prefix+\"_issued_at\",t.issued_at),localStorage.setItem(this._prefix+\"_id\",t.id),document.cookie=this._prefix+\"_loggedin=true;\"},f.prototype._removeTokens=function(){localStorage.removeItem(this._prefix+\"_access_token\"),localStorage.removeItem(this._prefix+\"_instance_url\"),localStorage.removeItem(this._prefix+\"_issued_at\"),localStorage.removeItem(this._prefix+\"_id\"),document.cookie=this._prefix+\"_loggedin=\"},f.prototype._getError=function(){try{var t=JSON.parse(localStorage.getItem(this._prefix+\"_error\"));return localStorage.removeItem(this._prefix+\"_error\"),t}catch(e){}},f.prototype._storeError=function(t){localStorage.setItem(this._prefix+\"_error\",JSON.stringify(t))},e.exports=new f,e.exports.Client=f},{\"../connection\":19,\"../oauth2\":25,events:47,inherits:84,\"lodash/core\":88,querystring:96}],16:[function(t,e,n){\"use strict\";var r=0;e.exports={supported:\"undefined\"!=typeof window&&\"undefined\"!=typeof document,createRequest:function(t,e){return t=t||\"callback\",e=e||1e4,function(n,i){if(\"GET\"!==n.method.toUpperCase())return i(new Error(\"JSONP only supports GET request.\"));var o=\"_jsforce_jsonpCallback_\"+ ++r,s=window,a=n.url;a+=a.indexOf(\"?\")>0?\"&\":\"?\",a+=t+\"=\"+o;var u=document.createElement(\"script\");u.type=\"text/javascript\",u.src=a,document.documentElement.appendChild(u);var c=setTimeout(function(){l(),i(new Error(\"JSONP call time out.\"))},e);s[o]=function(t){l(),i(null,{statusCode:200,headers:{\"content-type\":\"application/json\"},body:JSON.stringify(t)})};var l=function(){clearTimeout(c),document.documentElement.removeChild(u),delete s[o]}}}}},{}],17:[function(t,e,n){\"use strict\";function r(t){var e=(t.getAllResponseHeaders()||\"\").split(/[\\r\\n]+/);return o.map(e,function(t){return t.split(/\\s*:/)[0].toLowerCase()})}var i=t(\"readable-stream\").Duplex,o=t(\"lodash/core\");e.exports=function(t,e){var n=new XMLHttpRequest;if(n.open(t.method,t.url),t.headers)for(var s in t.headers)n.setRequestHeader(s,t.headers[s]);n.setRequestHeader(\"Accept\",\"*/*\");var a,u=new i;u._read=function(t){a&&u.push(a.body)};var c=[],l=!1;return u._write=function(t,e,n){c.push(t.toString(\"buffer\"===e?\"binary\":e)),n()},u.on(\"finish\",function(){l||(n.send(c.join(\"\")),l=!0)}),!t.body&&\"\"!==t.body&&/^(put|post|patch)$/i.test(t.method)||(n.send(t.body),l=!0),n.onreadystatechange=function(){if(4===n.readyState){var t=r(n),i={};o.forEach(t,function(t){t&&(i[t]=n.getResponseHeader(t))}),a={statusCode:n.status,headers:i,body:n.response},a.statusCode||(a.statusCode=400,a.body=\"Access Declined\"),e&&e(null,a,a.body),u.end()}},u}},{\"lodash/core\":88,\"readable-stream\":107}],18:[function(t,e,n){\"use strict\";function r(t,e){return e=Array.prototype.slice.apply(e),t+\"(\"+s.map(e,function(t){return JSON.stringify(t)}).join(\",\")+\")\"}var i=t(\"events\"),o=t(\"inherits\"),s=t(\"lodash/core\"),a=function(){this.fetching=!1};o(a,i.EventEmitter),a.prototype.get=function(t){return t?(this.once(\"value\",t),void(s.isUndefined(this._value)||this.emit(\"value\",this._value))):this._value},a.prototype.set=function(t){this._value=t,this.emit(\"value\",this._value)},a.prototype.clear=function(){this.fetching=!1,delete this._value};var u=function(){this._entries={}};u.prototype.get=function(t){if(t&&this._entries[t])return this._entries[t];var e=new a;return this._entries[t]=e,e},u.prototype.clear=function(t){for(var e in this._entries)t&&0!==e.indexOf(t)||this._entries[e].clear()},u.prototype.makeResponseCacheable=function(t,e,n){var i=this;return n=n||{},function(){var o=Array.prototype.slice.apply(arguments),a=o.pop();s.isFunction(a)||(o.push(a),a=null);var u=s.isString(n.key)?n.key:s.isFunction(n.key)?n.key.apply(e,o):r(n.namespace,o),c=i.get(u);c.fetching=!0,a&&o.push(function(t,e){c.set({error:t,result:e}),a(t,e)});var l,h;try{l=t.apply(e||this,o)}catch(p){h=p}if(l&&s.isFunction(l.then))return a?l:l.then(function(t){return c.set({error:void 0,result:t}),t},function(t){throw c.set({error:t,result:void 0}),t});if(c.set({error:h,result:l}),h)throw h;return l}},u.prototype.makeCacheable=function(t,e,n){var i=this;n=n||{};var o=function(){var o=Array.prototype.slice.apply(arguments),a=o.pop();s.isFunction(a)||o.push(a);var u=s.isString(n.key)?n.key:s.isFunction(n.key)?n.key.apply(e,o):r(n.namespace,o),c=i.get(u);if(!s.isFunction(a)){var l=c.get();if(!l)throw new Error(\"Function call result is not cached yet.\");if(l.error)throw l.error;return l.result}c.get(function(t){a(t.error,t.result)}),c.fetching||(c.fetching=!0,o.push(function(t,e){c.set({error:t,result:e})}),t.apply(e||this,o))};return o.clear=function(){var t=s.isString(n.key)?n.key:s.isFunction(n.key)?n.key.apply(e,arguments):r(n.namespace,arguments);i.clear(t)},o},e.exports=u},{events:47,inherits:84,\"lodash/core\":88}],19:[function(t,e,n){(function(n){\"use strict\";function r(t,e){t.oauth2.refreshToken(t.refreshToken,function(n,r){if(n)return e(n);var i=s(r.id);t.initialize({instanceUrl:r.instance_url,accessToken:r.access_token,userInfo:i}),e(null,r.access_token,r)})}function i(t){if(h.isString(t)){if(\"{\"===t[0])return JSON.parse(t);var e=t.split(\".\").pop(),r=n.from(e,\"base64\").toString(\"utf-8\");return JSON.parse(r)}return t}function o(t){function e(t){return t<10?\"0\"+t:t}return t.getUTCFullYear()+\"-\"+e(t.getUTCMonth()+1)+\"-\"+e(t.getUTCDate())+\"T\"+e(t.getUTCHours())+\":\"+e(t.getUTCMinutes())+\":\"+e(t.getUTCSeconds())+\"+00:00\"}function s(t){var e=t.split(\"/\"),n=e.pop(),r=e.pop();return{id:n,organizationId:r,url:t}}function a(t,e){return function(n,r){n.login(t,e,function(t){return t?r(t):void r(null,n.accessToken)})}}function u(t){return t&&String(t).replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\")}var c=t(\"events\"),l=t(\"inherits\"),h=t(\"lodash/core\"),p=t(\"./promise\"),f=t(\"./logger\"),d=t(\"./oauth2\"),y=t(\"./query\"),m=t(\"./sobject\"),_=t(\"./quick-action\"),g=t(\"./http-api\"),v=t(\"./transport\"),b=t(\"./process\"),w=t(\"./cache\"),E={loginUrl:\"https://login.salesforce.com\",instanceUrl:\"\",version:\"42.0\"},T=200,x=e.exports=function(e){e=e||{},this._logger=new f(e.logLevel);var n=e.oauth2||{loginUrl:e.loginUrl,clientId:e.clientId,clientSecret:e.clientSecret,redirectUri:e.redirectUri,proxyUrl:e.proxyUrl,httpProxy:e.httpProxy};this.oauth2=n=n instanceof d?n:new d(n),this.loginUrl=e.loginUrl||n.loginUrl||E.loginUrl,this.version=e.version||E.version,this.maxRequest=e.maxRequest||this.maxRequest||10,e.proxyUrl?this._transport=new v.ProxyTransport(e.proxyUrl):e.httpProxy?this._transport=new v.HttpProxyTransport(e.httpProxy):this._transport=new v,this.callOptions=e.callOptions;var i=t(\"./core\");i.emit(\"connection:new\",this),this.process=new b(this),this.cache=new w;var o=e.refreshFn;!o&&this.oauth2.clientId&&(o=r),o&&(this._refreshDelegate=new g.SessionRefreshDelegate(this,o));var s={key:function(t){return t?\"describe.\"+t:\"describe\"}};this.describe$=this.cache.makeCacheable(this.describe,this,s),this.describe=this.cache.makeResponseCacheable(this.describe,this,s),this.describeSObject$=this.describe$,this.describeSObject=this.describe,s={key:\"describeGlobal\"},this.describeGlobal$=this.cache.makeCacheable(this.describeGlobal,this,s),this.describeGlobal=this.cache.makeResponseCacheable(this.describeGlobal,this,s),this.initialize(e)};l(x,c.EventEmitter),x.prototype.initialize=function(t){if(!t.instanceUrl&&t.serverUrl&&(t.instanceUrl=t.serverUrl.split(\"/\").slice(0,3).join(\"/\")),this.instanceUrl=t.instanceUrl||t.serverUrl||this.instanceUrl||E.instanceUrl,this.accessToken=t.sessionId||t.accessToken||this.accessToken,this.refreshToken=t.refreshToken||this.refreshToken,this.refreshToken&&!this._refreshDelegate)throw new Error(\"Refresh token is specified without oauth2 client information or refresh function\");this.signedRequest=t.signedRequest&&i(t.signedRequest),this.signedRequest&&(this.accessToken=this.signedRequest.client.oauthToken,v.CanvasTransport.supported&&(this._transport=new v.CanvasTransport(this.signedRequest))),t.userInfo&&(this.userInfo=t.userInfo),this.limitInfo={},this.sobjects={},this.cache.clear(),this.cache.get(\"describeGlobal\").removeAllListeners(\"value\"),this.cache.get(\"describeGlobal\").on(\"value\",h.bind(function(t){if(t.result){var e=h.map(t.result.sobjects,function(t){return t.name});e.forEach(this.sobject,this)}},this)),this.tooling&&this.tooling.initialize(),this._sessionType=t.sessionId?\"soap\":\"oauth2\"},x.prototype._baseUrl=function(){return[this.instanceUrl,\"services/data\",\"v\"+this.version].join(\"/\")},x.prototype._normalizeUrl=function(t){return\"/\"===t[0]?0===t.indexOf(\"/services/\")?this.instanceUrl+t:this._baseUrl()+t:t},x.prototype.request=function(t,e,n){\"function\"==typeof e&&(n=e,e=null),e=e||{};var r=this;h.isString(t)&&(t={method:\"GET\",url:t}),t.url=this._normalizeUrl(t.url);var i=new g(this,e);return i.on(\"response\",function(t){if(t.headers&&t.headers[\"sforce-limit-info\"]){var e=t.headers[\"sforce-limit-info\"].match(/api\\-usage=(\\d+)\\/(\\d+)/);e&&(r.limitInfo={apiUsage:{used:parseInt(e[1],10),limit:parseInt(e[2],10)}})}}),i.request(t).thenCall(n)},x.prototype.requestGet=function(t,e,n){var r={method:\"GET\",url:t};return this.request(r,e,n)},x.prototype.requestPost=function(t,e,n,r){var i={method:\"POST\",url:t,body:JSON.stringify(e),headers:{\"content-type\":\"application/json\"}};return this.request(i,n,r)},x.prototype.requestPut=function(t,e,n,r){var i={method:\"PUT\",url:t,body:JSON.stringify(e),headers:{\"content-type\":\"application/json\"}};return this.request(i,n,r)},x.prototype.requestPatch=function(t,e,n,r){var i={method:\"PATCH\",url:t,body:JSON.stringify(e),headers:{\"content-type\":\"application/json\"}};return this.request(i,n,r)},x.prototype.requestDelete=function(t,e,n){var r={method:\"DELETE\",url:t};return this.request(r,e,n)},x.prototype.query=function(t,e,n){\"function\"==typeof e&&(n=e,e=void 0);var r=new y(this,t,e);return n&&r.run(n),r},x.prototype.queryAll=function(t,e,n){\"function\"==typeof e&&(n=e,e=void 0);var r=new y(this,t,e);return r.scanAll(!0),n&&r.run(n),r},x.prototype.queryMore=function(t,e,n){\"function\"==typeof e&&(n=e,e=void 0);var r=new y(this,{locator:t},e);return n&&r.run(n),r},x.prototype._ensureVersion=function(t){var e=this.version.split(\".\");return parseInt(e[0],10)>=t},x.prototype._supports=function(t){switch(t){case\"sobject-collection\":return this._ensureVersion(42);default:return!1}},x.prototype.retrieve=function(t,e,n,r){return\"function\"==typeof n&&(r=n,n={}),n=n||{},(h.isArray(e)?this._supports(\"sobject-collection\")?this._retrieveMany(t,e,n):this._retrieveParallel(t,e,n):this._retrieveSingle(t,e,n)).thenCall(r)},x.prototype._retrieveSingle=function(t,e,n){if(!e)return p.reject(new Error(\"Invalid record ID. Specify valid record ID value\"));var r=[this._baseUrl(),\"sobjects\",t,e].join(\"/\");return n.fields&&(r+=\"?fields=\"+n.fields.join(\",\")),this.request({method:\"GET\",url:r,headers:n.headers})},x.prototype._retrieveParallel=function(t,e,n){if(e.length>this.maxRequest)return p.reject(new Error(\"Exceeded max limit of concurrent call\"));var r=this;return p.all(e.map(function(e){return r._retrieveSingle(t,e,n)[\"catch\"](function(t){if(n.allOrNone||\"NOT_FOUND\"!==t.errorCode)throw t;return null})}))},x.prototype._retrieveMany=function(t,e,n){if(0===e.length)return p.resolve([]);var r=[this._baseUrl(),\"composite\",\"sobjects\",t].join(\"/\"),i=this;return(n.fields?p.resolve(n.fields):new p(function(e,n){i.describe$(t,function(t,r){if(t)n(t);else{var i=r.fields.map(function(t){return t.name});e(i)}})})).then(function(t){return i.request({method:\"POST\",url:r,body:JSON.stringify({ids:e,fields:t}),headers:h.defaults(n.headers||{},{\"Content-Type\":\"application/json\"})})})},x.prototype._toRecordResult=function(t,e){var n={statusCode:e.errorCode,message:e.message};e.content&&(n.content=e.content),e.fields&&(n.fields=e.fields);var r={success:!1,errors:[n]};return t&&(r.id=t),r},x.prototype.insert=x.prototype.create=function(t,e,n,r){return h.isString(t)||(r=n,n=e,e=t,t=null),\"function\"==typeof n&&(r=n,n={}),n=n||{},(h.isArray(e)?this._supports(\"sobject-collection\")?this._createMany(t,e,n):this._createParallel(t,e,n):this._createSingle(t,e,n)).thenCall(r)},x.prototype._createSingle=function(t,e,n){var r=t||e.attributes&&e.attributes.type||e.type;if(!r)return p.reject(new Error(\"No SObject Type defined in record\"));e=h.clone(e),delete e.Id,delete e.type,delete e.attributes;var i=[this._baseUrl(),\"sobjects\",r].join(\"/\");return this.request({method:\"POST\",url:i,body:JSON.stringify(e),headers:h.defaults(n.headers||{},{\"Content-Type\":\"application/json\"})})},x.prototype._createParallel=function(t,e,n){if(e.length>this.maxRequest)return p.reject(new Error(\"Exceeded max limit of concurrent call\"));var r=this;return p.all(e.map(function(e){return r._createSingle(t,e,n)[\"catch\"](function(t){if(n.allOrNone||!t.errorCode)throw t;return this._toRecordResult(null,t)})}))},x.prototype._createMany=function(t,e,n){if(0===e.length)return p.resolve([]);if(e.length>T&&n.allowRecursive){var r=this;return r._createMany(t,e.slice(0,T),n).then(function(i){return r._createMany(t,e.slice(T),n).then(function(t){return i.concat(t)})})}e=h.map(e,function(e){var n=t||e.attributes&&e.attributes.type||e.type;return n?(e=h.clone(e),delete e.Id,delete e.type,e.attributes={type:n},e):p.reject(new Error(\"No SObject Type defined in record\"))});var i=[this._baseUrl(),\"composite\",\"sobjects\"].join(\"/\");return this.request({method:\"POST\",url:i,body:JSON.stringify({allOrNone:n.allOrNone||!1,records:e}),headers:h.defaults(n.headers||{},{\"Content-Type\":\"application/json\"})})},x.prototype.update=function(t,e,n,r){return h.isString(t)||(r=n,n=e,e=t,t=null),\"function\"==typeof n&&(r=n,n={}),n=n||{},(h.isArray(e)?this._supports(\"sobject-collection\")?this._updateMany(t,e,n):this._updateParallel(t,e,n):this._updateSingle(t,e,n)).thenCall(r)},x.prototype._updateSingle=function(t,e,n){var r=e.Id;if(!r)return p.reject(new Error(\"Record id is not found in record.\"));var i=t||e.attributes&&e.attributes.type||e.type;if(!i)return p.reject(new Error(\"No SObject Type defined in record\"));e=h.clone(e),delete e.Id,delete e.type,delete e.attributes;var o=[this._baseUrl(),\"sobjects\",i,r].join(\"/\");return this.request({method:\"PATCH\",url:o,body:JSON.stringify(e),headers:h.defaults(n.headers||{},{\"Content-Type\":\"application/json\"})},{noContentResponse:{id:r,success:!0,errors:[]}})},x.prototype._updateParallel=function(t,e,n){if(e.length>this.maxRequest)return p.reject(new Error(\"Exceeded max limit of concurrent call\"));var r=this;return p.all(e.map(function(e){return r._updateSingle(t,e,n)[\"catch\"](function(t){if(n.allOrNone||!t.errorCode)throw t;return this._toRecordResult(e.Id,t)})}))},x.prototype._updateMany=function(t,e,n){if(0===e.length)return p.resolve([]);if(e.length>T&&n.allowRecursive){var r=this;return r._updateMany(t,e.slice(0,T),n).then(function(i){return r._updateMany(t,e.slice(T),n).then(function(t){return i.concat(t)})})}e=h.map(e,function(e){var n=e.Id;if(!n)throw new Error(\"Record id is not found in record.\");var r=t||e.attributes&&e.attributes.type||e.type;if(!r)throw new Error(\"No SObject Type defined in record\");return e=h.clone(e),delete e.Id,e.id=n,delete e.type,e.attributes={type:r},e});var i=[this._baseUrl(),\"composite\",\"sobjects\"].join(\"/\");return this.request({method:\"PATCH\",url:i,body:JSON.stringify({allOrNone:n.allOrNone||!1,records:e}),headers:h.defaults(n.headers||{},{\"Content-Type\":\"application/json\"})})},x.prototype.upsert=function(t,e,n,r,i){h.isString(t)||(i=r,r=n,n=e,e=t,t=null),\"function\"==typeof r&&(i=r,r={}),r=r||{};var o=this,s=h.isArray(e);return e=s?e:[e],e.length>this.maxRequest?p.reject(new Error(\"Exceeded max limit of concurrent call\")).thenCall(i):p.all(h.map(e,function(e){var i=t||e.attributes&&e.attributes.type||e.type,a=e[n];e=h.clone(e),delete e[n],delete e.type,delete e.attributes;var u=[o._baseUrl(),\"sobjects\",i,n,a].join(\"/\");return o.request({method:\"PATCH\",url:u,body:JSON.stringify(e),headers:h.defaults(r.headers||{},{\"Content-Type\":\"application/json\"})},{noContentResponse:{success:!0,errors:[]}})[\"catch\"](function(t){if(!s||r.allOrNone||!t.errorCode)throw t;return o._toRecordResult(null,t)})})).then(function(t){return!s&&h.isArray(t)?t[0]:t}).thenCall(i)},x.prototype[\"delete\"]=x.prototype.del=x.prototype.destroy=function(t,e,n,r){return\"function\"==typeof n&&(r=n,n={}),n=n||{},(h.isArray(e)?this._supports(\"sobject-collection\")?this._destroyMany(t,e,n):this._destroyParallel(t,e,n):this._destroySingle(t,e,n)).thenCall(r)},x.prototype._destroySingle=function(t,e,n){var r=[this._baseUrl(),\"sobjects\",t,e].join(\"/\");return this.request({method:\"DELETE\",url:r,headers:n.headers||null},{noContentResponse:{id:e,success:!0,errors:[]}})},x.prototype._destroyParallel=function(t,e,n){if(e.length>this.maxRequest)return p.reject(new Error(\"Exceeded max limit of concurrent call\"));var r=this;return p.all(e.map(function(e){return r._destroySingle(t,e,n)[\"catch\"](function(t){if(n.allOrNone||!t.errorCode)throw t;return this._toRecordResult(e,t)})}))},x.prototype._destroyMany=function(t,e,n){if(0===e.length)return p.resolve([]);if(e.length>T&&n.allowRecursive){var r=this;return r._destroyMany(t,e.slice(0,T),n).then(function(i){return r._destroyMany(t,e.slice(T),n).then(function(t){return i.concat(t)})})}var i=[this._baseUrl(),\"composite\",\"sobjects?ids=\"].join(\"/\")+e.join(\",\");return n.allOrNone&&(i+=\"&allOrNone=true\"),this.request({method:\"DELETE\",url:i,headers:n.headers||null})},x.prototype.search=function(t,e){var n=this._baseUrl()+\"/search?q=\"+encodeURIComponent(t);return this.request(n).thenCall(e)},x.prototype.describe=x.prototype.describeSObject=function(t,e){var n=[this._baseUrl(),\"sobjects\",t,\"describe\"].join(\"/\");return this.request(n).thenCall(e)},x.prototype.describeGlobal=function(t){var e=this._baseUrl()+\"/sobjects\";return this.request(e).thenCall(t)},x.prototype.sobject=function(t){this.sobjects=this.sobjects||{};var e=this.sobjects[t]=this.sobjects[t]||new m(this,t);return e},x.prototype.identity=function(t,e){\"function\"==typeof t&&(e=t,t={}),t=t||{};var n=this,r=this.userInfo&&this.userInfo.url;return p.resolve(r?{identity:r}:this.request({method:\"GET\",url:this._baseUrl(),headers:t.headers})).then(function(t){var e=t.identity;return n.request({method:\"GET\",url:e})}).then(function(t){return n.userInfo={id:t.user_id,organizationId:t.organization_id,url:t.id},t}).thenCall(e)},x.prototype.authorize=function(t,e,n){\"function\"==typeof e&&(n=e,e={});var r=this,i=this._logger;return this.oauth2.requestToken(t,e).then(function(t){var e=s(t.id);return r.initialize({instanceUrl:t.instance_url,accessToken:t.access_token,refreshToken:t.refresh_token,userInfo:e}),i.debug(\"<login> completed. user id = \"+e.id+\", org id = \"+e.organizationId),e}).thenCall(n)},x.prototype.login=function(t,e,n){return this._refreshDelegate=new g.SessionRefreshDelegate(this,a(t,e)),this.oauth2&&this.oauth2.clientId&&this.oauth2.clientSecret?this.loginByOAuth2(t,e,n):this.loginBySoap(t,e,n)},x.prototype.loginByOAuth2=function(t,e,n){var r=this,i=this._logger;return this.oauth2.authenticate(t,e).then(function(t){var e=s(t.id);return r.initialize({instanceUrl:t.instance_url,accessToken:t.access_token,userInfo:e}),i.debug(\"<login> completed. user id = \"+e.id+\", org id = \"+e.organizationId),e}).thenCall(n)},x.prototype.loginBySoap=function(t,e,n){var r=this,i=this._logger,o=['<se:Envelope xmlns:se=\"http://schemas.xmlsoap.org/soap/envelope/\">',\"<se:Header/>\",\"<se:Body>\",'<login xmlns=\"urn:partner.soap.sforce.com\">',\"<username>\"+u(t)+\"</username>\",\"<password>\"+u(e)+\"</password>\",\"</login>\",\"</se:Body>\",\"</se:Envelope>\"].join(\"\"),s=[this.loginUrl,\"services/Soap/u\",this.version].join(\"/\");return this._transport.httpRequest({method:\"POST\",url:s,body:o,headers:{\"Content-Type\":\"text/xml\",SOAPAction:'\"\"'}}).then(function(t){var e;if(t.statusCode>=400){e=t.body.match(/<faultstring>([^<]+)<\\/faultstring>/);var n=e&&e[1];throw new Error(n||t.body)}i.debug(\"SOAP response = \"+t.body),e=t.body.match(/<serverUrl>([^<]+)<\\/serverUrl>/);var o=e&&e[1];e=t.body.match(/<sessionId>([^<]+)<\\/sessionId>/);var a=e&&e[1];e=t.body.match(/<userId>([^<]+)<\\/userId>/);var u=e&&e[1];e=t.body.match(/<organizationId>([^<]+)<\\/organizationId>/);var c=e&&e[1],l=s.split(\"/\").slice(0,3).join(\"/\");l+=\"/id/\"+c+\"/\"+u;var h={id:u,organizationId:c,url:l};return r.initialize({serverUrl:o.split(\"/\").slice(0,3).join(\"/\"),sessionId:a,userInfo:h}),i.debug(\"<login> completed. user id = \"+u+\", org id = \"+c),h}).thenCall(n)},x.prototype.logout=function(t,e){return\"function\"==typeof t&&(e=t,t=!1),\"oauth2\"===this._sessionType?this.logoutByOAuth2(t,e):this.logoutBySoap(t,e)},x.prototype.logoutByOAuth2=function(t,e){\"function\"==typeof t&&(e=t,t=!1);var n=this;this._logger;return this.oauth2.revokeToken(t?this.refreshToken:this.accessToken).then(function(){n.accessToken=null,n.userInfo=null,n.refreshToken=null,n.instanceUrl=null,n.cache.clear()}).thenCall(e)},x.prototype.logoutBySoap=function(t,e){\"function\"==typeof t&&(e=t,t=!1);var n=this,r=this._logger,i=['<se:Envelope xmlns:se=\"http://schemas.xmlsoap.org/soap/envelope/\">',\"<se:Header>\",'<SessionHeader xmlns=\"urn:partner.soap.sforce.com\">',\"<sessionId>\"+u(t?this.refreshToken:this.accessToken)+\"</sessionId>\",\"</SessionHeader>\",\"</se:Header>\",\"<se:Body>\",'<logout xmlns=\"urn:partner.soap.sforce.com\"/>',\"</se:Body>\",\"</se:Envelope>\"].join(\"\");return this._transport.httpRequest({method:\"POST\",url:[this.instanceUrl,\"services/Soap/u\",this.version].join(\"/\"),body:i,headers:{\"Content-Type\":\"text/xml\",SOAPAction:'\"\"'}}).then(function(t){if(r.debug(\"SOAP statusCode = \"+t.statusCode+\", response = \"+t.body),t.statusCode>=400){var e=t.body.match(/<faultstring>([^<]+)<\\/faultstring>/),i=e&&e[1];throw new Error(i||t.body)}n.accessToken=null,n.userInfo=null,n.refreshToken=null,n.instanceUrl=null,n.cache.clear()}).thenCall(e)},x.prototype.recent=function(t,e,n){h.isString(t)||(n=e,e=t,t=void 0),h.isNumber(e)||(n=e,e=void 0);var r;return t?(r=[this._baseUrl(),\"sobjects\",t].join(\"/\"),this.request(r).then(function(t){return e?t.recentItems.slice(0,e):t.recentItems}).thenCall(n)):(r=this._baseUrl()+\"/recent\",e&&(r+=\"?limit=\"+e),this.request(r).thenCall(n))},x.prototype.updated=function(t,e,n,r){var i=[this._baseUrl(),\"sobjects\",t,\"updated\"].join(\"/\");return\"string\"==typeof e&&(e=new Date(e)),e instanceof Date&&(e=o(e)),e&&(i+=\"?start=\"+encodeURIComponent(e)),\"string\"==typeof n&&(n=new Date(n)),n instanceof Date&&(n=o(n)),n&&(i+=\"&end=\"+encodeURIComponent(n)),this.request(i).thenCall(r)},x.prototype.deleted=function(t,e,n,r){var i=[this._baseUrl(),\"sobjects\",t,\"deleted\"].join(\"/\");return\"string\"==typeof e&&(e=new Date(e)),e instanceof Date&&(e=o(e)),e&&(i+=\"?start=\"+encodeURIComponent(e)),\"string\"==typeof n&&(n=new Date(n)),n instanceof Date&&(n=o(n)),n&&(i+=\"&end=\"+encodeURIComponent(n)),this.request(i).thenCall(r)},x.prototype.tabs=function(t){var e=[this._baseUrl(),\"tabs\"].join(\"/\");\nreturn this.request(e).thenCall(t)},x.prototype.limits=function(t){var e=[this._baseUrl(),\"limits\"].join(\"/\");return this.request(e).thenCall(t)},x.prototype.theme=function(t){var e=[this._baseUrl(),\"theme\"].join(\"/\");return this.request(e).thenCall(t)},x.prototype.quickActions=function(t){return this.request(\"/quickActions\").thenCall(t)},x.prototype.quickAction=function(t){return new _(this,\"/quickActions/\"+t)}}).call(this,t(\"buffer\").Buffer)},{\"./cache\":18,\"./core\":20,\"./http-api\":23,\"./logger\":24,\"./oauth2\":25,\"./process\":26,\"./promise\":27,\"./query\":28,\"./quick-action\":29,\"./sobject\":34,\"./transport\":36,buffer:41,events:47,inherits:84,\"lodash/core\":88}],20:[function(t,e,n){\"use strict\";var r=t(\"events\").EventEmitter,i=e.exports=new r;i.VERSION=t(\"./VERSION\"),i.Connection=t(\"./connection\"),i.OAuth2=t(\"./oauth2\"),i.Date=i.SfDate=t(\"./date\"),i.RecordStream=t(\"./record-stream\"),i.Promise=t(\"./promise\"),i.require=t(\"./require\")},{\"./VERSION\":2,\"./connection\":19,\"./date\":22,\"./oauth2\":25,\"./promise\":27,\"./record-stream\":30,\"./require\":32,events:47}],21:[function(t,e,n){\"use strict\";function r(t,e){return e=a.extend({},e,{columns:!0}),c(t,e)}function i(t,e){return e=a.extend({},e,{header:!0}),h(t,e)}function o(t){return t=a.extend({},t,{columns:!0}),u(t)}function s(t){return t=a.extend({},t,{header:!0}),l(t)}var a=t(\"lodash/core\"),u=t(\"csv-parse\"),c=t(\"csv-parse/lib/sync\"),l=t(\"csv-stringify\"),h=t(\"csv-stringify/lib/sync\");e.exports={parseCSV:r,toCSV:i,parseCSVStream:o,serializeCSVStream:s}},{\"csv-parse\":43,\"csv-parse/lib/sync\":44,\"csv-stringify\":45,\"csv-stringify/lib/sync\":46,\"lodash/core\":88}],22:[function(t,e,n){\"use strict\";function r(t){return(t<10?\"0\":\"\")+t}function i(t){return function(e){return new s(t+\":\"+e)}}var o=t(\"lodash/core\"),s=e.exports=function(t){this._literal=t};s.prototype.toString=s.prototype.toJSON=function(){return this._literal},s.toDateLiteral=function(t){o.isNumber(t)?t=new Date(t):o.isString(t)&&(t=s.parseDate(t));var e=t.getFullYear(),n=t.getMonth()+1,i=t.getDate(),a=[e,r(n),r(i)].join(\"-\");return new s(a)},s.toDateTimeLiteral=function(t){o.isNumber(t)?t=new Date(t):o.isString(t)&&(t=s.parseDate(t));var e=t.getUTCFullYear(),n=t.getUTCMonth()+1,i=t.getUTCDate(),a=t.getUTCHours(),u=t.getUTCMinutes(),c=t.getUTCSeconds(),l=[e,r(n),r(i)].join(\"-\")+\"T\"+[r(a),r(u),r(c)].join(\":\")+\"Z\";return new s(l)},s.parseDate=function(t){var e=new Date,n=/^([\\d]{4})-?([\\d]{2})-?([\\d]{2})(T([\\d]{2}):?([\\d]{2}):?([\\d]{2})(.([\\d]{3}))?(Z|([\\+\\-])([\\d]{2}):?([\\d]{2})))?$/,r=t.match(n);if(r){if(e=new Date(0),r[4]){if(e.setUTCFullYear(parseInt(r[1],10)),e.setUTCDate(parseInt(r[3],10)),e.setUTCMonth(parseInt(r[2],10)-1),e.setUTCHours(parseInt(r[5],10)),e.setUTCMinutes(parseInt(r[6],10)),e.setUTCSeconds(parseInt(r[7],10)),e.setUTCMilliseconds(parseInt(r[9]||\"0\",10)),r[10]&&\"Z\"!==r[10]){var i=60*parseInt(r[12],10)+parseInt(r[13],10);e.setTime((\"+\"===r[11]?-1:1)*i*60*1e3+e.getTime())}}else e.setFullYear(parseInt(r[1],10)),e.setDate(parseInt(r[3],10)),e.setMonth(parseInt(r[2],10)-1),e.setHours(0),e.setMinutes(0),e.setSeconds(0),e.setMilliseconds(0);return e}throw new Error(\"Invalid date format is specified : \"+t)};var a={YESTERDAY:1,TODAY:1,TOMORROW:1,LAST_WEEK:1,THIS_WEEK:1,NEXT_WEEK:1,LAST_MONTH:1,THIS_MONTH:1,NEXT_MONTH:1,LAST_90_DAYS:1,NEXT_90_DAYS:1,LAST_N_DAYS:2,NEXT_N_DAYS:2,NEXT_N_WEEKS:2,LAST_N_WEEKS:2,NEXT_N_MONTHS:2,LAST_N_MONTHS:2,THIS_QUARTER:1,LAST_QUARTER:1,NEXT_QUARTER:1,NEXT_N_QUARTERS:2,LAST_N_QUARTERS:2,THIS_YEAR:1,LAST_YEAR:1,NEXT_YEAR:1,NEXT_N_YEARS:2,LAST_N_YEARS:2,THIS_FISCAL_QUARTER:1,LAST_FISCAL_QUARTER:1,NEXT_FISCAL_QUARTER:1,NEXT_N_FISCAL_QUARTERS:2,LAST_N_FISCAL_QUARTERS:2,THIS_FISCAL_YEAR:1,LAST_FISCAL_YEAR:1,NEXT_FISCAL_YEAR:1,NEXT_N_FISCAL_YEARS:2,LAST_N_FISCAL_YEARS:2};for(var u in a){var c=a[u];s[u]=1===c?new s(u):i(u)}},{\"lodash/core\":88}],23:[function(t,e,n){\"use strict\";function r(t){return JSON.parse(t)}function i(e){var n={};if(t(\"xml2js\").parseString(e,{explicitArray:!1},function(t,e){n={error:t,result:e}}),n.error)throw n.error;return n.result}function o(e){return t(\"./csv\").parseCSV(e)}function s(t){return t}var a=t(\"inherits\"),u=t(\"events\"),c=t(\"lodash/core\"),l=t(\"./promise\"),h=function(t,e){e=e||{},this._conn=t,this.on(\"resume\",function(e){t.emit(\"resume\",e)}),this._responseType=e.responseType,this._transport=e.transport||t._transport,this._noContentResponse=e.noContentResponse};a(h,u.EventEmitter),h.prototype.request=function(t,e){var n=this,r=this._conn,i=r._logger,o=this.getRefreshDelegate(),s=r.instanceUrl,a=l.defer(),u=function(e){return e?void a.reject(e):(s!==r.instanceUrl&&(t.url=t.url.replace(s,r.instanceUrl)),void n.request(t).then(function(t){a.resolve(t)},function(t){a.reject(t)}))};if(o&&o._refreshing)return o.once(\"resume\",u),a.promise.thenCall(e);n.beforeSend(t),n.emit(\"request\",t),i.debug(\"<request> method=\"+t.method+\", url=\"+t.url);var c=Date.now();return this._transport.httpRequest(t).then(function(e){var r=Date.now();if(i.debug(\"elappsed time : \"+(r-c)+\"msec\"),i.debug(\"<response> status=\"+e.statusCode+\", url=\"+t.url),n.emit(\"response\",e),n.isSessionExpired(e)&&o)return o.refresh(c,u),a.promise;if(n.isErrorResponse(e)){var s=n.getError(e);throw s}return n.getResponseBody(e)},function(t){var e=Date.now();throw i.debug(\"elappsed time : \"+(e-c)+\"msec\"),i.error(t),t}).thenCall(e)},h.prototype.getRefreshDelegate=function(){return this._conn._refreshDelegate},h.prototype.beforeSend=function(t){if(t.headers=t.headers||{},this._conn.accessToken&&(t.headers.Authorization=\"Bearer \"+this._conn.accessToken),this._conn.callOptions){var e=[];for(var n in this._conn.callOptions)e.push(n+\"=\"+this._conn.callOptions[n]);t.headers[\"Sforce-Call-Options\"]=e.join(\", \")}},h.prototype.getResponseContentType=function(t){return this._responseType||t.headers&&t.headers[\"content-type\"]},h.prototype.parseResponseBody=function(t){var e=this.getResponseContentType(t),n=/^(text|application)\\/xml(;|$)/.test(e)?i:/^application\\/json(;|$)/.test(e)?r:/^text\\/csv(;|$)/.test(e)?o:s;try{return n(t.body)}catch(a){return t.body}},h.prototype.getResponseBody=function(t){if(204===t.statusCode)return this._noContentResponse;var e,n=this.parseResponseBody(t);if(this.hasErrorInResponseBody(n))throw e=this.getError(t,n);if(300===t.statusCode)throw e=new Error(\"Multiple records found\"),e.name=\"MULTIPLE_CHOICES\",e.content=n,e;return n},h.prototype.isSessionExpired=function(t){return 401===t.statusCode},h.prototype.isErrorResponse=function(t){return t.statusCode>=400},h.prototype.hasErrorInResponseBody=function(t){return!1},h.prototype.parseError=function(t){var e=t;return c.isArray(e)?e[0]:e},h.prototype.getError=function(t,e){var n;try{n=this.parseError(e||this.parseResponseBody(t))}catch(r){}n=c.isObject(n)&&c.isString(n.message)?n:{errorCode:\"ERROR_HTTP_\"+t.statusCode,message:t.body};var i=new Error(n.message);i.name=n.errorCode;for(var o in n)i[o]=n[o];return i};var p=function(t,e){this._conn=t,this._refreshFn=e,this._refreshing=!1};a(p,u.EventEmitter),p.prototype.refresh=function(t,e){if(this._lastRefreshedAt>t)return e();var n=this,r=this._conn,i=r._logger;return n.once(\"resume\",e),n._refreshing?void 0:(i.debug(\"<refresh token>\"),n._refreshing=!0,n._refreshFn(r,function(t,e,o){t||(i.debug(\"Connection refresh completed.\"),r.accessToken=e,r.emit(\"refresh\",e,o)),n._lastRefreshedAt=Date.now(),n._refreshing=!1,n.emit(\"resume\",t)}))},h.SessionRefreshDelegate=p,e.exports=h},{\"./csv\":21,\"./promise\":27,events:47,inherits:84,\"lodash/core\":88,xml2js:123}],24:[function(t,e,n){\"use strict\";function r(t){return function(e){this.log(t,e)}}var i=e.exports=function(t){\"string\"==typeof t&&(t=o[t]),t||(t=o.INFO),this._logLevel=t},o=i.LogLevels={DEBUG:1,INFO:2,WARN:3,ERROR:4,FATAL:5};i.prototype.log=function(t,e){this._logLevel<=t&&(t<o.ERROR?console.log(e):console.error(e))};for(var s in o)i.prototype[s.toLowerCase()]=r(o[s])},{}],25:[function(t,e,n){\"use strict\";var r=t(\"querystring\"),i=t(\"lodash/core\"),o=t(\"./transport\"),s={loginUrl:\"https://login.salesforce.com\"},a=e.exports=function(t){t.authzServiceUrl&&t.tokenServiceUrl?(this.loginUrl=t.authzServiceUrl.split(\"/\").slice(0,3).join(\"/\"),this.authzServiceUrl=t.authzServiceUrl,this.tokenServiceUrl=t.tokenServiceUrl,this.revokeServiceUrl=t.revokeServiceUrl):(this.loginUrl=t.loginUrl||s.loginUrl,this.authzServiceUrl=this.loginUrl+\"/services/oauth2/authorize\",this.tokenServiceUrl=this.loginUrl+\"/services/oauth2/token\",this.revokeServiceUrl=this.loginUrl+\"/services/oauth2/revoke\"),this.clientId=t.clientId,this.clientSecret=t.clientSecret,this.redirectUri=t.redirectUri,t.proxyUrl?this._transport=new o.ProxyTransport(t.proxyUrl):t.httpProxy?this._transport=new o.HttpProxyTransport(t.httpProxy):this._transport=new o};i.extend(a.prototype,{getAuthorizationUrl:function(t){return t=i.extend({response_type:\"code\",client_id:this.clientId,redirect_uri:this.redirectUri},t||{}),this.authzServiceUrl+(this.authzServiceUrl.indexOf(\"?\")>=0?\"&\":\"?\")+r.stringify(t)},refreshToken:function(t,e){var n={grant_type:\"refresh_token\",refresh_token:t,client_id:this.clientId};return this.clientSecret&&(n.client_secret=this.clientSecret),this._postParams(n,e)},requestToken:function(t,e,n){return\"function\"==typeof e&&(n=e,e={}),e=i.extend({grant_type:\"authorization_code\",code:t,client_id:this.clientId,redirect_uri:this.redirectUri},e||{}),this.clientSecret&&(e.client_secret=this.clientSecret),this._postParams(e,n)},authenticate:function(t,e,n){return this._postParams({grant_type:\"password\",username:t,password:e,client_id:this.clientId,client_secret:this.clientSecret,redirect_uri:this.redirectUri},n)},revokeToken:function(t,e){return this._transport.httpRequest({method:\"POST\",url:this.revokeServiceUrl,body:r.stringify({token:t}),headers:{\"Content-Type\":\"application/x-www-form-urlencoded\"}}).then(function(t){if(t.statusCode>=400){var e=r.parse(t.body);e&&e.error||(e={error:\"ERROR_HTTP_\"+t.statusCode,error_description:t.body});var n=new Error(e.error_description);throw n.name=e.error,n}}).thenCall(e)},_postParams:function(t,e){return this._transport.httpRequest({method:\"POST\",url:this.tokenServiceUrl,body:r.stringify(t),headers:{\"content-type\":\"application/x-www-form-urlencoded\"}}).then(function(t){var e;try{e=JSON.parse(t.body)}catch(n){}if(t.statusCode>=400){e=e||{error:\"ERROR_HTTP_\"+t.statusCode,error_description:t.body};var r=new Error(e.error_description);throw r.name=e.error,r}return e}).thenCall(e)}})},{\"./transport\":36,\"lodash/core\":88,querystring:96}],26:[function(t,e,n){\"use strict\";var r=t(\"lodash/core\"),i=(t(\"./promise\"),t(\"./connection\"),e.exports=function(t){this.rule=new i(t),this.approval=new o(t)},function(t){this._conn=t});i.prototype.list=function(t){return this._conn.request(\"/process/rules\").then(function(t){return t.rules}).thenCall(t)},i.prototype.trigger=function(t,e){return t=r.isArray(t)?t:[t],this._conn.request({method:\"POST\",url:\"/process/rules/\",body:JSON.stringify({contextIds:t}),headers:{\"content-type\":\"application/json\"}}).thenCall(e)};var o=function(t){this._conn=t};o.prototype.list=function(t){return this._conn.request(\"/process/approvals\").then(function(t){return t.approvals}).thenCall(t)},o.prototype.request=function(t,e){return t=t.map(function(t){return t._request?t._request:t}),this._conn.request({method:\"POST\",url:\"/process/approvals\",headers:{\"content-type\":\"application/json\"},body:JSON.stringify({requests:t})}).thenCall(e)},o.prototype._createRequest=function(t,e,n,i,o){\"function\"==typeof n&&(o=n,i=null,n=null),\"function\"==typeof i&&(o=i,i=null),i=i||{};var a={actionType:t,contextId:e,comments:n};return r.extend(a,i),new s(this,a).thenCall(o)},o.prototype.submit=function(t,e,n,r){return this._createRequest(\"Submit\",t,e,n,r)},o.prototype.approve=function(t,e,n,r){return this._createRequest(\"Approve\",t,e,n,r)},o.prototype.reject=function(t,e,n,r){return this._createRequest(\"Reject\",t,e,n,r)};var s=function(t,e){this._process=t,this._request=e};s.prototype.then=function(t,e){this._promise||(this._promise=this._process.request([this]).then(function(t){return t[0]})),this._promise.then(t,e)},s.prototype.thenCall=function(t){return t?this.then(function(e){t(null,e)},function(e){t(e)}):this}},{\"./connection\":19,\"./promise\":27,\"lodash/core\":88}],27:[function(t,e,n){(function(n){\"use strict\";var r=t(\"lodash/core\"),i=t(\"promise/lib/es6-extensions\");i.prototype.thenCall=function(t){return r.isFunction(t)&&this.then(function(e){n.nextTick(function(){t(null,e)})},function(e){n.nextTick(function(){t(e)})}),this},i.prototype.fail=i.prototype[\"catch\"],i.defer=function(){return new o};var o=function(){var t=this;this.promise=new i(function(e,n){t.resolve=e,t.reject=n})};e.exports=i}).call(this,t(\"_process\"))},{_process:91,\"lodash/core\":88,\"promise/lib/es6-extensions\":93}],28:[function(t,e,n){(function(n){\"use strict\";var r=t(\"inherits\"),i=(t(\"events\"),t(\"readable-stream\")),o=t(\"lodash/core\"),s=t(\"./promise\"),a=(t(\"./date\"),t(\"./soql-builder\")),u=t(\"./record-stream\"),c=e.exports=function(t,e,n){c.super_.call(this,{objectMode:!0}),this._conn=t,o.isString(e)?this._soql=e:e.locator&&e.locator.indexOf(\"/\")>=0?this._locator=e.locator.split(\"/\").pop():(this._config=e,this.select(e.fields),e.includes&&this.include(e.includes),e.sort&&this.sort(e.sort)),this._options=o.defaults(n||{},{maxFetch:1e4,autoFetch:!1,scanAll:!1,responseTarget:l.QueryResult}),this._executed=!1,this._finished=!1,this._chaining=!1,this._deferred=s.defer()};r(c,i.Readable),c.prototype.select=function(t){if(this._soql)throw Error(\"Cannot set select fields for the query which has already built SOQL.\");if(t=t||\"*\",o.isString(t))t=t.split(/\\s*,\\s*/);else if(o.isObject(t)&&!o.isArray(t)){var e=[];for(var n in t)t[n]&&e.push(n);t=e}return this._config.fields=t,this},c.prototype.where=function(t){if(this._soql)throw Error(\"Cannot set where conditions for the query which has already built SOQL.\");return this._config.conditions=t,this},c.prototype.limit=function(t){if(this._soql)throw Error(\"Cannot set limit for the query which has already built SOQL.\");return this._config.limit=t,this},c.prototype.skip=c.prototype.offset=function(t){if(this._soql)throw Error(\"Cannot set skip/offset for the query which has already built SOQL.\");return this._config.offset=t,this},c.prototype.sort=c.prototype.orderby=function(t,e){if(this._soql)throw Error(\"Cannot set sort for the query which has already built SOQL.\");return o.isString(t)&&o.isString(e)&&(t=[[t,e]]),this._config.sort=t,this},c.prototype.include=function(t,e,n,r){if(this._soql)throw Error(\"Cannot include child relationship into the query which has already built SOQL.\");{if(!o.isObject(t)){var i={table:t,conditions:e,fields:n,limit:r&&r.limit,offset:r&&(r.offset||r.skip),sort:r&&r.sort};o.isArray(this._config.includes)||(this._config.includes=[]),this._config.includes.push(i);var s=new p(this._conn,this,i);return this._children=this._children||[],this._children.push(s),s}var a=t;for(var u in a){var c=a[u];this.include(u,c.conditions,c.fields,c)}}},c.prototype.maxFetch=function(t){return this._options.maxFetch=t,this},c.prototype.autoFetch=function(t){return this._options.autoFetch=t,this},c.prototype.scanAll=function(t){return this._options.scanAll=t,this};var l=c.ResponseTargets={};[\"QueryResult\",\"Records\",\"SingleRecord\",\"Count\"].forEach(function(t){l[t]=t}),c.prototype.setResponseTarget=function(t){return t in l&&(this._options.responseTarget=t),this},c.prototype.run=c.prototype.exec=c.prototype.execute=function(t,e){var n=this,r=this._conn._logger,i=this._deferred;if(this._executed)return i.reject(new Error(\"re-executing already executed query\")),this;if(this._finished)return i.reject(new Error(\"executing already closed query\")),this;\"function\"==typeof t&&(e=t,t={}),t=t||{},t={headers:t.headers||n._options.headers,responseTarget:t.responseTarget||n._options.responseTarget,autoFetch:t.autoFetch||n._options.autoFetch,maxFetch:t.maxFetch||n._options.maxFetch,scanAll:t.scanAll||n._options.scanAll};var s=function(t,n){if(o.isFunction(e))try{n=e(t,n),t=null}catch(r){t=r}t?i.reject(t):i.resolve(n)};return this.once(\"response\",function(t){s(null,t)}),this.once(\"error\",function(t){s(t)}),this.once(\"fetch\",function(){if(t.responseTarget===l.Records&&(n._chaining||e)){r.debug(\"--- collecting all fetched records ---\");var i=[],o=function(t){i.push(t)};n.on(\"record\",o),n.once(\"end\",function(){n.removeListener(\"record\",o),n.emit(\"response\",i,n)})}}),this._executed=!0,r.debug(\">>> Query start >>>\"),this._execute(t).then(function(){r.debug(\"*** Query finished ***\")}).fail(function(t){r.debug(\"--- Query error ---\"),n.emit(\"error\",t)}),this},c.prototype._execute=function(t){var e=this,n=this._conn._logger,r=t.responseTarget,i=t.autoFetch,o=t.maxFetch,a=t.scanAll;return s.resolve(e._locator?e._conn._baseUrl()+\"/query/\"+e._locator:e.toSOQL().then(function(t){return e.totalFetched=0,n.debug(\"SOQL = \"+t),e._conn._baseUrl()+\"/\"+(a?\"queryAll\":\"query\")+\"?q=\"+encodeURIComponent(t)})).then(function(n){return e._conn.request({method:\"GET\",url:n,headers:t.headers})}).then(function(n){e.emit(\"fetch\"),e.totalSize=n.totalSize;var s;switch(r){case l.SingleRecord:s=n.records&&n.records.length>0?n.records[0]:null;break;case l.Records:s=n.records;break;case l.Count:s=n.totalSize;break;default:s=n}r!==l.Records&&e.emit(\"response\",s,e);for(var a=n.records&&n.records.length||0,u=0;u<a;u++){if(e.totalFetched>=o){e._finished=!0;break}var c=n.records[u];e.push(c),e.emit(\"record\",c,e.totalFetched++,e)}return n.nextRecordsUrl&&(e._locator=n.nextRecordsUrl.split(\"/\").pop()),e._finished=e._finished||n.done||!i,e._finished?e.push(null):e._execute(t),s})},c.prototype._read=function(t){this._finished||this._executed||this.execute({autoFetch:!0})},c.prototype.on=function(t,e){if(\"record\"===t){var n=this;this.on(\"readable\",function(){for(;null!==n.read(););})}return c.super_.prototype.on.call(this,t,e)},c.prototype.addListener=c.prototype.on,c.prototype._expandFields=function(){function t(t){var n=r._parent._config.table;return i.debug('finding table for relation \"'+t+'\" in \"'+n+'\"...'),e(n).then(function(e){var n=t.toUpperCase(),r=o.find(e.childRelationships,function(t){return(t.relationshipName||\"\").toUpperCase()===n});return r?r.childSObject:s.reject(new Error(\"No child relationship found: \"+t))})}function e(t){i.debug(\"describe cache: \"+t);var e=s.defer();return a.describe$(t,function(t,n){i.debug(\"... done.\"),t?e.reject(t):e.resolve(n)}),e.promise}function n(t,r){i.debug('expanding field \"'+r+'\" in \"'+t+'\"...');var a=r.split(\".\");return\"*\"===a[a.length-1]?e(t).then(function(e){if(i.debug(\"table \"+t+\"has been described\"),a.length>1){var r=a.shift(),s=o.find(e.fields,function(t){return t.relationshipName&&t.relationshipName.toUpperCase()===r.toUpperCase()});if(s){var u=1===s.referenceTo.length?s.referenceTo[0]:\"Name\";return n(u,a.join(\".\")).then(function(t){return o.map(t,function(t){return r+\".\"+t})})}return[]}return o.map(e.fields,function(t){return t.name})}):s.resolve([r])}if(this._soql)return s.reject(new Error(\"Cannot expand fields for the query which has already built SOQL.\"));var r=this,i=r._conn._logger,a=this._conn,u=this._config.table,c=this._config.fields||[];return i.debug(\"_expandFields: table = \"+u+\", fields = \"+c.join(\", \")),s.all([s.resolve(r._parent?t(u):u).then(function(t){return s.all(o.map(c,function(e){return n(t,e)})).then(function(t){r._config.fields=o.flatten(t)})}),s.all(o.map(r._children||[],function(t){return t._expandFields()}))])},c.prototype.explain=function(t){var e=this,n=this._conn._logger;return e.toSOQL().then(function(t){n.debug(\"SOQL = \"+t);var r=\"/query/?explain=\"+encodeURIComponent(t);return e._conn.request(r)}).thenCall(t)},c.prototype.toSOQL=function(t){var e=this;return s.resolve(e._soql||e._expandFields().then(function(){return a.createSOQL(e._config)})).thenCall(t)},c.prototype.stream=u.Serializable.prototype.stream,c.prototype.map=u.prototype.map,c.prototype.filter=u.prototype.map;var h=200;c.prototype[\"delete\"]=c.prototype.del=c.prototype.destroy=function(t,e,n){if(\"function\"==typeof t?(n=t,e={},t=null):\"object\"==typeof t&&null!==t&&(n=e,e=t,t=null),e=e||{},t=t||this._config&&this._config.table,!t)throw new Error(\"SOQL based query needs SObject type information to bulk delete.\");var r=e.allowBulk===!1?-1:\"number\"==typeof e.bulkThreshold?e.bulkThreshold:this._conn._ensureVersion(42)?h:this._conn.maxRequest/2,i=this;return new s(function(e,n){var o=[],s=null,a=function(a){if(!a.Id)return void i.emit(\"error\",new Error(\"Queried record does not include Salesforce record ID.\"));var u={Id:a.Id};s?s.write(u):(o.push(u),(r<0||o.length>r)&&(s=i._conn.sobject(t).deleteBulk().on(\"response\",e).on(\"error\",n),o.forEach(function(t){s.write(t)}),o=[]))},u=function(){if(s)s.end();else{var r=o.map(function(t){return t.Id});i._conn.sobject(t).destroy(r,{allowRecursive:!0}).then(e,n)}};i.on(\"data\",a).on(\"end\",u).on(\"error\",n)}).thenCall(n)},c.prototype.update=function(t,e,n,r){if(\"function\"==typeof e?(r=e,n={},e=null):\"object\"==typeof e&&null!==e&&(r=n,n=e,e=null),n=n||{},e=e||this._config&&this._config.table,!e)throw new Error(\"SOQL based query needs SObject type information to bulk update.\");var i=o.isFunction(t)?u.map(t):u.recordMapStream(t),a=n.allowBulk===!1?-1:\"number\"==typeof n.bulkThreshold?n.bulkThreshold:this._conn._ensureVersion(42)?h:this._conn.maxRequest/2,c=this;return new s(function(t,n){var r=[],o=null,s=function(i){o?o.write(i):(r.push(i),(a<0||r.length>a)&&(o=c._conn.sobject(e).updateBulk().on(\"response\",t).on(\"error\",n),r.forEach(function(t){o.write(t)}),r=[]))},u=function(){o?o.end():c._conn.sobject(e).update(r,{allowRecursive:!0}).then(t,n)};c.on(\"error\",n).pipe(i).on(\"data\",s).on(\"end\",u).on(\"error\",n)}).thenCall(r)},c.prototype.then=function(t,e){return this._chaining=!0,this._finished||this._executed||this.execute(),this._deferred.promise.then.apply(this._deferred.promise,arguments)},c.prototype.thenCall=function(t){return o.isFunction(t)&&this.then(function(e){n.nextTick(function(){t(null,e)})},function(e){n.nextTick(function(){t(e)})}),this};var p=function(t,e,n){p.super_.call(this,t,n),this._parent=e};r(p,c),p.prototype.include=function(){throw new Error(\"Not allowed to include another subquery in subquery.\")},p.prototype.end=function(){return this._parent},p.prototype.run=p.prototype.exec=p.prototype.execute=function(){return this._parent.execute.apply(this._parent,arguments)}}).call(this,t(\"_process\"))},{\"./date\":22,\"./promise\":27,\"./record-stream\":30,\"./soql-builder\":35,_process:91,events:47,inherits:84,\"lodash/core\":88,\"readable-stream\":107}],29:[function(t,e,n){\"use strict\";var r=e.exports=function(t,e){this._conn=t,this._path=e};r.prototype.describe=function(t){var e=this._path+\"/describe\";return this._conn.request(e).thenCall(t)},r.prototype.defaultValues=function(t,e){\"function\"==typeof t&&(e=t,t=null);var n=this._path+\"/defaultValues\";return t&&(n+=\"/\"+t),this._conn.request(n).thenCall(e)},r.prototype.execute=function(t,e,n){var r={contextId:t,record:e};return this._conn.requestPost(this._path,r).thenCall(n)}},{}],30:[function(t,e,n){\"use strict\";function r(t,e){return Object.keys(t).reduce(function(t,n){var i=t[n],o={};if(\"attributes\"===n)t=c.extend({},t),delete t[n];else if(e.nullValue&&null===i)o[n]=e.nullValue,t=c.extend({},t,o);else if(null!==i&&\"object\"==typeof i){var s=r(i,e);t=Object.keys(s).reduce(function(t,e){return t[n+\".\"+e]=s[e],t},c.extend({},t))}return t},t)}function i(t,e){var n=new a;return n.on(\"pipe\",function(r){r.unpipe(n),r.pipe(t).pipe(e)}),n.pipe=function(t,n){return e.pipe(t,n)},n}var o=(t(\"events\"),t(\"readable-stream\")),s=(o.Duplex,o.Transform),a=o.PassThrough,u=t(\"inherits\"),c=t(\"lodash/core\"),l=t(\"./csv\"),h=e.exports=function(){h.super_.call(this,{objectMode:!0})};u(h,s),h.prototype._transform=function(t,e,n){this.emit(\"record\",t),this.push(t),n()},h.prototype.map=function(t){return this.pipe(h.map(t))},h.prototype.filter=function(t){return this.pipe(h.filter(t))};var p=h.Serializable=function(){p.super_.call(this),this._dataStream=null};u(p,h),p.prototype.stream=function(t,e){t=t||\"csv\";var n=y[t];if(!n)throw new Error(\"Converting [\"+t+\"] data stream is not supported.\");return this._dataStream||(this._dataStream=new a,this.pipe(n.serialize(e)).pipe(this._dataStream)),this._dataStream};var f=h.Parsable=function(){f.super_.call(this),this._dataStream=null};u(f,h),f.prototype.stream=function(t,e){t=t||\"csv\";var n=y[t],r=this;if(!n)throw new Error(\"Converting [\"+t+\"] data stream is not supported.\");return this._dataStream||(this._dataStream=new a,this._parserStream=n.parse(e).on(\"error\",function(t){r.emit(\"error\",t)}),this._parserStream.pipe(this).pipe(new a({objectMode:!0,highWaterMark:5e5}))),this._dataStream},f.prototype.on=function(t,e){return\"readable\"!==t&&\"record\"!==t||this._dataStream.pipe(this._parserStream),f.super_.prototype.on.call(this,t,e)},f.prototype.addListener=f.prototype.on,h.map=function(t){var e=new h.Serializable;return e._transform=function(e,n,r){var i=t(e)||e;this.push(i),r()},e},h.recordMapStream=function(t,e){function n(t,e){if(c.isString(t)){var n=/^\\$\\{(\\w+)\\}$/.exec(t);return n?e[n[1]]:t.replace(/\\$\\{(\\w+)\\}/g,function(t,n){var r=e[n];return c.isNull(r)||c.isUndefined(r)?\"\":String(r)})}return t}return h.map(function(r){var i={Id:r.Id};for(var o in t)i[o]=e?t[o]:n(t[o],r);return i})},h.filter=function(t){var e=new h.Serializable;return e._transform=function(e,n,r){t(e)&&this.push(e),r()},e};var d={serialize:function(t){return t=t||{},i(h.map(function(e){return r(e,t)}),l.serializeCSVStream(t))},parse:function(t){return l.parseCSVStream(t)}},y=h.DataStreamConverters={csv:d}},{\"./csv\":21,events:47,inherits:84,\"lodash/core\":88,\"readable-stream\":107}],31:[function(t,e,n){\"use strict\";var r=t(\"lodash/core\"),i=e.exports=function(t,e,n){this._conn=t,this.type=e,this.id=n};i.prototype.retrieve=function(t,e){return\"function\"==typeof t&&(e=t,t={}),this._conn.retrieve(this.type,this.id,t,e)},i.prototype.update=function(t,e,n){return\"function\"==typeof e&&(n=e,e={}),t=r.clone(t),t.Id=this.id,this._conn.update(this.type,t,e,n)},i.prototype[\"delete\"]=i.prototype.del=i.prototype.destroy=function(t,e){return\"function\"==typeof t&&(e=t,t={}),this._conn.destroy(this.type,this.id,t,e)},i.prototype.blob=function(t){var e=[this._conn._baseUrl(),\"sobjects\",this.type,this.id,t].join(\"/\");return this._conn.request(e).stream()}},{\"lodash/core\":88}],32:[function(t,e,n){\"use strict\";var r=t(\"./_required\");e.exports=function(t){\"./jsforce\"!==t&&\"jsforce\"!==t||(t=\"./core\");var e=r[t];if(\"undefined\"==typeof e)throw new Error(\"Cannot find module '\"+t+\"'\");return e}},{\"./_required\":3}],33:[function(t,e,n){\"use strict\";function r(t,e){if(a.isArray(t))return t.map(function(t){return r(t,e&&e[0])});if(a.isObject(t)){if(t.$&&\"true\"===t.$[\"xsi:nil\"])return null;if(a.isArray(e))return[r(t,e[0])];var n={};for(var i in t)n[i]=r(t[i],e&&e[i]);return n}if(a.isArray(e))return[r(t,e[0])];if(a.isObject(e))return{};switch(e){case\"string\":return String(t);case\"number\":return Number(t);case\"boolean\":return\"true\"===t;default:return t}}function i(t,e){var n=e.shift();if(n){for(var r in t)if(n.test(r))return i(t[r],e);return null}return t}function o(t,e){if(a.isObject(t)&&(e=t,t=null),a.isArray(e))return a.map(e,function(e){return o(t,e)}).join(\"\");var n=[],r=[];if(a.isObject(e)){for(var i in e){var s=e[i];\"@\"===i[0]?(i=i.substring(1),n.push(i+'=\"'+s+'\"')):r.push(o(i,s))}e=r.join(\"\")}else e=String(e).replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\").replace(/'/g,\"&apos;\");var u=t?\"<\"+t+(n.length>0?\" \"+n.join(\" \"):\"\")+\">\":\"\",c=t?\"</\"+t+\">\":\"\";return u+e+c}var s=t(\"inherits\"),a=t(\"lodash/core\"),u=(t(\"xml2js\"),t(\"./http-api\")),c=e.exports=function(t,e){c.super_.apply(this,arguments),this._endpointUrl=e.endpointUrl,this._xmlns=e.xmlns||\"urn:partner.soap.sforce.com\"};s(c,u),c.prototype.invoke=function(t,e,n,i){\"function\"==typeof n&&(i=n,n=null);var o={};return o[t]=e,this.request({method:\"POST\",url:this._endpointUrl,headers:{\"Content-Type\":\"text/xml\",SOAPAction:'\"\"'},message:o}).then(function(t){return n?r(t,n):t}).thenCall(i)},c.prototype.beforeSend=function(t){t.body=this._createEnvelope(t.message)},c.prototype.isSessionExpired=function(t){return 500===t.statusCode&&/<faultcode>[a-zA-Z]+:INVALID_SESSION_ID<\\/faultcode>/.test(t.body)},c.prototype.parseError=function(t){var e=i(t,[/:Envelope$/,/:Body$/,/:Fault$/]);return{errorCode:e.faultcode,message:e.faultstring}},c.prototype.getResponseBody=function(t){var e=c.super_.prototype.getResponseBody.call(this,t);return i(e,[/:Envelope$/,/:Body$/,/.+/])},c.prototype._createEnvelope=function(t){var e={},n=this._conn;return n.accessToken&&(e.SessionHeader={sessionId:this._conn.accessToken}),n.callOptions&&(e.CallOptions=n.callOptions),['<?xml version=\"1.0\" encoding=\"UTF-8\"?>','<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"',' xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"',' xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">','<soapenv:Header xmlns=\"'+this._xmlns+'\">',o(e),\"</soapenv:Header>\",'<soapenv:Body xmlns=\"'+this._xmlns+'\">',o(t),\"</soapenv:Body>\",\"</soapenv:Envelope>\"].join(\"\")}},{\"./http-api\":23,inherits:84,\"lodash/core\":88,xml2js:123}],34:[function(t,e,n){\"use strict\";var r=t(\"lodash/core\"),i=t(\"./record\"),o=t(\"./query\"),s=(t(\"./cache\"),t(\"./quick-action\")),a=e.exports=function(t,e){this._conn=t,this.type=e;var n={key:\"describe.\"+this.type};this.describe$=t.cache.makeCacheable(this.describe,this,n),this.describe=t.cache.makeResponseCacheable(this.describe,this,n),n={key:\"layouts.\"+this.type},this.layouts$=t.cache.makeCacheable(this.layouts,this,n),this.layouts=t.cache.makeResponseCacheable(this.layouts,this,n),n={key:\"compactLayouts.\"+this.type},this.compactLayouts$=t.cache.makeCacheable(this.compactLayouts,this,n),this.compactLayouts=t.cache.makeResponseCacheable(this.compactLayouts,this,n),n={key:\"approvalLayouts.\"+this.type},this.approvalLayouts$=t.cache.makeCacheable(this.approvalLayouts,this,n),this.approvalLayouts=t.cache.makeResponseCacheable(this.approvalLayouts,this,n)};a.prototype.insert=a.prototype.create=function(t,e,n){return\"function\"==typeof e&&(n=e,e={}),this._conn.create(this.type,t,e,n)},a.prototype.retrieve=function(t,e,n){return\"function\"==typeof e&&(n=e,e={}),this._conn.retrieve(this.type,t,e,n)},a.prototype.update=function(t,e,n){return\"function\"==typeof e&&(n=e,e={}),this._conn.update(this.type,t,e,n)},a.prototype.upsert=function(t,e,n,r){return\"function\"==typeof n&&(r=n,n={}),this._conn.upsert(this.type,t,e,n,r)},a.prototype[\"delete\"]=a.prototype.del=a.prototype.destroy=function(t,e,n){return\"function\"==typeof e&&(n=e,e={}),this._conn.destroy(this.type,t,e,n)},a.prototype.describe=function(t){return this._conn.describe(this.type,t)},a.prototype.record=function(t){return new i(this._conn,this.type,t)},a.prototype.find=function(t,e,n,r){\"function\"==typeof t?(r=t,t={},e=null,n=null):\"function\"==typeof e?(r=e,e=null,n=null):\"function\"==typeof n&&(r=n,n=null),n=n||{};var i={fields:e,includes:n.includes,table:this.type,conditions:t,limit:n.limit,sort:n.sort,offset:n.offset||n.skip},s=new o(this._conn,i,n);return s.setResponseTarget(o.ResponseTargets.Records),r&&s.run(r),s},a.prototype.findOne=function(t,e,n,i){\"function\"==typeof t?(i=t,t={},e=null,n=null):\"function\"==typeof e?(i=e,e=null,n=null):\"function\"==typeof n&&(i=n,n=null),n=r.extend(n||{},{limit:1});var s=this.find(t,e,n);return s.setResponseTarget(o.ResponseTargets.SingleRecord),i&&s.run(i),s},a.prototype.select=function(t,e){return this.find(null,t,null,e)},a.prototype.count=function(t,e){\"function\"==typeof t&&(e=t,t={});var n=this.find(t,{\"count()\":!0});return n.setResponseTarget(\"Count\"),e&&n.run(e),n},a.prototype.bulkload=function(t,e,n,r){return this._conn.bulk.load(this.type,t,e,n,r)},a.prototype.insertBulk=a.prototype.createBulk=function(t,e){return this.bulkload(\"insert\",t,e)},a.prototype.updateBulk=function(t,e){return this.bulkload(\"update\",t,e)},a.prototype.upsertBulk=function(t,e,n){return this.bulkload(\"upsert\",{extIdField:e\n},t,n)},a.prototype.deleteBulk=a.prototype.destroyBulk=function(t,e){return this.bulkload(\"delete\",t,e)},a.prototype.deleteHardBulk=a.prototype.destroyHardBulk=function(t,e){return this.bulkload(\"hardDelete\",t,e)},a.prototype.recent=function(t){return this._conn.recent(this.type,t)},a.prototype.updated=function(t,e,n){return this._conn.updated(this.type,t,e,n)},a.prototype.deleted=function(t,e,n){return this._conn.deleted(this.type,t,e,n)},a.prototype.layouts=function(t,e){\"function\"==typeof t&&(e=t,t=null);var n=\"/sobjects/\"+this.type+\"/describe/\"+(t?\"namedLayouts/\"+t:\"layouts\");return this._conn.request(n,e)},a.prototype.compactLayouts=function(t){var e=\"/sobjects/\"+this.type+\"/describe/compactLayouts\";return this._conn.request(e,t)},a.prototype.approvalLayouts=function(t){var e=\"/sobjects/\"+this.type+\"/describe/approvalLayouts\";return this._conn.request(e,t)},a.prototype.listviews=function(t){var e=this._conn._baseUrl()+\"/sobjects/\"+this.type+\"/listviews\";return this._conn.request(e,t)},a.prototype.listview=function(t){return new u(this._conn,this.type,t)},a.prototype.quickActions=function(t){return this._conn.request(\"/sobjects/\"+this.type+\"/quickActions\").thenCall(t)},a.prototype.quickAction=function(t){return new s(this._conn,\"/sobjects/\"+this.type+\"/quickActions/\"+t)};var u=function(t,e,n){this._conn=t,this.type=e,this.id=n};u.prototype.results=function(t){var e=this._conn._baseUrl()+\"/sobjects/\"+this.type+\"/listviews/\"+this.id+\"/results\";return this._conn.request(e,t)},u.prototype.describe=function(t,e){\"function\"==typeof t&&(e=t,t={}),t=t||{};var n=this._conn._baseUrl()+\"/sobjects/\"+this.type+\"/listviews/\"+this.id+\"/describe\";return this._conn.request({method:\"GET\",url:n,headers:t.headers},e)},u.prototype.explain=function(t){var e=\"/query/?explain=\"+this.id;return this._conn.request(e,t)}},{\"./cache\":18,\"./query\":28,\"./quick-action\":29,\"./record\":31,\"lodash/core\":88}],35:[function(t,e,n){\"use strict\";function r(t){var e=[\"SELECT \",i(t.fields,t.includes),\" FROM \",t.table].join(\"\"),n=o(t.conditions);n&&(e+=\" WHERE \"+n);var r=l(t.sort);return r&&(e+=\" ORDER BY \"+r),t.limit&&(e+=\" LIMIT \"+t.limit),t.offset&&(e+=\" OFFSET \"+t.offset),e}function i(t,e){return e=h.map(h.values(e||{}),function(t){return\"(\"+r(t)+\")\"}),(t||[\"Id\"]).concat(e).join(\", \")}function o(t,e,n){if(h.isString(t))return t;t=t||[],e=e||\"AND\",n=n||0,t=c(t)?t.map(function(t){var e=[];for(var n in t)e.push({key:n,value:t[n]});return e.length>1?e:e[0]}):h.keys(t).map(function(e){return{key:e,value:t[e]}}),t=t.map(function(r){var i,a=n+1;switch(r.key){case\"$or\":case\"$and\":case\"$not\":return\"NOT\"!==e&&1===t.length&&(a=n),i=\"$or\"===r.key?\"OR\":\"$and\"===r.key?\"AND\":\"NOT\",o(r.value,i,a);default:return s(r.key,r.value)}}).filter(function(t){return t});var r;return\"NOT\"===e?(r=n>0,(r?\"(\":\"\")+\"NOT \"+t[0]+(r?\")\":\"\")):(r=n>0&&t.length>1,(r?\"(\":\"\")+t.join(\" \"+e+\" \")+(r?\")\":\"\"))}function s(t,e){var n=\"$eq\";if(h.isArray(e))n=\"$in\";else if(h.isObject(e)){for(var r in e)if(\"$\"===r[0]){n=r,e=e[r];break}}var i=f[n];if(!i||h.isUndefined(e))return null;var o=a(e);if(h.isUndefined(o))return null;switch(i){case\"NOT LIKE\":return\"(\"+[\"NOT\",t,\"LIKE\",o].join(\" \")+\")\";case\"EXISTS\":return[t,e?\"!=\":\"=\",\"null\"].join(\" \");default:return[t,i,o].join(\" \")}}function a(t){return c(t)?t.length>0?\"(\"+t.map(a).join(\", \")+\")\":void 0:t instanceof p?t.toString():h.isString(t)?\"'\"+u(t)+\"'\":h.isNumber(t)?t.toString():h.isNull(t)?\"null\":t}function u(t){return String(t||\"\").replace(/'/g,\"\\\\'\")}function c(t){return h.isObject(t)&&h.isFunction(t.pop)}function l(t){if(t=t||[],h.isString(t)){if(/,|\\s+(asc|desc)\\s*$/.test(t))return t;t=t.split(/\\s+/).map(function(t){var e=\"ASC\",n=t[0];return\"-\"===n?(e=\"DESC\",t=t.substring(1)):\"+\"===n&&(t=t.substring(1)),[t,e]})}else c(t)||(t=h.keys(t).map(function(e){var n=t[e];return[e,n]}));return t.map(function(t){var e=t[0],n=t[1];switch(String(n)){case\"DESC\":case\"desc\":case\"descending\":case\"-\":case\"-1\":n=\"DESC\";break;default:n=\"ASC\"}return e+\" \"+n}).join(\", \")}var h=t(\"lodash/core\"),p=t(\"./date\"),f={\"=\":\"=\",$eq:\"=\",\"!=\":\"!=\",$ne:\"!=\",\">\":\">\",$gt:\">\",\"<\":\"<\",$lt:\"<\",\">=\":\">=\",$gte:\">=\",\"<=\":\"<=\",$lte:\"<=\",$like:\"LIKE\",$nlike:\"NOT LIKE\",$in:\"IN\",$nin:\"NOT IN\",$includes:\"INCLUDES\",$excludes:\"EXCLUDES\",$exists:\"EXISTS\"};n.createSOQL=r},{\"./date\":22,\"lodash/core\":88}],36:[function(t,e,n){(function(n){\"use strict\";function r(t,e){var n=t.then;return t.then=function(){e();var i=n.apply(t,arguments);return r(i,e)},t.stream=e,t}function i(t){var e=/(\\w+)\\.(visual\\.force|salesforce)\\.com$/.exec(t);return e&&(t=e[1]+\".salesforce.com\"),t}var o=t(\"inherits\"),s=t(\"./promise\"),a=t(\"request\"),u=t(\"./browser/canvas\"),c=t(\"./browser/jsonp\");if(a.defaults){var l={followAllRedirects:!0};n.env.HTTP_PROXY&&(l.proxy=n.env.HTTP_PROXY),parseInt(n.env.HTTP_TIMEOUT)&&(l.timeout=parseInt(n.env.HTTP_TIMEOUT)),a=a.defaults(l)}var h;if(\"undefined\"==typeof window)h=n.env.LOCATION_BASE_URL||\"\";else{var p=i(window.location.host);h=p?\"https://\"+p:\"\"}var f=e.exports=function(){};f.prototype.httpRequest=function(t,e){var n,i=s.defer(),o=this._getHttpRequestModule(),a=function(){return n||(n=o(t,function(t,e){t?i.reject(t):i.resolve(e)})),n};return r(i.promise,a).thenCall(e)},f.prototype._getHttpRequestModule=function(){return a};var d=f.JsonpTransport=function(t){this._jsonpParam=t};o(d,f),d.prototype._getHttpRequestModule=function(){return c.createRequest(this._jsonpParam)},d.supported=c.supported;var y=f.CanvasTransport=function(t){this._signedRequest=t};o(y,f),y.prototype._getHttpRequestModule=function(){return u.createRequest(this._signedRequest)},y.supported=u.supported;var m=f.ProxyTransport=function(t){this._proxyUrl=t};o(m,f),m.prototype.httpRequest=function(t,e){var n=t.url;0===n.indexOf(\"/\")&&(n=h+n);var r={method:t.method,url:this._proxyUrl+\"?\"+Date.now()+\".\"+(\"\"+Math.random()).substring(2),headers:{\"salesforceproxy-endpoint\":n}};if((t.body||\"\"===t.body)&&(r.body=t.body),t.headers)for(var i in t.headers)r.headers[i]=t.headers[i];return m.super_.prototype.httpRequest.call(this,r,e)};var _=f.HttpProxyTransport=function(t){this._httpProxy=t};o(_,f),_.prototype.httpRequest=function(t,e){var n=t.url;0===n.indexOf(\"/\")&&(n=h+n);var r={method:t.method,url:t.url,proxy:this._httpProxy,headers:{}};if((t.body||\"\"===t.body)&&(r.body=t.body),t.headers)for(var i in t.headers)r.headers[i]=t.headers[i];return _.super_.prototype.httpRequest.call(this,r,e)}}).call(this,t(\"_process\"))},{\"./browser/canvas\":14,\"./browser/jsonp\":16,\"./promise\":27,_process:91,inherits:84,request:17}],37:[function(t,e,n){\"use strict\";function r(){if(u.length)throw u.shift()}function i(t){var e;e=a.length?a.pop():new o,e.task=t,s(e)}function o(){this.task=null}var s=t(\"./raw\"),a=[],u=[],c=s.makeRequestCallFromTimer(r);e.exports=i,o.prototype.call=function(){try{this.task.call()}catch(t){i.onerror?i.onerror(t):(u.push(t),c())}finally{this.task=null,a[a.length]=this}}},{\"./raw\":38}],38:[function(t,e,n){(function(t){\"use strict\";function n(t){a.length||(s(),u=!0),a[a.length]=t}function r(){for(;c<a.length;){var t=c;if(c+=1,a[t].call(),c>l){for(var e=0,n=a.length-c;e<n;e++)a[e]=a[e+c];a.length-=c,c=0}}a.length=0,c=0,u=!1}function i(t){var e=1,n=new p(t),r=document.createTextNode(\"\");return n.observe(r,{characterData:!0}),function(){e=-e,r.data=e}}function o(t){return function(){function e(){clearTimeout(n),clearInterval(r),t()}var n=setTimeout(e,0),r=setInterval(e,50)}}e.exports=n;var s,a=[],u=!1,c=0,l=1024,h=\"undefined\"!=typeof t?t:self,p=h.MutationObserver||h.WebKitMutationObserver;s=\"function\"==typeof p?i(r):o(r),n.requestFlush=s,n.makeRequestCallFromTimer=o}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],39:[function(t,e,n){\"use strict\";function r(t){var e=t.length;if(e%4>0)throw new Error(\"Invalid string. Length must be a multiple of 4\");var n=t.indexOf(\"=\");n===-1&&(n=e);var r=n===e?0:4-n%4;return[n,r]}function i(t){var e=r(t),n=e[0],i=e[1];return 3*(n+i)/4-i}function o(t,e,n){return 3*(e+n)/4-n}function s(t){for(var e,n=r(t),i=n[0],s=n[1],a=new p(o(t,i,s)),u=0,c=s>0?i-4:i,l=0;l<c;l+=4)e=h[t.charCodeAt(l)]<<18|h[t.charCodeAt(l+1)]<<12|h[t.charCodeAt(l+2)]<<6|h[t.charCodeAt(l+3)],a[u++]=e>>16&255,a[u++]=e>>8&255,a[u++]=255&e;return 2===s&&(e=h[t.charCodeAt(l)]<<2|h[t.charCodeAt(l+1)]>>4,a[u++]=255&e),1===s&&(e=h[t.charCodeAt(l)]<<10|h[t.charCodeAt(l+1)]<<4|h[t.charCodeAt(l+2)]>>2,a[u++]=e>>8&255,a[u++]=255&e),a}function a(t){return l[t>>18&63]+l[t>>12&63]+l[t>>6&63]+l[63&t]}function u(t,e,n){for(var r,i=[],o=e;o<n;o+=3)r=(t[o]<<16&16711680)+(t[o+1]<<8&65280)+(255&t[o+2]),i.push(a(r));return i.join(\"\")}function c(t){for(var e,n=t.length,r=n%3,i=[],o=16383,s=0,a=n-r;s<a;s+=o)i.push(u(t,s,s+o>a?a:s+o));return 1===r?(e=t[n-1],i.push(l[e>>2]+l[e<<4&63]+\"==\")):2===r&&(e=(t[n-2]<<8)+t[n-1],i.push(l[e>>10]+l[e>>4&63]+l[e<<2&63]+\"=\")),i.join(\"\")}n.byteLength=i,n.toByteArray=s,n.fromByteArray=c;for(var l=[],h=[],p=\"undefined\"!=typeof Uint8Array?Uint8Array:Array,f=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",d=0,y=f.length;d<y;++d)l[d]=f[d],h[f.charCodeAt(d)]=d;h[\"-\".charCodeAt(0)]=62,h[\"_\".charCodeAt(0)]=63},{}],40:[function(t,e,n){},{}],41:[function(t,e,n){\"use strict\";function r(){try{var t=new Uint8Array(1);return t.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===t.foo()}catch(e){return!1}}function i(t){if(t>Q)throw new RangeError(\"Invalid typed array length\");var e=new Uint8Array(t);return e.__proto__=o.prototype,e}function o(t,e,n){if(\"number\"==typeof t){if(\"string\"==typeof e)throw new Error(\"If encoding is specified then the first argument must be a string\");return c(t)}return s(t,e,n)}function s(t,e,n){if(\"number\"==typeof t)throw new TypeError('\"value\" argument must not be a number');return W(t)||t&&W(t.buffer)?p(t,e,n):\"string\"==typeof t?l(t,e):f(t)}function a(t){if(\"number\"!=typeof t)throw new TypeError('\"size\" argument must be of type number');if(t<0)throw new RangeError('\"size\" argument must not be negative')}function u(t,e,n){return a(t),t<=0?i(t):void 0!==e?\"string\"==typeof n?i(t).fill(e,n):i(t).fill(e):i(t)}function c(t){return a(t),i(t<0?0:0|d(t))}function l(t,e){if(\"string\"==typeof e&&\"\"!==e||(e=\"utf8\"),!o.isEncoding(e))throw new TypeError(\"Unknown encoding: \"+e);var n=0|m(t,e),r=i(n),s=r.write(t,e);return s!==n&&(r=r.slice(0,s)),r}function h(t){for(var e=t.length<0?0:0|d(t.length),n=i(e),r=0;r<e;r+=1)n[r]=255&t[r];return n}function p(t,e,n){if(e<0||t.byteLength<e)throw new RangeError('\"offset\" is outside of buffer bounds');if(t.byteLength<e+(n||0))throw new RangeError('\"length\" is outside of buffer bounds');var r;return r=void 0===e&&void 0===n?new Uint8Array(t):void 0===n?new Uint8Array(t,e):new Uint8Array(t,e,n),r.__proto__=o.prototype,r}function f(t){if(o.isBuffer(t)){var e=0|d(t.length),n=i(e);return 0===n.length?n:(t.copy(n,0,0,e),n)}if(t){if(ArrayBuffer.isView(t)||\"length\"in t)return\"number\"!=typeof t.length||G(t.length)?i(0):h(t);if(\"Buffer\"===t.type&&Array.isArray(t.data))return h(t.data)}throw new TypeError(\"The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object.\")}function d(t){if(t>=Q)throw new RangeError(\"Attempt to allocate Buffer larger than maximum size: 0x\"+Q.toString(16)+\" bytes\");return 0|t}function y(t){return+t!=t&&(t=0),o.alloc(+t)}function m(t,e){if(o.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||W(t))return t.byteLength;\"string\"!=typeof t&&(t=\"\"+t);var n=t.length;if(0===n)return 0;for(var r=!1;;)switch(e){case\"ascii\":case\"latin1\":case\"binary\":return n;case\"utf8\":case\"utf-8\":case void 0:return B(t).length;case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return 2*n;case\"hex\":return n>>>1;case\"base64\":return H(t).length;default:if(r)return B(t).length;e=(\"\"+e).toLowerCase(),r=!0}}function _(t,e,n){var r=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return\"\";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return\"\";if(n>>>=0,e>>>=0,n<=e)return\"\";for(t||(t=\"utf8\");;)switch(t){case\"hex\":return j(this,e,n);case\"utf8\":case\"utf-8\":return N(this,e,n);case\"ascii\":return A(this,e,n);case\"latin1\":case\"binary\":return D(this,e,n);case\"base64\":return I(this,e,n);case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return k(this,e,n);default:if(r)throw new TypeError(\"Unknown encoding: \"+t);t=(t+\"\").toLowerCase(),r=!0}}function g(t,e,n){var r=t[e];t[e]=t[n],t[n]=r}function v(t,e,n,r,i){if(0===t.length)return-1;if(\"string\"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,G(n)&&(n=i?0:t.length-1),n<0&&(n=t.length+n),n>=t.length){if(i)return-1;n=t.length-1}else if(n<0){if(!i)return-1;n=0}if(\"string\"==typeof e&&(e=o.from(e,r)),o.isBuffer(e))return 0===e.length?-1:b(t,e,n,r,i);if(\"number\"==typeof e)return e=255&e,\"function\"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(t,e,n):Uint8Array.prototype.lastIndexOf.call(t,e,n):b(t,[e],n,r,i);throw new TypeError(\"val must be string, number or Buffer\")}function b(t,e,n,r,i){function o(t,e){return 1===s?t[e]:t.readUInt16BE(e*s)}var s=1,a=t.length,u=e.length;if(void 0!==r&&(r=String(r).toLowerCase(),\"ucs2\"===r||\"ucs-2\"===r||\"utf16le\"===r||\"utf-16le\"===r)){if(t.length<2||e.length<2)return-1;s=2,a/=2,u/=2,n/=2}var c;if(i){var l=-1;for(c=n;c<a;c++)if(o(t,c)===o(e,l===-1?0:c-l)){if(l===-1&&(l=c),c-l+1===u)return l*s}else l!==-1&&(c-=c-l),l=-1}else for(n+u>a&&(n=a-u),c=n;c>=0;c--){for(var h=!0,p=0;p<u;p++)if(o(t,c+p)!==o(e,p)){h=!1;break}if(h)return c}return-1}function w(t,e,n,r){n=Number(n)||0;var i=t.length-n;r?(r=Number(r),r>i&&(r=i)):r=i;var o=e.length;r>o/2&&(r=o/2);for(var s=0;s<r;++s){var a=parseInt(e.substr(2*s,2),16);if(G(a))return s;t[n+s]=a}return s}function E(t,e,n,r){return V(B(e,t.length-n),t,n,r)}function T(t,e,n,r){return V(X(e),t,n,r)}function x(t,e,n,r){return T(t,e,n,r)}function S(t,e,n,r){return V(H(e),t,n,r)}function C(t,e,n,r){return V(z(e,t.length-n),t,n,r)}function I(t,e,n){return 0===e&&n===t.length?$.fromByteArray(t):$.fromByteArray(t.slice(e,n))}function N(t,e,n){n=Math.min(t.length,n);for(var r=[],i=e;i<n;){var o=t[i],s=null,a=o>239?4:o>223?3:o>191?2:1;if(i+a<=n){var u,c,l,h;switch(a){case 1:o<128&&(s=o);break;case 2:u=t[i+1],128===(192&u)&&(h=(31&o)<<6|63&u,h>127&&(s=h));break;case 3:u=t[i+1],c=t[i+2],128===(192&u)&&128===(192&c)&&(h=(15&o)<<12|(63&u)<<6|63&c,h>2047&&(h<55296||h>57343)&&(s=h));break;case 4:u=t[i+1],c=t[i+2],l=t[i+3],128===(192&u)&&128===(192&c)&&128===(192&l)&&(h=(15&o)<<18|(63&u)<<12|(63&c)<<6|63&l,h>65535&&h<1114112&&(s=h))}}null===s?(s=65533,a=1):s>65535&&(s-=65536,r.push(s>>>10&1023|55296),s=56320|1023&s),r.push(s),i+=a}return O(r)}function O(t){var e=t.length;if(e<=J)return String.fromCharCode.apply(String,t);for(var n=\"\",r=0;r<e;)n+=String.fromCharCode.apply(String,t.slice(r,r+=J));return n}function A(t,e,n){var r=\"\";n=Math.min(t.length,n);for(var i=e;i<n;++i)r+=String.fromCharCode(127&t[i]);return r}function D(t,e,n){var r=\"\";n=Math.min(t.length,n);for(var i=e;i<n;++i)r+=String.fromCharCode(t[i]);return r}function j(t,e,n){var r=t.length;(!e||e<0)&&(e=0),(!n||n<0||n>r)&&(n=r);for(var i=\"\",o=e;o<n;++o)i+=F(t[o]);return i}function k(t,e,n){for(var r=t.slice(e,n),i=\"\",o=0;o<r.length;o+=2)i+=String.fromCharCode(r[o]+256*r[o+1]);return i}function L(t,e,n){if(t%1!==0||t<0)throw new RangeError(\"offset is not uint\");if(t+e>n)throw new RangeError(\"Trying to access beyond buffer length\")}function R(t,e,n,r,i,s){if(!o.isBuffer(t))throw new TypeError('\"buffer\" argument must be a Buffer instance');if(e>i||e<s)throw new RangeError('\"value\" argument is out of bounds');if(n+r>t.length)throw new RangeError(\"Index out of range\")}function M(t,e,n,r,i,o){if(n+r>t.length)throw new RangeError(\"Index out of range\");if(n<0)throw new RangeError(\"Index out of range\")}function U(t,e,n,r,i){return e=+e,n>>>=0,i||M(t,e,n,4,3.4028234663852886e38,-3.4028234663852886e38),Y.write(t,e,n,r,23,4),n+4}function q(t,e,n,r,i){return e=+e,n>>>=0,i||M(t,e,n,8,1.7976931348623157e308,-1.7976931348623157e308),Y.write(t,e,n,r,52,8),n+8}function P(t){if(t=t.split(\"=\")[0],t=t.trim().replace(K,\"\"),t.length<2)return\"\";for(;t.length%4!==0;)t+=\"=\";return t}function F(t){return t<16?\"0\"+t.toString(16):t.toString(16)}function B(t,e){e=e||1/0;for(var n,r=t.length,i=null,o=[],s=0;s<r;++s){if(n=t.charCodeAt(s),n>55295&&n<57344){if(!i){if(n>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(s+1===r){(e-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(e-=3)>-1&&o.push(239,191,189),i=n;continue}n=(i-55296<<10|n-56320)+65536}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((e-=1)<0)break;o.push(n)}else if(n<2048){if((e-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((e-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error(\"Invalid code point\");if((e-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function X(t){for(var e=[],n=0;n<t.length;++n)e.push(255&t.charCodeAt(n));return e}function z(t,e){for(var n,r,i,o=[],s=0;s<t.length&&!((e-=2)<0);++s)n=t.charCodeAt(s),r=n>>8,i=n%256,o.push(i),o.push(r);return o}function H(t){return $.toByteArray(P(t))}function V(t,e,n,r){for(var i=0;i<r&&!(i+n>=e.length||i>=t.length);++i)e[i+n]=t[i];return i}function W(t){return t instanceof ArrayBuffer||null!=t&&null!=t.constructor&&\"ArrayBuffer\"===t.constructor.name&&\"number\"==typeof t.byteLength}function G(t){return t!==t}var $=t(\"base64-js\"),Y=t(\"ieee754\");n.Buffer=o,n.SlowBuffer=y,n.INSPECT_MAX_BYTES=50;var Q=2147483647;n.kMaxLength=Q,o.TYPED_ARRAY_SUPPORT=r(),o.TYPED_ARRAY_SUPPORT||\"undefined\"==typeof console||\"function\"!=typeof console.error||console.error(\"This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.\"),Object.defineProperty(o.prototype,\"parent\",{get:function(){if(this instanceof o)return this.buffer}}),Object.defineProperty(o.prototype,\"offset\",{get:function(){if(this instanceof o)return this.byteOffset}}),\"undefined\"!=typeof Symbol&&Symbol.species&&o[Symbol.species]===o&&Object.defineProperty(o,Symbol.species,{value:null,configurable:!0,enumerable:!1,writable:!1}),o.poolSize=8192,o.from=function(t,e,n){return s(t,e,n)},o.prototype.__proto__=Uint8Array.prototype,o.__proto__=Uint8Array,o.alloc=function(t,e,n){return u(t,e,n)},o.allocUnsafe=function(t){return c(t)},o.allocUnsafeSlow=function(t){return c(t)},o.isBuffer=function(t){return null!=t&&t._isBuffer===!0},o.compare=function(t,e){if(!o.isBuffer(t)||!o.isBuffer(e))throw new TypeError(\"Arguments must be Buffers\");if(t===e)return 0;for(var n=t.length,r=e.length,i=0,s=Math.min(n,r);i<s;++i)if(t[i]!==e[i]){n=t[i],r=e[i];break}return n<r?-1:r<n?1:0},o.isEncoding=function(t){switch(String(t).toLowerCase()){case\"hex\":case\"utf8\":case\"utf-8\":case\"ascii\":case\"latin1\":case\"binary\":case\"base64\":case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return!0;default:return!1}},o.concat=function(t,e){if(!Array.isArray(t))throw new TypeError('\"list\" argument must be an Array of Buffers');if(0===t.length)return o.alloc(0);var n;if(void 0===e)for(e=0,n=0;n<t.length;++n)e+=t[n].length;var r=o.allocUnsafe(e),i=0;for(n=0;n<t.length;++n){var s=t[n];if(ArrayBuffer.isView(s)&&(s=o.from(s)),!o.isBuffer(s))throw new TypeError('\"list\" argument must be an Array of Buffers');s.copy(r,i),i+=s.length}return r},o.byteLength=m,o.prototype._isBuffer=!0,o.prototype.swap16=function(){var t=this.length;if(t%2!==0)throw new RangeError(\"Buffer size must be a multiple of 16-bits\");for(var e=0;e<t;e+=2)g(this,e,e+1);return this},o.prototype.swap32=function(){var t=this.length;if(t%4!==0)throw new RangeError(\"Buffer size must be a multiple of 32-bits\");for(var e=0;e<t;e+=4)g(this,e,e+3),g(this,e+1,e+2);return this},o.prototype.swap64=function(){var t=this.length;if(t%8!==0)throw new RangeError(\"Buffer size must be a multiple of 64-bits\");for(var e=0;e<t;e+=8)g(this,e,e+7),g(this,e+1,e+6),g(this,e+2,e+5),g(this,e+3,e+4);return this},o.prototype.toString=function(){var t=this.length;return 0===t?\"\":0===arguments.length?N(this,0,t):_.apply(this,arguments)},o.prototype.toLocaleString=o.prototype.toString,o.prototype.equals=function(t){if(!o.isBuffer(t))throw new TypeError(\"Argument must be a Buffer\");return this===t||0===o.compare(this,t)},o.prototype.inspect=function(){var t=\"\",e=n.INSPECT_MAX_BYTES;return this.length>0&&(t=this.toString(\"hex\",0,e).match(/.{2}/g).join(\" \"),this.length>e&&(t+=\" ... \")),\"<Buffer \"+t+\">\"},o.prototype.compare=function(t,e,n,r,i){if(!o.isBuffer(t))throw new TypeError(\"Argument must be a Buffer\");if(void 0===e&&(e=0),void 0===n&&(n=t?t.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),e<0||n>t.length||r<0||i>this.length)throw new RangeError(\"out of range index\");if(r>=i&&e>=n)return 0;if(r>=i)return-1;if(e>=n)return 1;if(e>>>=0,n>>>=0,r>>>=0,i>>>=0,this===t)return 0;for(var s=i-r,a=n-e,u=Math.min(s,a),c=this.slice(r,i),l=t.slice(e,n),h=0;h<u;++h)if(c[h]!==l[h]){s=c[h],a=l[h];break}return s<a?-1:a<s?1:0},o.prototype.includes=function(t,e,n){return this.indexOf(t,e,n)!==-1},o.prototype.indexOf=function(t,e,n){return v(this,t,e,n,!0)},o.prototype.lastIndexOf=function(t,e,n){return v(this,t,e,n,!1)},o.prototype.write=function(t,e,n,r){if(void 0===e)r=\"utf8\",n=this.length,e=0;else if(void 0===n&&\"string\"==typeof e)r=e,n=this.length,e=0;else{if(!isFinite(e))throw new Error(\"Buffer.write(string, encoding, offset[, length]) is no longer supported\");e>>>=0,isFinite(n)?(n>>>=0,void 0===r&&(r=\"utf8\")):(r=n,n=void 0)}var i=this.length-e;if((void 0===n||n>i)&&(n=i),t.length>0&&(n<0||e<0)||e>this.length)throw new RangeError(\"Attempt to write outside buffer bounds\");r||(r=\"utf8\");for(var o=!1;;)switch(r){case\"hex\":return w(this,t,e,n);case\"utf8\":case\"utf-8\":return E(this,t,e,n);case\"ascii\":return T(this,t,e,n);case\"latin1\":case\"binary\":return x(this,t,e,n);case\"base64\":return S(this,t,e,n);case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return C(this,t,e,n);default:if(o)throw new TypeError(\"Unknown encoding: \"+r);r=(\"\"+r).toLowerCase(),o=!0}},o.prototype.toJSON=function(){return{type:\"Buffer\",data:Array.prototype.slice.call(this._arr||this,0)}};var J=4096;o.prototype.slice=function(t,e){var n=this.length;t=~~t,e=void 0===e?n:~~e,t<0?(t+=n,t<0&&(t=0)):t>n&&(t=n),e<0?(e+=n,e<0&&(e=0)):e>n&&(e=n),e<t&&(e=t);var r=this.subarray(t,e);return r.__proto__=o.prototype,r},o.prototype.readUIntLE=function(t,e,n){t>>>=0,e>>>=0,n||L(t,e,this.length);for(var r=this[t],i=1,o=0;++o<e&&(i*=256);)r+=this[t+o]*i;return r},o.prototype.readUIntBE=function(t,e,n){t>>>=0,e>>>=0,n||L(t,e,this.length);for(var r=this[t+--e],i=1;e>0&&(i*=256);)r+=this[t+--e]*i;return r},o.prototype.readUInt8=function(t,e){return t>>>=0,e||L(t,1,this.length),this[t]},o.prototype.readUInt16LE=function(t,e){return t>>>=0,e||L(t,2,this.length),this[t]|this[t+1]<<8},o.prototype.readUInt16BE=function(t,e){return t>>>=0,e||L(t,2,this.length),this[t]<<8|this[t+1]},o.prototype.readUInt32LE=function(t,e){return t>>>=0,e||L(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},o.prototype.readUInt32BE=function(t,e){return t>>>=0,e||L(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},o.prototype.readIntLE=function(t,e,n){t>>>=0,e>>>=0,n||L(t,e,this.length);for(var r=this[t],i=1,o=0;++o<e&&(i*=256);)r+=this[t+o]*i;return i*=128,r>=i&&(r-=Math.pow(2,8*e)),r},o.prototype.readIntBE=function(t,e,n){t>>>=0,e>>>=0,n||L(t,e,this.length);for(var r=e,i=1,o=this[t+--r];r>0&&(i*=256);)o+=this[t+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*e)),o},o.prototype.readInt8=function(t,e){return t>>>=0,e||L(t,1,this.length),128&this[t]?(255-this[t]+1)*-1:this[t]},o.prototype.readInt16LE=function(t,e){t>>>=0,e||L(t,2,this.length);var n=this[t]|this[t+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(t,e){t>>>=0,e||L(t,2,this.length);var n=this[t+1]|this[t]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(t,e){return t>>>=0,e||L(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},o.prototype.readInt32BE=function(t,e){return t>>>=0,e||L(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},o.prototype.readFloatLE=function(t,e){return t>>>=0,e||L(t,4,this.length),Y.read(this,t,!0,23,4)},o.prototype.readFloatBE=function(t,e){return t>>>=0,e||L(t,4,this.length),Y.read(this,t,!1,23,4)},o.prototype.readDoubleLE=function(t,e){return t>>>=0,e||L(t,8,this.length),Y.read(this,t,!0,52,8)},o.prototype.readDoubleBE=function(t,e){return t>>>=0,e||L(t,8,this.length),Y.read(this,t,!1,52,8)},o.prototype.writeUIntLE=function(t,e,n,r){if(t=+t,e>>>=0,n>>>=0,!r){var i=Math.pow(2,8*n)-1;R(this,t,e,n,i,0)}var o=1,s=0;for(this[e]=255&t;++s<n&&(o*=256);)this[e+s]=t/o&255;return e+n},o.prototype.writeUIntBE=function(t,e,n,r){if(t=+t,e>>>=0,n>>>=0,!r){var i=Math.pow(2,8*n)-1;R(this,t,e,n,i,0)}var o=n-1,s=1;for(this[e+o]=255&t;--o>=0&&(s*=256);)this[e+o]=t/s&255;return e+n},o.prototype.writeUInt8=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,1,255,0),this[e]=255&t,e+1},o.prototype.writeUInt16LE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,2,65535,0),this[e]=255&t,this[e+1]=t>>>8,e+2},o.prototype.writeUInt16BE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,2,65535,0),this[e]=t>>>8,this[e+1]=255&t,e+2},o.prototype.writeUInt32LE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,4,4294967295,0),this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t,e+4},o.prototype.writeUInt32BE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,4,4294967295,0),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},o.prototype.writeIntLE=function(t,e,n,r){if(t=+t,e>>>=0,!r){var i=Math.pow(2,8*n-1);R(this,t,e,n,i-1,-i)}var o=0,s=1,a=0;for(this[e]=255&t;++o<n&&(s*=256);)t<0&&0===a&&0!==this[e+o-1]&&(a=1),this[e+o]=(t/s>>0)-a&255;return e+n},o.prototype.writeIntBE=function(t,e,n,r){if(t=+t,e>>>=0,!r){var i=Math.pow(2,8*n-1);R(this,t,e,n,i-1,-i)}var o=n-1,s=1,a=0;for(this[e+o]=255&t;--o>=0&&(s*=256);)t<0&&0===a&&0!==this[e+o+1]&&(a=1),this[e+o]=(t/s>>0)-a&255;return e+n},o.prototype.writeInt8=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,1,127,-128),t<0&&(t=255+t+1),this[e]=255&t,e+1},o.prototype.writeInt16LE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,2,32767,-32768),this[e]=255&t,this[e+1]=t>>>8,e+2},o.prototype.writeInt16BE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,2,32767,-32768),this[e]=t>>>8,this[e+1]=255&t,e+2},o.prototype.writeInt32LE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,4,2147483647,-2147483648),this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24,e+4},o.prototype.writeInt32BE=function(t,e,n){return t=+t,e>>>=0,n||R(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},o.prototype.writeFloatLE=function(t,e,n){return U(this,t,e,!0,n)},o.prototype.writeFloatBE=function(t,e,n){return U(this,t,e,!1,n)},o.prototype.writeDoubleLE=function(t,e,n){return q(this,t,e,!0,n)},o.prototype.writeDoubleBE=function(t,e,n){return q(this,t,e,!1,n)},o.prototype.copy=function(t,e,n,r){if(!o.isBuffer(t))throw new TypeError(\"argument should be a Buffer\");if(n||(n=0),r||0===r||(r=this.length),e>=t.length&&(e=t.length),e||(e=0),r>0&&r<n&&(r=n),r===n)return 0;if(0===t.length||0===this.length)return 0;if(e<0)throw new RangeError(\"targetStart out of bounds\");if(n<0||n>=this.length)throw new RangeError(\"Index out of range\");if(r<0)throw new RangeError(\"sourceEnd out of bounds\");r>this.length&&(r=this.length),t.length-e<r-n&&(r=t.length-e+n);var i=r-n;if(this===t&&\"function\"==typeof Uint8Array.prototype.copyWithin)this.copyWithin(e,n,r);else if(this===t&&n<e&&e<r)for(var s=i-1;s>=0;--s)t[s+e]=this[s+n];else Uint8Array.prototype.set.call(t,this.subarray(n,r),e);return i},o.prototype.fill=function(t,e,n,r){if(\"string\"==typeof t){if(\"string\"==typeof e?(r=e,e=0,n=this.length):\"string\"==typeof n&&(r=n,n=this.length),void 0!==r&&\"string\"!=typeof r)throw new TypeError(\"encoding must be a string\");if(\"string\"==typeof r&&!o.isEncoding(r))throw new TypeError(\"Unknown encoding: \"+r);if(1===t.length){var i=t.charCodeAt(0);(\"utf8\"===r&&i<128||\"latin1\"===r)&&(t=i)}}else\"number\"==typeof t&&(t=255&t);if(e<0||this.length<e||this.length<n)throw new RangeError(\"Out of range index\");if(n<=e)return this;e>>>=0,n=void 0===n?this.length:n>>>0,t||(t=0);var s;if(\"number\"==typeof t)for(s=e;s<n;++s)this[s]=t;else{var a=o.isBuffer(t)?t:new o(t,r),u=a.length;if(0===u)throw new TypeError('The value \"'+t+'\" is invalid for argument \"value\"');for(s=0;s<n-e;++s)this[s+e]=a[s%u]}return this};var K=/[^+\\/0-9A-Za-z-_]/g},{\"base64-js\":39,ieee754:83}],42:[function(t,e,n){(function(t){function e(t){return Array.isArray?Array.isArray(t):\"[object Array]\"===m(t)}function r(t){return\"boolean\"==typeof t}function i(t){return null===t}function o(t){return null==t}function s(t){return\"number\"==typeof t}function a(t){return\"string\"==typeof t}function u(t){return\"symbol\"==typeof t}function c(t){return void 0===t}function l(t){return\"[object RegExp]\"===m(t)}function h(t){return\"object\"==typeof t&&null!==t}function p(t){return\"[object Date]\"===m(t)}function f(t){return\"[object Error]\"===m(t)||t instanceof Error}function d(t){return\"function\"==typeof t}function y(t){return null===t||\"boolean\"==typeof t||\"number\"==typeof t||\"string\"==typeof t||\"symbol\"==typeof t||\"undefined\"==typeof t}function m(t){return Object.prototype.toString.call(t)}n.isArray=e,n.isBoolean=r,n.isNull=i,n.isNullOrUndefined=o,n.isNumber=s,n.isString=a,n.isSymbol=u,n.isUndefined=c,n.isRegExp=l,n.isObject=h,n.isDate=p,n.isError=f,n.isFunction=d,n.isPrimitive=y,n.isBuffer=t.isBuffer}).call(this,{isBuffer:t(\"../../is-buffer/index.js\")})},{\"../../is-buffer/index.js\":85}],43:[function(t,e,n){(function(n,r){var i,o,s,a,u;a=t(\"stream\"),u=t(\"util\"),o=t(\"string_decoder\").StringDecoder,e.exports=function(){var t,e,o,a,u,c,l;if(3===arguments.length){if(a=arguments[0],c=arguments[1],t=arguments[2],\"function\"!=typeof t)throw Error(\"Invalid callback argument: \"+JSON.stringify(t));if(\"string\"!=typeof a&&!r.isBuffer(arguments[0]))return t(Error(\"Invalid data argument: \"+JSON.stringify(a)))}else if(2===arguments.length){if(\"string\"==typeof arguments[0]||r.isBuffer(arguments[0])?a=arguments[0]:s(arguments[0])?c=arguments[0]:u=\"Invalid first argument: \"+JSON.stringify(arguments[0]),\"function\"==typeof arguments[1]?t=arguments[1]:s(arguments[1])?c?u=\"Invalid arguments: got options twice as first and second arguments\":c=arguments[1]:u=\"Invalid first argument: \"+JSON.stringify(arguments[1]),u){if(t)return t(Error(u));throw Error(u)}}else 1===arguments.length&&(\"function\"==typeof arguments[0]?t=arguments[0]:c=arguments[0]);return null==c&&(c={}),l=new i(c),null!=a&&n.nextTick(function(){return l.write(a),l.end()}),t&&(e=!1,o=c.objname?{}:[],l.on(\"readable\",function(){var t,e;for(e=[];t=l.read();)c.objname?e.push(o[t[0]]=t[1]):e.push(o.push(t));return e}),l.on(\"error\",function(n){return e=!0,t(n)}),l.on(\"end\",function(){if(!e)return t(null,o)})),l},i=function(t){var e,n,r,i,s,u,c,l,h,p,f,d,y,m,_,g,v,b,w;null==t&&(t={}),this.options={};for(b in t)w=t[b],this.options[b]=w;return this.options.objectMode=!0,a.Transform.call(this,this.options),null==(e=this.options).rowDelimiter&&(e.rowDelimiter=null),\"string\"==typeof this.options.rowDelimiter&&(this.options.rowDelimiter=[this.options.rowDelimiter]),null==(n=this.options).delimiter&&(n.delimiter=\",\"),void 0===this.options.quote||this.options.quote||(this.options.quote=\"\"),null==(p=this.options).quote&&(p.quote='\"'),null==(f=this.options).escape&&(f.escape='\"'),null==(d=this.options).columns&&(d.columns=null),null==(y=this.options).comment&&(y.comment=\"\"),null==(m=this.options).objname&&(m.objname=!1),null==(_=this.options).trim&&(_.trim=!1),null==(g=this.options).ltrim&&(g.ltrim=!1),null==(v=this.options).rtrim&&(v.rtrim=!1),null==(r=this.options).auto_parse&&(r.auto_parse=!1),null==(i=this.options).auto_parse_date&&(i.auto_parse_date=!1),this.options.auto_parse_date===!0&&(this.options.auto_parse_date=function(t){\nvar e;return e=Date.parse(t),isNaN(e)||(t=new Date(e)),t}),null==(s=this.options).relax&&(s.relax=!1),null==(u=this.options).relax_column_count&&(u.relax_column_count=!1),null==(c=this.options).skip_empty_lines&&(c.skip_empty_lines=!1),null==(l=this.options).max_limit_on_data_read&&(l.max_limit_on_data_read=128e3),null==(h=this.options).skip_lines_with_empty_values&&(h.skip_lines_with_empty_values=!1),this.lines=0,this.count=0,this.skipped_line_count=0,this.empty_line_count=0,this.is_int=/^(\\-|\\+)?([1-9]+[0-9]*)$/,this.is_float=function(t){return t-parseFloat(t)+1>=0},this._={decoder:new o,quoting:!1,commenting:!1,field:null,nextChar:null,closingQuote:0,line:[],chunks:[],rawBuf:\"\",buf:\"\",rowDelimiterLength:this.options.rowDelimiter?Math.max.apply(Math,this.options.rowDelimiter.map(function(t){return t.length})):void 0},this},u.inherits(i,a.Transform),e.exports.Parser=i,i.prototype._transform=function(t,e,n){var i;return t instanceof r&&(t=this._.decoder.write(t)),i=this.__write(t,!1),i?this.emit(\"error\",i):n()},i.prototype._flush=function(t){var e;return e=this.__write(this._.decoder.end(),!0),e?this.emit(\"error\",e):this._.quoting?void this.emit(\"error\",new Error(\"Quoted field not terminated at line \"+(this.lines+1))):this._.line.length>0&&(e=this.__push(this._.line))?t(e):t()},i.prototype.__push=function(t){var e,n,r,i,o,s,a,u,c,l,h;if(!this.options.skip_lines_with_empty_values||\"\"!==t.join(\"\").trim()){if(h=null,this.options.columns===!0)return this.options.columns=t,void(c=\"\");if(\"function\"==typeof this.options.columns)return e=function(t,e){var n,r;try{return n=t.call(null,e),[null,n]}catch(i){return r=i,[r]}},l=e(this.options.columns,t),r=l[0],n=l[1],r?r:(this.options.columns=n,void(c=\"\"));if(!this._.line_length&&t.length>0&&(this._.line_length=this.options.columns?this.options.columns.length:t.length),1===t.length&&\"\"===t[0])this.empty_line_count++;else if(t.length!==this._.line_length){if(!this.options.relax_column_count)return null!=this.options.columns?Error(\"Number of columns on line \"+this.lines+\" does not match header\"):Error(\"Number of columns is inconsistent on line \"+this.lines);this.count++,this.skipped_line_count++}else this.count++;if(null!=this.options.columns){for(u={},o=s=0,a=t.length;s<a;o=++s)i=t[o],this.options.columns[o]!==!1&&(u[this.options.columns[o]]=i);h=this.options.objname?[u[this.options.objname],u]:u}else h=t;if(!(this.count<this.options.from||this.count>this.options.to))return this.options.raw?(this.push({raw:this._.rawBuf,row:h}),this._.rawBuf=\"\"):this.push(h),null}},i.prototype.__write=function(t,e){var n,r,i,o,s,a,u,c,l,h,p,f,d,y,m,_,g,v,b,w,E,T,x,S,C,I,N,O;for(m=function(t){return function(e){return\"function\"==typeof t.is_int?t.is_int(e):t.is_int.test(e)}}(this),y=function(t){return function(e){return\"function\"==typeof t.is_float?t.is_float(e):t.is_float.test(e)}}(this),i=function(t){return function(e){return t.options.auto_parse?\"function\"==typeof t.options.auto_parse?t.options.auto_parse(e):(m(e)?e=parseInt(e):y(e)?e=parseFloat(e):t.options.auto_parse_date&&(e=t.options.auto_parse_date(e)),e):e}}(this),g=this.options.trim||this.options.ltrim,N=this.options.trim||this.options.rtrim,t=this._.buf+t,_=t.length,u=0,0===this.lines&&65279===t.charCodeAt(0)&&u++;u<_&&(e||(C=t.substr(u,_-u),!(!this.options.rowDelimiter&&u+3>_||!this._.commenting&&_-u<this.options.comment.length&&this.options.comment.substr(0,_-u)===C||this.options.rowDelimiter&&_-u<this._.rowDelimiterLength&&this.options.rowDelimiter.some(function(t){return t.substr(0,_-u)===C})||this.options.rowDelimiter&&this._.quoting&&_-u<this.options.quote.length+this._.rowDelimiterLength&&this.options.rowDelimiter.some(function(t){return function(e){return(t.options.quote+e).substr(0,_-u)===C}}(this))||_-u<=this.options.delimiter.length&&this.options.delimiter.substr(0,_-u)===C||_-u<=this.options.escape.length&&this.options.escape.substr(0,_-u)===C)));)if(o=this._.nextChar?this._.nextChar:t.charAt(u),this._.nextChar=_>u+1?t.charAt(u+1):\"\",this.options.raw&&(this._.rawBuf+=o),null==this.options.rowDelimiter&&(v=u,I=null,this._.quoting||\"\\n\"!==o&&\"\\r\"!==o?!this._.quoting||o!==this.options.quote||\"\\n\"!==(b=this._.nextChar)&&\"\\r\"!==b||(I=this._.nextChar,v+=2,this.raw&&(rawBuf+=this._.nextChar)):(I=o,v+=1),I&&(\"\\r\"===I&&\"\\n\"===t.charAt(v)&&(I+=\"\\n\"),this.options.rowDelimiter=[I],this._.rowDelimiterLength=I.length)),this._.commenting||o!==this.options.escape||(a=this.options.escape===this.options.quote,l=this._.nextChar===this.options.escape,p=this._.nextChar===this.options.quote,a&&null==this._.field&&!this._.quoting||!l&&!p)){if(!this._.commenting&&o===this.options.quote)if(this._.quoting){if(r=this.options.rowDelimiter&&this.options.rowDelimiter.some(function(e){return t.substr(u+1,e.length)===e}),n=t.substr(u+1,this.options.delimiter.length)===this.options.delimiter,h=this._.nextChar===this.options.comment,!this._.nextChar||r||n||h){this._.quoting=!1,this._.closingQuote=this.options.quote.length,u++,e&&u===_&&(this._.line.push(i(this._.field||\"\")),this._.field=null);continue}if(!this.options.relax)return Error(\"Invalid closing quote at line \"+(this.lines+1)+\"; found \"+JSON.stringify(this._.nextChar)+\" instead of delimiter \"+JSON.stringify(this.options.delimiter));this._.quoting=!1,this._.field&&(this._.field=\"\"+this.options.quote+this._.field)}else{if(!this._.field){this._.quoting=!0,u++;continue}if(null!=this._.field&&!this.options.relax)return Error(\"Invalid opening quote at line \"+(this.lines+1))}if(f=this.options.rowDelimiter&&this.options.rowDelimiter.some(function(e){return t.substr(u,e.length)===e}),(f||e&&u===_-1)&&this.lines++,O=!1,this._.commenting||this._.quoting||!this.options.comment||t.substr(u,this.options.comment.length)!==this.options.comment?this._.commenting&&f&&(O=!0,this._.commenting=!1):this._.commenting=!0,c=t.substr(u,this.options.delimiter.length)===this.options.delimiter,this._.commenting||this._.quoting||!c&&!f)this._.commenting||this._.quoting||\" \"!==o&&\"\\t\"!==o?this._.commenting?u++:(null==this._.field&&(this._.field=\"\"),this._.field+=o,u++):(null==this._.field&&(this._.field=\"\"),g&&!this._.field||(this._.field+=o),u++);else{if(f&&(d=this.options.rowDelimiter.filter(function(e){return t.substr(u,e.length)===e})[0].length),f&&0===this._.line.length&&null==this._.field&&(O||this.options.skip_empty_lines)){u+=d,this._.nextChar=t.charAt(u);continue}if(N&&(this._.closingQuote||(this._.field=null!=(w=this._.field)?w.trimRight():void 0)),this._.line.push(i(this._.field||\"\")),this._.closingQuote=0,this._.field=null,c&&(u+=this.options.delimiter.length,this._.nextChar=t.charAt(u),e&&!this._.nextChar&&(f=!0,this._.line.push(\"\"))),f){if(s=this.__push(this._.line))return s;this._.line=[],u+=d,this._.nextChar=t.charAt(u);continue}}if(!this._.commenting&&(null!=(E=this._.field)?E.length:void 0)>this.options.max_limit_on_data_read)return Error(\"Field exceeds max_limit_on_data_read setting (\"+this.options.max_limit_on_data_read+\") \"+JSON.stringify(this.options.delimiter));if(!this._.commenting&&(null!=(T=this._.line)?T.length:void 0)>this.options.max_limit_on_data_read)return Error(\"Row delimiter not found in the file \"+JSON.stringify(this.options.rowDelimiter))}else u++,o=this._.nextChar,this._.nextChar=t.charAt(u+1),null==this._.field&&(this._.field=\"\"),this._.field+=o,this.options.raw&&(this._.rawBuf+=o),u++;if(e){if(null!=this._.field&&(N&&(this._.closingQuote||(this._.field=null!=(x=this._.field)?x.trimRight():void 0)),this._.line.push(i(this._.field||\"\")),this._.field=null),(null!=(S=this._.field)?S.length:void 0)>this.options.max_limit_on_data_read)return Error(\"Delimiter not found in the file \"+JSON.stringify(this.options.delimiter));if(0===_&&this.lines++,this._.line.length>this.options.max_limit_on_data_read)return Error(\"Row delimiter not found in the file \"+JSON.stringify(this.options.rowDelimiter))}return this._.buf=t.substr(u),null},s=function(t){var e;return e=t,\"object\"==typeof t&&null!==t&&!Array.isArray(t)&&function(){for(;;)if(null===Object.getPrototypeOf(e=Object.getPrototypeOf(e)))break;return Object.getPrototypeOf(t===e)}()}}).call(this,t(\"_process\"),t(\"buffer\").Buffer)},{_process:91,buffer:41,stream:112,string_decoder:113,util:117}],44:[function(t,e,n){(function(n){var r,i;r=t(\"string_decoder\").StringDecoder,i=t(\"./index\"),e.exports=function(t,e){var o,s,a,u;if(null==e&&(e={}),u=e.objname?{}:[],t instanceof n&&(o=new r,t=o.write(t)),a=new i.Parser(e),a.push=function(t){return e.objname?u[t[0]]=t[1]:u.push(t)},s=a.__write(t,!1))throw s;if(t instanceof n&&(s=a.__write(t.end(),!0)))throw s;return a._flush(function(){}),u}}).call(this,t(\"buffer\").Buffer)},{\"./index\":43,buffer:41,string_decoder:113}],45:[function(t,e,n){(function(n){var r,i,o,s;o=t(\"stream\"),s=t(\"util\"),i=t(\"lodash.get\"),e.exports=function(){var t,e,i,o,s;return 3===arguments.length?(i=arguments[0],o=arguments[1],t=arguments[2]):2===arguments.length?(Array.isArray(arguments[0])?i=arguments[0]:o=arguments[0],\"function\"==typeof arguments[1]?t=arguments[1]:o=arguments[1]):1===arguments.length&&(\"function\"==typeof arguments[0]?t=arguments[0]:Array.isArray(arguments[0])?i=arguments[0]:o=arguments[0]),null==o&&(o={}),s=new r(o),i&&n.nextTick(function(){var t,e,n;for(e=0,n=i.length;e<n;e++)t=i[e],s.write(t);return s.end()}),t&&(e=[],s.on(\"readable\",function(){var t,n;for(n=[];t=s.read();)n.push(e.push(t));return n}),s.on(\"error\",function(e){return t(e)}),s.on(\"end\",function(){return t(null,e.join(\"\"))})),s},r=function(t){var e,n,r,i,s,a,u,c,l,h,p,f,d,y,m,_,g;null==t&&(t={}),_={};for(m in t)g=t[m],_[m]=g;switch(o.Transform.call(this,_),this.options=_,null==(e=this.options).delimiter&&(e.delimiter=\",\"),null==(n=this.options).quote&&(n.quote='\"'),null==(u=this.options).quoted&&(u.quoted=!1),null==(c=this.options).quotedEmpty&&(c.quotedEmpty=void 0),null==(l=this.options).quotedString&&(l.quotedString=!1),null==(h=this.options).eof&&(h.eof=!0),null==(p=this.options).escape&&(p.escape='\"'),null==(f=this.options).columns&&(f.columns=null),null==(d=this.options).header&&(d.header=!1),null==(y=this.options).formatters&&(y.formatters={}),null==(r=this.options.formatters).date&&(r.date=function(t){return\"\"+t.getTime()}),null==(i=this.options.formatters).bool&&(i.bool=function(t){return t?\"1\":\"\"}),null==(s=this.options.formatters).object&&(s.object=function(t){return JSON.stringify(t)}),null==(a=this.options).rowDelimiter&&(a.rowDelimiter=\"\\n\"),null==this.countWriten&&(this.countWriten=0),this.options.rowDelimiter){case\"auto\":this.options.rowDelimiter=null;break;case\"unix\":this.options.rowDelimiter=\"\\n\";break;case\"mac\":this.options.rowDelimiter=\"\\r\";break;case\"windows\":this.options.rowDelimiter=\"\\r\\n\";break;case\"unicode\":this.options.rowDelimiter=\"\\u2028\"}return this},s.inherits(r,o.Transform),e.exports.Stringifier=r,r.prototype.headers=function(){var t,e,n;if(this.options.header&&this.options.columns)return n=this.options.columns,\"object\"==typeof n&&(n=function(){var r;r=[];for(t in n)e=n[t],r.push(e);return r}()),n=this.options.eof?this.stringify(n)+this.options.rowDelimiter:this.stringify(n),o.Transform.prototype.write.call(this,n)},r.prototype.end=function(t,e,n){return 0===this.countWriten&&this.headers(),o.Transform.prototype.end.apply(this,arguments)},r.prototype.write=function(t,e,n){var r,i,s;if(null!=t){if(s=\"object\"!=typeof t,!s){0!==this.countWriten||Array.isArray(t)||null==(r=this.options).columns&&(r.columns=Object.keys(t));try{this.emit(\"record\",t,this.countWriten)}catch(a){return i=a,this.emit(\"error\",i)}this.options.eof?t=this.stringify(t)+this.options.rowDelimiter:(t=this.stringify(t),(this.options.header||this.countWriten)&&(t=this.options.rowDelimiter+t))}return\"number\"==typeof t&&(t=\"\"+t),0===this.countWriten&&this.headers(),s||this.countWriten++,o.Transform.prototype.write.call(this,t,e,n)}},r.prototype._transform=function(t,e,n){return this.push(t),n()},r.prototype.stringify=function(t){var e,n,r,o,s,a,u,c,l,h,p,f,d,y,m,_,g,v,b,w;if(\"object\"!=typeof t)return t;if(r=this.options.columns,\"object\"!=typeof r||null===r||Array.isArray(r)||(r=Object.keys(r)),c=this.options.delimiter,m=this.options.quote,l=this.options.escape,Array.isArray(t))r&&t.splice(r.length);else{if(e=[],r)for(p=f=0,_=r.length;0<=_?f<_:f>_;p=0<=_?++f:--f)n=r[p],w=i(t,n),e[p]=\"undefined\"==typeof w||null===w?\"\":w;else for(n in t)e.push(t[n]);t=e,e=null}if(Array.isArray(t)){for(y=\"\",p=d=0,g=t.length;0<=g?d<g:d>g;p=0<=g?++d:--d)h=t[p],\"string\"==typeof h||(\"number\"==typeof h?h=\"\"+h:\"boolean\"==typeof h?h=this.options.formatters.bool(h):h instanceof Date?h=this.options.formatters.date(h):\"object\"==typeof h&&null!==h&&(h=this.options.formatters.object(h))),h?(u=h.indexOf(c)>=0,a=h.indexOf(m)>=0,o=h.indexOf(l)>=0&&l!==m,s=h.indexOf(\"\\r\")>=0||h.indexOf(\"\\n\")>=0,b=a||u||s||this.options.quoted||this.options.quotedString&&\"string\"==typeof t[p],b&&o&&(v=\"\\\\\"===l?new RegExp(l+l,\"g\"):new RegExp(l,\"g\"),h=h.replace(v,l+l)),a&&(v=new RegExp(m,\"g\"),h=h.replace(v,l+m)),b&&(h=m+h+m),y+=h):(this.options.quotedEmpty||null==this.options.quotedEmpty&&\"\"===t[p]&&this.options.quotedString)&&(y+=m+m),p!==t.length-1&&(y+=c);t=y}return t}}).call(this,t(\"_process\"))},{_process:91,\"lodash.get\":87,stream:112,util:117}],46:[function(t,e,n){(function(n){var r,i;r=t(\"string_decoder\").StringDecoder,i=t(\"./index\"),e.exports=function(t,e){var o,s,a,u,c,l;for(null==e&&(e={}),o=[],t instanceof n&&(s=new r,t=s.write(t)),l=new i.Stringifier(e),l.push=function(t){if(t)return o.push(t.toString())},a=0,u=t.length;a<u;a++)c=t[a],l.write(c);return l.end(),o.join(\"\")}}).call(this,t(\"buffer\").Buffer)},{\"./index\":45,buffer:41,string_decoder:113}],47:[function(t,e,n){function r(){this._events&&Object.prototype.hasOwnProperty.call(this,\"_events\")||(this._events=w(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0}function i(t){return void 0===t._maxListeners?r.defaultMaxListeners:t._maxListeners}function o(t,e,n){if(e)t.call(n);else for(var r=t.length,i=m(t,r),o=0;o<r;++o)i[o].call(n)}function s(t,e,n,r){if(e)t.call(n,r);else for(var i=t.length,o=m(t,i),s=0;s<i;++s)o[s].call(n,r)}function a(t,e,n,r,i){if(e)t.call(n,r,i);else for(var o=t.length,s=m(t,o),a=0;a<o;++a)s[a].call(n,r,i)}function u(t,e,n,r,i,o){if(e)t.call(n,r,i,o);else for(var s=t.length,a=m(t,s),u=0;u<s;++u)a[u].call(n,r,i,o)}function c(t,e,n,r){if(e)t.apply(n,r);else for(var i=t.length,o=m(t,i),s=0;s<i;++s)o[s].apply(n,r)}function l(t,e,n,r){var o,s,a;if(\"function\"!=typeof n)throw new TypeError('\"listener\" argument must be a function');if(s=t._events,s?(s.newListener&&(t.emit(\"newListener\",e,n.listener?n.listener:n),s=t._events),a=s[e]):(s=t._events=w(null),t._eventsCount=0),a){if(\"function\"==typeof a?a=s[e]=r?[n,a]:[a,n]:r?a.unshift(n):a.push(n),!a.warned&&(o=i(t),o&&o>0&&a.length>o)){a.warned=!0;var u=new Error(\"Possible EventEmitter memory leak detected. \"+a.length+' \"'+String(e)+'\" listeners added. Use emitter.setMaxListeners() to increase limit.');u.name=\"MaxListenersExceededWarning\",u.emitter=t,u.type=e,u.count=a.length,\"object\"==typeof console&&console.warn&&console.warn(\"%s: %s\",u.name,u.message)}}else a=s[e]=n,++t._eventsCount;return t}function h(){if(!this.fired)switch(this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length){case 0:return this.listener.call(this.target);case 1:return this.listener.call(this.target,arguments[0]);case 2:return this.listener.call(this.target,arguments[0],arguments[1]);case 3:return this.listener.call(this.target,arguments[0],arguments[1],arguments[2]);default:for(var t=new Array(arguments.length),e=0;e<t.length;++e)t[e]=arguments[e];this.listener.apply(this.target,t)}}function p(t,e,n){var r={fired:!1,wrapFn:void 0,target:t,type:e,listener:n},i=T.call(h,r);return i.listener=n,r.wrapFn=i,i}function f(t,e,n){var r=t._events;if(!r)return[];var i=r[e];return i?\"function\"==typeof i?n?[i.listener||i]:[i]:n?_(i):m(i,i.length):[]}function d(t){var e=this._events;if(e){var n=e[t];if(\"function\"==typeof n)return 1;if(n)return n.length}return 0}function y(t,e){for(var n=e,r=n+1,i=t.length;r<i;n+=1,r+=1)t[n]=t[r];t.pop()}function m(t,e){for(var n=new Array(e),r=0;r<e;++r)n[r]=t[r];return n}function _(t){for(var e=new Array(t.length),n=0;n<e.length;++n)e[n]=t[n].listener||t[n];return e}function g(t){var e=function(){};return e.prototype=t,new e}function v(t){var e=[];for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e.push(n);return n}function b(t){var e=this;return function(){return e.apply(t,arguments)}}var w=Object.create||g,E=Object.keys||v,T=Function.prototype.bind||b;e.exports=r,r.EventEmitter=r,r.prototype._events=void 0,r.prototype._maxListeners=void 0;var x,S=10;try{var C={};Object.defineProperty&&Object.defineProperty(C,\"x\",{value:0}),x=0===C.x}catch(I){x=!1}x?Object.defineProperty(r,\"defaultMaxListeners\",{enumerable:!0,get:function(){return S},set:function(t){if(\"number\"!=typeof t||t<0||t!==t)throw new TypeError('\"defaultMaxListeners\" must be a positive number');S=t}}):r.defaultMaxListeners=S,r.prototype.setMaxListeners=function(t){if(\"number\"!=typeof t||t<0||isNaN(t))throw new TypeError('\"n\" argument must be a positive number');return this._maxListeners=t,this},r.prototype.getMaxListeners=function(){return i(this)},r.prototype.emit=function(t){var e,n,r,i,l,h,p=\"error\"===t;if(h=this._events)p=p&&null==h.error;else if(!p)return!1;if(p){if(arguments.length>1&&(e=arguments[1]),e instanceof Error)throw e;var f=new Error('Unhandled \"error\" event. ('+e+\")\");throw f.context=e,f}if(n=h[t],!n)return!1;var d=\"function\"==typeof n;switch(r=arguments.length){case 1:o(n,d,this);break;case 2:s(n,d,this,arguments[1]);break;case 3:a(n,d,this,arguments[1],arguments[2]);break;case 4:u(n,d,this,arguments[1],arguments[2],arguments[3]);break;default:for(i=new Array(r-1),l=1;l<r;l++)i[l-1]=arguments[l];c(n,d,this,i)}return!0},r.prototype.addListener=function(t,e){return l(this,t,e,!1)},r.prototype.on=r.prototype.addListener,r.prototype.prependListener=function(t,e){return l(this,t,e,!0)},r.prototype.once=function(t,e){if(\"function\"!=typeof e)throw new TypeError('\"listener\" argument must be a function');return this.on(t,p(this,t,e)),this},r.prototype.prependOnceListener=function(t,e){if(\"function\"!=typeof e)throw new TypeError('\"listener\" argument must be a function');return this.prependListener(t,p(this,t,e)),this},r.prototype.removeListener=function(t,e){var n,r,i,o,s;if(\"function\"!=typeof e)throw new TypeError('\"listener\" argument must be a function');if(r=this._events,!r)return this;if(n=r[t],!n)return this;if(n===e||n.listener===e)0===--this._eventsCount?this._events=w(null):(delete r[t],r.removeListener&&this.emit(\"removeListener\",t,n.listener||e));else if(\"function\"!=typeof n){for(i=-1,o=n.length-1;o>=0;o--)if(n[o]===e||n[o].listener===e){s=n[o].listener,i=o;break}if(i<0)return this;0===i?n.shift():y(n,i),1===n.length&&(r[t]=n[0]),r.removeListener&&this.emit(\"removeListener\",t,s||e)}return this},r.prototype.removeAllListeners=function(t){var e,n,r;if(n=this._events,!n)return this;if(!n.removeListener)return 0===arguments.length?(this._events=w(null),this._eventsCount=0):n[t]&&(0===--this._eventsCount?this._events=w(null):delete n[t]),this;if(0===arguments.length){var i,o=E(n);for(r=0;r<o.length;++r)i=o[r],\"removeListener\"!==i&&this.removeAllListeners(i);return this.removeAllListeners(\"removeListener\"),this._events=w(null),this._eventsCount=0,this}if(e=n[t],\"function\"==typeof e)this.removeListener(t,e);else if(e)for(r=e.length-1;r>=0;r--)this.removeListener(t,e[r]);return this},r.prototype.listeners=function(t){return f(this,t,!0)},r.prototype.rawListeners=function(t){return f(this,t,!1)},r.listenerCount=function(t,e){return\"function\"==typeof t.listenerCount?t.listenerCount(e):d.call(t,e)},r.prototype.listenerCount=d,r.prototype.eventNames=function(){return this._eventsCount>0?Reflect.ownKeys(this._events):[]}},{}],48:[function(t,e,n){\"use strict\";var r=t(\"./util/constants\"),i=t(\"./mixins/logging\"),o={VERSION:r.VERSION,Client:t(\"./protocol/client\"),Scheduler:t(\"./protocol/scheduler\")};i.wrapper=o,e.exports=o},{\"./mixins/logging\":50,\"./protocol/client\":54,\"./protocol/scheduler\":60,\"./util/constants\":72}],49:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/promise\");e.exports={then:function(t,e){var n=this;return this._promise||(this._promise=new r(function(t,e){n._resolve=t,n._reject=e})),0===arguments.length?this._promise:this._promise.then(t,e)},callback:function(t,e){return this.then(function(n){t.call(e,n)})},errback:function(t,e){return this.then(null,function(n){t.call(e,n)})},timeout:function(t,e){this.then();var r=this;this._timer=n.setTimeout(function(){r._reject(e)},1e3*t)},setDeferredStatus:function(t,e){this._timer&&n.clearTimeout(this._timer),this.then(),\"succeeded\"===t?this._resolve(e):\"failed\"===t?this._reject(e):delete this._promise}}}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../util/promise\":77}],50:[function(t,e,n){\"use strict\";var r=t(\"../util/to_json\"),i={LOG_LEVELS:{fatal:4,error:3,warn:2,info:1,debug:0},writeLog:function(t,e){var n=i.logger||(i.wrapper||i).logger;if(n){var o=Array.prototype.slice.apply(t),s=\"[Faye\",a=this.className,u=o.shift().replace(/\\?/g,function(){try{return r(o.shift())}catch(t){return\"[Object]\"}});a&&(s+=\".\"+a),s+=\"] \",\"function\"==typeof n[e]?n[e](s+u):\"function\"==typeof n&&n(s+u)}}};for(var o in i.LOG_LEVELS)(function(t){i[t]=function(){this.writeLog(arguments,t)}})(o);e.exports=i},{\"../util/to_json\":79}],51:[function(t,e,n){\"use strict\";var r=t(\"../util/extend\"),i=t(\"../util/event_emitter\"),o={countListeners:function(t){return this.listeners(t).length},bind:function(t,e,n){var r=Array.prototype.slice,i=function(){e.apply(n,r.call(arguments))};return this._listeners=this._listeners||[],this._listeners.push([t,e,n,i]),this.on(t,i)},unbind:function(t,e,n){this._listeners=this._listeners||[];for(var r,i=this._listeners.length;i--;)r=this._listeners[i],r[0]===t&&(!e||r[1]===e&&r[2]===n)&&(this._listeners.splice(i,1),this.removeListener(t,r[3]))}};r(o,i.prototype),o.trigger=o.emit,e.exports=o},{\"../util/event_emitter\":75,\"../util/extend\":76}],52:[function(t,e,n){(function(t){\"use strict\";e.exports={addTimeout:function(e,n,r,i){if(this._timeouts=this._timeouts||{},!this._timeouts.hasOwnProperty(e)){var o=this;this._timeouts[e]=t.setTimeout(function(){delete o._timeouts[e],r.call(i)},1e3*n)}},removeTimeout:function(e){this._timeouts=this._timeouts||{};var n=this._timeouts[e];n&&(t.clearTimeout(n),delete this._timeouts[e])},removeAllTimeouts:function(){this._timeouts=this._timeouts||{};for(var t in this._timeouts)this.removeTimeout(t)}}}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],53:[function(t,e,n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/extend\"),o=t(\"../mixins/publisher\"),s=t(\"./grammar\"),a=r({initialize:function(t){this.id=this.name=t},push:function(t){this.trigger(\"message\",t)},isUnused:function(){return 0===this.countListeners(\"message\")}});i(a.prototype,o),i(a,{HANDSHAKE:\"/meta/handshake\",CONNECT:\"/meta/connect\",SUBSCRIBE:\"/meta/subscribe\",UNSUBSCRIBE:\"/meta/unsubscribe\",DISCONNECT:\"/meta/disconnect\",META:\"meta\",SERVICE:\"service\",expand:function(t){var e=this.parse(t),n=[\"/**\",t],r=e.slice();r[r.length-1]=\"*\",n.push(this.unparse(r));for(var i=1,o=e.length;i<o;i++)r=e.slice(0,i),r.push(\"**\"),n.push(this.unparse(r));return n},isValid:function(t){return s.CHANNEL_NAME.test(t)||s.CHANNEL_PATTERN.test(t)},parse:function(t){return this.isValid(t)?t.split(\"/\").slice(1):null},unparse:function(t){return\"/\"+t.join(\"/\")},isMeta:function(t){var e=this.parse(t);return e?e[0]===this.META:null},isService:function(t){var e=this.parse(t);return e?e[0]===this.SERVICE:null},isSubscribable:function(t){return this.isValid(t)?!this.isMeta(t)&&!this.isService(t):null},Set:r({initialize:function(){this._channels={}},getKeys:function(){var t=[];for(var e in this._channels)t.push(e);return t},remove:function(t){delete this._channels[t]},hasSubscription:function(t){return this._channels.hasOwnProperty(t)},subscribe:function(t,e){for(var n,r=0,i=t.length;r<i;r++){n=t[r];var o=this._channels[n]=this._channels[n]||new a(n);o.bind(\"message\",e)}},unsubscribe:function(t,e){var n=this._channels[t];return!!n&&(n.unbind(\"message\",e),!!n.isUnused()&&(this.remove(t),!0))},distributeMessage:function(t){for(var e=a.expand(t.channel),n=0,r=e.length;n<r;n++){var i=this._channels[e[n]];i&&i.trigger(\"message\",t)}}})}),e.exports=a},{\"../mixins/publisher\":51,\"../util/class\":71,\"../util/extend\":76,\"./grammar\":58}],54:[function(t,e,n){(function(n){\"use strict\";var r=t(\"asap\"),i=t(\"../util/class\"),o=(t(\"../util/promise\"),t(\"../util/uri\")),s=t(\"../util/array\"),a=t(\"../util/browser\"),u=t(\"../util/constants\"),c=t(\"../util/extend\"),l=t(\"../util/validate_options\"),h=t(\"../mixins/deferrable\"),p=t(\"../mixins/logging\"),f=t(\"../mixins/publisher\"),d=t(\"./channel\"),y=t(\"./dispatcher\"),m=t(\"./error\"),_=t(\"./extensible\"),g=t(\"./publication\"),v=t(\"./subscription\"),b=i({className:\"Client\",UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:\"handshake\",RETRY:\"retry\",NONE:\"none\",CONNECTION_TIMEOUT:60,DEFAULT_ENDPOINT:\"/bayeux\",INTERVAL:0,initialize:function(t,e){this.info(\"New client created for ?\",t),e=e||{},l(e,[\"interval\",\"timeout\",\"endpoints\",\"proxy\",\"retry\",\"scheduler\",\"websocketExtensions\",\"tls\",\"ca\"]),this._channels=new d.Set,this._dispatcher=y.create(this,t||this.DEFAULT_ENDPOINT,e),this._messageId=0,this._state=this.UNCONNECTED,this._responseCallbacks={},this._advice={reconnect:this.RETRY,interval:1e3*(e.interval||this.INTERVAL),timeout:1e3*(e.timeout||this.CONNECTION_TIMEOUT)},this._dispatcher.timeout=this._advice.timeout/1e3,this._dispatcher.bind(\"message\",this._receiveMessage,this),a.Event&&void 0!==n.onbeforeunload&&a.Event.on(n,\"beforeunload\",function(){s.indexOf(this._dispatcher._disabled,\"autodisconnect\")<0&&this.disconnect()},this)},addWebsocketExtension:function(t){return this._dispatcher.addWebsocketExtension(t)},disable:function(t){return this._dispatcher.disable(t)},setHeader:function(t,e){return this._dispatcher.setHeader(t,e)},handshake:function(t,e){if(this._advice.reconnect!==this.NONE&&this._state===this.UNCONNECTED){this._state=this.CONNECTING;var i=this;this.info(\"Initiating handshake with ?\",o.stringify(this._dispatcher.endpoint)),this._dispatcher.selectTransport(u.MANDATORY_CONNECTION_TYPES),this._sendMessage({channel:d.HANDSHAKE,version:u.BAYEUX_VERSION,supportedConnectionTypes:this._dispatcher.getConnectionTypes()},{},function(o){o.successful?(this._state=this.CONNECTED,this._dispatcher.clientId=o.clientId,this._dispatcher.selectTransport(o.supportedConnectionTypes),this.info(\"Handshake successful: ?\",this._dispatcher.clientId),this.subscribe(this._channels.getKeys(),!0),t&&r(function(){t.call(e)})):(this.info(\"Handshake unsuccessful\"),n.setTimeout(function(){i.handshake(t,e)},1e3*this._dispatcher.retry),this._state=this.UNCONNECTED)},this)}},connect:function(t,e){if(this._advice.reconnect!==this.NONE&&this._state!==this.DISCONNECTED){if(this._state===this.UNCONNECTED)return this.handshake(function(){this.connect(t,e)},this);this.callback(t,e),this._state===this.CONNECTED&&(this.info(\"Calling deferred actions for ?\",this._dispatcher.clientId),this.setDeferredStatus(\"succeeded\"),this.setDeferredStatus(\"unknown\"),this._connectRequest||(this._connectRequest=!0,this.info(\"Initiating connection for ?\",this._dispatcher.clientId),this._sendMessage({channel:d.CONNECT,clientId:this._dispatcher.clientId,connectionType:this._dispatcher.connectionType},{},this._cycleConnection,this)))}},disconnect:function(){if(this._state===this.CONNECTED){this._state=this.DISCONNECTED,this.info(\"Disconnecting ?\",this._dispatcher.clientId);var t=new g;return this._sendMessage({channel:d.DISCONNECT,clientId:this._dispatcher.clientId},{},function(e){e.successful?(this._dispatcher.close(),t.setDeferredStatus(\"succeeded\")):t.setDeferredStatus(\"failed\",m.parse(e.error))},this),this.info(\"Clearing channel listeners for ?\",this._dispatcher.clientId),this._channels=new d.Set,t}},subscribe:function(t,e,n){if(t instanceof Array)return s.map(t,function(t){return this.subscribe(t,e,n)},this);var r=new v(this,t,e,n),i=e===!0,o=this._channels.hasSubscription(t);return o&&!i?(this._channels.subscribe([t],r),r.setDeferredStatus(\"succeeded\"),r):(this.connect(function(){this.info(\"Client ? attempting to subscribe to ?\",this._dispatcher.clientId,t),i||this._channels.subscribe([t],r),this._sendMessage({channel:d.SUBSCRIBE,clientId:this._dispatcher.clientId,subscription:t},{},function(e){if(!e.successful)return r.setDeferredStatus(\"failed\",m.parse(e.error)),this._channels.unsubscribe(t,r);var n=[].concat(e.subscription);this.info(\"Subscription acknowledged for ? to ?\",this._dispatcher.clientId,n),r.setDeferredStatus(\"succeeded\")},this)},this),r)},unsubscribe:function(t,e){if(t instanceof Array)return s.map(t,function(t){return this.unsubscribe(t,e)},this);var n=this._channels.unsubscribe(t,e);n&&this.connect(function(){this.info(\"Client ? attempting to unsubscribe from ?\",this._dispatcher.clientId,t),this._sendMessage({channel:d.UNSUBSCRIBE,clientId:this._dispatcher.clientId,subscription:t},{},function(t){if(t.successful){var e=[].concat(t.subscription);this.info(\"Unsubscription acknowledged for ? from ?\",this._dispatcher.clientId,e)}},this)},this)},publish:function(t,e,n){l(n||{},[\"attempts\",\"deadline\"]);var r=new g;return this.connect(function(){this.info(\"Client ? queueing published message to ?: ?\",this._dispatcher.clientId,t,e),this._sendMessage({channel:t,data:e,clientId:this._dispatcher.clientId},n,function(t){t.successful?r.setDeferredStatus(\"succeeded\"):r.setDeferredStatus(\"failed\",m.parse(t.error))},this)},this),r},_sendMessage:function(t,e,n,r){t.id=this._generateMessageId();var i=this._advice.timeout?1.2*this._advice.timeout/1e3:1.2*this._dispatcher.retry;this.pipeThroughExtensions(\"outgoing\",t,null,function(t){t&&(n&&(this._responseCallbacks[t.id]=[n,r]),this._dispatcher.sendMessage(t,i,e||{}))},this)},_generateMessageId:function(){return this._messageId+=1,this._messageId>=Math.pow(2,32)&&(this._messageId=0),this._messageId.toString(36)},_receiveMessage:function(t){var e,n=t.id;void 0!==t.successful&&(e=this._responseCallbacks[n],delete this._responseCallbacks[n]),this.pipeThroughExtensions(\"incoming\",t,null,function(t){t&&(t.advice&&this._handleAdvice(t.advice),this._deliverMessage(t),e&&e[0].call(e[1],t))},this)},_handleAdvice:function(t){c(this._advice,t),this._dispatcher.timeout=this._advice.timeout/1e3,this._advice.reconnect===this.HANDSHAKE&&this._state!==this.DISCONNECTED&&(this._state=this.UNCONNECTED,this._dispatcher.clientId=null,this._cycleConnection())},_deliverMessage:function(t){t.channel&&void 0!==t.data&&(this.info(\"Client ? calling listeners for ? with ?\",this._dispatcher.clientId,t.channel,t.data),this._channels.distributeMessage(t))},_cycleConnection:function(){this._connectRequest&&(this._connectRequest=null,this.info(\"Closed connection for ?\",this._dispatcher.clientId));var t=this;n.setTimeout(function(){t.connect()},this._advice.interval)}});c(b.prototype,h),c(b.prototype,f),c(b.prototype,p),c(b.prototype,_),e.exports=b}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../mixins/deferrable\":49,\"../mixins/logging\":50,\"../mixins/publisher\":51,\"../util/array\":69,\"../util/browser\":70,\"../util/class\":71,\"../util/constants\":72,\"../util/extend\":76,\"../util/promise\":77,\"../util/uri\":80,\"../util/validate_options\":81,\"./channel\":53,\"./dispatcher\":55,\"./error\":56,\"./extensible\":57,\"./publication\":59,\"./subscription\":61,asap:37}],55:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/uri\"),o=t(\"../util/cookies\"),s=t(\"../util/extend\"),a=t(\"../mixins/logging\"),u=t(\"../mixins/publisher\"),c=t(\"../transport\"),l=t(\"./scheduler\"),h=r({className:\"Dispatcher\",MAX_REQUEST_SIZE:2048,DEFAULT_RETRY:5,\nUP:1,DOWN:2,initialize:function(t,e,n){this._client=t,this.endpoint=i.parse(e),this._alternates=n.endpoints||{},this.cookies=o.CookieJar&&new o.CookieJar,this._disabled=[],this._envelopes={},this.headers={},this.retry=n.retry||this.DEFAULT_RETRY,this._scheduler=n.scheduler||l,this._state=0,this.transports={},this.wsExtensions=[],this.proxy=n.proxy||{},\"string\"==typeof this._proxy&&(this._proxy={origin:this._proxy});var r=n.websocketExtensions;if(r){r=[].concat(r);for(var s=0,a=r.length;s<a;s++)this.addWebsocketExtension(r[s])}this.tls=n.tls||{},this.tls.ca=this.tls.ca||n.ca;for(var u in this._alternates)this._alternates[u]=i.parse(this._alternates[u]);this.maxRequestSize=this.MAX_REQUEST_SIZE},endpointFor:function(t){return this._alternates[t]||this.endpoint},addWebsocketExtension:function(t){this.wsExtensions.push(t)},disable:function(t){this._disabled.push(t)},setHeader:function(t,e){this.headers[t]=e},close:function(){var t=this._transport;delete this._transport,t&&t.close()},getConnectionTypes:function(){return c.getConnectionTypes()},selectTransport:function(t){c.get(this,t,this._disabled,function(t){this.debug(\"Selected ? transport for ?\",t.connectionType,i.stringify(t.endpoint)),t!==this._transport&&(this._transport&&this._transport.close(),this._transport=t,this.connectionType=t.connectionType)},this)},sendMessage:function(t,e,n){n=n||{};var r,i=t.id,o=n.attempts,s=n.deadline&&(new Date).getTime()+1e3*n.deadline,a=this._envelopes[i];a||(r=new this._scheduler(t,{timeout:e,interval:this.retry,attempts:o,deadline:s}),a=this._envelopes[i]={message:t,scheduler:r}),this._sendEnvelope(a)},_sendEnvelope:function(t){if(this._transport&&!t.request&&!t.timer){var e=t.message,r=t.scheduler,i=this;if(!r.isDeliverable())return r.abort(),void delete this._envelopes[e.id];t.timer=n.setTimeout(function(){i.handleError(e)},1e3*r.getTimeout()),r.send(),t.request=this._transport.sendMessage(e)}},handleResponse:function(t){var e=this._envelopes[t.id];void 0!==t.successful&&e&&(e.scheduler.succeed(),delete this._envelopes[t.id],n.clearTimeout(e.timer)),this.trigger(\"message\",t),this._state!==this.UP&&(this._state=this.UP,this._client.trigger(\"transport:up\"))},handleError:function(t,e){var r=this._envelopes[t.id],i=r&&r.request,o=this;if(i){i.then(function(t){t&&t.abort&&t.abort()});var s=r.scheduler;s.fail(),n.clearTimeout(r.timer),r.request=r.timer=null,e?this._sendEnvelope(r):r.timer=n.setTimeout(function(){r.timer=null,o._sendEnvelope(r)},1e3*s.getInterval()),this._state!==this.DOWN&&(this._state=this.DOWN,this._client.trigger(\"transport:down\"))}}});h.create=function(t,e,n){return new h(t,e,n)},s(h.prototype,u),s(h.prototype,a),e.exports=h}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../mixins/logging\":50,\"../mixins/publisher\":51,\"../transport\":62,\"../util/class\":71,\"../util/cookies\":73,\"../util/extend\":76,\"../util/uri\":80,\"./scheduler\":60}],56:[function(t,e,n){\"use strict\";var r=t(\"../util/class\"),i=t(\"./grammar\"),o=r({initialize:function(t,e,n){this.code=t,this.params=Array.prototype.slice.call(e),this.message=n},toString:function(){return this.code+\":\"+this.params.join(\",\")+\":\"+this.message}});o.parse=function(t){if(t=t||\"\",!i.ERROR.test(t))return new o(null,[],t);var e=t.split(\":\"),n=parseInt(e[0]),r=e[1].split(\",\"),t=e[2];return new o(n,r,t)};var s={versionMismatch:[300,\"Version mismatch\"],conntypeMismatch:[301,\"Connection types not supported\"],extMismatch:[302,\"Extension mismatch\"],badRequest:[400,\"Bad request\"],clientUnknown:[401,\"Unknown client\"],parameterMissing:[402,\"Missing required parameter\"],channelForbidden:[403,\"Forbidden channel\"],channelUnknown:[404,\"Unknown channel\"],channelInvalid:[405,\"Invalid channel\"],extUnknown:[406,\"Unknown extension\"],publishFailed:[407,\"Failed to publish\"],serverError:[500,\"Internal server error\"]};for(var a in s)(function(t){o[t]=function(){return new o(s[t][0],arguments,s[t][1]).toString()}})(a);e.exports=o},{\"../util/class\":71,\"./grammar\":58}],57:[function(t,e,n){\"use strict\";var r=t(\"../util/extend\"),i=t(\"../mixins/logging\"),o={addExtension:function(t){this._extensions=this._extensions||[],this._extensions.push(t),t.added&&t.added(this)},removeExtension:function(t){if(this._extensions)for(var e=this._extensions.length;e--;)this._extensions[e]===t&&(this._extensions.splice(e,1),t.removed&&t.removed(this))},pipeThroughExtensions:function(t,e,n,r,i){if(this.debug(\"Passing through ? extensions: ?\",t,e),!this._extensions)return r.call(i,e);var o=this._extensions.slice(),s=function(e){if(!e)return r.call(i,e);var a=o.shift();if(!a)return r.call(i,e);var u=a[t];return u?void(u.length>=3?a[t](e,n,s):a[t](e,s)):s(e)};s(e)}};r(o,i),e.exports=o},{\"../mixins/logging\":50,\"../util/extend\":76}],58:[function(t,e,n){\"use strict\";e.exports={CHANNEL_NAME:/^\\/(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)))+(\\/(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)))+)*$/,CHANNEL_PATTERN:/^(\\/(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)))+)*\\/\\*{1,2}$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)| |\\/|\\*|\\.))*(,(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)| |\\/|\\*|\\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)| |\\/|\\*|\\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\\-|\\_|\\!|\\~|\\(|\\)|\\$|\\@)| |\\/|\\*|\\.))*)$/,VERSION:/^([0-9])+(\\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\\-|\\_))*)*$/}},{}],59:[function(t,e,n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../mixins/deferrable\");e.exports=r(i)},{\"../mixins/deferrable\":49,\"../util/class\":71}],60:[function(t,e,n){\"use strict\";var r=t(\"../util/extend\"),i=function(t,e){this.message=t,this.options=e,this.attempts=0};r(i.prototype,{getTimeout:function(){return this.options.timeout},getInterval:function(){return this.options.interval},isDeliverable:function(){var t=this.options.attempts,e=this.attempts,n=this.options.deadline,r=(new Date).getTime();return!(void 0!==t&&e>=t)&&!(void 0!==n&&r>n)},send:function(){this.attempts+=1},succeed:function(){},fail:function(){},abort:function(){}}),e.exports=i},{\"../util/extend\":76}],61:[function(t,e,n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/extend\"),o=t(\"../mixins/deferrable\"),s=r({initialize:function(t,e,n,r){this._client=t,this._channels=e,this._callback=n,this._context=r,this._cancelled=!1},withChannel:function(t,e){return this._withChannel=[t,e],this},apply:function(t,e){var n=e[0];this._callback&&this._callback.call(this._context,n.data),this._withChannel&&this._withChannel[0].call(this._withChannel[1],n.channel,n.data)},cancel:function(){this._cancelled||(this._client.unsubscribe(this._channels,this),this._cancelled=!0)},unsubscribe:function(){this.cancel()}});i(s.prototype,o),e.exports=s},{\"../mixins/deferrable\":49,\"../util/class\":71,\"../util/extend\":76}],62:[function(t,e,n){\"use strict\";var r=t(\"./transport\");r.register(\"websocket\",t(\"./web_socket\")),r.register(\"eventsource\",t(\"./event_source\")),r.register(\"long-polling\",t(\"./xhr\")),r.register(\"cross-origin-long-polling\",t(\"./cors\")),r.register(\"callback-polling\",t(\"./jsonp\")),e.exports=r},{\"./cors\":63,\"./event_source\":64,\"./jsonp\":65,\"./transport\":66,\"./web_socket\":67,\"./xhr\":68}],63:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/set\"),o=t(\"../util/uri\"),s=t(\"../util/extend\"),a=t(\"../util/to_json\"),u=t(\"./transport\"),c=s(r(u,{encode:function(t){return\"message=\"+encodeURIComponent(a(t))},request:function(t){var e,r=n.XDomainRequest?XDomainRequest:XMLHttpRequest,i=new r,s=++c._id,a=this._dispatcher.headers,u=this;if(i.open(\"POST\",o.stringify(this.endpoint),!0),i.setRequestHeader){i.setRequestHeader(\"Pragma\",\"no-cache\");for(e in a)a.hasOwnProperty(e)&&i.setRequestHeader(e,a[e])}var l=function(){return!!i&&(c._pending.remove(s),i.onload=i.onerror=i.ontimeout=i.onprogress=null,void(i=null))};return i.onload=function(){var e;try{e=JSON.parse(i.responseText)}catch(n){}l(),e?u._receive(e):u._handleError(t)},i.onerror=i.ontimeout=function(){l(),u._handleError(t)},i.onprogress=function(){},r===n.XDomainRequest&&c._pending.add({id:s,xhr:i}),i.send(this.encode(t)),i}}),{_id:0,_pending:new i,isUsable:function(t,e,r,i){if(o.isSameOrigin(e))return r.call(i,!1);if(n.XDomainRequest)return r.call(i,e.protocol===location.protocol);if(n.XMLHttpRequest){var s=new XMLHttpRequest;return r.call(i,void 0!==s.withCredentials)}return r.call(i,!1)}});e.exports=c}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../util/class\":71,\"../util/extend\":76,\"../util/set\":78,\"../util/to_json\":79,\"../util/uri\":80,\"./transport\":66}],64:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/uri\"),o=t(\"../util/copy_object\"),s=t(\"../util/extend\"),a=t(\"../mixins/deferrable\"),u=t(\"./transport\"),c=t(\"./xhr\"),l=s(r(u,{initialize:function(t,e){if(u.prototype.initialize.call(this,t,e),!n.EventSource)return this.setDeferredStatus(\"failed\");this._xhr=new c(t,e),e=o(e),e.pathname+=\"/\"+t.clientId;var r=new n.EventSource(i.stringify(e)),s=this;r.onopen=function(){s._everConnected=!0,s.setDeferredStatus(\"succeeded\")},r.onerror=function(){s._everConnected?s._handleError([]):(s.setDeferredStatus(\"failed\"),r.close())},r.onmessage=function(t){var e;try{e=JSON.parse(t.data)}catch(n){}e?s._receive(e):s._handleError([])},this._socket=r},close:function(){this._socket&&(this._socket.onopen=this._socket.onerror=this._socket.onmessage=null,this._socket.close(),delete this._socket)},isUsable:function(t,e){this.callback(function(){t.call(e,!0)}),this.errback(function(){t.call(e,!1)})},encode:function(t){return this._xhr.encode(t)},request:function(t){return this._xhr.request(t)}}),{isUsable:function(t,e,n,r){var i=t.clientId;return i?void c.isUsable(t,e,function(i){return i?void this.create(t,e).isUsable(n,r):n.call(r,!1)},this):n.call(r,!1)},create:function(t,e){var n=t.transports.eventsource=t.transports.eventsource||{},r=t.clientId,s=o(e);return s.pathname+=\"/\"+(r||\"\"),s=i.stringify(s),n[s]=n[s]||new this(t,e),n[s]}});s(l.prototype,a),e.exports=l}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../mixins/deferrable\":49,\"../util/class\":71,\"../util/copy_object\":74,\"../util/extend\":76,\"../util/uri\":80,\"./transport\":66,\"./xhr\":68}],65:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/uri\"),o=t(\"../util/copy_object\"),s=t(\"../util/extend\"),a=t(\"../util/to_json\"),u=t(\"./transport\"),c=s(r(u,{encode:function(t){var e=o(this.endpoint);return e.query.message=a(t),e.query.jsonp=\"__jsonp\"+c._cbCount+\"__\",i.stringify(e)},request:function(t){var e=document.getElementsByTagName(\"head\")[0],r=document.createElement(\"script\"),s=c.getCallbackName(),u=o(this.endpoint),l=this;u.query.message=a(t),u.query.jsonp=s;var h=function(){if(!n[s])return!1;n[s]=void 0;try{delete n[s]}catch(t){}r.parentNode.removeChild(r)};return n[s]=function(t){h(),l._receive(t)},r.type=\"text/javascript\",r.src=i.stringify(u),e.appendChild(r),r.onerror=function(){h(),l._handleError(t)},{abort:h}}}),{_cbCount:0,getCallbackName:function(){return this._cbCount+=1,\"__jsonp\"+this._cbCount+\"__\"},isUsable:function(t,e,n,r){n.call(r,!0)}});e.exports=c}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../util/class\":71,\"../util/copy_object\":74,\"../util/extend\":76,\"../util/to_json\":79,\"../util/uri\":80,\"./transport\":66}],66:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/cookies\").Cookie,o=t(\"../util/promise\"),s=t(\"../util/uri\"),a=t(\"../util/array\"),u=t(\"../util/extend\"),c=t(\"../mixins/logging\"),l=t(\"../mixins/timeouts\"),h=t(\"../protocol/channel\"),p=u(r({className:\"Transport\",DEFAULT_PORTS:{\"http:\":80,\"https:\":443,\"ws:\":80,\"wss:\":443},MAX_DELAY:0,batching:!0,initialize:function(t,e){this._dispatcher=t,this.endpoint=e,this._outbox=[],this._proxy=u({},this._dispatcher.proxy),this._proxy.origin||(this._proxy.origin=this._findProxy())},close:function(){},encode:function(t){return\"\"},sendMessage:function(t){return this.debug(\"Client ? sending message to ?: ?\",this._dispatcher.clientId,s.stringify(this.endpoint),t),this.batching?(this._outbox.push(t),this._flushLargeBatch(),t.channel===h.HANDSHAKE?this._publish(.01):(t.channel===h.CONNECT&&(this._connectMessage=t),this._publish(this.MAX_DELAY))):o.resolve(this.request([t]))},_makePromise:function(){var t=this;this._requestPromise=this._requestPromise||new o(function(e){t._resolvePromise=e})},_publish:function(t){return this._makePromise(),this.addTimeout(\"publish\",t,function(){this._flush(),delete this._requestPromise},this),this._requestPromise},_flush:function(){this.removeTimeout(\"publish\"),this._outbox.length>1&&this._connectMessage&&(this._connectMessage.advice={timeout:0}),this._resolvePromise(this.request(this._outbox)),this._connectMessage=null,this._outbox=[]},_flushLargeBatch:function(){var t=this.encode(this._outbox);if(!(t.length<this._dispatcher.maxRequestSize)){var e=this._outbox.pop();this._makePromise(),this._flush(),e&&this._outbox.push(e)}},_receive:function(t){if(t){t=[].concat(t),this.debug(\"Client ? received from ? via ?: ?\",this._dispatcher.clientId,s.stringify(this.endpoint),this.connectionType,t);for(var e=0,n=t.length;e<n;e++)this._dispatcher.handleResponse(t[e])}},_handleError:function(t,e){t=[].concat(t),this.debug(\"Client ? failed to send to ? via ?: ?\",this._dispatcher.clientId,s.stringify(this.endpoint),this.connectionType,t);for(var n=0,r=t.length;n<r;n++)this._dispatcher.handleError(t[n])},_getCookies:function(){var t=this._dispatcher.cookies,e=s.stringify(this.endpoint);return t?a.map(t.getCookiesSync(e),function(t){return t.cookieString()}).join(\"; \"):\"\"},_storeCookies:function(t){var e,n=this._dispatcher.cookies,r=s.stringify(this.endpoint);if(t&&n){t=[].concat(t);for(var o=0,a=t.length;o<a;o++)e=i.parse(t[o]),n.setCookieSync(e,r)}},_findProxy:function(){if(\"undefined\"!=typeof n){var t=this.endpoint.protocol;if(t){var e,r,i=t.replace(/:$/,\"\").toLowerCase()+\"_proxy\",o=i.toUpperCase(),s=n.env;return\"http_proxy\"===i&&s.REQUEST_METHOD?(e=Object.keys(s).filter(function(t){return/^http_proxy$/i.test(t)}),1===e.length?e[0]===i&&void 0===s[o]&&(r=s[i]):e.length>1&&(r=s[i]),r=r||s[\"CGI_\"+o]):(r=s[i]||s[o],r&&!s[i]&&console.warn(\"The environment variable \"+o+\" is discouraged. Use \"+i+\".\")),r}}}}),{get:function(t,e,n,r,i){var o=t.endpoint;a.asyncEach(this._transports,function(o,s){var u=o[0],c=o[1],l=t.endpointFor(u);return a.indexOf(n,u)>=0?s():a.indexOf(e,u)<0?(c.isUsable(t,l,function(){}),s()):void c.isUsable(t,l,function(e){if(!e)return s();var n=c.hasOwnProperty(\"create\")?c.create(t,l):new c(t,l);r.call(i,n)})},function(){throw new Error(\"Could not find a usable connection type for \"+s.stringify(o))})},register:function(t,e){this._transports.push([t,e]),e.prototype.connectionType=t},getConnectionTypes:function(){return a.map(this._transports,function(t){return t[0]})},_transports:[]});u(p.prototype,c),u(p.prototype,l),e.exports=p}).call(this,t(\"_process\"))},{\"../mixins/logging\":50,\"../mixins/timeouts\":52,\"../protocol/channel\":53,\"../util/array\":69,\"../util/class\":71,\"../util/cookies\":73,\"../util/extend\":76,\"../util/promise\":77,\"../util/uri\":80,_process:91}],67:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/promise\"),o=t(\"../util/set\"),s=t(\"../util/uri\"),a=t(\"../util/browser\"),u=t(\"../util/copy_object\"),c=t(\"../util/extend\"),l=t(\"../util/to_json\"),h=t(\"../util/websocket\"),p=t(\"../mixins/deferrable\"),f=t(\"./transport\"),d=c(r(f,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,batching:!1,isUsable:function(t,e){this.callback(function(){t.call(e,!0)}),this.errback(function(){t.call(e,!1)}),this.connect()},request:function(t){this._pending=this._pending||new o;for(var e=0,n=t.length;e<n;e++)this._pending.add(t[e]);var r=this,s=new i(function(e,n){r.callback(function(n){n&&1===n.readyState&&(n.send(l(t)),e(n))}),r.connect()});return{abort:function(){s.then(function(t){t.close()})}}},connect:function(){if(!d._unloaded&&(this._state=this._state||this.UNCONNECTED,this._state===this.UNCONNECTED)){this._state=this.CONNECTING;var t=this._createSocket();if(!t)return this.setDeferredStatus(\"failed\");var e=this;t.onopen=function(){t.headers&&e._storeCookies(t.headers[\"set-cookie\"]),e._socket=t,e._state=e.CONNECTED,e._everConnected=!0,e._ping(),e.setDeferredStatus(\"succeeded\",t)};var n=!1;t.onclose=t.onerror=function(){if(!n){n=!0;var r=e._state===e.CONNECTED;t.onopen=t.onclose=t.onerror=t.onmessage=null,delete e._socket,e._state=e.UNCONNECTED,e.removeTimeout(\"ping\");var i=e._pending?e._pending.toArray():[];delete e._pending,r||e._everConnected?(e.setDeferredStatus(\"unknown\"),e._handleError(i,r)):e.setDeferredStatus(\"failed\")}},t.onmessage=function(t){var n;try{n=JSON.parse(t.data)}catch(r){}if(n){n=[].concat(n);for(var i=0,o=n.length;i<o;i++)void 0!==n[i].successful&&e._pending.remove(n[i]);e._receive(n)}}}},close:function(){this._socket&&this._socket.close()},_createSocket:function(){var t=d.getSocketUrl(this.endpoint),e=this._dispatcher.headers,n=this._dispatcher.wsExtensions,r=this._getCookies(),i=this._dispatcher.tls,o={extensions:n,headers:e,proxy:this._proxy,tls:i};return\"\"!==r&&(o.headers.Cookie=r),h.create(t,[],o)},_ping:function(){this._socket&&1===this._socket.readyState&&(this._socket.send(\"[]\"),this.addTimeout(\"ping\",this._dispatcher.timeout/2,this._ping,this))}}),{PROTOCOLS:{\"http:\":\"ws:\",\"https:\":\"wss:\"},create:function(t,e){var n=t.transports.websocket=t.transports.websocket||{};return n[e.href]=n[e.href]||new this(t,e),n[e.href]},getSocketUrl:function(t){return t=u(t),t.protocol=this.PROTOCOLS[t.protocol],s.stringify(t)},isUsable:function(t,e,n,r){this.create(t,e).isUsable(n,r)}});c(d.prototype,p),a.Event&&void 0!==n.onbeforeunload&&a.Event.on(n,\"beforeunload\",function(){d._unloaded=!0}),e.exports=d}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../mixins/deferrable\":49,\"../util/browser\":70,\"../util/class\":71,\"../util/copy_object\":74,\"../util/extend\":76,\"../util/promise\":77,\"../util/set\":78,\"../util/to_json\":79,\"../util/uri\":80,\"../util/websocket\":82,\"./transport\":66}],68:[function(t,e,n){(function(n){\"use strict\";var r=t(\"../util/class\"),i=t(\"../util/uri\"),o=t(\"../util/browser\"),s=t(\"../util/extend\"),a=t(\"../util/to_json\"),u=t(\"./transport\"),c=s(r(u,{encode:function(t){return a(t)},request:function(t){var e,r=this.endpoint.href,i=this;if(n.XMLHttpRequest)e=new XMLHttpRequest;else{if(!n.ActiveXObject)return this._handleError(t);e=new ActiveXObject(\"Microsoft.XMLHTTP\")}e.open(\"POST\",r,!0),e.setRequestHeader(\"Content-Type\",\"application/json\"),e.setRequestHeader(\"Pragma\",\"no-cache\"),e.setRequestHeader(\"X-Requested-With\",\"XMLHttpRequest\");var s=this._dispatcher.headers;for(var a in s)s.hasOwnProperty(a)&&e.setRequestHeader(a,s[a]);var u=function(){e.abort()};return void 0!==n.onbeforeunload&&o.Event.on(n,\"beforeunload\",u),e.onreadystatechange=function(){if(e&&4===e.readyState){var r=null,s=e.status,a=e.responseText,c=s>=200&&s<300||304===s||1223===s;if(void 0!==n.onbeforeunload&&o.Event.detach(n,\"beforeunload\",u),e.onreadystatechange=function(){},e=null,!c)return i._handleError(t);try{r=JSON.parse(a)}catch(l){}r?i._receive(r):i._handleError(t)}},e.send(this.encode(t)),e}}),{isUsable:function(t,e,n,r){var o=\"ReactNative\"===navigator.product||i.isSameOrigin(e);n.call(r,o)}});e.exports=c}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"../util/browser\":70,\"../util/class\":71,\"../util/extend\":76,\"../util/to_json\":79,\"../util/uri\":80,\"./transport\":66}],69:[function(t,e,n){\"use strict\";e.exports={commonElement:function(t,e){for(var n=0,r=t.length;n<r;n++)if(this.indexOf(e,t[n])!==-1)return t[n];return null},indexOf:function(t,e){if(t.indexOf)return t.indexOf(e);for(var n=0,r=t.length;n<r;n++)if(t[n]===e)return n;return-1},map:function(t,e,n){if(t.map)return t.map(e,n);var r=[];if(t instanceof Array)for(var i=0,o=t.length;i<o;i++)r.push(e.call(n||null,t[i],i));else for(var s in t)t.hasOwnProperty(s)&&r.push(e.call(n||null,s,t[s]));return r},filter:function(t,e,n){if(t.filter)return t.filter(e,n);for(var r=[],i=0,o=t.length;i<o;i++)e.call(n||null,t[i],i)&&r.push(t[i]);return r},asyncEach:function(t,e,n,r){var i=t.length,o=-1,s=0,a=!1,u=function(){return s-=1,o+=1,o===i?n&&n.call(r):void e(t[o],l)},c=function(){if(!a){for(a=!0;s>0;)u();a=!1}},l=function(){s+=1,c()};l()}}},{}],70:[function(t,e,n){(function(t){\"use strict\";var n={_registry:[],on:function(t,e,n,r){var i=function(){n.call(r)};t.addEventListener?t.addEventListener(e,i,!1):t.attachEvent(\"on\"+e,i),this._registry.push({_element:t,_type:e,_callback:n,_context:r,_handler:i})},detach:function(t,e,n,r){for(var i,o=this._registry.length;o--;)i=this._registry[o],t&&t!==i._element||e&&e!==i._type||n&&n!==i._callback||r&&r!==i._context||(i._element.removeEventListener?i._element.removeEventListener(i._type,i._handler,!1):i._element.detachEvent(\"on\"+i._type,i._handler),this._registry.splice(o,1),i=null)}};void 0!==t.onunload&&n.on(t,\"unload\",n.detach,n),e.exports={Event:n}}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],71:[function(t,e,n){\"use strict\";var r=t(\"./extend\");e.exports=function(t,e){\"function\"!=typeof t&&(e=t,t=Object);var n=function(){return this.initialize?this.initialize.apply(this,arguments)||this:this},i=function(){};return i.prototype=t.prototype,n.prototype=new i,r(n.prototype,e),n}},{\"./extend\":76}],72:[function(t,e,n){e.exports={VERSION:\"1.2.4\",BAYEUX_VERSION:\"1.0\",ID_LENGTH:160,JSONP_CALLBACK:\"jsonpcallback\",CONNECTION_TYPES:[\"long-polling\",\"cross-origin-long-polling\",\"callback-polling\",\"websocket\",\"eventsource\",\"in-process\"],MANDATORY_CONNECTION_TYPES:[\"long-polling\",\"callback-polling\",\"in-process\"]}},{}],73:[function(t,e,n){\"use strict\";e.exports={}},{}],74:[function(t,e,n){\"use strict\";var r=function(t){var e,n,i;if(t instanceof Array){for(e=[],n=t.length;n--;)e[n]=r(t[n]);return e}if(\"object\"==typeof t){e=null===t?null:{};for(i in t)e[i]=r(t[i]);return e}return t};e.exports=r},{}],75:[function(t,e,n){function r(t,e){if(t.indexOf)return t.indexOf(e);for(var n=0;n<t.length;n++)if(e===t[n])return n;return-1}function i(){}var o=\"function\"==typeof Array.isArray?Array.isArray:function(t){return\"[object Array]\"===Object.prototype.toString.call(t)};e.exports=i,i.prototype.emit=function(t){if(\"error\"===t&&(!this._events||!this._events.error||o(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error(\"Uncaught, unspecified 'error' event.\");if(!this._events)return!1;var e=this._events[t];if(!e)return!1;if(\"function\"==typeof e){switch(arguments.length){case 1:e.call(this);break;case 2:e.call(this,arguments[1]);break;case 3:e.call(this,arguments[1],arguments[2]);break;default:var n=Array.prototype.slice.call(arguments,1);e.apply(this,n)}return!0}if(o(e)){for(var n=Array.prototype.slice.call(arguments,1),r=e.slice(),i=0,s=r.length;i<s;i++)r[i].apply(this,n);return!0}return!1},i.prototype.addListener=function(t,e){if(\"function\"!=typeof e)throw new Error(\"addListener only takes instances of Function\");return this._events||(this._events={}),this.emit(\"newListener\",t,e),this._events[t]?o(this._events[t])?this._events[t].push(e):this._events[t]=[this._events[t],e]:this._events[t]=e,this},i.prototype.on=i.prototype.addListener,i.prototype.once=function(t,e){var n=this;return n.on(t,function r(){n.removeListener(t,r),e.apply(this,arguments)}),this},i.prototype.removeListener=function(t,e){if(\"function\"!=typeof e)throw new Error(\"removeListener only takes instances of Function\");if(!this._events||!this._events[t])return this;var n=this._events[t];if(o(n)){var i=r(n,e);if(i<0)return this;n.splice(i,1),0==n.length&&delete this._events[t]}else this._events[t]===e&&delete this._events[t];return this},i.prototype.removeAllListeners=function(t){return 0===arguments.length?(this._events={},this):(t&&this._events&&this._events[t]&&(this._events[t]=null),this)},i.prototype.listeners=function(t){return this._events||(this._events={}),this._events[t]||(this._events[t]=[]),o(this._events[t])||(this._events[t]=[this._events[t]]),this._events[t]}},{}],76:[function(t,e,n){\"use strict\";e.exports=function(t,e,n){if(!e)return t;for(var r in e)e.hasOwnProperty(r)&&(t.hasOwnProperty(r)&&n===!1||t[r]!==e[r]&&(t[r]=e[r]));return t}},{}],77:[function(t,e,n){\"use strict\";var r=t(\"asap\"),i=0,o=1,s=2,a=function(t){return t},u=function(t){throw t},c=function(t){if(this._state=i,this._onFulfilled=[],this._onRejected=[],\"function\"==typeof t){var e=this;t(function(t){d(e,t)},function(t){m(e,t)})}};c.prototype.then=function(t,e){var n=new c;return l(this,t,n),h(this,e,n),n},c.prototype[\"catch\"]=function(t){return this.then(null,t)};var l=function(t,e,n){\"function\"!=typeof e&&(e=a);var r=function(t){p(e,t,n)};t._state===i?t._onFulfilled.push(r):t._state===o&&r(t._value)},h=function(t,e,n){\"function\"!=typeof e&&(e=u);var r=function(t){p(e,t,n)};t._state===i?t._onRejected.push(r):t._state===s&&r(t._reason)},p=function(t,e,n){r(function(){f(t,e,n)})},f=function(t,e,n){var r;try{r=t(e)}catch(i){return m(n,i)}r===n?m(n,new TypeError(\"Recursive promise chain detected\")):d(n,r)},d=function(t,e){var n,r,i=!1;try{if(n=typeof e,r=null!==e&&(\"function\"===n||\"object\"===n)&&e.then,\"function\"!=typeof r)return y(t,e);r.call(e,function(e){i^(i=!0)&&d(t,e)},function(e){i^(i=!0)&&m(t,e)})}catch(o){if(!(i^(i=!0)))return;m(t,o)}},y=function(t,e){if(t._state===i){t._state=o,t._value=e,t._onRejected=[];for(var n,r=t._onFulfilled;n=r.shift();)n(e)}},m=function(t,e){if(t._state===i){t._state=s,t._reason=e,t._onFulfilled=[];for(var n,r=t._onRejected;n=r.shift();)n(e)}};c.resolve=function(t){return new c(function(e,n){e(t)})},c.reject=function(t){return new c(function(e,n){n(t)})},c.all=function(t){return new c(function(e,n){var r,i=[],o=t.length;if(0===o)return e(i);for(r=0;r<o;r++)(function(t,r){c.resolve(t).then(function(t){i[r]=t,0===--o&&e(i)},n)})(t[r],r)})},c.race=function(t){return new c(function(e,n){for(var r=0,i=t.length;r<i;r++)c.resolve(t[r]).then(e,n)})},c.deferred=c.pending=function(){var t={};return t.promise=new c(function(e,n){t.resolve=e,t.reject=n}),t},e.exports=c},{asap:37}],78:[function(t,e,n){\"use strict\";var r=t(\"./class\");e.exports=r({initialize:function(){this._index={}},add:function(t){var e=void 0!==t.id?t.id:t;return!this._index.hasOwnProperty(e)&&(this._index[e]=t,!0)},forEach:function(t,e){for(var n in this._index)this._index.hasOwnProperty(n)&&t.call(e,this._index[n])},isEmpty:function(){for(var t in this._index)if(this._index.hasOwnProperty(t))return!1;return!0},member:function(t){for(var e in this._index)if(this._index[e]===t)return!0;return!1},remove:function(t){var e=void 0!==t.id?t.id:t,n=this._index[e];return delete this._index[e],n},toArray:function(){var t=[];return this.forEach(function(e){t.push(e)}),t}})},{\"./class\":71}],79:[function(t,e,n){\"use strict\";e.exports=function(t){return JSON.stringify(t,function(t,e){return this[t]instanceof Array?this[t]:e})}},{}],80:[function(t,e,n){\"use strict\";e.exports={isURI:function(t){return t&&t.protocol&&t.host&&t.path},isSameOrigin:function(t){return t.protocol===location.protocol&&t.hostname===location.hostname&&t.port===location.port},parse:function(t){if(\"string\"!=typeof t)return t;var e,n,r,i,o,s,a={},u=function(e,n){t=t.replace(n,function(t){return a[e]=t,\"\"}),a[e]=a[e]||\"\"};for(u(\"protocol\",/^[a-z]+\\:/i),u(\"host\",/^\\/\\/[^\\/\\?#]+/),/^\\//.test(t)||a.host||(t=location.pathname.replace(/[^\\/]*$/,\"\")+t),u(\"pathname\",/^[^\\?#]*/),u(\"search\",/^\\?[^#]*/),u(\"hash\",/^#.*/),a.protocol=a.protocol||location.protocol,a.host?(a.host=a.host.substr(2),e=a.host.split(\":\"),a.hostname=e[0],a.port=e[1]||\"\"):(a.host=location.host,a.hostname=location.hostname,a.port=location.port),a.pathname=a.pathname||\"/\",a.path=a.pathname+a.search,n=a.search.replace(/^\\?/,\"\"),r=n?n.split(\"&\"):[],s={},i=0,o=r.length;i<o;i++)e=r[i].split(\"=\"),s[decodeURIComponent(e[0]||\"\")]=decodeURIComponent(e[1]||\"\");return a.query=s,a.href=this.stringify(a),a},stringify:function(t){var e=t.protocol+\"//\"+t.hostname;return t.port&&(e+=\":\"+t.port),e+=t.pathname+this.queryString(t.query)+(t.hash||\"\")},queryString:function(t){var e=[];for(var n in t)t.hasOwnProperty(n)&&e.push(encodeURIComponent(n)+\"=\"+encodeURIComponent(t[n]));return 0===e.length?\"\":\"?\"+e.join(\"&\")}}},{}],81:[function(t,e,n){\"use strict\";var r=t(\"./array\");e.exports=function(t,e){for(var n in t)if(r.indexOf(e,n)<0)throw new Error(\"Unrecognized option: \"+n)}},{\"./array\":69}],82:[function(t,e,n){(function(t){\"use strict\";var n=t.MozWebSocket||t.WebSocket;e.exports={create:function(t,e,r){return\"function\"!=typeof n?null:new n(t)}}}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],83:[function(t,e,n){n.read=function(t,e,n,r,i){var o,s,a=8*i-r-1,u=(1<<a)-1,c=u>>1,l=-7,h=n?i-1:0,p=n?-1:1,f=t[e+h];for(h+=p,o=f&(1<<-l)-1,f>>=-l,l+=a;l>0;o=256*o+t[e+h],h+=p,l-=8);for(s=o&(1<<-l)-1,o>>=-l,l+=r;l>0;s=256*s+t[e+h],h+=p,l-=8);if(0===o)o=1-c;else{if(o===u)return s?NaN:(f?-1:1)*(1/0);s+=Math.pow(2,r),o-=c}return(f?-1:1)*s*Math.pow(2,o-r)},n.write=function(t,e,n,r,i,o){var s,a,u,c=8*o-i-1,l=(1<<c)-1,h=l>>1,p=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,f=r?0:o-1,d=r?1:-1,y=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=l):(s=Math.floor(Math.log(e)/Math.LN2),e*(u=Math.pow(2,-s))<1&&(s--,u*=2),e+=s+h>=1?p/u:p*Math.pow(2,1-h),e*u>=2&&(s++,u/=2),s+h>=l?(a=0,s=l):s+h>=1?(a=(e*u-1)*Math.pow(2,i),s+=h):(a=e*Math.pow(2,h-1)*Math.pow(2,i),s=0));i>=8;t[n+f]=255&a,f+=d,a/=256,i-=8);for(s=s<<i|a,c+=i;c>0;t[n+f]=255&s,f+=d,s/=256,c-=8);t[n+f-d]|=128*y}},{}],84:[function(t,e,n){\"function\"==typeof Object.create?e.exports=function(t,e){t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(t,e){t.super_=e;var n=function(){};n.prototype=e.prototype,t.prototype=new n,t.prototype.constructor=t}},{}],85:[function(t,e,n){function r(t){return!!t.constructor&&\"function\"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)}function i(t){return\"function\"==typeof t.readFloatLE&&\"function\"==typeof t.slice&&r(t.slice(0,0))}e.exports=function(t){return null!=t&&(r(t)||i(t)||!!t._isBuffer)}},{}],86:[function(t,e,n){var r={}.toString;e.exports=Array.isArray||function(t){return\"[object Array]\"==r.call(t)}},{}],87:[function(t,e,n){(function(t){function n(t,e){return null==t?void 0:t[e]}function r(t){var e=!1;if(null!=t&&\"function\"!=typeof t.toString)try{e=!!(t+\"\")}catch(n){}return e}function i(t){var e=-1,n=t?t.length:0;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function o(){this.__data__=mt?mt(null):{}}function s(t){return this.has(t)&&delete this.__data__[t]}function a(t){var e=this.__data__;if(mt){var n=e[t];return n===z?void 0:n}return lt.call(e,t)?e[t]:void 0}function u(t){var e=this.__data__;return mt?void 0!==e[t]:lt.call(e,t)}function c(t,e){var n=this.__data__;return n[t]=mt&&void 0===e?z:e,this}function l(t){var e=-1,n=t?t.length:0;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function h(){this.__data__=[]}function p(t){var e=this.__data__,n=E(e,t);if(n<0)return!1;var r=e.length-1;return n==r?e.pop():dt.call(e,n,1),!0}function f(t){var e=this.__data__,n=E(e,t);return n<0?void 0:e[n][1]}function d(t){return E(this.__data__,t)>-1}function y(t,e){var n=this.__data__,r=E(n,t);return r<0?n.push([t,e]):n[r][1]=e,this}function m(t){var e=-1,n=t?t.length:0;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function _(){this.__data__={hash:new i,map:new(yt||l),string:new i}}function g(t){return I(this,t)[\"delete\"](t)}function v(t){return I(this,t).get(t)}function b(t){return I(this,t).has(t)}function w(t,e){\nreturn I(this,t).set(t,e),this}function E(t,e){for(var n=t.length;n--;)if(R(t[n][0],e))return n;return-1}function T(t,e){e=O(e,t)?[e]:C(e);for(var n=0,r=e.length;null!=t&&n<r;)t=t[j(e[n++])];return n&&n==r?t:void 0}function x(t){if(!U(t)||D(t))return!1;var e=M(t)||r(t)?pt:tt;return e.test(k(t))}function S(t){if(\"string\"==typeof t)return t;if(P(t))return gt?gt.call(t):\"\";var e=t+\"\";return\"0\"==e&&1/t==-H?\"-0\":e}function C(t){return bt(t)?t:vt(t)}function I(t,e){var n=t.__data__;return A(e)?n[\"string\"==typeof e?\"string\":\"hash\"]:n.map}function N(t,e){var r=n(t,e);return x(r)?r:void 0}function O(t,e){if(bt(t))return!1;var n=typeof t;return!(\"number\"!=n&&\"symbol\"!=n&&\"boolean\"!=n&&null!=t&&!P(t))||(Y.test(t)||!$.test(t)||null!=e&&t in Object(e))}function A(t){var e=typeof t;return\"string\"==e||\"number\"==e||\"symbol\"==e||\"boolean\"==e?\"__proto__\"!==t:null===t}function D(t){return!!ut&&ut in t}function j(t){if(\"string\"==typeof t||P(t))return t;var e=t+\"\";return\"0\"==e&&1/t==-H?\"-0\":e}function k(t){if(null!=t){try{return ct.call(t)}catch(e){}try{return t+\"\"}catch(e){}}return\"\"}function L(t,e){if(\"function\"!=typeof t||e&&\"function\"!=typeof e)throw new TypeError(X);var n=function(){var r=arguments,i=e?e.apply(this,r):r[0],o=n.cache;if(o.has(i))return o.get(i);var s=t.apply(this,r);return n.cache=o.set(i,s),s};return n.cache=new(L.Cache||m),n}function R(t,e){return t===e||t!==t&&e!==e}function M(t){var e=U(t)?ht.call(t):\"\";return e==V||e==W}function U(t){var e=typeof t;return!!t&&(\"object\"==e||\"function\"==e)}function q(t){return!!t&&\"object\"==typeof t}function P(t){return\"symbol\"==typeof t||q(t)&&ht.call(t)==G}function F(t){return null==t?\"\":S(t)}function B(t,e,n){var r=null==t?void 0:T(t,e);return void 0===r?n:r}var X=\"Expected a function\",z=\"__lodash_hash_undefined__\",H=1/0,V=\"[object Function]\",W=\"[object GeneratorFunction]\",G=\"[object Symbol]\",$=/\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,Y=/^\\w*$/,Q=/^\\./,J=/[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g,K=/[\\\\^$.*+?()[\\]{}|]/g,Z=/\\\\(\\\\)?/g,tt=/^\\[object .+?Constructor\\]$/,et=\"object\"==typeof t&&t&&t.Object===Object&&t,nt=\"object\"==typeof self&&self&&self.Object===Object&&self,rt=et||nt||Function(\"return this\")(),it=Array.prototype,ot=Function.prototype,st=Object.prototype,at=rt[\"__core-js_shared__\"],ut=function(){var t=/[^.]+$/.exec(at&&at.keys&&at.keys.IE_PROTO||\"\");return t?\"Symbol(src)_1.\"+t:\"\"}(),ct=ot.toString,lt=st.hasOwnProperty,ht=st.toString,pt=RegExp(\"^\"+ct.call(lt).replace(K,\"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g,\"$1.*?\")+\"$\"),ft=rt.Symbol,dt=it.splice,yt=N(rt,\"Map\"),mt=N(Object,\"create\"),_t=ft?ft.prototype:void 0,gt=_t?_t.toString:void 0;i.prototype.clear=o,i.prototype[\"delete\"]=s,i.prototype.get=a,i.prototype.has=u,i.prototype.set=c,l.prototype.clear=h,l.prototype[\"delete\"]=p,l.prototype.get=f,l.prototype.has=d,l.prototype.set=y,m.prototype.clear=_,m.prototype[\"delete\"]=g,m.prototype.get=v,m.prototype.has=b,m.prototype.set=w;var vt=L(function(t){t=F(t);var e=[];return Q.test(t)&&e.push(\"\"),t.replace(J,function(t,n,r,i){e.push(r?i.replace(Z,\"$1\"):n||t)}),e});L.Cache=m;var bt=Array.isArray;e.exports=B}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],88:[function(e,n,r){(function(e){(function(){function i(t,e){return t.push.apply(t,e),t}function o(t,e,n,r){for(var i=t.length,o=n+(r?1:-1);r?o--:++o<i;)if(e(t[o],o,t))return o;return-1}function s(t){return function(e){return null==e?re:e[t]}}function a(t){return function(e){return null==t?re:t[e]}}function u(t,e,n,r,i){return i(t,function(t,i,o){n=r?(r=!1,t):e(n,t,i,o)}),n}function c(t,e){return A(e,function(e){return t[e]})}function l(t,e){return function(n){return t(e(n))}}function h(t){return t instanceof p?t:new p(t)}function p(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e}function f(t,e,n){var r=t[e];Ue.call(t,e)&&It(r,n)&&(n!==re||e in t)||d(t,e,n)}function d(t,e,n){t[e]=n}function y(t,e,n){if(\"function\"!=typeof t)throw new TypeError(oe);return setTimeout(function(){t.apply(re,n)},e)}function m(t,e){var n=!0;return Ge(t,function(t,r,i){return n=!!e(t,r,i)}),n}function _(t,e,n){for(var r=-1,i=t.length;++r<i;){var o=t[r],s=e(o);if(null!=s&&(a===re?s===s&&!0:n(s,a)))var a=s,u=o}return u}function g(t,e){var n=[];return Ge(t,function(t,r,i){e(t,r,i)&&n.push(t)}),n}function v(t,e,n,r,o){var s=-1,a=t.length;for(n||(n=Q),o||(o=[]);++s<a;){var u=t[s];e>0&&n(u)?e>1?v(u,e-1,n,r,o):i(o,u):r||(o[o.length]=u)}return o}function b(t,e){return t&&$e(t,e,hn)}function w(t,e){return g(e,function(e){return kt(t[e])})}function E(t){return tt(t)}function T(t,e){return t>e}function x(t){return Mt(t)&&E(t)==me}function S(t,e,n,r,i){return t===e||(null==t||null==e||!Mt(t)&&!Mt(e)?t!==t&&e!==e:C(t,e,n,r,S,i))}function C(t,e,n,r,i,o){var s=nn(t),a=nn(e),u=s?fe:E(t),c=a?fe:E(e);u=u==pe?we:u,c=c==pe?we:c;var l=u==we,h=c==we,p=u==c;o||(o=[]);var f=Je(o,function(e){return e[0]==t}),d=Je(o,function(t){return t[0]==e});if(f&&d)return f[1]==e;if(o.push([t,e]),o.push([e,t]),p&&!l){var y=s?W(t,e,n,r,i,o):G(t,e,u,n,r,i,o);return o.pop(),y}if(!(n&se)){var m=l&&Ue.call(t,\"__wrapped__\"),_=h&&Ue.call(e,\"__wrapped__\");if(m||_){var g=m?t.value():t,v=_?e.value():e,y=i(g,v,n,r,o);return o.pop(),y}}if(!p)return!1;var y=$(t,e,n,r,i,o);return o.pop(),y}function I(t){return Mt(t)&&E(t)==Te}function N(t){return\"function\"==typeof t?t:null==t?Yt:(\"object\"==typeof t?D:s)(t)}function O(t,e){return t<e}function A(t,e){var n=-1,r=Nt(t)?Array(t.length):[];return Ge(t,function(t,i,o){r[++n]=e(t,i,o)}),r}function D(t){var e=He(t);return function(n){var r=e.length;if(null==n)return!r;for(n=Object(n);r--;){var i=e[r];if(!(i in n&&S(t[i],n[i],se|ae)))return!1}return!0}}function j(t,e){return t=Object(t),vt(e,function(e,n){return n in t&&(e[n]=t[n]),e},{})}function k(t,e){return Qe(et(t,e,Yt),t+\"\")}function L(t,e,n){var r=-1,i=t.length;e<0&&(e=-e>i?0:i+e),n=n>i?i:n,n<0&&(n+=i),i=e>n?0:n-e>>>0,e>>>=0;for(var o=Array(i);++r<i;)o[r]=t[r+e];return o}function R(t){return L(t,0,t.length)}function M(t,e){var n;return Ge(t,function(t,r,i){return n=e(t,r,i),!n}),!!n}function U(t,e){var n=t;return vt(e,function(t,e){return e.func.apply(e.thisArg,i([t],e.args))},n)}function q(t,e){if(t!==e){var n=t!==re,r=null===t,i=t===t,o=!1,s=e!==re,a=null===e,u=e===e,c=!1;if(!a&&!c&&!o&&t>e||o&&s&&u&&!a&&!c||r&&s&&u||!n&&u||!i)return 1;if(!r&&!o&&!c&&t<e||c&&n&&i&&!r&&!o||a&&n&&i||!s&&i||!u)return-1}return 0}function P(t,e,n,r){var i=!n;n||(n={});for(var o=-1,s=e.length;++o<s;){var a=e[o],u=r?r(n[a],t[a],a,n,t):re;u===re&&(u=t[a]),i?d(n,a,u):f(n,a,u)}return n}function F(t){return k(function(e,n){var r=-1,i=n.length,o=i>1?n[i-1]:re;for(o=t.length>3&&\"function\"==typeof o?(i--,o):re,e=Object(e);++r<i;){var s=n[r];s&&t(e,s,r,o)}return e})}function B(t,e){return function(n,r){if(null==n)return n;if(!Nt(n))return t(n,r);for(var i=n.length,o=e?i:-1,s=Object(n);(e?o--:++o<i)&&r(s[o],o,s)!==!1;);return n}}function X(t){return function(e,n,r){for(var i=-1,o=Object(e),s=r(e),a=s.length;a--;){var u=s[t?a:++i];if(n(o[u],u,o)===!1)break}return e}}function z(t){return function(){var e=arguments,n=We(t.prototype),r=t.apply(n,e);return Rt(r)?r:n}}function H(t){return function(e,n,r){var i=Object(e);if(!Nt(e)){var o=N(n,3);e=hn(e),n=function(t){return o(i[t],t,i)}}var s=t(e,n,r);return s>-1?i[o?e[s]:s]:re}}function V(t,e,n,r){function i(){for(var e=-1,a=arguments.length,u=-1,c=r.length,l=Array(c+a),h=this&&this!==De&&this instanceof i?s:t;++u<c;)l[u]=r[u];for(;a--;)l[u++]=arguments[++e];return h.apply(o?n:this,l)}if(\"function\"!=typeof t)throw new TypeError(oe);var o=e&ue,s=z(t);return i}function W(t,e,n,r,i,o){var s=n&se,a=t.length,u=e.length;if(a!=u&&!(s&&u>a))return!1;for(var c=-1,l=!0,h=n&ae?[]:re;++c<a;){var p,f=t[c],d=e[c];if(p!==re){if(p)continue;l=!1;break}if(h){if(!M(e,function(t,e){if(!ut(h,e)&&(f===t||i(f,t,n,r,o)))return h.push(e)})){l=!1;break}}else if(f!==d&&!i(f,d,n,r,o)){l=!1;break}}return l}function G(t,e,n,r,i,o,s){switch(n){case ye:case me:case be:return It(+t,+e);case _e:return t.name==e.name&&t.message==e.message;case Te:case xe:return t==e+\"\"}return!1}function $(t,e,n,r,i,o){var s=n&se,a=hn(t),u=a.length,c=hn(e),l=c.length;if(u!=l&&!s)return!1;for(var h=u;h--;){var p=a[h];if(!(s?p in e:Ue.call(e,p)))return!1}for(var f=!0,d=s;++h<u;){p=a[h];var y,m=t[p],_=e[p];if(!(y===re?m===_||i(m,_,n,r,o):y)){f=!1;break}d||(d=\"constructor\"==p)}if(f&&!d){var g=t.constructor,v=e.constructor;g!=v&&\"constructor\"in t&&\"constructor\"in e&&!(\"function\"==typeof g&&g instanceof g&&\"function\"==typeof v&&v instanceof v)&&(f=!1)}return f}function Y(t){return Qe(et(t,re,ot),t+\"\")}function Q(t){return nn(t)||en(t)}function J(t,e){var n=typeof t;return e=null==e?he:e,!!e&&(\"number\"==n||\"symbol\"!=n&&Ie.test(t))&&t>-1&&t%1==0&&t<e}function K(t,e,n){if(!Rt(n))return!1;var r=typeof e;return!!(\"number\"==r?Nt(n)&&J(e,n.length):\"string\"==r&&e in n)&&It(n[e],t)}function Z(t){var e=[];if(null!=t)for(var n in Object(t))e.push(n);return e}function tt(t){return Pe.call(t)}function et(t,e,n){return e=Ve(e===re?t.length-1:e,0),function(){for(var r=arguments,i=-1,o=Ve(r.length-e,0),s=Array(o);++i<o;)s[i]=r[e+i];i=-1;for(var a=Array(e+1);++i<e;)a[i]=r[i];return a[e]=n(s),t.apply(this,a)}}function nt(t){return g(t,Boolean)}function rt(){var t=arguments.length;if(!t)return[];for(var e=Array(t-1),n=arguments[0],r=t;r--;)e[r-1]=arguments[r];return i(nn(n)?R(n):[n],v(e,1))}function it(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:sn(n);return i<0&&(i=Ve(r+i,0)),o(t,N(e,3),i)}function ot(t){var e=null==t?0:t.length;return e?v(t,1):[]}function st(t){var e=null==t?0:t.length;return e?v(t,le):[]}function at(t){return t&&t.length?t[0]:re}function ut(t,e,n){var r=null==t?0:t.length;n=\"number\"==typeof n?n<0?Ve(r+n,0):n:0;for(var i=(n||0)-1,o=e===e;++i<r;){var s=t[i];if(o?s===e:s!==s)return i}return-1}function ct(t){var e=null==t?0:t.length;return e?t[e-1]:re}function lt(t,e,n){var r=null==t?0:t.length;return e=null==e?0:+e,n=n===re?r:+n,r?L(t,e,n):[]}function ht(t){var e=h(t);return e.__chain__=!0,e}function pt(t,e){return e(t),t}function ft(t,e){return e(t)}function dt(){return U(this.__wrapped__,this.__actions__)}function yt(t,e,n){return e=n?re:e,m(t,N(e))}function mt(t,e){return g(t,N(e))}function _t(t,e){return Ge(t,N(e))}function gt(t,e){return A(t,N(e))}function vt(t,e,n){return u(t,N(e),n,arguments.length<3,Ge)}function bt(t){return null==t?0:(t=Nt(t)?t:He(t),t.length)}function wt(t,e,n){return e=n?re:e,M(t,N(e))}function Et(t,e){var n=0;return e=N(e),A(A(t,function(t,r,i){return{value:t,index:n++,criteria:e(t,r,i)}}).sort(function(t,e){return q(t.criteria,e.criteria)||t.index-e.index}),s(\"value\"))}function Tt(t,e){var n;if(\"function\"!=typeof e)throw new TypeError(oe);return t=sn(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=re),n}}function xt(t){if(\"function\"!=typeof t)throw new TypeError(oe);return function(){var e=arguments;return!t.apply(this,e)}}function St(t){return Tt(2,t)}function Ct(t){return Rt(t)?nn(t)?R(t):P(t,He(t)):t}function It(t,e){return t===e||t!==t&&e!==e}function Nt(t){return null!=t&&Lt(t.length)&&!kt(t)}function Ot(t){return t===!0||t===!1||Mt(t)&&E(t)==ye}function At(t){return Nt(t)&&(nn(t)||Ft(t)||kt(t.splice)||en(t))?!t.length:!He(t).length}function Dt(t,e){return S(t,e)}function jt(t){return\"number\"==typeof t&&ze(t)}function kt(t){if(!Rt(t))return!1;var e=E(t);return e==ge||e==ve||e==de||e==Ee}function Lt(t){return\"number\"==typeof t&&t>-1&&t%1==0&&t<=he}function Rt(t){var e=typeof t;return null!=t&&(\"object\"==e||\"function\"==e)}function Mt(t){return null!=t&&\"object\"==typeof t}function Ut(t){return Pt(t)&&t!=+t}function qt(t){return null===t}function Pt(t){return\"number\"==typeof t||Mt(t)&&E(t)==be}function Ft(t){return\"string\"==typeof t||!nn(t)&&Mt(t)&&E(t)==xe}function Bt(t){return t===re}function Xt(t){return Nt(t)?t.length?R(t):[]:Gt(t)}function zt(t){return\"string\"==typeof t?t:null==t?\"\":t+\"\"}function Ht(t,e){var n=We(t);return null==e?n:un(n,e)}function Vt(t,e){return null!=t&&Ue.call(t,e)}function Wt(t,e,n){var r=null==t?re:t[e];return r===re&&(r=n),kt(r)?r.call(t):r}function Gt(t){return null==t?[]:c(t,hn(t))}function $t(t){return t=zt(t),t&&Ce.test(t)?t.replace(Se,Le):t}function Yt(t){return t}function Qt(t){return D(un({},t))}function Jt(t,e,n){var r=hn(e),o=w(e,r);null!=n||Rt(e)&&(o.length||!r.length)||(n=e,e=t,t=this,o=w(e,hn(e)));var s=!(Rt(n)&&\"chain\"in n&&!n.chain),a=kt(t);return Ge(o,function(n){var r=e[n];t[n]=r,a&&(t.prototype[n]=function(){var e=this.__chain__;if(s||e){var n=t(this.__wrapped__),o=n.__actions__=R(this.__actions__);return o.push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.apply(t,i([this.value()],arguments))})}),t}function Kt(){return De._===this&&(De._=Fe),this}function Zt(){}function te(t){var e=++qe;return zt(t)+e}function ee(t){return t&&t.length?_(t,Yt,T):re}function ne(t){return t&&t.length?_(t,Yt,O):re}var re,ie=\"4.17.14\",oe=\"Expected a function\",se=1,ae=2,ue=1,ce=32,le=1/0,he=9007199254740991,pe=\"[object Arguments]\",fe=\"[object Array]\",de=\"[object AsyncFunction]\",ye=\"[object Boolean]\",me=\"[object Date]\",_e=\"[object Error]\",ge=\"[object Function]\",ve=\"[object GeneratorFunction]\",be=\"[object Number]\",we=\"[object Object]\",Ee=\"[object Proxy]\",Te=\"[object RegExp]\",xe=\"[object String]\",Se=/[&<>\"']/g,Ce=RegExp(Se.source),Ie=/^(?:0|[1-9]\\d*)$/,Ne={\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#39;\"},Oe=\"object\"==typeof e&&e&&e.Object===Object&&e,Ae=\"object\"==typeof self&&self&&self.Object===Object&&self,De=Oe||Ae||Function(\"return this\")(),je=\"object\"==typeof r&&r&&!r.nodeType&&r,ke=je&&\"object\"==typeof n&&n&&!n.nodeType&&n,Le=a(Ne),Re=Array.prototype,Me=Object.prototype,Ue=Me.hasOwnProperty,qe=0,Pe=Me.toString,Fe=De._,Be=Object.create,Xe=Me.propertyIsEnumerable,ze=De.isFinite,He=l(Object.keys,Object),Ve=Math.max,We=function(){function t(){}return function(e){if(!Rt(e))return{};if(Be)return Be(e);t.prototype=e;var n=new t;return t.prototype=re,n}}();p.prototype=We(h.prototype),p.prototype.constructor=p;var Ge=B(b),$e=X(),Ye=Zt,Qe=Yt,Je=H(it),Ke=k(function(t,e,n){return V(t,ue|ce,e,n)}),Ze=k(function(t,e){return y(t,1,e)}),tn=k(function(t,e,n){return y(t,an(e)||0,n)}),en=Ye(function(){return arguments}())?Ye:function(t){return Mt(t)&&Ue.call(t,\"callee\")&&!Xe.call(t,\"callee\")},nn=Array.isArray,rn=x,on=I,sn=Number,an=Number,un=F(function(t,e){P(e,He(e),t)}),cn=F(function(t,e){P(e,Z(e),t)}),ln=k(function(t,e){t=Object(t);var n=-1,r=e.length,i=r>2?e[2]:re;for(i&&K(e[0],e[1],i)&&(r=1);++n<r;)for(var o=e[n],s=pn(o),a=-1,u=s.length;++a<u;){var c=s[a],l=t[c];(l===re||It(l,Me[c])&&!Ue.call(t,c))&&(t[c]=o[c])}return t}),hn=He,pn=Z,fn=Y(function(t,e){return null==t?{}:j(t,e)}),dn=N;h.assignIn=cn,h.before=Tt,h.bind=Ke,h.chain=ht,h.compact=nt,h.concat=rt,h.create=Ht,h.defaults=ln,h.defer=Ze,h.delay=tn,h.filter=mt,h.flatten=ot,h.flattenDeep=st,h.iteratee=dn,h.keys=hn,h.map=gt,h.matches=Qt,h.mixin=Jt,h.negate=xt,h.once=St,h.pick=fn,h.slice=lt,h.sortBy=Et,h.tap=pt,h.thru=ft,h.toArray=Xt,h.values=Gt,h.extend=cn,Jt(h,h),h.clone=Ct,h.escape=$t,h.every=yt,h.find=Je,h.forEach=_t,h.has=Vt,h.head=at,h.identity=Yt,h.indexOf=ut,h.isArguments=en,h.isArray=nn,h.isBoolean=Ot,h.isDate=rn,h.isEmpty=At,h.isEqual=Dt,h.isFinite=jt,h.isFunction=kt,h.isNaN=Ut,h.isNull=qt,h.isNumber=Pt,h.isObject=Rt,h.isRegExp=on,h.isString=Ft,h.isUndefined=Bt,h.last=ct,h.max=ee,h.min=ne,h.noConflict=Kt,h.noop=Zt,h.reduce=vt,h.result=Wt,h.size=bt,h.some=wt,h.uniqueId=te,h.each=_t,h.first=at,Jt(h,function(){var t={};return b(h,function(e,n){Ue.call(h.prototype,n)||(t[n]=e)}),t}(),{chain:!1}),h.VERSION=ie,Ge([\"pop\",\"join\",\"replace\",\"reverse\",\"split\",\"push\",\"shift\",\"sort\",\"splice\",\"unshift\"],function(t){var e=(/^(?:replace|split)$/.test(t)?String.prototype:Re)[t],n=/^(?:push|sort|unshift)$/.test(t)?\"tap\":\"thru\",r=/^(?:pop|join|replace|shift)$/.test(t);h.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return e.apply(nn(i)?i:[],t)}return this[n](function(n){return e.apply(nn(n)?n:[],t)})}}),h.prototype.toJSON=h.prototype.valueOf=h.prototype.value=dt,\"function\"==typeof t&&\"object\"==typeof t.amd&&t.amd?(De._=h,t(function(){return h})):ke?((ke.exports=h)._=h,je._=h):De._=h}).call(this)}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],89:[function(t,e,n){function r(t,e){var n=this;return n instanceof r?(u.Readable.call(n,e),n.destroyed=!1,n._drained=!1,n._forwarding=!1,n._current=null,n._toStreams2=e&&e.objectMode?i:o,\"function\"==typeof t?n._queue=t:(n._queue=t.map(n._toStreams2),n._queue.forEach(function(t){\"function\"!=typeof t&&n._attachErrorListener(t)})),void n._next()):new r(t,e)}function i(t){return s(t,{objectMode:!0,highWaterMark:16})}function o(t){return s(t)}function s(t,e){if(!t||\"function\"==typeof t||t._readableState)return t;var n=new u.Readable(e).wrap(t);return t.destroy&&(n.destroy=t.destroy.bind(t)),n}e.exports=r;var a=t(\"inherits\"),u=t(\"readable-stream\");a(r,u.Readable),r.obj=function(t){return new r(t,{objectMode:!0,highWaterMark:16})},r.prototype._read=function(){this._drained=!0,this._forward()},r.prototype._forward=function(){if(!this._forwarding&&this._drained&&this._current){this._forwarding=!0;for(var t;null!==(t=this._current.read());)this._drained=this.push(t);this._forwarding=!1}},r.prototype.destroy=function(t){this.destroyed||(this.destroyed=!0,this._current&&this._current.destroy&&this._current.destroy(),\"function\"!=typeof this._queue&&this._queue.forEach(function(t){t.destroy&&t.destroy()}),t&&this.emit(\"error\",t),this.emit(\"close\"))},r.prototype._next=function(){var t=this;if(t._current=null,\"function\"==typeof t._queue)t._queue(function(e,n){return e?t.destroy(e):(n=t._toStreams2(n),t._attachErrorListener(n),void t._gotNextStream(n))});else{var e=t._queue.shift();\"function\"==typeof e&&(e=t._toStreams2(e()),t._attachErrorListener(e)),t._gotNextStream(e)}},r.prototype._gotNextStream=function(t){function e(){i._forward()}function n(){t._readableState.ended||i.destroy()}function r(){i._current=null,t.removeListener(\"readable\",e),t.removeListener(\"end\",r),t.removeListener(\"close\",n),i._next()}var i=this;return t?(i._current=t,i._forward(),t.on(\"readable\",e),t.once(\"end\",r),void t.once(\"close\",n)):(i.push(null),void i.destroy())},r.prototype._attachErrorListener=function(t){function e(r){t.removeListener(\"error\",e),n.destroy(r)}var n=this;t&&t.once(\"error\",e)}},{inherits:84,\"readable-stream\":107}],90:[function(t,e,n){(function(t){\"use strict\";function n(e,n,r,i){if(\"function\"!=typeof e)throw new TypeError('\"callback\" argument must be a function');var o,s,a=arguments.length;switch(a){case 0:case 1:return t.nextTick(e);case 2:return t.nextTick(function(){e.call(null,n)});case 3:return t.nextTick(function(){e.call(null,n,r)});case 4:return t.nextTick(function(){e.call(null,n,r,i)});default:for(o=new Array(a-1),s=0;s<o.length;)o[s++]=arguments[s];return t.nextTick(function(){e.apply(null,o)})}}!t.version||0===t.version.indexOf(\"v0.\")||0===t.version.indexOf(\"v1.\")&&0!==t.version.indexOf(\"v1.8.\")?e.exports={nextTick:n}:e.exports=t}).call(this,t(\"_process\"))},{_process:91}],91:[function(t,e,n){function r(){throw new Error(\"setTimeout has not been defined\")}function i(){throw new Error(\"clearTimeout has not been defined\")}function o(t){if(h===setTimeout)return setTimeout(t,0);if((h===r||!h)&&setTimeout)return h=setTimeout,setTimeout(t,0);try{return h(t,0)}catch(e){try{return h.call(null,t,0)}catch(e){return h.call(this,t,0)}}}function s(t){if(p===clearTimeout)return clearTimeout(t);if((p===i||!p)&&clearTimeout)return p=clearTimeout,clearTimeout(t);try{return p(t)}catch(e){try{return p.call(null,t)}catch(e){return p.call(this,t)}}}function a(){m&&d&&(m=!1,d.length?y=d.concat(y):_=-1,y.length&&u())}function u(){if(!m){var t=o(a);m=!0;for(var e=y.length;e;){for(d=y,y=[];++_<e;)d&&d[_].run();_=-1,e=y.length}d=null,m=!1,s(t)}}function c(t,e){this.fun=t,this.array=e}function l(){}var h,p,f=e.exports={};!function(){try{h=\"function\"==typeof setTimeout?setTimeout:r}catch(t){h=r}try{p=\"function\"==typeof clearTimeout?clearTimeout:i}catch(t){p=i}}();var d,y=[],m=!1,_=-1;f.nextTick=function(t){var e=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)e[n-1]=arguments[n];y.push(new c(t,e)),1!==y.length||m||o(u)},c.prototype.run=function(){this.fun.apply(null,this.array)},f.title=\"browser\",f.browser=!0,f.env={},f.argv=[],f.version=\"\",f.versions={},f.on=l,f.addListener=l,f.once=l,f.off=l,f.removeListener=l,f.removeAllListeners=l,f.emit=l,f.prependListener=l,f.prependOnceListener=l,f.listeners=function(t){return[]},f.binding=function(t){throw new Error(\"process.binding is not supported\")},f.cwd=function(){return\"/\"},f.chdir=function(t){throw new Error(\"process.chdir is not supported\")},f.umask=function(){return 0}},{}],92:[function(t,e,n){\"use strict\";function r(){}function i(t){try{return t.then}catch(e){return _=e,g}}function o(t,e){try{return t(e)}catch(n){return _=n,g}}function s(t,e,n){try{t(e,n)}catch(r){return _=r,g}}function a(t){if(\"object\"!=typeof this)throw new TypeError(\"Promises must be constructed via new\");if(\"function\"!=typeof t)throw new TypeError(\"Promise constructor's argument is not a function\");this._40=0,this._65=0,this._55=null,this._72=null,t!==r&&y(t,this)}function u(t,e,n){return new t.constructor(function(i,o){var s=new a(r);s.then(i,o),c(t,new d(e,n,s))})}function c(t,e){for(;3===t._65;)t=t._55;return a._37&&a._37(t),0===t._65?0===t._40?(t._40=1,void(t._72=e)):1===t._40?(t._40=2,void(t._72=[t._72,e])):void t._72.push(e):void l(t,e)}function l(t,e){m(function(){var n=1===t._65?e.onFulfilled:e.onRejected;if(null===n)return void(1===t._65?h(e.promise,t._55):p(e.promise,t._55));var r=o(n,t._55);r===g?p(e.promise,_):h(e.promise,r)})}function h(t,e){if(e===t)return p(t,new TypeError(\"A promise cannot be resolved with itself.\"));if(e&&(\"object\"==typeof e||\"function\"==typeof e)){var n=i(e);if(n===g)return p(t,_);if(n===t.then&&e instanceof a)return t._65=3,t._55=e,void f(t);if(\"function\"==typeof n)return void y(n.bind(e),t)}t._65=1,t._55=e,f(t)}function p(t,e){t._65=2,t._55=e,a._87&&a._87(t,e),f(t)}function f(t){if(1===t._40&&(c(t,t._72),t._72=null),2===t._40){for(var e=0;e<t._72.length;e++)c(t,t._72[e]);t._72=null}}function d(t,e,n){this.onFulfilled=\"function\"==typeof t?t:null,this.onRejected=\"function\"==typeof e?e:null,this.promise=n}function y(t,e){var n=!1,r=s(t,function(t){n||(n=!0,h(e,t))},function(t){n||(n=!0,p(e,t))});n||r!==g||(n=!0,p(e,_))}var m=t(\"asap/raw\"),_=null,g={};e.exports=a,a._37=null,a._87=null,a._61=r,a.prototype.then=function(t,e){if(this.constructor!==a)return u(this,t,e);var n=new a(r);return c(this,new d(t,e,n)),n}},{\"asap/raw\":38}],93:[function(t,e,n){\"use strict\";function r(t){var e=new i(i._61);return e._65=1,e._55=t,e}var i=t(\"./core.js\");e.exports=i;var o=r(!0),s=r(!1),a=r(null),u=r(void 0),c=r(0),l=r(\"\");i.resolve=function(t){if(t instanceof i)return t;if(null===t)return a;if(void 0===t)return u;if(t===!0)return o;if(t===!1)return s;if(0===t)return c;if(\"\"===t)return l;if(\"object\"==typeof t||\"function\"==typeof t)try{var e=t.then;if(\"function\"==typeof e)return new i(e.bind(t))}catch(n){return new i(function(t,e){e(n)})}return r(t)},i.all=function(t){var e=Array.prototype.slice.call(t);return new i(function(t,n){function r(s,a){if(a&&(\"object\"==typeof a||\"function\"==typeof a)){if(a instanceof i&&a.then===i.prototype.then){for(;3===a._65;)a=a._55;return 1===a._65?r(s,a._55):(2===a._65&&n(a._55),void a.then(function(t){r(s,t)},n))}var u=a.then;if(\"function\"==typeof u){var c=new i(u.bind(a));return void c.then(function(t){r(s,t)},n)}}e[s]=a,0===--o&&t(e)}if(0===e.length)return t([]);for(var o=e.length,s=0;s<e.length;s++)r(s,e[s])})},i.reject=function(t){return new i(function(e,n){n(t)})},i.race=function(t){return new i(function(e,n){t.forEach(function(t){i.resolve(t).then(e,n)})})},i.prototype[\"catch\"]=function(t){return this.then(null,t)}},{\"./core.js\":92}],94:[function(t,e,n){\"use strict\";function r(t,e){return Object.prototype.hasOwnProperty.call(t,e)}e.exports=function(t,e,n,o){e=e||\"&\",n=n||\"=\";var s={};if(\"string\"!=typeof t||0===t.length)return s;var a=/\\+/g;t=t.split(e);var u=1e3;o&&\"number\"==typeof o.maxKeys&&(u=o.maxKeys);var c=t.length;u>0&&c>u&&(c=u);for(var l=0;l<c;++l){var h,p,f,d,y=t[l].replace(a,\"%20\"),m=y.indexOf(n);m>=0?(h=y.substr(0,m),p=y.substr(m+1)):(h=y,p=\"\"),f=decodeURIComponent(h),d=decodeURIComponent(p),r(s,f)?i(s[f])?s[f].push(d):s[f]=[s[f],d]:s[f]=d}return s};var i=Array.isArray||function(t){return\"[object Array]\"===Object.prototype.toString.call(t)}},{}],95:[function(t,e,n){\"use strict\";function r(t,e){if(t.map)return t.map(e);for(var n=[],r=0;r<t.length;r++)n.push(e(t[r],r));return n}var i=function(t){switch(typeof t){case\"string\":return t;case\"boolean\":return t?\"true\":\"false\";case\"number\":return isFinite(t)?t:\"\";default:return\"\"}};e.exports=function(t,e,n,a){return e=e||\"&\",n=n||\"=\",null===t&&(t=void 0),\"object\"==typeof t?r(s(t),function(s){var a=encodeURIComponent(i(s))+n;return o(t[s])?r(t[s],function(t){return a+encodeURIComponent(i(t))}).join(e):a+encodeURIComponent(i(t[s]))}).join(e):a?encodeURIComponent(i(a))+n+encodeURIComponent(i(t)):\"\"};var o=Array.isArray||function(t){return\"[object Array]\"===Object.prototype.toString.call(t)},s=Object.keys||function(t){var e=[];for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e.push(n);return e}},{}],96:[function(t,e,n){\"use strict\";n.decode=n.parse=t(\"./decode\"),n.encode=n.stringify=t(\"./encode\")},{\"./decode\":94,\"./encode\":95}],97:[function(t,e,n){e.exports=t(\"./lib/_stream_duplex.js\")},{\"./lib/_stream_duplex.js\":98}],98:[function(t,e,n){\"use strict\";function r(t){return this instanceof r?(c.call(this,t),l.call(this,t),t&&t.readable===!1&&(this.readable=!1),t&&t.writable===!1&&(this.writable=!1),this.allowHalfOpen=!0,t&&t.allowHalfOpen===!1&&(this.allowHalfOpen=!1),void this.once(\"end\",i)):new r(t)}function i(){this.allowHalfOpen||this._writableState.ended||s.nextTick(o,this)}function o(t){t.end()}var s=t(\"process-nextick-args\"),a=Object.keys||function(t){var e=[];for(var n in t)e.push(n);return e};e.exports=r;var u=t(\"core-util-is\");u.inherits=t(\"inherits\");var c=t(\"./_stream_readable\"),l=t(\"./_stream_writable\");u.inherits(r,c);for(var h=a(l.prototype),p=0;p<h.length;p++){var f=h[p];r.prototype[f]||(r.prototype[f]=l.prototype[f])}Object.defineProperty(r.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),Object.defineProperty(r.prototype,\"destroyed\",{get:function(){return void 0!==this._readableState&&void 0!==this._writableState&&(this._readableState.destroyed&&this._writableState.destroyed)},set:function(t){void 0!==this._readableState&&void 0!==this._writableState&&(this._readableState.destroyed=t,this._writableState.destroyed=t)}}),r.prototype._destroy=function(t,e){this.push(null),this.end(),s.nextTick(e,t)}},{\"./_stream_readable\":100,\"./_stream_writable\":102,\"core-util-is\":42,inherits:84,\"process-nextick-args\":90}],99:[function(t,e,n){\"use strict\";function r(t){return this instanceof r?void i.call(this,t):new r(t)}e.exports=r;var i=t(\"./_stream_transform\"),o=t(\"core-util-is\");o.inherits=t(\"inherits\"),o.inherits(r,i),r.prototype._transform=function(t,e,n){n(null,t)}},{\"./_stream_transform\":101,\"core-util-is\":42,inherits:84}],100:[function(t,e,n){(function(n,r){\"use strict\";function i(t){return U.from(t)}function o(t){return U.isBuffer(t)||t instanceof q}function s(t,e,n){return\"function\"==typeof t.prependListener?t.prependListener(e,n):void(t._events&&t._events[e]?L(t._events[e])?t._events[e].unshift(n):t._events[e]=[n,t._events[e]]:t.on(e,n))}function a(e,n){k=k||t(\"./_stream_duplex\"),e=e||{};var r=n instanceof k;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var i=e.highWaterMark,o=e.readableHighWaterMark,s=this.objectMode?16:16384;i||0===i?this.highWaterMark=i:r&&(o||0===o)?this.highWaterMark=o:this.highWaterMark=s,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new z,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||\"utf8\",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(X||(X=t(\"string_decoder/\").StringDecoder),this.decoder=new X(e.encoding),this.encoding=e.encoding)}function u(e){return k=k||t(\"./_stream_duplex\"),this instanceof u?(this._readableState=new a(e,this),this.readable=!0,e&&(\"function\"==typeof e.read&&(this._read=e.read),\"function\"==typeof e.destroy&&(this._destroy=e.destroy)),void M.call(this)):new u(e)}function c(t,e,n,r,o){var s=t._readableState;if(null===e)s.reading=!1,y(t,s);else{var a;o||(a=h(s,e)),a?t.emit(\"error\",a):s.objectMode||e&&e.length>0?(\"string\"==typeof e||s.objectMode||Object.getPrototypeOf(e)===U.prototype||(e=i(e)),r?s.endEmitted?t.emit(\"error\",new Error(\"stream.unshift() after end event\")):l(t,s,e,!0):s.ended?t.emit(\"error\",new Error(\"stream.push() after EOF\")):(s.reading=!1,s.decoder&&!n?(e=s.decoder.write(e),s.objectMode||0!==e.length?l(t,s,e,!1):g(t,s)):l(t,s,e,!1))):r||(s.reading=!1)}return p(s)}function l(t,e,n,r){e.flowing&&0===e.length&&!e.sync?(t.emit(\"data\",n),t.read(0)):(e.length+=e.objectMode?1:n.length,r?e.buffer.unshift(n):e.buffer.push(n),e.needReadable&&m(t)),g(t,e)}function h(t,e){var n;return o(e)||\"string\"==typeof e||void 0===e||t.objectMode||(n=new TypeError(\"Invalid non-string/buffer chunk\")),n}function p(t){return!t.ended&&(t.needReadable||t.length<t.highWaterMark||0===t.length)}function f(t){return t>=W?t=W:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function d(t,e){return t<=0||0===e.length&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=f(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}function y(t,e){if(!e.ended){if(e.decoder){var n=e.decoder.end();n&&n.length&&(e.buffer.push(n),e.length+=e.objectMode?1:n.length)}e.ended=!0,m(t)}}function m(t){var e=t._readableState;e.needReadable=!1,e.emittedReadable||(B(\"emitReadable\",e.flowing),e.emittedReadable=!0,e.sync?j.nextTick(_,t):_(t))}function _(t){B(\"emit readable\"),t.emit(\"readable\"),x(t)}function g(t,e){e.readingMore||(e.readingMore=!0,j.nextTick(v,t,e))}function v(t,e){for(var n=e.length;!e.reading&&!e.flowing&&!e.ended&&e.length<e.highWaterMark&&(B(\"maybeReadMore read 0\"),t.read(0),n!==e.length);)n=e.length;e.readingMore=!1}function b(t){return function(){var e=t._readableState;B(\"pipeOnDrain\",e.awaitDrain),e.awaitDrain&&e.awaitDrain--,0===e.awaitDrain&&R(t,\"data\")&&(e.flowing=!0,x(t))}}function w(t){B(\"readable nexttick read 0\"),t.read(0)}function E(t,e){e.resumeScheduled||(e.resumeScheduled=!0,j.nextTick(T,t,e))}function T(t,e){e.reading||(B(\"resume read 0\"),t.read(0)),e.resumeScheduled=!1,e.awaitDrain=0,t.emit(\"resume\"),x(t),e.flowing&&!e.reading&&t.read(0)}function x(t){var e=t._readableState;for(B(\"flow\",e.flowing);e.flowing&&null!==t.read(););}function S(t,e){if(0===e.length)return null;var n;return e.objectMode?n=e.buffer.shift():!t||t>=e.length?(n=e.decoder?e.buffer.join(\"\"):1===e.buffer.length?e.buffer.head.data:e.buffer.concat(e.length),e.buffer.clear()):n=C(t,e.buffer,e.decoder),n}function C(t,e,n){var r;return t<e.head.data.length?(r=e.head.data.slice(0,t),e.head.data=e.head.data.slice(t)):r=t===e.head.data.length?e.shift():n?I(t,e):N(t,e),r}function I(t,e){var n=e.head,r=1,i=n.data;for(t-=i.length;n=n.next;){var o=n.data,s=t>o.length?o.length:t;if(i+=s===o.length?o:o.slice(0,t),t-=s,0===t){s===o.length?(++r,n.next?e.head=n.next:e.head=e.tail=null):(e.head=n,n.data=o.slice(s));break}++r}return e.length-=r,i}function N(t,e){\nvar n=U.allocUnsafe(t),r=e.head,i=1;for(r.data.copy(n),t-=r.data.length;r=r.next;){var o=r.data,s=t>o.length?o.length:t;if(o.copy(n,n.length-t,0,s),t-=s,0===t){s===o.length?(++i,r.next?e.head=r.next:e.head=e.tail=null):(e.head=r,r.data=o.slice(s));break}++i}return e.length-=i,n}function O(t){var e=t._readableState;if(e.length>0)throw new Error('\"endReadable()\" called on non-empty stream');e.endEmitted||(e.ended=!0,j.nextTick(A,e,t))}function A(t,e){t.endEmitted||0!==t.length||(t.endEmitted=!0,e.readable=!1,e.emit(\"end\"))}function D(t,e){for(var n=0,r=t.length;n<r;n++)if(t[n]===e)return n;return-1}var j=t(\"process-nextick-args\");e.exports=u;var k,L=t(\"isarray\");u.ReadableState=a;var R=(t(\"events\").EventEmitter,function(t,e){return t.listeners(e).length}),M=t(\"./internal/streams/stream\"),U=t(\"safe-buffer\").Buffer,q=r.Uint8Array||function(){},P=t(\"core-util-is\");P.inherits=t(\"inherits\");var F=t(\"util\"),B=void 0;B=F&&F.debuglog?F.debuglog(\"stream\"):function(){};var X,z=t(\"./internal/streams/BufferList\"),H=t(\"./internal/streams/destroy\");P.inherits(u,M);var V=[\"error\",\"close\",\"destroy\",\"pause\",\"resume\"];Object.defineProperty(u.prototype,\"destroyed\",{get:function(){return void 0!==this._readableState&&this._readableState.destroyed},set:function(t){this._readableState&&(this._readableState.destroyed=t)}}),u.prototype.destroy=H.destroy,u.prototype._undestroy=H.undestroy,u.prototype._destroy=function(t,e){this.push(null),e(t)},u.prototype.push=function(t,e){var n,r=this._readableState;return r.objectMode?n=!0:\"string\"==typeof t&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=U.from(t,e),e=\"\"),n=!0),c(this,t,e,!1,n)},u.prototype.unshift=function(t){return c(this,t,null,!0,!1)},u.prototype.isPaused=function(){return this._readableState.flowing===!1},u.prototype.setEncoding=function(e){return X||(X=t(\"string_decoder/\").StringDecoder),this._readableState.decoder=new X(e),this._readableState.encoding=e,this};var W=8388608;u.prototype.read=function(t){B(\"read\",t),t=parseInt(t,10);var e=this._readableState,n=t;if(0!==t&&(e.emittedReadable=!1),0===t&&e.needReadable&&(e.length>=e.highWaterMark||e.ended))return B(\"read: emitReadable\",e.length,e.ended),0===e.length&&e.ended?O(this):m(this),null;if(t=d(t,e),0===t&&e.ended)return 0===e.length&&O(this),null;var r=e.needReadable;B(\"need readable\",r),(0===e.length||e.length-t<e.highWaterMark)&&(r=!0,B(\"length less than watermark\",r)),e.ended||e.reading?(r=!1,B(\"reading or ended\",r)):r&&(B(\"do read\"),e.reading=!0,e.sync=!0,0===e.length&&(e.needReadable=!0),this._read(e.highWaterMark),e.sync=!1,e.reading||(t=d(n,e)));var i;return i=t>0?S(t,e):null,null===i?(e.needReadable=!0,t=0):e.length-=t,0===e.length&&(e.ended||(e.needReadable=!0),n!==t&&e.ended&&O(this)),null!==i&&this.emit(\"data\",i),i},u.prototype._read=function(t){this.emit(\"error\",new Error(\"_read() is not implemented\"))},u.prototype.pipe=function(t,e){function r(t,e){B(\"onunpipe\"),t===p&&e&&e.hasUnpiped===!1&&(e.hasUnpiped=!0,o())}function i(){B(\"onend\"),t.end()}function o(){B(\"cleanup\"),t.removeListener(\"close\",c),t.removeListener(\"finish\",l),t.removeListener(\"drain\",m),t.removeListener(\"error\",u),t.removeListener(\"unpipe\",r),p.removeListener(\"end\",i),p.removeListener(\"end\",h),p.removeListener(\"data\",a),_=!0,!f.awaitDrain||t._writableState&&!t._writableState.needDrain||m()}function a(e){B(\"ondata\"),g=!1;var n=t.write(e);!1!==n||g||((1===f.pipesCount&&f.pipes===t||f.pipesCount>1&&D(f.pipes,t)!==-1)&&!_&&(B(\"false write response, pause\",p._readableState.awaitDrain),p._readableState.awaitDrain++,g=!0),p.pause())}function u(e){B(\"onerror\",e),h(),t.removeListener(\"error\",u),0===R(t,\"error\")&&t.emit(\"error\",e)}function c(){t.removeListener(\"finish\",l),h()}function l(){B(\"onfinish\"),t.removeListener(\"close\",c),h()}function h(){B(\"unpipe\"),p.unpipe(t)}var p=this,f=this._readableState;switch(f.pipesCount){case 0:f.pipes=t;break;case 1:f.pipes=[f.pipes,t];break;default:f.pipes.push(t)}f.pipesCount+=1,B(\"pipe count=%d opts=%j\",f.pipesCount,e);var d=(!e||e.end!==!1)&&t!==n.stdout&&t!==n.stderr,y=d?i:h;f.endEmitted?j.nextTick(y):p.once(\"end\",y),t.on(\"unpipe\",r);var m=b(p);t.on(\"drain\",m);var _=!1,g=!1;return p.on(\"data\",a),s(t,\"error\",u),t.once(\"close\",c),t.once(\"finish\",l),t.emit(\"pipe\",p),f.flowing||(B(\"pipe resume\"),p.resume()),t},u.prototype.unpipe=function(t){var e=this._readableState,n={hasUnpiped:!1};if(0===e.pipesCount)return this;if(1===e.pipesCount)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit(\"unpipe\",this,n),this);if(!t){var r=e.pipes,i=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var o=0;o<i;o++)r[o].emit(\"unpipe\",this,n);return this}var s=D(e.pipes,t);return s===-1?this:(e.pipes.splice(s,1),e.pipesCount-=1,1===e.pipesCount&&(e.pipes=e.pipes[0]),t.emit(\"unpipe\",this,n),this)},u.prototype.on=function(t,e){var n=M.prototype.on.call(this,t,e);if(\"data\"===t)this._readableState.flowing!==!1&&this.resume();else if(\"readable\"===t){var r=this._readableState;r.endEmitted||r.readableListening||(r.readableListening=r.needReadable=!0,r.emittedReadable=!1,r.reading?r.length&&m(this):j.nextTick(w,this))}return n},u.prototype.addListener=u.prototype.on,u.prototype.resume=function(){var t=this._readableState;return t.flowing||(B(\"resume\"),t.flowing=!0,E(this,t)),this},u.prototype.pause=function(){return B(\"call pause flowing=%j\",this._readableState.flowing),!1!==this._readableState.flowing&&(B(\"pause\"),this._readableState.flowing=!1,this.emit(\"pause\")),this},u.prototype.wrap=function(t){var e=this,n=this._readableState,r=!1;t.on(\"end\",function(){if(B(\"wrapped end\"),n.decoder&&!n.ended){var t=n.decoder.end();t&&t.length&&e.push(t)}e.push(null)}),t.on(\"data\",function(i){if(B(\"wrapped data\"),n.decoder&&(i=n.decoder.write(i)),(!n.objectMode||null!==i&&void 0!==i)&&(n.objectMode||i&&i.length)){var o=e.push(i);o||(r=!0,t.pause())}});for(var i in t)void 0===this[i]&&\"function\"==typeof t[i]&&(this[i]=function(e){return function(){return t[e].apply(t,arguments)}}(i));for(var o=0;o<V.length;o++)t.on(V[o],this.emit.bind(this,V[o]));return this._read=function(e){B(\"wrapped _read\",e),r&&(r=!1,t.resume())},this},Object.defineProperty(u.prototype,\"readableHighWaterMark\",{enumerable:!1,get:function(){return this._readableState.highWaterMark}}),u._fromList=S}).call(this,t(\"_process\"),\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"./_stream_duplex\":98,\"./internal/streams/BufferList\":103,\"./internal/streams/destroy\":104,\"./internal/streams/stream\":105,_process:91,\"core-util-is\":42,events:47,inherits:84,isarray:86,\"process-nextick-args\":90,\"safe-buffer\":110,\"string_decoder/\":113,util:40}],101:[function(t,e,n){\"use strict\";function r(t,e){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit(\"error\",new Error(\"write callback called multiple times\"));n.writechunk=null,n.writecb=null,null!=e&&this.push(e),r(t);var i=this._readableState;i.reading=!1,(i.needReadable||i.length<i.highWaterMark)&&this._read(i.highWaterMark)}function i(t){return this instanceof i?(a.call(this,t),this._transformState={afterTransform:r.bind(this),needTransform:!1,transforming:!1,writecb:null,writechunk:null,writeencoding:null},this._readableState.needReadable=!0,this._readableState.sync=!1,t&&(\"function\"==typeof t.transform&&(this._transform=t.transform),\"function\"==typeof t.flush&&(this._flush=t.flush)),void this.on(\"prefinish\",o)):new i(t)}function o(){var t=this;\"function\"==typeof this._flush?this._flush(function(e,n){s(t,e,n)}):s(this,null,null)}function s(t,e,n){if(e)return t.emit(\"error\",e);if(null!=n&&t.push(n),t._writableState.length)throw new Error(\"Calling transform done when ws.length != 0\");if(t._transformState.transforming)throw new Error(\"Calling transform done when still transforming\");return t.push(null)}e.exports=i;var a=t(\"./_stream_duplex\"),u=t(\"core-util-is\");u.inherits=t(\"inherits\"),u.inherits(i,a),i.prototype.push=function(t,e){return this._transformState.needTransform=!1,a.prototype.push.call(this,t,e)},i.prototype._transform=function(t,e,n){throw new Error(\"_transform() is not implemented\")},i.prototype._write=function(t,e,n){var r=this._transformState;if(r.writecb=n,r.writechunk=t,r.writeencoding=e,!r.transforming){var i=this._readableState;(r.needTransform||i.needReadable||i.length<i.highWaterMark)&&this._read(i.highWaterMark)}},i.prototype._read=function(t){var e=this._transformState;null!==e.writechunk&&e.writecb&&!e.transforming?(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform)):e.needTransform=!0},i.prototype._destroy=function(t,e){var n=this;a.prototype._destroy.call(this,t,function(t){e(t),n.emit(\"close\")})}},{\"./_stream_duplex\":98,\"core-util-is\":42,inherits:84}],102:[function(t,e,n){(function(n,r,i){\"use strict\";function o(t){var e=this;this.next=null,this.entry=null,this.finish=function(){I(e,t)}}function s(t){return L.from(t)}function a(t){return L.isBuffer(t)||t instanceof R}function u(){}function c(e,n){O=O||t(\"./_stream_duplex\"),e=e||{};var r=n instanceof O;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var i=e.highWaterMark,s=e.writableHighWaterMark,a=this.objectMode?16:16384;i||0===i?this.highWaterMark=i:r&&(s||0===s)?this.highWaterMark=s:this.highWaterMark=a,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var u=e.decodeStrings===!1;this.decodeStrings=!u,this.defaultEncoding=e.defaultEncoding||\"utf8\",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(t){g(n,t)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new o(this)}function l(e){return O=O||t(\"./_stream_duplex\"),U.call(l,this)||this instanceof O?(this._writableState=new c(e,this),this.writable=!0,e&&(\"function\"==typeof e.write&&(this._write=e.write),\"function\"==typeof e.writev&&(this._writev=e.writev),\"function\"==typeof e.destroy&&(this._destroy=e.destroy),\"function\"==typeof e[\"final\"]&&(this._final=e[\"final\"])),void k.call(this)):new l(e)}function h(t,e){var n=new Error(\"write after end\");t.emit(\"error\",n),N.nextTick(e,n)}function p(t,e,n,r){var i=!0,o=!1;return null===n?o=new TypeError(\"May not write null values to stream\"):\"string\"==typeof n||void 0===n||e.objectMode||(o=new TypeError(\"Invalid non-string/buffer chunk\")),o&&(t.emit(\"error\",o),N.nextTick(r,o),i=!1),i}function f(t,e,n){return t.objectMode||t.decodeStrings===!1||\"string\"!=typeof e||(e=L.from(e,n)),e}function d(t,e,n,r,i,o){if(!n){var s=f(e,r,i);r!==s&&(n=!0,i=\"buffer\",r=s)}var a=e.objectMode?1:r.length;e.length+=a;var u=e.length<e.highWaterMark;if(u||(e.needDrain=!0),e.writing||e.corked){var c=e.lastBufferedRequest;e.lastBufferedRequest={chunk:r,encoding:i,isBuf:n,callback:o,next:null},c?c.next=e.lastBufferedRequest:e.bufferedRequest=e.lastBufferedRequest,e.bufferedRequestCount+=1}else y(t,e,!1,a,r,i,o);return u}function y(t,e,n,r,i,o,s){e.writelen=r,e.writecb=s,e.writing=!0,e.sync=!0,n?t._writev(i,e.onwrite):t._write(i,o,e.onwrite),e.sync=!1}function m(t,e,n,r,i){--e.pendingcb,n?(N.nextTick(i,r),N.nextTick(S,t,e),t._writableState.errorEmitted=!0,t.emit(\"error\",r)):(i(r),t._writableState.errorEmitted=!0,t.emit(\"error\",r),S(t,e))}function _(t){t.writing=!1,t.writecb=null,t.length-=t.writelen,t.writelen=0}function g(t,e){var n=t._writableState,r=n.sync,i=n.writecb;if(_(n),e)m(t,n,r,e,i);else{var o=E(n);o||n.corked||n.bufferProcessing||!n.bufferedRequest||w(t,n),r?A(v,t,n,o,i):v(t,n,o,i)}}function v(t,e,n,r){n||b(t,e),e.pendingcb--,r(),S(t,e)}function b(t,e){0===e.length&&e.needDrain&&(e.needDrain=!1,t.emit(\"drain\"))}function w(t,e){e.bufferProcessing=!0;var n=e.bufferedRequest;if(t._writev&&n&&n.next){var r=e.bufferedRequestCount,i=new Array(r),s=e.corkedRequestsFree;s.entry=n;for(var a=0,u=!0;n;)i[a]=n,n.isBuf||(u=!1),n=n.next,a+=1;i.allBuffers=u,y(t,e,!0,e.length,i,\"\",s.finish),e.pendingcb++,e.lastBufferedRequest=null,s.next?(e.corkedRequestsFree=s.next,s.next=null):e.corkedRequestsFree=new o(e),e.bufferedRequestCount=0}else{for(;n;){var c=n.chunk,l=n.encoding,h=n.callback,p=e.objectMode?1:c.length;if(y(t,e,!1,p,c,l,h),n=n.next,e.bufferedRequestCount--,e.writing)break}null===n&&(e.lastBufferedRequest=null)}e.bufferedRequest=n,e.bufferProcessing=!1}function E(t){return t.ending&&0===t.length&&null===t.bufferedRequest&&!t.finished&&!t.writing}function T(t,e){t._final(function(n){e.pendingcb--,n&&t.emit(\"error\",n),e.prefinished=!0,t.emit(\"prefinish\"),S(t,e)})}function x(t,e){e.prefinished||e.finalCalled||(\"function\"==typeof t._final?(e.pendingcb++,e.finalCalled=!0,N.nextTick(T,t,e)):(e.prefinished=!0,t.emit(\"prefinish\")))}function S(t,e){var n=E(e);return n&&(x(t,e),0===e.pendingcb&&(e.finished=!0,t.emit(\"finish\"))),n}function C(t,e,n){e.ending=!0,S(t,e),n&&(e.finished?N.nextTick(n):t.once(\"finish\",n)),e.ended=!0,t.writable=!1}function I(t,e,n){var r=t.entry;for(t.entry=null;r;){var i=r.callback;e.pendingcb--,i(n),r=r.next}e.corkedRequestsFree?e.corkedRequestsFree.next=t:e.corkedRequestsFree=t}var N=t(\"process-nextick-args\");e.exports=l;var O,A=!n.browser&&[\"v0.10\",\"v0.9.\"].indexOf(n.version.slice(0,5))>-1?i:N.nextTick;l.WritableState=c;var D=t(\"core-util-is\");D.inherits=t(\"inherits\");var j={deprecate:t(\"util-deprecate\")},k=t(\"./internal/streams/stream\"),L=t(\"safe-buffer\").Buffer,R=r.Uint8Array||function(){},M=t(\"./internal/streams/destroy\");D.inherits(l,k),c.prototype.getBuffer=function(){for(var t=this.bufferedRequest,e=[];t;)e.push(t),t=t.next;return e},function(){try{Object.defineProperty(c.prototype,\"buffer\",{get:j.deprecate(function(){return this.getBuffer()},\"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.\",\"DEP0003\")})}catch(t){}}();var U;\"function\"==typeof Symbol&&Symbol.hasInstance&&\"function\"==typeof Function.prototype[Symbol.hasInstance]?(U=Function.prototype[Symbol.hasInstance],Object.defineProperty(l,Symbol.hasInstance,{value:function(t){return!!U.call(this,t)||this===l&&(t&&t._writableState instanceof c)}})):U=function(t){return t instanceof this},l.prototype.pipe=function(){this.emit(\"error\",new Error(\"Cannot pipe, not readable\"))},l.prototype.write=function(t,e,n){var r=this._writableState,i=!1,o=!r.objectMode&&a(t);return o&&!L.isBuffer(t)&&(t=s(t)),\"function\"==typeof e&&(n=e,e=null),o?e=\"buffer\":e||(e=r.defaultEncoding),\"function\"!=typeof n&&(n=u),r.ended?h(this,n):(o||p(this,r,t,n))&&(r.pendingcb++,i=d(this,r,o,t,e,n)),i},l.prototype.cork=function(){var t=this._writableState;t.corked++},l.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,t.writing||t.corked||t.finished||t.bufferProcessing||!t.bufferedRequest||w(this,t))},l.prototype.setDefaultEncoding=function(t){if(\"string\"==typeof t&&(t=t.toLowerCase()),!([\"hex\",\"utf8\",\"utf-8\",\"ascii\",\"binary\",\"base64\",\"ucs2\",\"ucs-2\",\"utf16le\",\"utf-16le\",\"raw\"].indexOf((t+\"\").toLowerCase())>-1))throw new TypeError(\"Unknown encoding: \"+t);return this._writableState.defaultEncoding=t,this},Object.defineProperty(l.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),l.prototype._write=function(t,e,n){n(new Error(\"_write() is not implemented\"))},l.prototype._writev=null,l.prototype.end=function(t,e,n){var r=this._writableState;\"function\"==typeof t?(n=t,t=null,e=null):\"function\"==typeof e&&(n=e,e=null),null!==t&&void 0!==t&&this.write(t,e),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||C(this,r,n)},Object.defineProperty(l.prototype,\"destroyed\",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(t){this._writableState&&(this._writableState.destroyed=t)}}),l.prototype.destroy=M.destroy,l.prototype._undestroy=M.undestroy,l.prototype._destroy=function(t,e){this.end(),e(t)}}).call(this,t(\"_process\"),\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},t(\"timers\").setImmediate)},{\"./_stream_duplex\":98,\"./internal/streams/destroy\":104,\"./internal/streams/stream\":105,_process:91,\"core-util-is\":42,inherits:84,\"process-nextick-args\":90,\"safe-buffer\":110,timers:114,\"util-deprecate\":115}],103:[function(t,e,n){\"use strict\";function r(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function i(t,e,n){t.copy(e,n)}var o=t(\"safe-buffer\").Buffer,s=t(\"util\");e.exports=function(){function t(){r(this,t),this.head=null,this.tail=null,this.length=0}return t.prototype.push=function(t){var e={data:t,next:null};this.length>0?this.tail.next=e:this.head=e,this.tail=e,++this.length},t.prototype.unshift=function(t){var e={data:t,next:this.head};0===this.length&&(this.tail=e),this.head=e,++this.length},t.prototype.shift=function(){if(0!==this.length){var t=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,t}},t.prototype.clear=function(){this.head=this.tail=null,this.length=0},t.prototype.join=function(t){if(0===this.length)return\"\";for(var e=this.head,n=\"\"+e.data;e=e.next;)n+=t+e.data;return n},t.prototype.concat=function(t){if(0===this.length)return o.alloc(0);if(1===this.length)return this.head.data;for(var e=o.allocUnsafe(t>>>0),n=this.head,r=0;n;)i(n.data,e,r),r+=n.data.length,n=n.next;return e},t}(),s&&s.inspect&&s.inspect.custom&&(e.exports.prototype[s.inspect.custom]=function(){var t=s.inspect({length:this.length});return this.constructor.name+\" \"+t})},{\"safe-buffer\":110,util:40}],104:[function(t,e,n){\"use strict\";function r(t,e){var n=this,r=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return r||i?(e?e(t):!t||this._writableState&&this._writableState.errorEmitted||s.nextTick(o,this,t),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(t){!e&&t?(s.nextTick(o,n,t),n._writableState&&(n._writableState.errorEmitted=!0)):e&&e(t)}),this)}function i(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function o(t,e){t.emit(\"error\",e)}var s=t(\"process-nextick-args\");e.exports={destroy:r,undestroy:i}},{\"process-nextick-args\":90}],105:[function(t,e,n){e.exports=t(\"events\").EventEmitter},{events:47}],106:[function(t,e,n){e.exports=t(\"./readable\").PassThrough},{\"./readable\":107}],107:[function(t,e,n){n=e.exports=t(\"./lib/_stream_readable.js\"),n.Stream=n,n.Readable=n,n.Writable=t(\"./lib/_stream_writable.js\"),n.Duplex=t(\"./lib/_stream_duplex.js\"),n.Transform=t(\"./lib/_stream_transform.js\"),n.PassThrough=t(\"./lib/_stream_passthrough.js\")},{\"./lib/_stream_duplex.js\":98,\"./lib/_stream_passthrough.js\":99,\"./lib/_stream_readable.js\":100,\"./lib/_stream_transform.js\":101,\"./lib/_stream_writable.js\":102}],108:[function(t,e,n){e.exports=t(\"./readable\").Transform},{\"./readable\":107}],109:[function(t,e,n){e.exports=t(\"./lib/_stream_writable.js\")},{\"./lib/_stream_writable.js\":102}],110:[function(t,e,n){function r(t,e){for(var n in t)e[n]=t[n]}function i(t,e,n){return s(t,e,n)}var o=t(\"buffer\"),s=o.Buffer;s.from&&s.alloc&&s.allocUnsafe&&s.allocUnsafeSlow?e.exports=o:(r(o,n),n.Buffer=i),r(s,i),i.from=function(t,e,n){if(\"number\"==typeof t)throw new TypeError(\"Argument must not be a number\");return s(t,e,n)},i.alloc=function(t,e,n){if(\"number\"!=typeof t)throw new TypeError(\"Argument must be a number\");var r=s(t);return void 0!==e?\"string\"==typeof n?r.fill(e,n):r.fill(e):r.fill(0),r},i.allocUnsafe=function(t){if(\"number\"!=typeof t)throw new TypeError(\"Argument must be a number\");return s(t)},i.allocUnsafeSlow=function(t){if(\"number\"!=typeof t)throw new TypeError(\"Argument must be a number\");return o.SlowBuffer(t)}},{buffer:41}],111:[function(t,e,n){(function(e){!function(n){function r(t,e){if(!(this instanceof r))return new r(t,e);var i=this;o(i),i.q=i.c=\"\",i.bufferCheckPosition=n.MAX_BUFFER_LENGTH,i.opt=e||{},i.opt.lowercase=i.opt.lowercase||i.opt.lowercasetags,i.looseCase=i.opt.lowercase?\"toLowerCase\":\"toUpperCase\",i.tags=[],i.closed=i.closedRoot=i.sawRoot=!1,i.tag=i.error=null,i.strict=!!t,i.noscript=!(!t&&!i.opt.noscript),i.state=z.BEGIN,i.strictEntities=i.opt.strictEntities,i.ENTITIES=i.strictEntities?Object.create(n.XML_ENTITIES):Object.create(n.ENTITIES),i.attribList=[],i.opt.xmlns&&(i.ns=Object.create(q)),i.trackPosition=i.opt.position!==!1,i.trackPosition&&(i.position=i.line=i.column=0),d(i,\"onready\")}function i(t){for(var e=Math.max(n.MAX_BUFFER_LENGTH,10),r=0,i=0,o=A.length;i<o;i++){var s=t[A[i]].length;if(s>e)switch(A[i]){case\"textNode\":m(t);break;case\"cdata\":y(t,\"oncdata\",t.cdata),t.cdata=\"\";break;case\"script\":y(t,\"onscript\",t.script),t.script=\"\";break;default:g(t,\"Max buffer length exceeded: \"+A[i])}r=Math.max(r,s)}var a=n.MAX_BUFFER_LENGTH-r;t.bufferCheckPosition=a+t.position}function o(t){for(var e=0,n=A.length;e<n;e++)t[A[e]]=\"\"}function s(t){m(t),\"\"!==t.cdata&&(y(t,\"oncdata\",t.cdata),t.cdata=\"\"),\"\"!==t.script&&(y(t,\"onscript\",t.script),t.script=\"\")}function a(t,e){return new u(t,e)}function u(t,e){if(!(this instanceof u))return new u(t,e);D.apply(this),this._parser=new r(t,e),this.writable=!0,this.readable=!0;var n=this;this._parser.onend=function(){n.emit(\"end\")},this._parser.onerror=function(t){n.emit(\"error\",t),n._parser.error=null},this._decoder=null,k.forEach(function(t){Object.defineProperty(n,\"on\"+t,{get:function(){return n._parser[\"on\"+t]},set:function(e){return e?void n.on(t,e):(n.removeAllListeners(t),n._parser[\"on\"+t]=e,e)},enumerable:!0,configurable:!1})})}function c(t){return\" \"===t||\"\\n\"===t||\"\\r\"===t||\"\\t\"===t}function l(t){return'\"'===t||\"'\"===t}function h(t){return\">\"===t||c(t)}function p(t,e){return t.test(e)}function f(t,e){return!p(t,e)}function d(t,e,n){t[e]&&t[e](n)}function y(t,e,n){t.textNode&&m(t),d(t,e,n)}function m(t){t.textNode=_(t.opt,t.textNode),t.textNode&&d(t,\"ontext\",t.textNode),t.textNode=\"\"}function _(t,e){return t.trim&&(e=e.trim()),t.normalize&&(e=e.replace(/\\s+/g,\" \")),e}function g(t,e){return m(t),t.trackPosition&&(e+=\"\\nLine: \"+t.line+\"\\nColumn: \"+t.column+\"\\nChar: \"+t.c),e=new Error(e),t.error=e,d(t,\"onerror\",e),t}function v(t){return t.sawRoot&&!t.closedRoot&&b(t,\"Unclosed root tag\"),t.state!==z.BEGIN&&t.state!==z.BEGIN_WHITESPACE&&t.state!==z.TEXT&&g(t,\"Unexpected end\"),m(t),t.c=\"\",t.closed=!0,d(t,\"onend\"),r.call(t,t.strict,t.opt),t}function b(t,e){if(\"object\"!=typeof t||!(t instanceof r))throw new Error(\"bad call to strictFail\");t.strict&&g(t,e)}function w(t){t.strict||(t.tagName=t.tagName[t.looseCase]());var e=t.tags[t.tags.length-1]||t,n=t.tag={name:t.tagName,attributes:{}};t.opt.xmlns&&(n.ns=e.ns),t.attribList.length=0,y(t,\"onopentagstart\",n)}function E(t,e){var n=t.indexOf(\":\"),r=n<0?[\"\",t]:t.split(\":\"),i=r[0],o=r[1];return e&&\"xmlns\"===t&&(i=\"xmlns\",o=\"\"),{prefix:i,local:o}}function T(t){if(t.strict||(t.attribName=t.attribName[t.looseCase]()),t.attribList.indexOf(t.attribName)!==-1||t.tag.attributes.hasOwnProperty(t.attribName))return void(t.attribName=t.attribValue=\"\");if(t.opt.xmlns){var e=E(t.attribName,!0),n=e.prefix,r=e.local;if(\"xmlns\"===n)if(\"xml\"===r&&t.attribValue!==M)b(t,\"xml: prefix must be bound to \"+M+\"\\nActual: \"+t.attribValue);else if(\"xmlns\"===r&&t.attribValue!==U)b(t,\"xmlns: prefix must be bound to \"+U+\"\\nActual: \"+t.attribValue);else{var i=t.tag,o=t.tags[t.tags.length-1]||t;i.ns===o.ns&&(i.ns=Object.create(o.ns)),i.ns[r]=t.attribValue}t.attribList.push([t.attribName,t.attribValue])}else t.tag.attributes[t.attribName]=t.attribValue,y(t,\"onattribute\",{name:t.attribName,value:t.attribValue});t.attribName=t.attribValue=\"\"}function x(t,e){if(t.opt.xmlns){var n=t.tag,r=E(t.tagName);n.prefix=r.prefix,n.local=r.local,n.uri=n.ns[r.prefix]||\"\",n.prefix&&!n.uri&&(b(t,\"Unbound namespace prefix: \"+JSON.stringify(t.tagName)),n.uri=r.prefix);var i=t.tags[t.tags.length-1]||t;n.ns&&i.ns!==n.ns&&Object.keys(n.ns).forEach(function(e){y(t,\"onopennamespace\",{prefix:e,uri:n.ns[e]})});for(var o=0,s=t.attribList.length;o<s;o++){var a=t.attribList[o],u=a[0],c=a[1],l=E(u,!0),h=l.prefix,p=l.local,f=\"\"===h?\"\":n.ns[h]||\"\",d={name:u,value:c,prefix:h,local:p,uri:f};h&&\"xmlns\"!==h&&!f&&(b(t,\"Unbound namespace prefix: \"+JSON.stringify(h)),d.uri=h),t.tag.attributes[u]=d,y(t,\"onattribute\",d)}t.attribList.length=0}t.tag.isSelfClosing=!!e,t.sawRoot=!0,t.tags.push(t.tag),y(t,\"onopentag\",t.tag),e||(t.noscript||\"script\"!==t.tagName.toLowerCase()?t.state=z.TEXT:t.state=z.SCRIPT,t.tag=null,t.tagName=\"\"),t.attribName=t.attribValue=\"\",t.attribList.length=0}function S(t){if(!t.tagName)return b(t,\"Weird empty close tag.\"),t.textNode+=\"</>\",void(t.state=z.TEXT);if(t.script){if(\"script\"!==t.tagName)return t.script+=\"</\"+t.tagName+\">\",t.tagName=\"\",void(t.state=z.SCRIPT);y(t,\"onscript\",t.script),t.script=\"\"}var e=t.tags.length,n=t.tagName;t.strict||(n=n[t.looseCase]());for(var r=n;e--;){var i=t.tags[e];if(i.name===r)break;b(t,\"Unexpected close tag\")}if(e<0)return b(t,\"Unmatched closing tag: \"+t.tagName),t.textNode+=\"</\"+t.tagName+\">\",void(t.state=z.TEXT);t.tagName=n;for(var o=t.tags.length;o-- >e;){var s=t.tag=t.tags.pop();t.tagName=t.tag.name,y(t,\"onclosetag\",t.tagName);var a={};for(var u in s.ns)a[u]=s.ns[u];var c=t.tags[t.tags.length-1]||t;t.opt.xmlns&&s.ns!==c.ns&&Object.keys(s.ns).forEach(function(e){var n=s.ns[e];y(t,\"onclosenamespace\",{prefix:e,uri:n})})}0===e&&(t.closedRoot=!0),t.tagName=t.attribValue=t.attribName=\"\",t.attribList.length=0,t.state=z.TEXT}function C(t){var e,n=t.entity,r=n.toLowerCase(),i=\"\";return t.ENTITIES[n]?t.ENTITIES[n]:t.ENTITIES[r]?t.ENTITIES[r]:(n=r,\"#\"===n.charAt(0)&&(\"x\"===n.charAt(1)?(n=n.slice(2),e=parseInt(n,16),i=e.toString(16)):(n=n.slice(1),e=parseInt(n,10),i=e.toString(10))),n=n.replace(/^0+/,\"\"),isNaN(e)||i.toLowerCase()!==n?(b(t,\"Invalid character entity\"),\"&\"+t.entity+\";\"):String.fromCodePoint(e))}function I(t,e){\"<\"===e?(t.state=z.OPEN_WAKA,t.startTagPosition=t.position):c(e)||(b(t,\"Non-whitespace before first tag.\"),t.textNode=e,t.state=z.TEXT)}function N(t,e){var n=\"\";return e<t.length&&(n=t.charAt(e)),n}function O(t){var e=this;if(this.error)throw this.error;if(e.closed)return g(e,\"Cannot write after close. Assign an onready handler.\");if(null===t)return v(e);\"object\"==typeof t&&(t=t.toString());for(var n=0,r=\"\";;){if(r=N(t,n++),e.c=r,!r)break;switch(e.trackPosition&&(e.position++,\"\\n\"===r?(e.line++,e.column=0):e.column++),e.state){case z.BEGIN:if(e.state=z.BEGIN_WHITESPACE,\"\\ufeff\"===r)continue;I(e,r);continue;case z.BEGIN_WHITESPACE:I(e,r);continue;case z.TEXT:if(e.sawRoot&&!e.closedRoot){for(var o=n-1;r&&\"<\"!==r&&\"&\"!==r;)r=N(t,n++),r&&e.trackPosition&&(e.position++,\"\\n\"===r?(e.line++,e.column=0):e.column++);e.textNode+=t.substring(o,n-1)}\"<\"!==r||e.sawRoot&&e.closedRoot&&!e.strict?(c(r)||e.sawRoot&&!e.closedRoot||b(e,\"Text data outside of root node.\"),\"&\"===r?e.state=z.TEXT_ENTITY:e.textNode+=r):(e.state=z.OPEN_WAKA,e.startTagPosition=e.position);continue;case z.SCRIPT:\"<\"===r?e.state=z.SCRIPT_ENDING:e.script+=r;continue;case z.SCRIPT_ENDING:\"/\"===r?e.state=z.CLOSE_TAG:(e.script+=\"<\"+r,e.state=z.SCRIPT);continue;case z.OPEN_WAKA:if(\"!\"===r)e.state=z.SGML_DECL,e.sgmlDecl=\"\";else if(c(r));else if(p(P,r))e.state=z.OPEN_TAG,e.tagName=r;else if(\"/\"===r)e.state=z.CLOSE_TAG,e.tagName=\"\";else if(\"?\"===r)e.state=z.PROC_INST,e.procInstName=e.procInstBody=\"\";else{if(b(e,\"Unencoded <\"),e.startTagPosition+1<e.position){var s=e.position-e.startTagPosition;r=new Array(s).join(\" \")+r}e.textNode+=\"<\"+r,e.state=z.TEXT}continue;case z.SGML_DECL:(e.sgmlDecl+r).toUpperCase()===L?(y(e,\"onopencdata\"),e.state=z.CDATA,e.sgmlDecl=\"\",e.cdata=\"\"):e.sgmlDecl+r===\"--\"?(e.state=z.COMMENT,e.comment=\"\",e.sgmlDecl=\"\"):(e.sgmlDecl+r).toUpperCase()===R?(e.state=z.DOCTYPE,(e.doctype||e.sawRoot)&&b(e,\"Inappropriately located doctype declaration\"),e.doctype=\"\",e.sgmlDecl=\"\"):\">\"===r?(y(e,\"onsgmldeclaration\",e.sgmlDecl),e.sgmlDecl=\"\",e.state=z.TEXT):l(r)?(e.state=z.SGML_DECL_QUOTED,e.sgmlDecl+=r):e.sgmlDecl+=r;continue;case z.SGML_DECL_QUOTED:r===e.q&&(e.state=z.SGML_DECL,e.q=\"\"),e.sgmlDecl+=r;continue;case z.DOCTYPE:\">\"===r?(e.state=z.TEXT,y(e,\"ondoctype\",e.doctype),e.doctype=!0):(e.doctype+=r,\"[\"===r?e.state=z.DOCTYPE_DTD:l(r)&&(e.state=z.DOCTYPE_QUOTED,e.q=r));continue;case z.DOCTYPE_QUOTED:e.doctype+=r,r===e.q&&(e.q=\"\",e.state=z.DOCTYPE);continue;case z.DOCTYPE_DTD:e.doctype+=r,\"]\"===r?e.state=z.DOCTYPE:l(r)&&(e.state=z.DOCTYPE_DTD_QUOTED,e.q=r);continue;case z.DOCTYPE_DTD_QUOTED:e.doctype+=r,r===e.q&&(e.state=z.DOCTYPE_DTD,e.q=\"\");continue;case z.COMMENT:\"-\"===r?e.state=z.COMMENT_ENDING:e.comment+=r;continue;case z.COMMENT_ENDING:\"-\"===r?(e.state=z.COMMENT_ENDED,e.comment=_(e.opt,e.comment),e.comment&&y(e,\"oncomment\",e.comment),e.comment=\"\"):(e.comment+=\"-\"+r,e.state=z.COMMENT);continue;case z.COMMENT_ENDED:\">\"!==r?(b(e,\"Malformed comment\"),e.comment+=\"--\"+r,e.state=z.COMMENT):e.state=z.TEXT;continue;case z.CDATA:\"]\"===r?e.state=z.CDATA_ENDING:e.cdata+=r;continue;case z.CDATA_ENDING:\"]\"===r?e.state=z.CDATA_ENDING_2:(e.cdata+=\"]\"+r,e.state=z.CDATA);continue;case z.CDATA_ENDING_2:\">\"===r?(e.cdata&&y(e,\"oncdata\",e.cdata),y(e,\"onclosecdata\"),e.cdata=\"\",e.state=z.TEXT):\"]\"===r?e.cdata+=\"]\":(e.cdata+=\"]]\"+r,e.state=z.CDATA);continue;case z.PROC_INST:\"?\"===r?e.state=z.PROC_INST_ENDING:c(r)?e.state=z.PROC_INST_BODY:e.procInstName+=r;continue;case z.PROC_INST_BODY:if(!e.procInstBody&&c(r))continue;\"?\"===r?e.state=z.PROC_INST_ENDING:e.procInstBody+=r;continue;case z.PROC_INST_ENDING:\">\"===r?(y(e,\"onprocessinginstruction\",{name:e.procInstName,body:e.procInstBody}),e.procInstName=e.procInstBody=\"\",e.state=z.TEXT):(e.procInstBody+=\"?\"+r,e.state=z.PROC_INST_BODY);continue;case z.OPEN_TAG:p(F,r)?e.tagName+=r:(w(e),\">\"===r?x(e):\"/\"===r?e.state=z.OPEN_TAG_SLASH:(c(r)||b(e,\"Invalid character in tag name\"),e.state=z.ATTRIB));continue;case z.OPEN_TAG_SLASH:\">\"===r?(x(e,!0),S(e)):(b(e,\"Forward-slash in opening tag not followed by >\"),e.state=z.ATTRIB);continue;case z.ATTRIB:if(c(r))continue;\">\"===r?x(e):\"/\"===r?e.state=z.OPEN_TAG_SLASH:p(P,r)?(e.attribName=r,e.attribValue=\"\",e.state=z.ATTRIB_NAME):b(e,\"Invalid attribute name\");continue;case z.ATTRIB_NAME:\"=\"===r?e.state=z.ATTRIB_VALUE:\">\"===r?(b(e,\"Attribute without value\"),e.attribValue=e.attribName,T(e),x(e)):c(r)?e.state=z.ATTRIB_NAME_SAW_WHITE:p(F,r)?e.attribName+=r:b(e,\"Invalid attribute name\");continue;case z.ATTRIB_NAME_SAW_WHITE:if(\"=\"===r)e.state=z.ATTRIB_VALUE;else{if(c(r))continue;b(e,\"Attribute without value\"),e.tag.attributes[e.attribName]=\"\",e.attribValue=\"\",y(e,\"onattribute\",{name:e.attribName,value:\"\"}),e.attribName=\"\",\">\"===r?x(e):p(P,r)?(e.attribName=r,e.state=z.ATTRIB_NAME):(b(e,\"Invalid attribute name\"),e.state=z.ATTRIB)}continue;case z.ATTRIB_VALUE:if(c(r))continue;l(r)?(e.q=r,e.state=z.ATTRIB_VALUE_QUOTED):(b(e,\"Unquoted attribute value\"),e.state=z.ATTRIB_VALUE_UNQUOTED,e.attribValue=r);continue;case z.ATTRIB_VALUE_QUOTED:if(r!==e.q){\"&\"===r?e.state=z.ATTRIB_VALUE_ENTITY_Q:e.attribValue+=r;continue}T(e),e.q=\"\",e.state=z.ATTRIB_VALUE_CLOSED;continue;case z.ATTRIB_VALUE_CLOSED:c(r)?e.state=z.ATTRIB:\">\"===r?x(e):\"/\"===r?e.state=z.OPEN_TAG_SLASH:p(P,r)?(b(e,\"No whitespace between attributes\"),e.attribName=r,e.attribValue=\"\",e.state=z.ATTRIB_NAME):b(e,\"Invalid attribute name\");continue;case z.ATTRIB_VALUE_UNQUOTED:if(!h(r)){\"&\"===r?e.state=z.ATTRIB_VALUE_ENTITY_U:e.attribValue+=r;continue}T(e),\">\"===r?x(e):e.state=z.ATTRIB;continue;case z.CLOSE_TAG:if(e.tagName)\">\"===r?S(e):p(F,r)?e.tagName+=r:e.script?(e.script+=\"</\"+e.tagName,e.tagName=\"\",e.state=z.SCRIPT):(c(r)||b(e,\"Invalid tagname in closing tag\"),e.state=z.CLOSE_TAG_SAW_WHITE);else{if(c(r))continue;f(P,r)?e.script?(e.script+=\"</\"+r,\ne.state=z.SCRIPT):b(e,\"Invalid tagname in closing tag.\"):e.tagName=r}continue;case z.CLOSE_TAG_SAW_WHITE:if(c(r))continue;\">\"===r?S(e):b(e,\"Invalid characters in closing tag\");continue;case z.TEXT_ENTITY:case z.ATTRIB_VALUE_ENTITY_Q:case z.ATTRIB_VALUE_ENTITY_U:var a,u;switch(e.state){case z.TEXT_ENTITY:a=z.TEXT,u=\"textNode\";break;case z.ATTRIB_VALUE_ENTITY_Q:a=z.ATTRIB_VALUE_QUOTED,u=\"attribValue\";break;case z.ATTRIB_VALUE_ENTITY_U:a=z.ATTRIB_VALUE_UNQUOTED,u=\"attribValue\"}\";\"===r?(e[u]+=C(e),e.entity=\"\",e.state=a):p(e.entity.length?X:B,r)?e.entity+=r:(b(e,\"Invalid character in entity name\"),e[u]+=\"&\"+e.entity+r,e.entity=\"\",e.state=a);continue;default:throw new Error(e,\"Unknown state: \"+e.state)}}return e.position>=e.bufferCheckPosition&&i(e),e}n.parser=function(t,e){return new r(t,e)},n.SAXParser=r,n.SAXStream=u,n.createStream=a,n.MAX_BUFFER_LENGTH=65536;var A=[\"comment\",\"sgmlDecl\",\"textNode\",\"tagName\",\"doctype\",\"procInstName\",\"procInstBody\",\"entity\",\"attribName\",\"attribValue\",\"cdata\",\"script\"];n.EVENTS=[\"text\",\"processinginstruction\",\"sgmldeclaration\",\"doctype\",\"comment\",\"opentagstart\",\"attribute\",\"opentag\",\"closetag\",\"opencdata\",\"cdata\",\"closecdata\",\"error\",\"end\",\"ready\",\"script\",\"opennamespace\",\"closenamespace\"],Object.create||(Object.create=function(t){function e(){}e.prototype=t;var n=new e;return n}),Object.keys||(Object.keys=function(t){var e=[];for(var n in t)t.hasOwnProperty(n)&&e.push(n);return e}),r.prototype={end:function(){v(this)},write:O,resume:function(){return this.error=null,this},close:function(){return this.write(null)},flush:function(){s(this)}};var D;try{D=t(\"stream\").Stream}catch(j){D=function(){}}var k=n.EVENTS.filter(function(t){return\"error\"!==t&&\"end\"!==t});u.prototype=Object.create(D.prototype,{constructor:{value:u}}),u.prototype.write=function(n){if(\"function\"==typeof e&&\"function\"==typeof e.isBuffer&&e.isBuffer(n)){if(!this._decoder){var r=t(\"string_decoder\").StringDecoder;this._decoder=new r(\"utf8\")}n=this._decoder.write(n)}return this._parser.write(n.toString()),this.emit(\"data\",n),!0},u.prototype.end=function(t){return t&&t.length&&this.write(t),this._parser.end(),!0},u.prototype.on=function(t,e){var n=this;return n._parser[\"on\"+t]||k.indexOf(t)===-1||(n._parser[\"on\"+t]=function(){var e=1===arguments.length?[arguments[0]]:Array.apply(null,arguments);e.splice(0,0,t),n.emit.apply(n,e)}),D.prototype.on.call(n,t,e)};var L=\"[CDATA[\",R=\"DOCTYPE\",M=\"http://www.w3.org/XML/1998/namespace\",U=\"http://www.w3.org/2000/xmlns/\",q={xml:M,xmlns:U},P=/[:_A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]/,F=/[:_A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\u00B7\\u0300-\\u036F\\u203F-\\u2040.\\d-]/,B=/[#:_A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]/,X=/[#:_A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\u00B7\\u0300-\\u036F\\u203F-\\u2040.\\d-]/,z=0;n.STATE={BEGIN:z++,BEGIN_WHITESPACE:z++,TEXT:z++,TEXT_ENTITY:z++,OPEN_WAKA:z++,SGML_DECL:z++,SGML_DECL_QUOTED:z++,DOCTYPE:z++,DOCTYPE_QUOTED:z++,DOCTYPE_DTD:z++,DOCTYPE_DTD_QUOTED:z++,COMMENT_STARTING:z++,COMMENT:z++,COMMENT_ENDING:z++,COMMENT_ENDED:z++,CDATA:z++,CDATA_ENDING:z++,CDATA_ENDING_2:z++,PROC_INST:z++,PROC_INST_BODY:z++,PROC_INST_ENDING:z++,OPEN_TAG:z++,OPEN_TAG_SLASH:z++,ATTRIB:z++,ATTRIB_NAME:z++,ATTRIB_NAME_SAW_WHITE:z++,ATTRIB_VALUE:z++,ATTRIB_VALUE_QUOTED:z++,ATTRIB_VALUE_CLOSED:z++,ATTRIB_VALUE_UNQUOTED:z++,ATTRIB_VALUE_ENTITY_Q:z++,ATTRIB_VALUE_ENTITY_U:z++,CLOSE_TAG:z++,CLOSE_TAG_SAW_WHITE:z++,SCRIPT:z++,SCRIPT_ENDING:z++},n.XML_ENTITIES={amp:\"&\",gt:\">\",lt:\"<\",quot:'\"',apos:\"'\"},n.ENTITIES={amp:\"&\",gt:\">\",lt:\"<\",quot:'\"',apos:\"'\",AElig:198,Aacute:193,Acirc:194,Agrave:192,Aring:197,Atilde:195,Auml:196,Ccedil:199,ETH:208,Eacute:201,Ecirc:202,Egrave:200,Euml:203,Iacute:205,Icirc:206,Igrave:204,Iuml:207,Ntilde:209,Oacute:211,Ocirc:212,Ograve:210,Oslash:216,Otilde:213,Ouml:214,THORN:222,Uacute:218,Ucirc:219,Ugrave:217,Uuml:220,Yacute:221,aacute:225,acirc:226,aelig:230,agrave:224,aring:229,atilde:227,auml:228,ccedil:231,eacute:233,ecirc:234,egrave:232,eth:240,euml:235,iacute:237,icirc:238,igrave:236,iuml:239,ntilde:241,oacute:243,ocirc:244,ograve:242,oslash:248,otilde:245,ouml:246,szlig:223,thorn:254,uacute:250,ucirc:251,ugrave:249,uuml:252,yacute:253,yuml:255,copy:169,reg:174,nbsp:160,iexcl:161,cent:162,pound:163,curren:164,yen:165,brvbar:166,sect:167,uml:168,ordf:170,laquo:171,not:172,shy:173,macr:175,deg:176,plusmn:177,sup1:185,sup2:178,sup3:179,acute:180,micro:181,para:182,middot:183,cedil:184,ordm:186,raquo:187,frac14:188,frac12:189,frac34:190,iquest:191,times:215,divide:247,OElig:338,oelig:339,Scaron:352,scaron:353,Yuml:376,fnof:402,circ:710,tilde:732,Alpha:913,Beta:914,Gamma:915,Delta:916,Epsilon:917,Zeta:918,Eta:919,Theta:920,Iota:921,Kappa:922,Lambda:923,Mu:924,Nu:925,Xi:926,Omicron:927,Pi:928,Rho:929,Sigma:931,Tau:932,Upsilon:933,Phi:934,Chi:935,Psi:936,Omega:937,alpha:945,beta:946,gamma:947,delta:948,epsilon:949,zeta:950,eta:951,theta:952,iota:953,kappa:954,lambda:955,mu:956,nu:957,xi:958,omicron:959,pi:960,rho:961,sigmaf:962,sigma:963,tau:964,upsilon:965,phi:966,chi:967,psi:968,omega:969,thetasym:977,upsih:978,piv:982,ensp:8194,emsp:8195,thinsp:8201,zwnj:8204,zwj:8205,lrm:8206,rlm:8207,ndash:8211,mdash:8212,lsquo:8216,rsquo:8217,sbquo:8218,ldquo:8220,rdquo:8221,bdquo:8222,dagger:8224,Dagger:8225,bull:8226,hellip:8230,permil:8240,prime:8242,Prime:8243,lsaquo:8249,rsaquo:8250,oline:8254,frasl:8260,euro:8364,image:8465,weierp:8472,real:8476,trade:8482,alefsym:8501,larr:8592,uarr:8593,rarr:8594,darr:8595,harr:8596,crarr:8629,lArr:8656,uArr:8657,rArr:8658,dArr:8659,hArr:8660,forall:8704,part:8706,exist:8707,empty:8709,nabla:8711,isin:8712,notin:8713,ni:8715,prod:8719,sum:8721,minus:8722,lowast:8727,radic:8730,prop:8733,infin:8734,ang:8736,and:8743,or:8744,cap:8745,cup:8746,\"int\":8747,there4:8756,sim:8764,cong:8773,asymp:8776,ne:8800,equiv:8801,le:8804,ge:8805,sub:8834,sup:8835,nsub:8836,sube:8838,supe:8839,oplus:8853,otimes:8855,perp:8869,sdot:8901,lceil:8968,rceil:8969,lfloor:8970,rfloor:8971,lang:9001,rang:9002,loz:9674,spades:9824,clubs:9827,hearts:9829,diams:9830},Object.keys(n.ENTITIES).forEach(function(t){var e=n.ENTITIES[t],r=\"number\"==typeof e?String.fromCharCode(e):e;n.ENTITIES[t]=r});for(var H in n.STATE)n.STATE[n.STATE[H]]=H;z=n.STATE,String.fromCodePoint||!function(){var t=String.fromCharCode,e=Math.floor,n=function(){var n,r,i=16384,o=[],s=-1,a=arguments.length;if(!a)return\"\";for(var u=\"\";++s<a;){var c=Number(arguments[s]);if(!isFinite(c)||c<0||c>1114111||e(c)!==c)throw RangeError(\"Invalid code point: \"+c);c<=65535?o.push(c):(c-=65536,n=(c>>10)+55296,r=c%1024+56320,o.push(n,r)),(s+1===a||o.length>i)&&(u+=t.apply(null,o),o.length=0)}return u};Object.defineProperty?Object.defineProperty(String,\"fromCodePoint\",{value:n,configurable:!0,writable:!0}):String.fromCodePoint=n}()}(\"undefined\"==typeof n?this.sax={}:n)}).call(this,t(\"buffer\").Buffer)},{buffer:41,stream:112,string_decoder:113}],112:[function(t,e,n){function r(){i.call(this)}e.exports=r;var i=t(\"events\").EventEmitter,o=t(\"inherits\");o(r,i),r.Readable=t(\"readable-stream/readable.js\"),r.Writable=t(\"readable-stream/writable.js\"),r.Duplex=t(\"readable-stream/duplex.js\"),r.Transform=t(\"readable-stream/transform.js\"),r.PassThrough=t(\"readable-stream/passthrough.js\"),r.Stream=r,r.prototype.pipe=function(t,e){function n(e){t.writable&&!1===t.write(e)&&c.pause&&c.pause()}function r(){c.readable&&c.resume&&c.resume()}function o(){l||(l=!0,t.end())}function s(){l||(l=!0,\"function\"==typeof t.destroy&&t.destroy())}function a(t){if(u(),0===i.listenerCount(this,\"error\"))throw t}function u(){c.removeListener(\"data\",n),t.removeListener(\"drain\",r),c.removeListener(\"end\",o),c.removeListener(\"close\",s),c.removeListener(\"error\",a),t.removeListener(\"error\",a),c.removeListener(\"end\",u),c.removeListener(\"close\",u),t.removeListener(\"close\",u)}var c=this;c.on(\"data\",n),t.on(\"drain\",r),t._isStdio||e&&e.end===!1||(c.on(\"end\",o),c.on(\"close\",s));var l=!1;return c.on(\"error\",a),t.on(\"error\",a),c.on(\"end\",u),c.on(\"close\",u),t.on(\"close\",u),t.emit(\"pipe\",c),t}},{events:47,inherits:84,\"readable-stream/duplex.js\":97,\"readable-stream/passthrough.js\":106,\"readable-stream/readable.js\":107,\"readable-stream/transform.js\":108,\"readable-stream/writable.js\":109}],113:[function(t,e,n){\"use strict\";function r(t){if(!t)return\"utf8\";for(var e;;)switch(t){case\"utf8\":case\"utf-8\":return\"utf8\";case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return\"utf16le\";case\"latin1\":case\"binary\":return\"latin1\";case\"base64\":case\"ascii\":case\"hex\":return t;default:if(e)return;t=(\"\"+t).toLowerCase(),e=!0}}function i(t){var e=r(t);if(\"string\"!=typeof e&&(g.isEncoding===v||!v(t)))throw new Error(\"Unknown encoding: \"+t);return e||t}function o(t){this.encoding=i(t);var e;switch(this.encoding){case\"utf16le\":this.text=p,this.end=f,e=4;break;case\"utf8\":this.fillLast=c,e=4;break;case\"base64\":this.text=d,this.end=y,e=3;break;default:return this.write=m,void(this.end=_)}this.lastNeed=0,this.lastTotal=0,this.lastChar=g.allocUnsafe(e)}function s(t){return t<=127?0:t>>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function a(t,e,n){var r=e.length-1;if(r<n)return 0;var i=s(e[r]);return i>=0?(i>0&&(t.lastNeed=i-1),i):--r<n||i===-2?0:(i=s(e[r]),i>=0?(i>0&&(t.lastNeed=i-2),i):--r<n||i===-2?0:(i=s(e[r]),i>=0?(i>0&&(2===i?i=0:t.lastNeed=i-3),i):0))}function u(t,e,n){if(128!==(192&e[0]))return t.lastNeed=0,\"�\";if(t.lastNeed>1&&e.length>1){if(128!==(192&e[1]))return t.lastNeed=1,\"�\";if(t.lastNeed>2&&e.length>2&&128!==(192&e[2]))return t.lastNeed=2,\"�\"}}function c(t){var e=this.lastTotal-this.lastNeed,n=u(this,t,e);return void 0!==n?n:this.lastNeed<=t.length?(t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(t.copy(this.lastChar,e,0,t.length),void(this.lastNeed-=t.length))}function l(t,e){var n=a(this,t,e);if(!this.lastNeed)return t.toString(\"utf8\",e);this.lastTotal=n;var r=t.length-(n-this.lastNeed);return t.copy(this.lastChar,0,r),t.toString(\"utf8\",e,r)}function h(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+\"�\":e}function p(t,e){if((t.length-e)%2===0){var n=t.toString(\"utf16le\",e);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString(\"utf16le\",e,t.length-1)}function f(t){var e=t&&t.length?this.write(t):\"\";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return e+this.lastChar.toString(\"utf16le\",0,n)}return e}function d(t,e){var n=(t.length-e)%3;return 0===n?t.toString(\"base64\",e):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString(\"base64\",e,t.length-n))}function y(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+this.lastChar.toString(\"base64\",0,3-this.lastNeed):e}function m(t){return t.toString(this.encoding)}function _(t){return t&&t.length?this.write(t):\"\"}var g=t(\"safe-buffer\").Buffer,v=g.isEncoding||function(t){switch(t=\"\"+t,t&&t.toLowerCase()){case\"hex\":case\"utf8\":case\"utf-8\":case\"ascii\":case\"binary\":case\"base64\":case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":case\"raw\":return!0;default:return!1}};n.StringDecoder=o,o.prototype.write=function(t){if(0===t.length)return\"\";var e,n;if(this.lastNeed){if(e=this.fillLast(t),void 0===e)return\"\";n=this.lastNeed,this.lastNeed=0}else n=0;return n<t.length?e?e+this.text(t,n):this.text(t,n):e||\"\"},o.prototype.end=h,o.prototype.text=l,o.prototype.fillLast=function(t){return this.lastNeed<=t.length?(t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,t.length),void(this.lastNeed-=t.length))}},{\"safe-buffer\":110}],114:[function(t,e,n){(function(e,r){function i(t,e){this._id=t,this._clearFn=e}var o=t(\"process/browser.js\").nextTick,s=Function.prototype.apply,a=Array.prototype.slice,u={},c=0;n.setTimeout=function(){return new i(s.call(setTimeout,window,arguments),clearTimeout)},n.setInterval=function(){return new i(s.call(setInterval,window,arguments),clearInterval)},n.clearTimeout=n.clearInterval=function(t){t.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(window,this._id)},n.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},n.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},n._unrefActive=n.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},n.setImmediate=\"function\"==typeof e?e:function(t){var e=c++,r=!(arguments.length<2)&&a.call(arguments,1);return u[e]=!0,o(function(){u[e]&&(r?t.apply(null,r):t.call(null),n.clearImmediate(e))}),e},n.clearImmediate=\"function\"==typeof r?r:function(t){delete u[t]}}).call(this,t(\"timers\").setImmediate,t(\"timers\").clearImmediate)},{\"process/browser.js\":91,timers:114}],115:[function(t,e,n){(function(t){function n(t,e){function n(){if(!i){if(r(\"throwDeprecation\"))throw new Error(e);r(\"traceDeprecation\")?console.trace(e):console.warn(e),i=!0}return t.apply(this,arguments)}if(r(\"noDeprecation\"))return t;var i=!1;return n}function r(e){try{if(!t.localStorage)return!1}catch(n){return!1}var r=t.localStorage[e];return null!=r&&\"true\"===String(r).toLowerCase()}e.exports=n}).call(this,\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{}],116:[function(t,e,n){e.exports=function(t){return t&&\"object\"==typeof t&&\"function\"==typeof t.copy&&\"function\"==typeof t.fill&&\"function\"==typeof t.readUInt8}},{}],117:[function(t,e,n){(function(e,r){function i(t,e){var r={seen:[],stylize:s};return arguments.length>=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),y(e)?r.showHidden=e:e&&n._extend(r,e),w(r.showHidden)&&(r.showHidden=!1),w(r.depth)&&(r.depth=2),w(r.colors)&&(r.colors=!1),w(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=o),u(r,t,r.depth)}function o(t,e){var n=i.styles[e];return n?\"\u001b[\"+i.colors[n][0]+\"m\"+t+\"\u001b[\"+i.colors[n][1]+\"m\":t}function s(t,e){return t}function a(t){var e={};return t.forEach(function(t,n){e[t]=!0}),e}function u(t,e,r){if(t.customInspect&&e&&C(e.inspect)&&e.inspect!==n.inspect&&(!e.constructor||e.constructor.prototype!==e)){var i=e.inspect(r,t);return v(i)||(i=u(t,i,r)),i}var o=c(t,e);if(o)return o;var s=Object.keys(e),y=a(s);if(t.showHidden&&(s=Object.getOwnPropertyNames(e)),S(e)&&(s.indexOf(\"message\")>=0||s.indexOf(\"description\")>=0))return l(e);if(0===s.length){if(C(e)){var m=e.name?\": \"+e.name:\"\";return t.stylize(\"[Function\"+m+\"]\",\"special\")}if(E(e))return t.stylize(RegExp.prototype.toString.call(e),\"regexp\");if(x(e))return t.stylize(Date.prototype.toString.call(e),\"date\");if(S(e))return l(e)}var _=\"\",g=!1,b=[\"{\",\"}\"];if(d(e)&&(g=!0,b=[\"[\",\"]\"]),C(e)){var w=e.name?\": \"+e.name:\"\";_=\" [Function\"+w+\"]\"}if(E(e)&&(_=\" \"+RegExp.prototype.toString.call(e)),x(e)&&(_=\" \"+Date.prototype.toUTCString.call(e)),S(e)&&(_=\" \"+l(e)),0===s.length&&(!g||0==e.length))return b[0]+_+b[1];if(r<0)return E(e)?t.stylize(RegExp.prototype.toString.call(e),\"regexp\"):t.stylize(\"[Object]\",\"special\");t.seen.push(e);var T;return T=g?h(t,e,r,y,s):s.map(function(n){return p(t,e,r,y,n,g)}),t.seen.pop(),f(T,_,b)}function c(t,e){if(w(e))return t.stylize(\"undefined\",\"undefined\");if(v(e)){var n=\"'\"+JSON.stringify(e).replace(/^\"|\"$/g,\"\").replace(/'/g,\"\\\\'\").replace(/\\\\\"/g,'\"')+\"'\";return t.stylize(n,\"string\")}return g(e)?t.stylize(\"\"+e,\"number\"):y(e)?t.stylize(\"\"+e,\"boolean\"):m(e)?t.stylize(\"null\",\"null\"):void 0}function l(t){return\"[\"+Error.prototype.toString.call(t)+\"]\"}function h(t,e,n,r,i){for(var o=[],s=0,a=e.length;s<a;++s)D(e,String(s))?o.push(p(t,e,n,r,String(s),!0)):o.push(\"\");return i.forEach(function(i){i.match(/^\\d+$/)||o.push(p(t,e,n,r,i,!0))}),o}function p(t,e,n,r,i,o){var s,a,c;if(c=Object.getOwnPropertyDescriptor(e,i)||{value:e[i]},c.get?a=c.set?t.stylize(\"[Getter/Setter]\",\"special\"):t.stylize(\"[Getter]\",\"special\"):c.set&&(a=t.stylize(\"[Setter]\",\"special\")),D(r,i)||(s=\"[\"+i+\"]\"),a||(t.seen.indexOf(c.value)<0?(a=m(n)?u(t,c.value,null):u(t,c.value,n-1),a.indexOf(\"\\n\")>-1&&(a=o?a.split(\"\\n\").map(function(t){return\"  \"+t}).join(\"\\n\").substr(2):\"\\n\"+a.split(\"\\n\").map(function(t){return\"   \"+t}).join(\"\\n\"))):a=t.stylize(\"[Circular]\",\"special\")),w(s)){if(o&&i.match(/^\\d+$/))return a;s=JSON.stringify(\"\"+i),s.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)?(s=s.substr(1,s.length-2),s=t.stylize(s,\"name\")):(s=s.replace(/'/g,\"\\\\'\").replace(/\\\\\"/g,'\"').replace(/(^\"|\"$)/g,\"'\"),s=t.stylize(s,\"string\"))}return s+\": \"+a}function f(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf(\"\\n\")>=0&&r++,t+e.replace(/\\u001b\\[\\d\\d?m/g,\"\").length+1},0);return i>60?n[0]+(\"\"===e?\"\":e+\"\\n \")+\" \"+t.join(\",\\n  \")+\" \"+n[1]:n[0]+e+\" \"+t.join(\", \")+\" \"+n[1]}function d(t){return Array.isArray(t)}function y(t){return\"boolean\"==typeof t}function m(t){return null===t}function _(t){return null==t}function g(t){return\"number\"==typeof t}function v(t){return\"string\"==typeof t}function b(t){return\"symbol\"==typeof t}function w(t){return void 0===t}function E(t){return T(t)&&\"[object RegExp]\"===N(t)}function T(t){return\"object\"==typeof t&&null!==t}function x(t){return T(t)&&\"[object Date]\"===N(t)}function S(t){return T(t)&&(\"[object Error]\"===N(t)||t instanceof Error)}function C(t){return\"function\"==typeof t}function I(t){return null===t||\"boolean\"==typeof t||\"number\"==typeof t||\"string\"==typeof t||\"symbol\"==typeof t||\"undefined\"==typeof t}function N(t){return Object.prototype.toString.call(t)}function O(t){return t<10?\"0\"+t.toString(10):t.toString(10)}function A(){var t=new Date,e=[O(t.getHours()),O(t.getMinutes()),O(t.getSeconds())].join(\":\");return[t.getDate(),R[t.getMonth()],e].join(\" \")}function D(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var j=/%[sdj%]/g;n.format=function(t){if(!v(t)){for(var e=[],n=0;n<arguments.length;n++)e.push(i(arguments[n]));return e.join(\" \")}for(var n=1,r=arguments,o=r.length,s=String(t).replace(j,function(t){if(\"%%\"===t)return\"%\";if(n>=o)return t;switch(t){case\"%s\":return String(r[n++]);case\"%d\":return Number(r[n++]);case\"%j\":try{return JSON.stringify(r[n++])}catch(e){return\"[Circular]\"}default:return t}}),a=r[n];n<o;a=r[++n])s+=m(a)||!T(a)?\" \"+a:\" \"+i(a);return s},n.deprecate=function(t,i){function o(){if(!s){if(e.throwDeprecation)throw new Error(i);e.traceDeprecation?console.trace(i):console.error(i),s=!0}return t.apply(this,arguments)}if(w(r.process))return function(){return n.deprecate(t,i).apply(this,arguments)};if(e.noDeprecation===!0)return t;var s=!1;return o};var k,L={};n.debuglog=function(t){if(w(k)&&(k=e.env.NODE_DEBUG||\"\"),t=t.toUpperCase(),!L[t])if(new RegExp(\"\\\\b\"+t+\"\\\\b\",\"i\").test(k)){var r=e.pid;L[t]=function(){var e=n.format.apply(n,arguments);console.error(\"%s %d: %s\",t,r,e)}}else L[t]=function(){};return L[t]},n.inspect=i,i.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},i.styles={special:\"cyan\",number:\"yellow\",\"boolean\":\"yellow\",undefined:\"grey\",\"null\":\"bold\",string:\"green\",date:\"magenta\",regexp:\"red\"},n.isArray=d,n.isBoolean=y,n.isNull=m,n.isNullOrUndefined=_,n.isNumber=g,n.isString=v,n.isSymbol=b,n.isUndefined=w,n.isRegExp=E,n.isObject=T,n.isDate=x,n.isError=S,n.isFunction=C,n.isPrimitive=I,n.isBuffer=t(\"./support/isBuffer\");var R=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];n.log=function(){console.log(\"%s - %s\",A(),n.format.apply(n,arguments))},n.inherits=t(\"inherits\"),n._extend=function(t,e){if(!e||!T(e))return t;for(var n=Object.keys(e),r=n.length;r--;)t[n[r]]=e[n[r]];return t}}).call(this,t(\"_process\"),\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{})},{\"./support/isBuffer\":116,_process:91,inherits:84}],118:[function(t,e,n){(function(){\"use strict\";n.stripBOM=function(t){return\"\\ufeff\"===t[0]?t.substring(1):t}}).call(this)},{}],119:[function(t,e,n){(function(){\"use strict\";var e,r,i,o,s,a={}.hasOwnProperty;e=t(\"xmlbuilder\"),r=t(\"./defaults\").defaults,o=function(t){return\"string\"==typeof t&&(t.indexOf(\"&\")>=0||t.indexOf(\">\")>=0||t.indexOf(\"<\")>=0)},s=function(t){return\"<![CDATA[\"+i(t)+\"]]>\"},i=function(t){return t.replace(\"]]>\",\"]]]]><![CDATA[>\")},n.Builder=function(){function t(t){var e,n,i;this.options={},n=r[.2];for(e in n)a.call(n,e)&&(i=n[e],this.options[e]=i);for(e in t)a.call(t,e)&&(i=t[e],this.options[e]=i)}return t.prototype.buildObject=function(t){var n,i,u,c,l;return n=this.options.attrkey,i=this.options.charkey,1===Object.keys(t).length&&this.options.rootName===r[.2].rootName?(l=Object.keys(t)[0],t=t[l]):l=this.options.rootName,u=function(t){return function(e,r){var c,l,h,p,f,d;if(\"object\"!=typeof r)t.options.cdata&&o(r)?e.raw(s(r)):e.txt(r);else if(Array.isArray(r)){for(p in r)if(a.call(r,p)){l=r[p];for(f in l)h=l[f],e=u(e.ele(f),h).up()}}else for(f in r)if(a.call(r,f))if(l=r[f],f===n){if(\"object\"==typeof l)for(c in l)d=l[c],e=e.att(c,d)}else if(f===i)e=t.options.cdata&&o(l)?e.raw(s(l)):e.txt(l);else if(Array.isArray(l))for(p in l)a.call(l,p)&&(h=l[p],e=\"string\"==typeof h?t.options.cdata&&o(h)?e.ele(f).raw(s(h)).up():e.ele(f,h).up():u(e.ele(f),h).up());else\"object\"==typeof l?e=u(e.ele(f),l).up():\"string\"==typeof l&&t.options.cdata&&o(l)?e=e.ele(f).raw(s(l)).up():(null==l&&(l=\"\"),e=e.ele(f,l.toString()).up());return e}}(this),c=e.create(l,this.options.xmldec,this.options.doctype,{headless:this.options.headless,allowSurrogateChars:this.options.allowSurrogateChars}),u(c,t).end(this.options.renderOpts)},t}()}).call(this)},{\"./defaults\":120,xmlbuilder:145}],120:[function(t,e,n){(function(){n.defaults={.1:{explicitCharkey:!1,trim:!0,normalize:!0,normalizeTags:!1,attrkey:\"@\",charkey:\"#\",explicitArray:!1,ignoreAttrs:!1,mergeAttrs:!1,explicitRoot:!1,validator:null,xmlns:!1,explicitChildren:!1,childkey:\"@@\",charsAsChildren:!1,includeWhiteChars:!1,async:!1,strict:!0,attrNameProcessors:null,attrValueProcessors:null,tagNameProcessors:null,valueProcessors:null,emptyTag:\"\"},.2:{explicitCharkey:!1,trim:!1,normalize:!1,normalizeTags:!1,attrkey:\"$\",charkey:\"_\",explicitArray:!0,ignoreAttrs:!1,mergeAttrs:!1,explicitRoot:!0,validator:null,xmlns:!1,explicitChildren:!1,preserveChildrenOrder:!1,childkey:\"$$\",charsAsChildren:!1,includeWhiteChars:!1,async:!1,strict:!0,attrNameProcessors:null,attrValueProcessors:null,tagNameProcessors:null,valueProcessors:null,rootName:\"root\",xmldec:{version:\"1.0\",encoding:\"UTF-8\",standalone:!0},doctype:null,renderOpts:{pretty:!0,indent:\"  \",newline:\"\\n\"},headless:!1,chunkSize:1e4,emptyTag:\"\",cdata:!1}}}).call(this)},{}],121:[function(t,e,n){(function(){\"use strict\";var e,r,i,o,s,a,u,c,l=function(t,e){return function(){return t.apply(e,arguments)}},h=function(t,e){function n(){this.constructor=t}for(var r in e)p.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},p={}.hasOwnProperty;u=t(\"sax\"),i=t(\"events\"),e=t(\"./bom\"),a=t(\"./processors\"),c=t(\"timers\").setImmediate,r=t(\"./defaults\").defaults,o=function(t){return\"object\"==typeof t&&null!=t&&0===Object.keys(t).length},s=function(t,e,n){var r,i,o;for(r=0,i=t.length;r<i;r++)o=t[r],e=o(e,n);return e},n.Parser=function(t){function i(t){this.parseString=l(this.parseString,this),this.reset=l(this.reset,this),this.assignOrPush=l(this.assignOrPush,this),this.processAsync=l(this.processAsync,this);var e,i,o;if(!(this instanceof n.Parser))return new n.Parser(t);this.options={},i=r[.2];for(e in i)p.call(i,e)&&(o=i[e],this.options[e]=o);for(e in t)p.call(t,e)&&(o=t[e],this.options[e]=o);this.options.xmlns&&(this.options.xmlnskey=this.options.attrkey+\"ns\"),this.options.normalizeTags&&(this.options.tagNameProcessors||(this.options.tagNameProcessors=[]),this.options.tagNameProcessors.unshift(a.normalize)),this.reset()}return h(i,t),i.prototype.processAsync=function(){var t,e;try{return this.remaining.length<=this.options.chunkSize?(t=this.remaining,this.remaining=\"\",this.saxParser=this.saxParser.write(t),this.saxParser.close()):(t=this.remaining.substr(0,this.options.chunkSize),this.remaining=this.remaining.substr(this.options.chunkSize,this.remaining.length),this.saxParser=this.saxParser.write(t),c(this.processAsync))}catch(n){if(e=n,!this.saxParser.errThrown)return this.saxParser.errThrown=!0,this.emit(e)}},i.prototype.assignOrPush=function(t,e,n){return e in t?(t[e]instanceof Array||(t[e]=[t[e]]),t[e].push(n)):this.options.explicitArray?t[e]=[n]:t[e]=n},i.prototype.reset=function(){var t,e,n,r;return this.removeAllListeners(),this.saxParser=u.parser(this.options.strict,{trim:!1,normalize:!1,xmlns:this.options.xmlns}),this.saxParser.errThrown=!1,this.saxParser.onerror=function(t){return function(e){if(t.saxParser.resume(),!t.saxParser.errThrown)return t.saxParser.errThrown=!0,t.emit(\"error\",e)}}(this),this.saxParser.onend=function(t){return function(){if(!t.saxParser.ended)return t.saxParser.ended=!0,t.emit(\"end\",t.resultObject)}}(this),this.saxParser.ended=!1,this.EXPLICIT_CHARKEY=this.options.explicitCharkey,this.resultObject=null,r=[],t=this.options.attrkey,e=this.options.charkey,this.saxParser.onopentag=function(n){return function(i){var o,a,u,c,l;if(u={},u[e]=\"\",!n.options.ignoreAttrs){l=i.attributes;for(o in l)p.call(l,o)&&(t in u||n.options.mergeAttrs||(u[t]={}),a=n.options.attrValueProcessors?s(n.options.attrValueProcessors,i.attributes[o],o):i.attributes[o],c=n.options.attrNameProcessors?s(n.options.attrNameProcessors,o):o,n.options.mergeAttrs?n.assignOrPush(u,c,a):u[t][c]=a)}return u[\"#name\"]=n.options.tagNameProcessors?s(n.options.tagNameProcessors,i.name):i.name,n.options.xmlns&&(u[n.options.xmlnskey]={uri:i.uri,local:i.local}),r.push(u)}}(this),this.saxParser.onclosetag=function(t){return function(){var n,i,a,u,c,l,h,f,d,y;if(l=r.pop(),c=l[\"#name\"],t.options.explicitChildren&&t.options.preserveChildrenOrder||delete l[\"#name\"],l.cdata===!0&&(n=l.cdata,delete l.cdata),d=r[r.length-1],l[e].match(/^\\s*$/)&&!n?(i=l[e],delete l[e]):(t.options.trim&&(l[e]=l[e].trim()),t.options.normalize&&(l[e]=l[e].replace(/\\s{2,}/g,\" \").trim()),l[e]=t.options.valueProcessors?s(t.options.valueProcessors,l[e],c):l[e],1===Object.keys(l).length&&e in l&&!t.EXPLICIT_CHARKEY&&(l=l[e])),o(l)&&(l=\"\"!==t.options.emptyTag?t.options.emptyTag:i),null!=t.options.validator&&(y=\"/\"+function(){var t,e,n;for(n=[],t=0,e=r.length;t<e;t++)u=r[t],n.push(u[\"#name\"]);return n}().concat(c).join(\"/\"),function(){var e;try{return l=t.options.validator(y,d&&d[c],l)}catch(n){return e=n,t.emit(\"error\",e)}}()),t.options.explicitChildren&&!t.options.mergeAttrs&&\"object\"==typeof l)if(t.options.preserveChildrenOrder){if(d){d[t.options.childkey]=d[t.options.childkey]||[],h={};for(a in l)p.call(l,a)&&(h[a]=l[a]);d[t.options.childkey].push(h),delete l[\"#name\"],1===Object.keys(l).length&&e in l&&!t.EXPLICIT_CHARKEY&&(l=l[e])}}else u={},t.options.attrkey in l&&(u[t.options.attrkey]=l[t.options.attrkey],delete l[t.options.attrkey]),!t.options.charsAsChildren&&t.options.charkey in l&&(u[t.options.charkey]=l[t.options.charkey],delete l[t.options.charkey]),Object.getOwnPropertyNames(l).length>0&&(u[t.options.childkey]=l),l=u;return r.length>0?t.assignOrPush(d,c,l):(t.options.explicitRoot&&(f=l,l={},l[c]=f),t.resultObject=l,t.saxParser.ended=!0,t.emit(\"end\",t.resultObject))}}(this),n=function(t){return function(n){var i,o;if(o=r[r.length-1])return o[e]+=n,t.options.explicitChildren&&t.options.preserveChildrenOrder&&t.options.charsAsChildren&&(t.options.includeWhiteChars||\"\"!==n.replace(/\\\\n/g,\"\").trim())&&(o[t.options.childkey]=o[t.options.childkey]||[],i={\"#name\":\"__text__\"},i[e]=n,t.options.normalize&&(i[e]=i[e].replace(/\\s{2,}/g,\" \").trim()),o[t.options.childkey].push(i)),o}}(this),this.saxParser.ontext=n,this.saxParser.oncdata=function(t){return function(t){var e;if(e=n(t))return e.cdata=!0}}(this)},i.prototype.parseString=function(t,n){var r;null!=n&&\"function\"==typeof n&&(this.on(\"end\",function(t){return this.reset(),n(null,t)}),this.on(\"error\",function(t){return this.reset(),n(t)}));try{return t=t.toString(),\"\"===t.trim()?(this.emit(\"end\",null),!0):(t=e.stripBOM(t),this.options.async?(this.remaining=t,c(this.processAsync),this.saxParser):this.saxParser.write(t).close())}catch(i){if(r=i,!this.saxParser.errThrown&&!this.saxParser.ended)return this.emit(\"error\",r),this.saxParser.errThrown=!0;if(this.saxParser.ended)throw r}},i}(i.EventEmitter),n.parseString=function(t,e,r){var i,o,s;return null!=r?(\"function\"==typeof r&&(i=r),\"object\"==typeof e&&(o=e)):(\"function\"==typeof e&&(i=e),o={}),s=new n.Parser(o),s.parseString(t,i)}}).call(this)},{\"./bom\":118,\"./defaults\":120,\"./processors\":122,events:47,sax:111,timers:114}],122:[function(t,e,n){(function(){\"use strict\";var t;t=new RegExp(/(?!xmlns)^.*:/),n.normalize=function(t){return t.toLowerCase()},n.firstCharLowerCase=function(t){return t.charAt(0).toLowerCase()+t.slice(1)},n.stripPrefix=function(e){return e.replace(t,\"\")},n.parseNumbers=function(t){return isNaN(t)||(t=t%1===0?parseInt(t,10):parseFloat(t)),t},n.parseBooleans=function(t){return/^(?:true|false)$/i.test(t)&&(t=\"true\"===t.toLowerCase()),t}}).call(this)},{}],123:[function(t,e,n){(function(){\"use strict\";var e,r,i,o,s=function(t,e){function n(){this.constructor=t}for(var r in e)a.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t(\"./defaults\"),e=t(\"./builder\"),i=t(\"./parser\"),o=t(\"./processors\"),n.defaults=r.defaults,n.processors=o,n.ValidationError=function(t){function e(t){this.message=t}return s(e,t),e}(Error),n.Builder=e.Builder,n.Parser=i.Parser,n.parseString=i.parseString}).call(this)},{\"./builder\":119,\"./defaults\":120,\"./parser\":121,\"./processors\":122}],124:[function(t,e,n){(function(){var t,n,r,i,o,s,a=[].slice,u={}.hasOwnProperty;t=function(){var t,e,n,r,o,s;if(s=arguments[0],o=2<=arguments.length?a.call(arguments,1):[],i(Object.assign))Object.assign.apply(null,arguments);else for(t=0,n=o.length;t<n;t++)if(r=o[t],null!=r)for(e in r)u.call(r,e)&&(s[e]=r[e]);return s},i=function(t){return!!t&&\"[object Function]\"===Object.prototype.toString.call(t)},o=function(t){var e;return!!t&&(\"function\"==(e=typeof t)||\"object\"===e)},n=function(t){return i(Array.isArray)?Array.isArray(t):\"[object Array]\"===Object.prototype.toString.call(t)},r=function(t){var e;if(n(t))return!t.length;for(e in t)if(u.call(t,e))return!1;return!0},s=function(t){var e,n;return o(t)&&(n=Object.getPrototypeOf(t))&&(e=n.constructor)&&\"function\"==typeof e&&e instanceof e&&Function.prototype.toString.call(e)===Function.prototype.toString.call(Object)},e.exports.assign=t,e.exports.isFunction=i,e.exports.isObject=o,e.exports.isArray=n,e.exports.isEmpty=r,e.exports.isPlainObject=s}).call(this)},{}],125:[function(t,e,n){(function(){var t;e.exports=t=function(){function t(t,e,n){if(this.options=t.options,this.stringify=t.stringify,null==e)throw new Error(\"Missing attribute name of element \"+t.name);if(null==n)throw new Error(\"Missing attribute value for attribute \"+e+\" of element \"+t.name);this.name=this.stringify.attName(e),this.value=this.stringify.attValue(n)}return t.prototype.clone=function(){return Object.create(this)},t.prototype.toString=function(t){return this.options.writer.set(t).attribute(this)},t}()}).call(this)},{}],126:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);\nreturn n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing CDATA text\");this.text=this.stringify.cdata(n)}return i(e,t),e.prototype.clone=function(){return Object.create(this)},e.prototype.toString=function(t){return this.options.writer.set(t).cdata(this)},e}(r)}).call(this)},{\"./XMLNode\":137}],127:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing comment text\");this.text=this.stringify.comment(n)}return i(e,t),e.prototype.clone=function(){return Object.create(this)},e.prototype.toString=function(t){return this.options.writer.set(t).comment(this)},e}(r)}).call(this)},{\"./XMLNode\":137}],128:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n,r,i,o,s){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing DTD element name\");if(null==r)throw new Error(\"Missing DTD attribute name\");if(!i)throw new Error(\"Missing DTD attribute type\");if(!o)throw new Error(\"Missing DTD attribute default\");if(0!==o.indexOf(\"#\")&&(o=\"#\"+o),!o.match(/^(#REQUIRED|#IMPLIED|#FIXED|#DEFAULT)$/))throw new Error(\"Invalid default value type; expected: #REQUIRED, #IMPLIED, #FIXED or #DEFAULT\");if(s&&!o.match(/^(#FIXED|#DEFAULT)$/))throw new Error(\"Default value only applies to #FIXED or #DEFAULT\");this.elementName=this.stringify.eleName(n),this.attributeName=this.stringify.attName(r),this.attributeType=this.stringify.dtdAttType(i),this.defaultValue=this.stringify.dtdAttDefault(s),this.defaultValueType=o}return i(e,t),e.prototype.toString=function(t){return this.options.writer.set(t).dtdAttList(this)},e}(r)}).call(this)},{\"./XMLNode\":137}],129:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n,r){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing DTD element name\");r||(r=\"(#PCDATA)\"),Array.isArray(r)&&(r=\"(\"+r.join(\",\")+\")\"),this.name=this.stringify.eleName(n),this.value=this.stringify.dtdElementValue(r)}return i(e,t),e.prototype.toString=function(t){return this.options.writer.set(t).dtdElement(this)},e}(r)}).call(this)},{\"./XMLNode\":137}],130:[function(t,e,n){(function(){var n,r,i,o=function(t,e){function n(){this.constructor=t}for(var r in e)s.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},s={}.hasOwnProperty;i=t(\"./Utility\").isObject,r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n,r,o){if(e.__super__.constructor.call(this,t),null==r)throw new Error(\"Missing entity name\");if(null==o)throw new Error(\"Missing entity value\");if(this.pe=!!n,this.name=this.stringify.eleName(r),i(o)){if(!o.pubID&&!o.sysID)throw new Error(\"Public and/or system identifiers are required for an external entity\");if(o.pubID&&!o.sysID)throw new Error(\"System identifier is required for a public external entity\");if(null!=o.pubID&&(this.pubID=this.stringify.dtdPubID(o.pubID)),null!=o.sysID&&(this.sysID=this.stringify.dtdSysID(o.sysID)),null!=o.nData&&(this.nData=this.stringify.dtdNData(o.nData)),this.pe&&this.nData)throw new Error(\"Notation declaration is not allowed in a parameter entity\")}else this.value=this.stringify.dtdEntityValue(o)}return o(e,t),e.prototype.toString=function(t){return this.options.writer.set(t).dtdEntity(this)},e}(r)}).call(this)},{\"./Utility\":124,\"./XMLNode\":137}],131:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n,r){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing notation name\");if(!r.pubID&&!r.sysID)throw new Error(\"Public or system identifiers are required for an external entity\");this.name=this.stringify.eleName(n),null!=r.pubID&&(this.pubID=this.stringify.dtdPubID(r.pubID)),null!=r.sysID&&(this.sysID=this.stringify.dtdSysID(r.sysID))}return i(e,t),e.prototype.toString=function(t){return this.options.writer.set(t).dtdNotation(this)},e}(r)}).call(this)},{\"./XMLNode\":137}],132:[function(t,e,n){(function(){var n,r,i,o=function(t,e){function n(){this.constructor=t}for(var r in e)s.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},s={}.hasOwnProperty;i=t(\"./Utility\").isObject,r=t(\"./XMLNode\"),e.exports=n=function(t){function e(t,n,r,o){var s;e.__super__.constructor.call(this,t),i(n)&&(s=n,n=s.version,r=s.encoding,o=s.standalone),n||(n=\"1.0\"),this.version=this.stringify.xmlVersion(n),null!=r&&(this.encoding=this.stringify.xmlEncoding(r)),null!=o&&(this.standalone=this.stringify.xmlStandalone(o))}return o(e,t),e.prototype.toString=function(t){return this.options.writer.set(t).declaration(this)},e}(r)}).call(this)},{\"./Utility\":124,\"./XMLNode\":137}],133:[function(t,e,n){(function(){var n,r,i,o,s,a,u,c=function(t,e){function n(){this.constructor=t}for(var r in e)l.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},l={}.hasOwnProperty;u=t(\"./Utility\").isObject,a=t(\"./XMLNode\"),n=t(\"./XMLDTDAttList\"),i=t(\"./XMLDTDEntity\"),r=t(\"./XMLDTDElement\"),o=t(\"./XMLDTDNotation\"),e.exports=s=function(t){function e(t,n,r){var i,o;e.__super__.constructor.call(this,t),this.documentObject=t,u(n)&&(i=n,n=i.pubID,r=i.sysID),null==r&&(o=[n,r],r=o[0],n=o[1]),null!=n&&(this.pubID=this.stringify.dtdPubID(n)),null!=r&&(this.sysID=this.stringify.dtdSysID(r))}return c(e,t),e.prototype.element=function(t,e){var n;return n=new r(this,t,e),this.children.push(n),this},e.prototype.attList=function(t,e,r,i,o){var s;return s=new n(this,t,e,r,i,o),this.children.push(s),this},e.prototype.entity=function(t,e){var n;return n=new i(this,(!1),t,e),this.children.push(n),this},e.prototype.pEntity=function(t,e){var n;return n=new i(this,(!0),t,e),this.children.push(n),this},e.prototype.notation=function(t,e){var n;return n=new o(this,t,e),this.children.push(n),this},e.prototype.toString=function(t){return this.options.writer.set(t).docType(this)},e.prototype.ele=function(t,e){return this.element(t,e)},e.prototype.att=function(t,e,n,r,i){return this.attList(t,e,n,r,i)},e.prototype.ent=function(t,e){return this.entity(t,e)},e.prototype.pent=function(t,e){return this.pEntity(t,e)},e.prototype.not=function(t,e){return this.notation(t,e)},e.prototype.up=function(){return this.root()||this.documentObject},e}(a)}).call(this)},{\"./Utility\":124,\"./XMLDTDAttList\":128,\"./XMLDTDElement\":129,\"./XMLDTDEntity\":130,\"./XMLDTDNotation\":131,\"./XMLNode\":137}],134:[function(t,e,n){(function(){var n,r,i,o,s,a=function(t,e){function n(){this.constructor=t}for(var r in e)u.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},u={}.hasOwnProperty;s=t(\"./Utility\").isPlainObject,r=t(\"./XMLNode\"),o=t(\"./XMLStringifier\"),i=t(\"./XMLStringWriter\"),e.exports=n=function(t){function e(t){e.__super__.constructor.call(this,null),t||(t={}),t.writer||(t.writer=new i),this.options=t,this.stringify=new o(t),this.isDocument=!0}return a(e,t),e.prototype.end=function(t){var e;return t?s(t)&&(e=t,t=this.options.writer.set(e)):t=this.options.writer,t.document(this)},e.prototype.toString=function(t){return this.options.writer.set(t).document(this)},e}(r)}).call(this)},{\"./Utility\":124,\"./XMLNode\":137,\"./XMLStringWriter\":141,\"./XMLStringifier\":142}],135:[function(t,e,n){(function(){var n,r,i,o,s,a,u,c,l,h,p,f,d,y,m,_,g,v,b,w,E={}.hasOwnProperty;w=t(\"./Utility\"),v=w.isObject,g=w.isFunction,b=w.isPlainObject,p=t(\"./XMLElement\"),r=t(\"./XMLCData\"),i=t(\"./XMLComment\"),d=t(\"./XMLRaw\"),_=t(\"./XMLText\"),f=t(\"./XMLProcessingInstruction\"),c=t(\"./XMLDeclaration\"),l=t(\"./XMLDocType\"),o=t(\"./XMLDTDAttList\"),a=t(\"./XMLDTDEntity\"),s=t(\"./XMLDTDElement\"),u=t(\"./XMLDTDNotation\"),n=t(\"./XMLAttribute\"),m=t(\"./XMLStringifier\"),y=t(\"./XMLStringWriter\"),e.exports=h=function(){function t(t,e,n){var r;t||(t={}),t.writer?b(t.writer)&&(r=t.writer,t.writer=new y(r)):t.writer=new y(t),this.options=t,this.writer=t.writer,this.stringify=new m(t),this.onDataCallback=e||function(){},this.onEndCallback=n||function(){},this.currentNode=null,this.currentLevel=-1,this.openTags={},this.documentStarted=!1,this.documentCompleted=!1,this.root=null}return t.prototype.node=function(t,e,n){var r;if(null==t)throw new Error(\"Missing node name\");if(this.root&&this.currentLevel===-1)throw new Error(\"Document can only have one root node\");return this.openCurrent(),t=t.valueOf(),null==e&&(e={}),e=e.valueOf(),v(e)||(r=[e,n],n=r[0],e=r[1]),this.currentNode=new p(this,t,e),this.currentNode.children=!1,this.currentLevel++,this.openTags[this.currentLevel]=this.currentNode,null!=n&&this.text(n),this},t.prototype.element=function(t,e,n){return this.currentNode&&this.currentNode instanceof l?this.dtdElement.apply(this,arguments):this.node(t,e,n)},t.prototype.attribute=function(t,e){var r,i;if(!this.currentNode||this.currentNode.children)throw new Error(\"att() can only be used immediately after an ele() call in callback mode\");if(null!=t&&(t=t.valueOf()),v(t))for(r in t)E.call(t,r)&&(i=t[r],this.attribute(r,i));else g(e)&&(e=e.apply()),this.options.skipNullAttributes&&null==e||(this.currentNode.attributes[t]=new n(this,t,e));return this},t.prototype.text=function(t){var e;return this.openCurrent(),e=new _(this,t),this.onData(this.writer.text(e,this.currentLevel+1)),this},t.prototype.cdata=function(t){var e;return this.openCurrent(),e=new r(this,t),this.onData(this.writer.cdata(e,this.currentLevel+1)),this},t.prototype.comment=function(t){var e;return this.openCurrent(),e=new i(this,t),this.onData(this.writer.comment(e,this.currentLevel+1)),this},t.prototype.raw=function(t){var e;return this.openCurrent(),e=new d(this,t),this.onData(this.writer.raw(e,this.currentLevel+1)),this},t.prototype.instruction=function(t,e){var n,r,i,o,s;if(this.openCurrent(),null!=t&&(t=t.valueOf()),null!=e&&(e=e.valueOf()),Array.isArray(t))for(n=0,o=t.length;n<o;n++)r=t[n],this.instruction(r);else if(v(t))for(r in t)E.call(t,r)&&(i=t[r],this.instruction(r,i));else g(e)&&(e=e.apply()),s=new f(this,t,e),this.onData(this.writer.processingInstruction(s,this.currentLevel+1));return this},t.prototype.declaration=function(t,e,n){var r;if(this.openCurrent(),this.documentStarted)throw new Error(\"declaration() must be the first node\");return r=new c(this,t,e,n),this.onData(this.writer.declaration(r,this.currentLevel+1)),this},t.prototype.doctype=function(t,e,n){if(this.openCurrent(),null==t)throw new Error(\"Missing root node name\");if(this.root)throw new Error(\"dtd() must come before the root node\");return this.currentNode=new l(this,e,n),this.currentNode.rootNodeName=t,this.currentNode.children=!1,this.currentLevel++,this.openTags[this.currentLevel]=this.currentNode,this},t.prototype.dtdElement=function(t,e){var n;return this.openCurrent(),n=new s(this,t,e),this.onData(this.writer.dtdElement(n,this.currentLevel+1)),this},t.prototype.attList=function(t,e,n,r,i){var s;return this.openCurrent(),s=new o(this,t,e,n,r,i),this.onData(this.writer.dtdAttList(s,this.currentLevel+1)),this},t.prototype.entity=function(t,e){var n;return this.openCurrent(),n=new a(this,(!1),t,e),this.onData(this.writer.dtdEntity(n,this.currentLevel+1)),this},t.prototype.pEntity=function(t,e){var n;return this.openCurrent(),n=new a(this,(!0),t,e),this.onData(this.writer.dtdEntity(n,this.currentLevel+1)),this},t.prototype.notation=function(t,e){var n;return this.openCurrent(),n=new u(this,t,e),this.onData(this.writer.dtdNotation(n,this.currentLevel+1)),this},t.prototype.up=function(){if(this.currentLevel<0)throw new Error(\"The document node has no parent\");return this.currentNode?(this.currentNode.children?this.closeNode(this.currentNode):this.openNode(this.currentNode),this.currentNode=null):this.closeNode(this.openTags[this.currentLevel]),delete this.openTags[this.currentLevel],this.currentLevel--,this},t.prototype.end=function(){for(;this.currentLevel>=0;)this.up();return this.onEnd()},t.prototype.openCurrent=function(){if(this.currentNode)return this.currentNode.children=!0,this.openNode(this.currentNode)},t.prototype.openNode=function(t){if(!t.isOpen)return!this.root&&0===this.currentLevel&&t instanceof p&&(this.root=t),this.onData(this.writer.openNode(t,this.currentLevel)),t.isOpen=!0},t.prototype.closeNode=function(t){if(!t.isClosed)return this.onData(this.writer.closeNode(t,this.currentLevel)),t.isClosed=!0},t.prototype.onData=function(t){return this.documentStarted=!0,this.onDataCallback(t)},t.prototype.onEnd=function(){return this.documentCompleted=!0,this.onEndCallback()},t.prototype.ele=function(){return this.element.apply(this,arguments)},t.prototype.nod=function(t,e,n){return this.node(t,e,n)},t.prototype.txt=function(t){return this.text(t)},t.prototype.dat=function(t){return this.cdata(t)},t.prototype.com=function(t){return this.comment(t)},t.prototype.ins=function(t,e){return this.instruction(t,e)},t.prototype.dec=function(t,e,n){return this.declaration(t,e,n)},t.prototype.dtd=function(t,e,n){return this.doctype(t,e,n)},t.prototype.e=function(t,e,n){return this.element(t,e,n)},t.prototype.n=function(t,e,n){return this.node(t,e,n)},t.prototype.t=function(t){return this.text(t)},t.prototype.d=function(t){return this.cdata(t)},t.prototype.c=function(t){return this.comment(t)},t.prototype.r=function(t){return this.raw(t)},t.prototype.i=function(t,e){return this.instruction(t,e)},t.prototype.att=function(){return this.currentNode&&this.currentNode instanceof l?this.attList.apply(this,arguments):this.attribute.apply(this,arguments)},t.prototype.a=function(){return this.currentNode&&this.currentNode instanceof l?this.attList.apply(this,arguments):this.attribute.apply(this,arguments)},t.prototype.ent=function(t,e){return this.entity(t,e)},t.prototype.pent=function(t,e){return this.pEntity(t,e)},t.prototype.not=function(t,e){return this.notation(t,e)},t}()}).call(this)},{\"./Utility\":124,\"./XMLAttribute\":125,\"./XMLCData\":126,\"./XMLComment\":127,\"./XMLDTDAttList\":128,\"./XMLDTDElement\":129,\"./XMLDTDEntity\":130,\"./XMLDTDNotation\":131,\"./XMLDeclaration\":132,\"./XMLDocType\":133,\"./XMLElement\":136,\"./XMLProcessingInstruction\":138,\"./XMLRaw\":139,\"./XMLStringWriter\":141,\"./XMLStringifier\":142,\"./XMLText\":143}],136:[function(t,e,n){(function(){var n,r,i,o,s,a,u=function(t,e){function n(){this.constructor=t}for(var r in e)c.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},c={}.hasOwnProperty;a=t(\"./Utility\"),s=a.isObject,o=a.isFunction,i=t(\"./XMLNode\"),n=t(\"./XMLAttribute\"),e.exports=r=function(t){function e(t,n,r){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing element name\");this.name=this.stringify.eleName(n),this.attributes={},null!=r&&this.attribute(r),t.isDocument&&(this.isRoot=!0,this.documentObject=t,t.rootObject=this)}return u(e,t),e.prototype.clone=function(){var t,e,n,r;n=Object.create(this),n.isRoot&&(n.documentObject=null),n.attributes={},r=this.attributes;for(e in r)c.call(r,e)&&(t=r[e],n.attributes[e]=t.clone());return n.children=[],this.children.forEach(function(t){var e;return e=t.clone(),e.parent=n,n.children.push(e)}),n},e.prototype.attribute=function(t,e){var r,i;if(null!=t&&(t=t.valueOf()),s(t))for(r in t)c.call(t,r)&&(i=t[r],this.attribute(r,i));else o(e)&&(e=e.apply()),this.options.skipNullAttributes&&null==e||(this.attributes[t]=new n(this,t,e));return this},e.prototype.removeAttribute=function(t){var e,n,r;if(null==t)throw new Error(\"Missing attribute name\");if(t=t.valueOf(),Array.isArray(t))for(n=0,r=t.length;n<r;n++)e=t[n],delete this.attributes[e];else delete this.attributes[t];return this},e.prototype.toString=function(t){return this.options.writer.set(t).element(this)},e.prototype.att=function(t,e){return this.attribute(t,e)},e.prototype.a=function(t,e){return this.attribute(t,e)},e}(i)}).call(this)},{\"./Utility\":124,\"./XMLAttribute\":125,\"./XMLNode\":137}],137:[function(t,e,n){(function(){var n,r,i,o,s,a,u,c,l,h,p,f,d,y={}.hasOwnProperty;d=t(\"./Utility\"),f=d.isObject,p=d.isFunction,h=d.isEmpty,s=null,n=null,r=null,i=null,o=null,c=null,l=null,u=null,e.exports=a=function(){function e(e){this.parent=e,this.parent&&(this.options=this.parent.options,this.stringify=this.parent.stringify),this.children=[],s||(s=t(\"./XMLElement\"),n=t(\"./XMLCData\"),r=t(\"./XMLComment\"),i=t(\"./XMLDeclaration\"),o=t(\"./XMLDocType\"),c=t(\"./XMLRaw\"),l=t(\"./XMLText\"),u=t(\"./XMLProcessingInstruction\"))}return e.prototype.element=function(t,e,n){var r,i,o,s,a,u,c,l,d,m;if(u=null,null==e&&(e={}),e=e.valueOf(),f(e)||(d=[e,n],n=d[0],e=d[1]),null!=t&&(t=t.valueOf()),Array.isArray(t))for(o=0,c=t.length;o<c;o++)i=t[o],u=this.element(i);else if(p(t))u=this.element(t.apply());else if(f(t)){for(a in t)if(y.call(t,a))if(m=t[a],p(m)&&(m=m.apply()),f(m)&&h(m)&&(m=null),!this.options.ignoreDecorators&&this.stringify.convertAttKey&&0===a.indexOf(this.stringify.convertAttKey))u=this.attribute(a.substr(this.stringify.convertAttKey.length),m);else if(!this.options.separateArrayItems&&Array.isArray(m))for(s=0,l=m.length;s<l;s++)i=m[s],r={},r[a]=i,u=this.element(r);else f(m)?(u=this.element(a),u.element(m)):u=this.element(a,m)}else u=!this.options.ignoreDecorators&&this.stringify.convertTextKey&&0===t.indexOf(this.stringify.convertTextKey)?this.text(n):!this.options.ignoreDecorators&&this.stringify.convertCDataKey&&0===t.indexOf(this.stringify.convertCDataKey)?this.cdata(n):!this.options.ignoreDecorators&&this.stringify.convertCommentKey&&0===t.indexOf(this.stringify.convertCommentKey)?this.comment(n):!this.options.ignoreDecorators&&this.stringify.convertRawKey&&0===t.indexOf(this.stringify.convertRawKey)?this.raw(n):!this.options.ignoreDecorators&&this.stringify.convertPIKey&&0===t.indexOf(this.stringify.convertPIKey)?this.instruction(t.substr(this.stringify.convertPIKey.length),n):this.node(t,e,n);if(null==u)throw new Error(\"Could not create any elements with: \"+t);return u},e.prototype.insertBefore=function(t,e,n){var r,i,o;if(this.isRoot)throw new Error(\"Cannot insert elements at root level\");return i=this.parent.children.indexOf(this),o=this.parent.children.splice(i),r=this.parent.element(t,e,n),Array.prototype.push.apply(this.parent.children,o),r},e.prototype.insertAfter=function(t,e,n){var r,i,o;if(this.isRoot)throw new Error(\"Cannot insert elements at root level\");return i=this.parent.children.indexOf(this),o=this.parent.children.splice(i+1),r=this.parent.element(t,e,n),Array.prototype.push.apply(this.parent.children,o),r},e.prototype.remove=function(){var t,e;if(this.isRoot)throw new Error(\"Cannot remove the root element\");return t=this.parent.children.indexOf(this),[].splice.apply(this.parent.children,[t,t-t+1].concat(e=[])),e,this.parent},e.prototype.node=function(t,e,n){var r,i;return null!=t&&(t=t.valueOf()),e||(e={}),e=e.valueOf(),f(e)||(i=[e,n],n=i[0],e=i[1]),r=new s(this,t,e),null!=n&&r.text(n),this.children.push(r),r},e.prototype.text=function(t){var e;return e=new l(this,t),this.children.push(e),this},e.prototype.cdata=function(t){var e;return e=new n(this,t),this.children.push(e),this},e.prototype.comment=function(t){var e;return e=new r(this,t),this.children.push(e),this},e.prototype.commentBefore=function(t){var e,n,r;return n=this.parent.children.indexOf(this),r=this.parent.children.splice(n),e=this.parent.comment(t),Array.prototype.push.apply(this.parent.children,r),this},e.prototype.commentAfter=function(t){var e,n,r;return n=this.parent.children.indexOf(this),r=this.parent.children.splice(n+1),e=this.parent.comment(t),Array.prototype.push.apply(this.parent.children,r),this},e.prototype.raw=function(t){var e;return e=new c(this,t),this.children.push(e),this},e.prototype.instruction=function(t,e){var n,r,i,o,s;if(null!=t&&(t=t.valueOf()),null!=e&&(e=e.valueOf()),Array.isArray(t))for(o=0,s=t.length;o<s;o++)n=t[o],this.instruction(n);else if(f(t))for(n in t)y.call(t,n)&&(r=t[n],this.instruction(n,r));else p(e)&&(e=e.apply()),i=new u(this,t,e),this.children.push(i);return this},e.prototype.instructionBefore=function(t,e){var n,r,i;return r=this.parent.children.indexOf(this),i=this.parent.children.splice(r),n=this.parent.instruction(t,e),Array.prototype.push.apply(this.parent.children,i),this},e.prototype.instructionAfter=function(t,e){var n,r,i;return r=this.parent.children.indexOf(this),i=this.parent.children.splice(r+1),n=this.parent.instruction(t,e),Array.prototype.push.apply(this.parent.children,i),this},e.prototype.declaration=function(t,e,n){var r,o;return r=this.document(),o=new i(r,t,e,n),r.children[0]instanceof i?r.children[0]=o:r.children.unshift(o),r.root()||r},e.prototype.doctype=function(t,e){var n,r,i,s,a,u,c,l,h,p;for(r=this.document(),i=new o(r,t,e),h=r.children,s=a=0,c=h.length;a<c;s=++a)if(n=h[s],n instanceof o)return r.children[s]=i,i;for(p=r.children,s=u=0,l=p.length;u<l;s=++u)if(n=p[s],n.isRoot)return r.children.splice(s,0,i),i;return r.children.push(i),i},e.prototype.up=function(){if(this.isRoot)throw new Error(\"The root node has no parent. Use doc() if you need to get the document object.\");return this.parent},e.prototype.root=function(){var t;for(t=this;t;){if(t.isDocument)return t.rootObject;if(t.isRoot)return t;t=t.parent}},e.prototype.document=function(){var t;for(t=this;t;){if(t.isDocument)return t;t=t.parent}},e.prototype.end=function(t){return this.document().end(t)},e.prototype.prev=function(){var t;if(t=this.parent.children.indexOf(this),t<1)throw new Error(\"Already at the first node\");return this.parent.children[t-1]},e.prototype.next=function(){var t;if(t=this.parent.children.indexOf(this),t===-1||t===this.parent.children.length-1)throw new Error(\"Already at the last node\");return this.parent.children[t+1]},e.prototype.importDocument=function(t){var e;return e=t.root().clone(),e.parent=this,e.isRoot=!1,this.children.push(e),this},e.prototype.ele=function(t,e,n){return this.element(t,e,n)},e.prototype.nod=function(t,e,n){return this.node(t,e,n)},e.prototype.txt=function(t){return this.text(t)},e.prototype.dat=function(t){return this.cdata(t)},e.prototype.com=function(t){return this.comment(t)},e.prototype.ins=function(t,e){return this.instruction(t,e)},e.prototype.doc=function(){return this.document()},e.prototype.dec=function(t,e,n){return this.declaration(t,e,n)},e.prototype.dtd=function(t,e){return this.doctype(t,e)},e.prototype.e=function(t,e,n){return this.element(t,e,n)},e.prototype.n=function(t,e,n){return this.node(t,e,n)},e.prototype.t=function(t){return this.text(t)},e.prototype.d=function(t){return this.cdata(t)},e.prototype.c=function(t){return this.comment(t)},e.prototype.r=function(t){return this.raw(t)},e.prototype.i=function(t,e){return this.instruction(t,e)},e.prototype.u=function(){return this.up()},e.prototype.importXMLBuilder=function(t){return this.importDocument(t)},e}()}).call(this)},{\"./Utility\":124,\"./XMLCData\":126,\"./XMLComment\":127,\"./XMLDeclaration\":132,\"./XMLDocType\":133,\"./XMLElement\":136,\"./XMLProcessingInstruction\":138,\"./XMLRaw\":139,\"./XMLText\":143}],138:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;n=t(\"./XMLNode\"),e.exports=r=function(t){function e(t,n,r){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing instruction target\");this.target=this.stringify.insTarget(n),r&&(this.value=this.stringify.insValue(r))}return i(e,t),e.prototype.clone=function(){return Object.create(this)},e.prototype.toString=function(t){return this.options.writer.set(t).processingInstruction(this)},e}(n)}).call(this)},{\"./XMLNode\":137}],139:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;n=t(\"./XMLNode\"),e.exports=r=function(t){function e(t,n){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing raw text\");this.value=this.stringify.raw(n)}return i(e,t),e.prototype.clone=function(){return Object.create(this)},e.prototype.toString=function(t){return this.options.writer.set(t).raw(this)},e}(n)}).call(this)},{\"./XMLNode\":137}],140:[function(t,e,n){(function(){var n,r,i,o,s,a,u,c,l,h,p,f,d,y,m=function(t,e){function n(){this.constructor=t}for(var r in e)_.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},_={}.hasOwnProperty;u=t(\"./XMLDeclaration\"),c=t(\"./XMLDocType\"),n=t(\"./XMLCData\"),r=t(\"./XMLComment\"),l=t(\"./XMLElement\"),p=t(\"./XMLRaw\"),d=t(\"./XMLText\"),h=t(\"./XMLProcessingInstruction\"),i=t(\"./XMLDTDAttList\"),o=t(\"./XMLDTDElement\"),s=t(\"./XMLDTDEntity\"),a=t(\"./XMLDTDNotation\"),y=t(\"./XMLWriterBase\"),e.exports=f=function(t){function e(t,n){e.__super__.constructor.call(this,n),this.stream=t}return m(e,t),e.prototype.document=function(t){var e,n,i,o,s,a,l,p;for(a=t.children,n=0,o=a.length;n<o;n++)e=a[n],e.isLastRootNode=!1;for(t.children[t.children.length-1].isLastRootNode=!0,l=t.children,p=[],i=0,s=l.length;i<s;i++)switch(e=l[i],!1){case!(e instanceof u):p.push(this.declaration(e));break;case!(e instanceof c):p.push(this.docType(e));break;case!(e instanceof r):p.push(this.comment(e));break;case!(e instanceof h):p.push(this.processingInstruction(e));break;default:p.push(this.element(e))}return p},e.prototype.attribute=function(t){return this.stream.write(\" \"+t.name+'=\"'+t.value+'\"')},e.prototype.cdata=function(t,e){return this.stream.write(this.space(e)+\"<![CDATA[\"+t.text+\"]]>\"+this.endline(t))},e.prototype.comment=function(t,e){return this.stream.write(this.space(e)+\"<!-- \"+t.text+\" -->\"+this.endline(t))},e.prototype.declaration=function(t,e){return this.stream.write(this.space(e)),this.stream.write('<?xml version=\"'+t.version+'\"'),null!=t.encoding&&this.stream.write(' encoding=\"'+t.encoding+'\"'),null!=t.standalone&&this.stream.write(' standalone=\"'+t.standalone+'\"'),this.stream.write(this.spacebeforeslash+\"?>\"),this.stream.write(this.endline(t))},e.prototype.docType=function(t,e){var u,c,l,p;if(e||(e=0),this.stream.write(this.space(e)),this.stream.write(\"<!DOCTYPE \"+t.root().name),t.pubID&&t.sysID?this.stream.write(' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"'):t.sysID&&this.stream.write(' SYSTEM \"'+t.sysID+'\"'),t.children.length>0){for(this.stream.write(\" [\"),this.stream.write(this.endline(t)),p=t.children,c=0,l=p.length;c<l;c++)switch(u=p[c],!1){case!(u instanceof i):this.dtdAttList(u,e+1);break;case!(u instanceof o):this.dtdElement(u,e+1);break;case!(u instanceof s):this.dtdEntity(u,e+1);break;case!(u instanceof a):this.dtdNotation(u,e+1);break;case!(u instanceof n):this.cdata(u,e+1);break;case!(u instanceof r):this.comment(u,e+1);break;case!(u instanceof h):this.processingInstruction(u,e+1);break;default:throw new Error(\"Unknown DTD node type: \"+u.constructor.name)}this.stream.write(\"]\")}return this.stream.write(this.spacebeforeslash+\">\"),this.stream.write(this.endline(t))},e.prototype.element=function(t,e){var i,o,s,a,u,c,f,y;e||(e=0),y=this.space(e),this.stream.write(y+\"<\"+t.name),c=t.attributes;for(u in c)_.call(c,u)&&(i=c[u],this.attribute(i));if(0===t.children.length||t.children.every(function(t){return\"\"===t.value}))this.allowEmpty?this.stream.write(\"></\"+t.name+\">\"):this.stream.write(this.spacebeforeslash+\"/>\");else if(this.pretty&&1===t.children.length&&null!=t.children[0].value)this.stream.write(\">\"),this.stream.write(t.children[0].value),this.stream.write(\"</\"+t.name+\">\");else{for(this.stream.write(\">\"+this.newline),f=t.children,s=0,a=f.length;s<a;s++)switch(o=f[s],!1){case!(o instanceof n):this.cdata(o,e+1);break;case!(o instanceof r):this.comment(o,e+1);break;case!(o instanceof l):this.element(o,e+1);break;case!(o instanceof p):this.raw(o,e+1);break;case!(o instanceof d):this.text(o,e+1);break;case!(o instanceof h):this.processingInstruction(o,e+1);break;default:throw new Error(\"Unknown XML node type: \"+o.constructor.name)}this.stream.write(y+\"</\"+t.name+\">\")}return this.stream.write(this.endline(t))},e.prototype.processingInstruction=function(t,e){return this.stream.write(this.space(e)+\"<?\"+t.target),t.value&&this.stream.write(\" \"+t.value),this.stream.write(this.spacebeforeslash+\"?>\"+this.endline(t))},e.prototype.raw=function(t,e){return this.stream.write(this.space(e)+t.value+this.endline(t))},e.prototype.text=function(t,e){return this.stream.write(this.space(e)+t.value+this.endline(t))},e.prototype.dtdAttList=function(t,e){return this.stream.write(this.space(e)+\"<!ATTLIST \"+t.elementName+\" \"+t.attributeName+\" \"+t.attributeType),\"#DEFAULT\"!==t.defaultValueType&&this.stream.write(\" \"+t.defaultValueType),t.defaultValue&&this.stream.write(' \"'+t.defaultValue+'\"'),this.stream.write(this.spacebeforeslash+\">\"+this.endline(t))},e.prototype.dtdElement=function(t,e){return this.stream.write(this.space(e)+\"<!ELEMENT \"+t.name+\" \"+t.value),this.stream.write(this.spacebeforeslash+\">\"+this.endline(t))},e.prototype.dtdEntity=function(t,e){return this.stream.write(this.space(e)+\"<!ENTITY\"),t.pe&&this.stream.write(\" %\"),this.stream.write(\" \"+t.name),t.value?this.stream.write(' \"'+t.value+'\"'):(t.pubID&&t.sysID?this.stream.write(' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"'):t.sysID&&this.stream.write(' SYSTEM \"'+t.sysID+'\"'),t.nData&&this.stream.write(\" NDATA \"+t.nData)),this.stream.write(this.spacebeforeslash+\">\"+this.endline(t))},e.prototype.dtdNotation=function(t,e){return this.stream.write(this.space(e)+\"<!NOTATION \"+t.name),t.pubID&&t.sysID?this.stream.write(' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"'):t.pubID?this.stream.write(' PUBLIC \"'+t.pubID+'\"'):t.sysID&&this.stream.write(' SYSTEM \"'+t.sysID+'\"'),this.stream.write(this.spacebeforeslash+\">\"+this.endline(t))},e.prototype.endline=function(t){return t.isLastRootNode?\"\":this.newline},e}(y)}).call(this)},{\"./XMLCData\":126,\"./XMLComment\":127,\"./XMLDTDAttList\":128,\"./XMLDTDElement\":129,\"./XMLDTDEntity\":130,\"./XMLDTDNotation\":131,\"./XMLDeclaration\":132,\"./XMLDocType\":133,\"./XMLElement\":136,\"./XMLProcessingInstruction\":138,\"./XMLRaw\":139,\"./XMLText\":143,\"./XMLWriterBase\":144}],141:[function(t,e,n){(function(){var n,r,i,o,s,a,u,c,l,h,p,f,d,y,m=function(t,e){function n(){this.constructor=t}for(var r in e)_.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},_={}.hasOwnProperty;u=t(\"./XMLDeclaration\"),c=t(\"./XMLDocType\"),n=t(\"./XMLCData\"),r=t(\"./XMLComment\"),l=t(\"./XMLElement\"),p=t(\"./XMLRaw\"),d=t(\"./XMLText\"),h=t(\"./XMLProcessingInstruction\"),i=t(\"./XMLDTDAttList\"),o=t(\"./XMLDTDElement\"),s=t(\"./XMLDTDEntity\"),a=t(\"./XMLDTDNotation\"),y=t(\"./XMLWriterBase\"),e.exports=f=function(t){function e(t){e.__super__.constructor.call(this,t)}return m(e,t),e.prototype.document=function(t){var e,n,i,o,s;for(this.textispresent=!1,o=\"\",s=t.children,n=0,i=s.length;n<i;n++)e=s[n],o+=function(){switch(!1){case!(e instanceof u):return this.declaration(e);case!(e instanceof c):return this.docType(e);case!(e instanceof r):return this.comment(e);case!(e instanceof h):return this.processingInstruction(e);default:return this.element(e,0)}}.call(this);return this.pretty&&o.slice(-this.newline.length)===this.newline&&(o=o.slice(0,-this.newline.length)),o},e.prototype.attribute=function(t){\nreturn\" \"+t.name+'=\"'+t.value+'\"'},e.prototype.cdata=function(t,e){return this.space(e)+\"<![CDATA[\"+t.text+\"]]>\"+this.newline},e.prototype.comment=function(t,e){return this.space(e)+\"<!-- \"+t.text+\" -->\"+this.newline},e.prototype.declaration=function(t,e){var n;return n=this.space(e),n+='<?xml version=\"'+t.version+'\"',null!=t.encoding&&(n+=' encoding=\"'+t.encoding+'\"'),null!=t.standalone&&(n+=' standalone=\"'+t.standalone+'\"'),n+=this.spacebeforeslash+\"?>\",n+=this.newline},e.prototype.docType=function(t,e){var u,c,l,p,f;if(e||(e=0),p=this.space(e),p+=\"<!DOCTYPE \"+t.root().name,t.pubID&&t.sysID?p+=' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"':t.sysID&&(p+=' SYSTEM \"'+t.sysID+'\"'),t.children.length>0){for(p+=\" [\",p+=this.newline,f=t.children,c=0,l=f.length;c<l;c++)u=f[c],p+=function(){switch(!1){case!(u instanceof i):return this.dtdAttList(u,e+1);case!(u instanceof o):return this.dtdElement(u,e+1);case!(u instanceof s):return this.dtdEntity(u,e+1);case!(u instanceof a):return this.dtdNotation(u,e+1);case!(u instanceof n):return this.cdata(u,e+1);case!(u instanceof r):return this.comment(u,e+1);case!(u instanceof h):return this.processingInstruction(u,e+1);default:throw new Error(\"Unknown DTD node type: \"+u.constructor.name)}}.call(this);p+=\"]\"}return p+=this.spacebeforeslash+\">\",p+=this.newline},e.prototype.element=function(t,e){var i,o,s,a,u,c,f,y,m,g,v,b,w;e||(e=0),w=!1,this.textispresent?(this.newline=\"\",this.pretty=!1):(this.newline=this.newlinedefault,this.pretty=this.prettydefault),b=this.space(e),y=\"\",y+=b+\"<\"+t.name,m=t.attributes;for(f in m)_.call(m,f)&&(i=m[f],y+=this.attribute(i));if(0===t.children.length||t.children.every(function(t){return\"\"===t.value}))y+=this.allowEmpty?\"></\"+t.name+\">\"+this.newline:this.spacebeforeslash+\"/>\"+this.newline;else if(this.pretty&&1===t.children.length&&null!=t.children[0].value)y+=\">\",y+=t.children[0].value,y+=\"</\"+t.name+\">\"+this.newline;else{if(this.dontprettytextnodes)for(g=t.children,s=0,u=g.length;s<u;s++)if(o=g[s],null!=o.value){this.textispresent++,w=!0;break}for(this.textispresent&&(this.newline=\"\",this.pretty=!1,b=this.space(e)),y+=\">\"+this.newline,v=t.children,a=0,c=v.length;a<c;a++)o=v[a],y+=function(){switch(!1){case!(o instanceof n):return this.cdata(o,e+1);case!(o instanceof r):return this.comment(o,e+1);case!(o instanceof l):return this.element(o,e+1);case!(o instanceof p):return this.raw(o,e+1);case!(o instanceof d):return this.text(o,e+1);case!(o instanceof h):return this.processingInstruction(o,e+1);default:throw new Error(\"Unknown XML node type: \"+o.constructor.name)}}.call(this);w&&this.textispresent--,this.textispresent||(this.newline=this.newlinedefault,this.pretty=this.prettydefault),y+=b+\"</\"+t.name+\">\"+this.newline}return y},e.prototype.processingInstruction=function(t,e){var n;return n=this.space(e)+\"<?\"+t.target,t.value&&(n+=\" \"+t.value),n+=this.spacebeforeslash+\"?>\"+this.newline},e.prototype.raw=function(t,e){return this.space(e)+t.value+this.newline},e.prototype.text=function(t,e){return this.space(e)+t.value+this.newline},e.prototype.dtdAttList=function(t,e){var n;return n=this.space(e)+\"<!ATTLIST \"+t.elementName+\" \"+t.attributeName+\" \"+t.attributeType,\"#DEFAULT\"!==t.defaultValueType&&(n+=\" \"+t.defaultValueType),t.defaultValue&&(n+=' \"'+t.defaultValue+'\"'),n+=this.spacebeforeslash+\">\"+this.newline},e.prototype.dtdElement=function(t,e){return this.space(e)+\"<!ELEMENT \"+t.name+\" \"+t.value+this.spacebeforeslash+\">\"+this.newline},e.prototype.dtdEntity=function(t,e){var n;return n=this.space(e)+\"<!ENTITY\",t.pe&&(n+=\" %\"),n+=\" \"+t.name,t.value?n+=' \"'+t.value+'\"':(t.pubID&&t.sysID?n+=' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"':t.sysID&&(n+=' SYSTEM \"'+t.sysID+'\"'),t.nData&&(n+=\" NDATA \"+t.nData)),n+=this.spacebeforeslash+\">\"+this.newline},e.prototype.dtdNotation=function(t,e){var n;return n=this.space(e)+\"<!NOTATION \"+t.name,t.pubID&&t.sysID?n+=' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"':t.pubID?n+=' PUBLIC \"'+t.pubID+'\"':t.sysID&&(n+=' SYSTEM \"'+t.sysID+'\"'),n+=this.spacebeforeslash+\">\"+this.newline},e.prototype.openNode=function(t,e){var n,r,i,o;if(e||(e=0),t instanceof l){i=this.space(e)+\"<\"+t.name,o=t.attributes;for(r in o)_.call(o,r)&&(n=o[r],i+=this.attribute(n));return i+=(t.children?\">\":\"/>\")+this.newline}return i=this.space(e)+\"<!DOCTYPE \"+t.rootNodeName,t.pubID&&t.sysID?i+=' PUBLIC \"'+t.pubID+'\" \"'+t.sysID+'\"':t.sysID&&(i+=' SYSTEM \"'+t.sysID+'\"'),i+=(t.children?\" [\":\">\")+this.newline},e.prototype.closeNode=function(t,e){switch(e||(e=0),!1){case!(t instanceof l):return this.space(e)+\"</\"+t.name+\">\"+this.newline;case!(t instanceof c):return this.space(e)+\"]>\"+this.newline}},e}(y)}).call(this)},{\"./XMLCData\":126,\"./XMLComment\":127,\"./XMLDTDAttList\":128,\"./XMLDTDElement\":129,\"./XMLDTDEntity\":130,\"./XMLDTDNotation\":131,\"./XMLDeclaration\":132,\"./XMLDocType\":133,\"./XMLElement\":136,\"./XMLProcessingInstruction\":138,\"./XMLRaw\":139,\"./XMLText\":143,\"./XMLWriterBase\":144}],142:[function(t,e,n){(function(){var t,n=function(t,e){return function(){return t.apply(e,arguments)}},r={}.hasOwnProperty;e.exports=t=function(){function t(t){this.assertLegalChar=n(this.assertLegalChar,this);var e,i,o;t||(t={}),this.noDoubleEncoding=t.noDoubleEncoding,i=t.stringify||{};for(e in i)r.call(i,e)&&(o=i[e],this[e]=o)}return t.prototype.eleName=function(t){return t=\"\"+t||\"\",this.assertLegalChar(t)},t.prototype.eleText=function(t){return t=\"\"+t||\"\",this.assertLegalChar(this.elEscape(t))},t.prototype.cdata=function(t){return t=\"\"+t||\"\",t=t.replace(\"]]>\",\"]]]]><![CDATA[>\"),this.assertLegalChar(t)},t.prototype.comment=function(t){if(t=\"\"+t||\"\",t.match(/--/))throw new Error(\"Comment text cannot contain double-hypen: \"+t);return this.assertLegalChar(t)},t.prototype.raw=function(t){return\"\"+t||\"\"},t.prototype.attName=function(t){return t=\"\"+t||\"\"},t.prototype.attValue=function(t){return t=\"\"+t||\"\",this.attEscape(t)},t.prototype.insTarget=function(t){return\"\"+t||\"\"},t.prototype.insValue=function(t){if(t=\"\"+t||\"\",t.match(/\\?>/))throw new Error(\"Invalid processing instruction value: \"+t);return t},t.prototype.xmlVersion=function(t){if(t=\"\"+t||\"\",!t.match(/1\\.[0-9]+/))throw new Error(\"Invalid version number: \"+t);return t},t.prototype.xmlEncoding=function(t){if(t=\"\"+t||\"\",!t.match(/^[A-Za-z](?:[A-Za-z0-9._-])*$/))throw new Error(\"Invalid encoding: \"+t);return t},t.prototype.xmlStandalone=function(t){return t?\"yes\":\"no\"},t.prototype.dtdPubID=function(t){return\"\"+t||\"\"},t.prototype.dtdSysID=function(t){return\"\"+t||\"\"},t.prototype.dtdElementValue=function(t){return\"\"+t||\"\"},t.prototype.dtdAttType=function(t){return\"\"+t||\"\"},t.prototype.dtdAttDefault=function(t){return null!=t?\"\"+t||\"\":t},t.prototype.dtdEntityValue=function(t){return\"\"+t||\"\"},t.prototype.dtdNData=function(t){return\"\"+t||\"\"},t.prototype.convertAttKey=\"@\",t.prototype.convertPIKey=\"?\",t.prototype.convertTextKey=\"#text\",t.prototype.convertCDataKey=\"#cdata\",t.prototype.convertCommentKey=\"#comment\",t.prototype.convertRawKey=\"#raw\",t.prototype.assertLegalChar=function(t){var e;if(e=t.match(/[\\0\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/))throw new Error(\"Invalid character in string: \"+t+\" at index \"+e.index);return t},t.prototype.elEscape=function(t){var e;return e=this.noDoubleEncoding?/(?!&\\S+;)&/g:/&/g,t.replace(e,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\\r/g,\"&#xD;\")},t.prototype.attEscape=function(t){var e;return e=this.noDoubleEncoding?/(?!&\\S+;)&/g:/&/g,t.replace(e,\"&amp;\").replace(/</g,\"&lt;\").replace(/\"/g,\"&quot;\").replace(/\\t/g,\"&#x9;\").replace(/\\n/g,\"&#xA;\").replace(/\\r/g,\"&#xD;\")},t}()}).call(this)},{}],143:[function(t,e,n){(function(){var n,r,i=function(t,e){function n(){this.constructor=t}for(var r in e)o.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},o={}.hasOwnProperty;n=t(\"./XMLNode\"),e.exports=r=function(t){function e(t,n){if(e.__super__.constructor.call(this,t),null==n)throw new Error(\"Missing element text\");this.value=this.stringify.eleText(n)}return i(e,t),e.prototype.clone=function(){return Object.create(this)},e.prototype.toString=function(t){return this.options.writer.set(t).text(this)},e}(n)}).call(this)},{\"./XMLNode\":137}],144:[function(t,e,n){(function(){var t,n={}.hasOwnProperty;e.exports=t=function(){function t(t){var e,r,i,o,s,a,u,c,l;t||(t={}),this.pretty=t.pretty||!1,this.allowEmpty=null!=(r=t.allowEmpty)&&r,this.pretty?(this.indent=null!=(i=t.indent)?i:\"  \",this.newline=null!=(o=t.newline)?o:\"\\n\",this.offset=null!=(s=t.offset)?s:0,this.dontprettytextnodes=null!=(a=t.dontprettytextnodes)?a:0):(this.indent=\"\",this.newline=\"\",this.offset=0,this.dontprettytextnodes=0),this.spacebeforeslash=null!=(u=t.spacebeforeslash)?u:\"\",this.spacebeforeslash===!0&&(this.spacebeforeslash=\" \"),this.newlinedefault=this.newline,this.prettydefault=this.pretty,c=t.writer||{};for(e in c)n.call(c,e)&&(l=c[e],this[e]=l)}return t.prototype.set=function(t){var e,r,i;t||(t={}),\"pretty\"in t&&(this.pretty=t.pretty),\"allowEmpty\"in t&&(this.allowEmpty=t.allowEmpty),this.pretty?(this.indent=\"indent\"in t?t.indent:\"  \",this.newline=\"newline\"in t?t.newline:\"\\n\",this.offset=\"offset\"in t?t.offset:0,this.dontprettytextnodes=\"dontprettytextnodes\"in t?t.dontprettytextnodes:0):(this.indent=\"\",this.newline=\"\",this.offset=0,this.dontprettytextnodes=0),this.spacebeforeslash=\"spacebeforeslash\"in t?t.spacebeforeslash:\"\",this.spacebeforeslash===!0&&(this.spacebeforeslash=\" \"),this.newlinedefault=this.newline,this.prettydefault=this.pretty,r=t.writer||{};for(e in r)n.call(r,e)&&(i=r[e],this[e]=i);return this},t.prototype.space=function(t){var e;return this.pretty?(e=(t||0)+this.offset+1,e>0?new Array(e).join(this.indent):\"\"):\"\"},t}()}).call(this)},{}],145:[function(t,e,n){(function(){var n,r,i,o,s,a,u;u=t(\"./Utility\"),s=u.assign,a=u.isFunction,n=t(\"./XMLDocument\"),r=t(\"./XMLDocumentCB\"),o=t(\"./XMLStringWriter\"),i=t(\"./XMLStreamWriter\"),e.exports.create=function(t,e,r,i){var o,a;if(null==t)throw new Error(\"Root element needs a name\");return i=s({},e,r,i),o=new n(i),a=o.element(t),i.headless||(o.declaration(i),null==i.pubID&&null==i.sysID||o.doctype(i)),a},e.exports.begin=function(t,e,i){var o;return a(t)&&(o=[t,e],e=o[0],i=o[1],t={}),e?new r(t,e,i):new n(t)},e.exports.stringWriter=function(t){return new o(t)},e.exports.streamWriter=function(t,e){return new i(t,e)}}).call(this)},{\"./Utility\":124,\"./XMLDocument\":134,\"./XMLDocumentCB\":135,\"./XMLStreamWriter\":140,\"./XMLStringWriter\":141}]},{},[1])(1)});\n//# sourceMappingURL=jsforce.min.js.map"
  },
  {
    "path": "force-app/main/default/staticresources/jsforce.resource-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<StaticResource xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <cacheControl>Public</cacheControl>\n    <contentType>application/javascript</contentType>\n    <description>v1.9.2\nhttp://jsforce.github.io/</description>\n</StaticResource>\n"
  },
  {
    "path": "force-app/main/default/staticresources/penpal.js",
    "content": "/**\n * Author: Aaron Hardy\n * https://unpkg.com/penpal@4.1.1/dist/penpal.min.js\n * https://github.com/Aaronius/penpal\n */\nvar Penpal=function(){\"use strict\";const e=\"handshake\";const n=\"handshake-reply\";const t=\"call\";const r=\"reply\";const o=\"fulfilled\";const i=\"rejected\";const c=\"message\";const s=\"DataCloneError\";const a=\"ConnectionDestroyed\";const d=\"ConnectionTimeout\";const l=\"NotInIframe\";const u=\"NoIframeSrc\";var m=()=>{const e=[];let n=false;return{destroy(){n=true;e.forEach(e=>{e()})},onDestroy(t){n?t():e.push(t)}}};const h={\"http:\":\"80\",\"https:\":\"443\"};const f=/^(https?:)?\\/\\/([^\\/:]+)?(:(\\d+))?/;const g=[\"file:\",\"data:\"];var p=e=>{if(e&&g.find(n=>e.startsWith(n))){return\"null\"}const n=document.location;const t=f.exec(e);let r;let o;let i;if(t){r=t[1]?t[1]:n.protocol;o=t[2];i=t[4]}else{r=n.protocol;o=n.hostname;i=n.port}const c=i&&i!==h[r]?`:${i}`:\"\";return`${r}//${o}${c}`};var v=e=>{return function(){if(e){for(var n=arguments.length,t=new Array(n),r=0;r<n;r++){t[r]=arguments[r]}console.log(\"[Penpal]\",...t)}}};const E=e=>{let n=e.name,t=e.message,r=e.stack;return{name:n,message:t,stack:r}};const w=e=>{const n=new Error;Object.keys(e).forEach(t=>n[t]=e[t]);return n};var y=(e,n,a)=>{const d=e.localName,l=e.local,u=e.remote,m=e.originForSending,h=e.originForReceiving;let f=false;a(`${d}: Connecting call receiver`);const g=e=>{if(e.source!==u||e.data.penpal!==t){return}if(e.origin!==h){a(`${d} received message from origin ${e.origin} which did not match expected origin ${h}`);return}const c=e.data,l=c.methodName,g=c.args,p=c.id;a(`${d}: Received ${l}() call`);const v=e=>{return n=>{a(`${d}: Sending ${l}() reply`);if(f){a(`${d}: Unable to send ${l}() reply due to destroyed connection`);return}const t={penpal:r,id:p,resolution:e,returnValue:n};if(e===i&&n instanceof Error){t.returnValue=E(n);t.returnValueIsError=true}try{u.postMessage(t,m)}catch(e){if(e.name===s){u.postMessage({penpal:r,id:p,resolution:i,returnValue:E(e),returnValueIsError:true},m)}throw e}}};new Promise(e=>e(n[l].apply(n,g))).then(v(o),v(i))};l.addEventListener(c,g);return()=>{f=true;l.removeEventListener(c,g)}};let $=0;var N=()=>++$;var C=(e,n,i,s,d)=>{const l=n.localName,u=n.local,m=n.remote,h=n.originForSending,f=n.originForReceiving;let g=false;d(`${l}: Connecting call sender`);const p=e=>{return function(){for(var n=arguments.length,i=new Array(n),p=0;p<n;p++){i[p]=arguments[p]}d(`${l}: Sending ${e}() call`);let v;try{if(m.closed){v=true}}catch(e){v=true}if(v){s()}if(g){const n=new Error(`Unable to send ${e}() call due `+`to destroyed connection`);n.code=a;throw n}return new Promise((n,s)=>{const a=N();const g=t=>{if(t.source!==m||t.data.penpal!==r||t.data.id!==a){return}if(t.origin!==f){d(`${l} received message from origin ${t.origin} which did not match expected origin ${f}`);return}d(`${l}: Received ${e}() reply`);u.removeEventListener(c,g);let i=t.data.returnValue;if(t.data.returnValueIsError){i=w(i)}(t.data.resolution===o?n:s)(i)};u.addEventListener(c,g);m.postMessage({penpal:t,id:a,methodName:e,args:i},h)})}};i.reduce((e,n)=>{e[n]=p(n);return e},e);return()=>{g=true}};const I=6e4;var T=t=>{let r=t.iframe,o=t.methods,i=o===void 0?{}:o,s=t.childOrigin,l=t.timeout,h=t.debug;const f=v(h);const g=window;const E=m(),w=E.destroy,$=E.onDestroy;if(!s){if(!r.src&&!r.srcdoc){const e=new Error(\"Iframe must have src or srcdoc property defined.\");e.code=u;throw e}s=p(r.src)}const N=s===\"null\"?\"*\":s;const T=new Promise((t,o)=>{let u;if(l!==undefined){u=setTimeout(()=>{const e=new Error(`Connection to child timed out after ${l}ms`);e.code=d;o(e);w()},l)}const m={};let h;let p;const v=o=>{const c=r.contentWindow;if(o.source!==c||o.data.penpal!==e){return}if(o.origin!==s){f(`Parent received handshake from origin ${o.origin} which did not match expected origin ${s}`);return}f(\"Parent: Received handshake, sending reply\");o.source.postMessage({penpal:n,methodNames:Object.keys(i)},N);const a={localName:\"Parent\",local:g,remote:c,originForSending:N,originForReceiving:s};if(p){p()}p=y(a,i,f);$(p);if(h){h.forEach(e=>{delete m[e]})}h=o.data.methodNames;const d=C(m,a,h,w,f);$(d);clearTimeout(u);t(m)};g.addEventListener(c,v);f(\"Parent: Awaiting handshake\");var E=setInterval(()=>{if(!document.contains(r)){clearInterval(E);w()}},I);$(()=>{g.removeEventListener(c,v);clearInterval(E);const e=new Error(\"Connection destroyed\");e.code=a;o(e)})});return{promise:T,destroy:w}};var k=function(){let t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{},r=t.parentOrigin,o=r===void 0?\"*\":r,i=t.methods,s=i===void 0?{}:i,u=t.timeout,h=t.debug;const f=v(h);if(window===window.top){const e=new Error(\"connectToParent() must be called within an iframe\");e.code=l;throw e}const g=m(),p=g.destroy,E=g.onDestroy;const w=window;const $=w.parent;const N=new Promise((t,r)=>{let i;if(u!==undefined){i=setTimeout(()=>{const e=new Error(`Connection to parent timed out after ${u}ms`);e.code=d;r(e);p()},u)}const l=e=>{try{clearTimeout()}catch(e){return}if(e.source!==$||e.data.penpal!==n){return}if(o!==\"*\"&&o!==e.origin){f(`Child received handshake reply from origin ${e.origin} which did not match expected origin ${o}`);return}f(\"Child: Received handshake reply\");w.removeEventListener(c,l);const r={localName:\"Child\",local:w,remote:$,originForSending:e.origin===\"null\"?\"*\":e.origin,originForReceiving:e.origin};const a={};const d=y(r,s,f);E(d);const u=C(a,r,e.data.methodNames,p,f);E(u);clearTimeout(i);t(a)};w.addEventListener(c,l);E(()=>{w.removeEventListener(c,l);const e=new Error(\"Connection destroyed\");e.code=a;r(e)});f(\"Child: Sending handshake\");$.postMessage({penpal:e,methodNames:Object.keys(s)},o)});return{promise:N,destroy:p}};var O={ERR_CONNECTION_DESTROYED:a,ERR_CONNECTION_TIMEOUT:d,ERR_NOT_IN_IFRAME:l,ERR_NO_IFRAME_SRC:u,connectToChild:T,connectToParent:k};return O}();\n\n// Expose penpal to lightning components by adding it to the `window` object.\n// https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_share_code.htm\nwindow.Penpal = Penpal;\n\n/*\nThe MIT License (MIT)\n\nCopyright (c) 2016, Aaron Hardy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n */"
  },
  {
    "path": "force-app/main/default/staticresources/penpal.resource-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<StaticResource xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <cacheControl>Public</cacheControl>\n    <contentType>application/javascript</contentType>\n    <description>v4.1.1\nhttps://github.com/Aaronius/penpal</description>\n</StaticResource>\n"
  },
  {
    "path": "force-app/main/default/tabs/MA_SetupAuthWizardPageTab.tab-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomTab xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <label>Mass Action Auth. Setup</label>\n    <motif>Custom76: Keys</motif>\n    <page>MA_SetupAuthWizardPage</page>\n</CustomTab>\n"
  },
  {
    "path": "force-app/main/default/tabs/Mass_Action_Configuration__c.tab-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomTab xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <customObject>true</customObject>\n    <motif>Custom67: Gears</motif>\n</CustomTab>\n"
  },
  {
    "path": "force-app/main/default/tabs/Mass_Action_Log__c.tab-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CustomTab xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <customObject>true</customObject>\n    <motif>Custom55: Books</motif>\n</CustomTab>\n"
  },
  {
    "path": "force-app/main/default/testSuites/Mass_Action_Scheduler_Test_Suite.testSuite-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexTestSuite xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <testClassName>LC_URLControllerTest</testClassName>\n    <testClassName>LC_VisualforceDomainControllerTest</testClassName>\n    <testClassName>MA_BatchApexErrorEventInvocableTest</testClassName>\n    <testClassName>MA_BatchApexStatusEventTriggerTest</testClassName>\n    <testClassName>MA_EditConfigCmpControllerTest</testClassName>\n    <testClassName>MA_EditConfigRestControllerTest</testClassName>\n    <testClassName>MA_ExceptionsTest</testClassName>\n    <testClassName>MA_InstallHandlerTest</testClassName>\n    <testClassName>MA_IterableSourceBatchableTest</testClassName>\n    <testClassName>MA_JobChangeEventTriggerHandlerTest</testClassName>\n    <testClassName>MA_ListViewDescribeResultTest</testClassName>\n    <testClassName>MA_ListViewSourceBatchableTest</testClassName>\n    <testClassName>MA_MapUtilsTest</testClassName>\n    <testClassName>MA_MassActionBatchUtilsTest</testClassName>\n    <testClassName>MA_MassActionConfigTriggerHandlerTest</testClassName>\n    <testClassName>MA_MassActionLogTriggerHandlerTest</testClassName>\n    <testClassName>MA_MassActionSchedulableTest</testClassName>\n    <testClassName>MA_MassActionScheduleUtilsTest</testClassName>\n    <testClassName>MA_MetadataDeployCallbackTest</testClassName>\n    <testClassName>MA_ReportServiceTest</testClassName>\n    <testClassName>MA_ReportSourceBatchableTest</testClassName>\n    <testClassName>MA_RunConfigCmpControllerTest</testClassName>\n    <testClassName>MA_RunConfigInvocableTest</testClassName>\n    <testClassName>MA_SetConfigUniqueNameBatchableTest</testClassName>\n    <testClassName>MA_SetupAuthWizardPageControllerTest</testClassName>\n    <testClassName>MA_SoqlQueryExecuteResultTest</testClassName>\n    <testClassName>MA_SoqlSourceBatchableTest</testClassName>\n    <testClassName>MA_SoqlSourceIterableTest</testClassName>\n    <testClassName>MA_StringUtilsTest</testClassName>\n    <testClassName>MA_UpgradeMassActionLogsBatchableTest</testClassName>\n    <testClassName>MA_UpgradePageLayoutsServiceTest</testClassName>\n    <testClassName>MA_XMLUtilsTest</testClassName>\n</ApexTestSuite>\n"
  },
  {
    "path": "force-app/main/default/triggers/MA_BatchApexStatusEventTrigger.trigger",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\ntrigger MA_BatchApexStatusEventTrigger on Mass_Action_Batch_Apex_Status_Event__e ( after insert ) {\n\n    MA_BatchApexStatusEventTriggerHandler handler = new MA_BatchApexStatusEventTriggerHandler();\n\n    if ( Trigger.isAfter && Trigger.isInsert ) {\n        handler.handleAfterInsert( Trigger.new, Trigger.newMap );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/triggers/MA_BatchApexStatusEventTrigger.trigger-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexTrigger xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexTrigger>\n"
  },
  {
    "path": "force-app/main/default/triggers/MA_JobChangeEventTrigger.trigger",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\ntrigger MA_JobChangeEventTrigger on Mass_Action_Job_Change_Event__e ( after insert ) {\n\n    MA_JobChangeEventTriggerHandler handler = new MA_JobChangeEventTriggerHandler();\n\n    if ( Trigger.isAfter && Trigger.isInsert ) {\n        handler.handleAfterInsert( Trigger.new, Trigger.newMap );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/triggers/MA_JobChangeEventTrigger.trigger-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexTrigger xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexTrigger>\n"
  },
  {
    "path": "force-app/main/default/triggers/MA_MassActionConfigTrigger.trigger",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\ntrigger MA_MassActionConfigTrigger on Mass_Action_Configuration__c ( before insert, before update, before delete,\n                                                                     after insert, after update, after delete ) {\n\n    MA_MassActionConfigTriggerHandler handler = new MA_MassActionConfigTriggerHandler();\n\n    if ( Trigger.isBefore && Trigger.isInsert ) {\n        handler.handleBeforeInsert( Trigger.new );\n    }\n    else if ( Trigger.isBefore && Trigger.isUpdate ) {\n        handler.handleBeforeUpdate( Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap );\n    }\n    else if ( Trigger.isBefore && Trigger.isDelete ) {\n        handler.handleBeforeDelete( Trigger.old, Trigger.oldMap );\n    }\n    else if ( Trigger.isAfter && Trigger.isInsert ) {\n        handler.handleAfterInsert( Trigger.new, Trigger.newMap );\n    }\n    else if ( Trigger.isAfter && Trigger.isUpdate ) {\n        handler.handleAfterUpdate( Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap );\n    }\n    else if ( Trigger.isAfter && Trigger.isDelete ) {\n        handler.handleAfterDelete( Trigger.old, Trigger.oldMap );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/triggers/MA_MassActionConfigTrigger.trigger-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexTrigger xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexTrigger>\n"
  },
  {
    "path": "force-app/main/default/triggers/MA_MassActionLogTrigger.trigger",
    "content": "/**\n * Author: Doug Ayers\n * Website: https://douglascayers.com\n * GitHub: https://github.com/sfdx-mass-action-scheduler/sfdx-mass-action-scheduler\n * License: BSD 3-Clause License\n */\ntrigger MA_MassActionLogTrigger on Mass_Action_Log__c ( before insert, before update, before delete,\n                                                        after insert, after update, after delete ) {\n\n    MA_MassActionLogTriggerHandler handler = new MA_MassActionLogTriggerHandler();\n\n    if ( Trigger.isBefore && Trigger.isInsert ) {\n        handler.handleBeforeInsert( Trigger.new );\n    }\n    else if ( Trigger.isBefore && Trigger.isUpdate ) {\n        handler.handleBeforeUpdate( Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap );\n    }\n    else if ( Trigger.isBefore && Trigger.isDelete ) {\n        handler.handleBeforeDelete( Trigger.old, Trigger.oldMap );\n    }\n    else if ( Trigger.isAfter && Trigger.isInsert ) {\n        handler.handleAfterInsert( Trigger.new, Trigger.newMap );\n    }\n    else if ( Trigger.isAfter && Trigger.isUpdate ) {\n        handler.handleAfterUpdate( Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap );\n    }\n    else if ( Trigger.isAfter && Trigger.isDelete ) {\n        handler.handleAfterDelete( Trigger.old, Trigger.oldMap );\n    }\n\n}\n/*\nBSD 3-Clause License\n\nCopyright (c) 2017-2023, Doug Ayers, douglascayers.com\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  },
  {
    "path": "force-app/main/default/triggers/MA_MassActionLogTrigger.trigger-meta.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ApexTrigger xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <apiVersion>54.0</apiVersion>\n    <status>Active</status>\n</ApexTrigger>\n"
  },
  {
    "path": "licenses/appiphony.txt",
    "content": "http://www.lightningstrike.io/\n\nBSD 3-Clause License\n\nCopyright (c) 2017, Appiphony\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "licenses/jquery.txt",
    "content": "https://github.com/jquery/jquery/blob/master/LICENSE.txt\n\nCopyright JS Foundation and other contributors, https://js.foundation/\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "licenses/jsforce.txt",
    "content": "https://github.com/jsforce/jsforce/blob/master/LICENSE\n\n(The MIT License)\n\nCopyright (c) 2011 Shinichi Tomita <shinichi.tomita@gmail.com>;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "licenses/penpal.txt",
    "content": "https://github.com/Aaronius/penpal/blob/master/LICENSE\n\nThe MIT License (MIT)\n\nCopyright (c) 2016, Aaron Hardy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "licenses/sfdc-lax.txt",
    "content": "https://github.com/ruslan-kurchenko/sfdc-lax\n\nMIT License\n\nCopyright (c) 2017 Ruslan Kurchenko\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "licenses/soql-parser.txt",
    "content": "https://github.com/stomita/soql-parse\n\n(The MIT License)\n\nCopyright (c) 2017 Shinichi Tomita <shinichi.tomita@gmail.com>;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "manifest/package.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Package xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n    <types>\n        <members>LC_URLController</members>\n        <members>LC_URLControllerTest</members>\n        <members>LC_VisualforceDomainController</members>\n        <members>LC_VisualforceDomainControllerTest</members>\n        <members>MA_AnonymousApexExecuteResult</members>\n        <members>MA_AsyncApexJobMock</members>\n        <members>MA_BatchApexErrorEventInvocable</members>\n        <members>MA_BatchApexErrorEventInvocableTest</members>\n        <members>MA_BatchApexStatusEventTriggerHandler</members>\n        <members>MA_BatchApexStatusEventTriggerTest</members>\n        <members>MA_EditConfigCmpController</members>\n        <members>MA_EditConfigCmpControllerTest</members>\n        <members>MA_EditConfigRestController</members>\n        <members>MA_EditConfigRestControllerTest</members>\n        <members>MA_Exceptions</members>\n        <members>MA_ExceptionsTest</members>\n        <members>MA_HttpCalloutMock</members>\n        <members>MA_InstallHandler</members>\n        <members>MA_InstallHandlerTest</members>\n        <members>MA_IterableSourceBatchable</members>\n        <members>MA_IterableSourceBatchableTest</members>\n        <members>MA_JobChangeEvent</members>\n        <members>MA_JobChangeEventTriggerHandler</members>\n        <members>MA_JobChangeEventTriggerHandlerTest</members>\n        <members>MA_ListViewDescribeResult</members>\n        <members>MA_ListViewDescribeResultTest</members>\n        <members>MA_ListViewSourceBatchable</members>\n        <members>MA_ListViewSourceBatchableTest</members>\n        <members>MA_MapUtils</members>\n        <members>MA_MapUtilsTest</members>\n        <members>MA_MassActionBatchEnqueuer</members>\n        <members>MA_MassActionBatchUtils</members>\n        <members>MA_MassActionBatchUtilsTest</members>\n        <members>MA_MassActionConfigTriggerHandler</members>\n        <members>MA_MassActionConfigTriggerHandlerTest</members>\n        <members>MA_MassActionConfigWrapper</members>\n        <members>MA_MassActionLogTriggerHandler</members>\n        <members>MA_MassActionLogTriggerHandlerTest</members>\n        <members>MA_MassActionSchedulable</members>\n        <members>MA_MassActionSchedulableTest</members>\n        <members>MA_MassActionScheduleUtils</members>\n        <members>MA_MassActionScheduleUtilsTest</members>\n        <members>MA_MassActionUtils</members>\n        <members>MA_MetadataDeployCallback</members>\n        <members>MA_MetadataDeployCallbackTest</members>\n        <members>MA_NamespaceUtils</members>\n        <members>MA_ReportService</members>\n        <members>MA_ReportServiceTest</members>\n        <members>MA_ReportSourceBatchable</members>\n        <members>MA_ReportSourceBatchableTest</members>\n        <members>MA_RunConfigCmpController</members>\n        <members>MA_RunConfigCmpControllerTest</members>\n        <members>MA_RunConfigInvocable</members>\n        <members>MA_RunConfigInvocableTest</members>\n        <members>MA_SetConfigUniqueNameBatchable</members>\n        <members>MA_SetConfigUniqueNameBatchableTest</members>\n        <members>MA_SetupAuthWizardPageController</members>\n        <members>MA_SetupAuthWizardPageControllerTest</members>\n        <members>MA_SoqlQueryExecuteResult</members>\n        <members>MA_SoqlQueryExecuteResultTest</members>\n        <members>MA_SoqlSourceBatchable</members>\n        <members>MA_SoqlSourceBatchableTest</members>\n        <members>MA_SoqlSourceIterable</members>\n        <members>MA_SoqlSourceIterableTest</members>\n        <members>MA_StringUtils</members>\n        <members>MA_StringUtilsTest</members>\n        <members>MA_UpgradeMassActionLogsBatchable</members>\n        <members>MA_UpgradeMassActionLogsBatchableTest</members>\n        <members>MA_UpgradePageLayoutsService</members>\n        <members>MA_UpgradePageLayoutsServiceTest</members>\n        <members>MA_XMLUtils</members>\n        <members>MA_XMLUtilsTest</members>\n        <name>ApexClass</name>\n    </types>\n    <types>\n        <members>LC_APIPage</members>\n        <members>LC_VisualforceDomainPage</members>\n        <members>MA_SetupAuthWizardPage</members>\n        <name>ApexPage</name>\n    </types>\n    <types>\n        <members>Mass_Action_Scheduler_Test_Suite</members>\n        <name>ApexTestSuite</name>\n    </types>\n    <types>\n        <members>MA_BatchApexStatusEventTrigger</members>\n        <members>MA_JobChangeEventTrigger</members>\n        <members>MA_MassActionConfigTrigger</members>\n        <members>MA_MassActionLogTrigger</members>\n        <name>ApexTrigger</name>\n    </types>\n    <types>\n        <members>LC_API</members>\n        <members>LC_URL</members>\n        <members>MA_CheckForPackageUpdatesCmp</members>\n        <members>MA_DevelopedByCmp</members>\n        <members>MA_EditConfigCmp</members>\n        <members>MA_FlowStagePathCmp</members>\n        <members>MA_RunConfigCmp</members>\n        <members>MA_WizardCoachingCmp</members>\n        <members>defaultTokens</members>\n        <members>lax</members>\n        <members>slds_label</members>\n        <members>slds_section</members>\n        <members>strike_evt</members>\n        <members>strike_wizard</members>\n        <name>AuraDefinitionBundle</name>\n    </types>\n    <types>\n        <members>Mass_Action_Configuration__c.Default_Compact_Layout</members>\n        <members>Mass_Action_Log__c.Child_Log_Compact_Layout</members>\n        <members>Mass_Action_Log__c.Default_Compact_Layout</members>\n        <members>Mass_Action_Log__c.Parent_Log_Compact_Layout</members>\n        <members>Mass_Action_Mapping__c.Default_Compact_Layout</members>\n        <name>CompactLayout</name>\n    </types>\n    <types>\n        <members>maslogominimal</members>\n        <name>ContentAsset</name>\n    </types>\n    <types>\n        <members>Mass_Action_Scheduler</members>\n        <members>Mass_Action_Scheduler_Lightning</members>\n        <name>CustomApplication</name>\n    </types>\n    <types>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Job_ID__c</members>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Job_Scope__c</members>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Long_Message__c</members>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Message_Type__c</members>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Message__c</members>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Phase__c</members>\n        <members>Mass_Action_Batch_Apex_Status_Event__e.Timestamp__c</members>\n        <members>Mass_Action_Configuration__c.Active__c</members>\n        <members>Mass_Action_Configuration__c.Batch_Size__c</members>\n        <members>Mass_Action_Configuration__c.Description__c</members>\n        <members>Mass_Action_Configuration__c.DeveloperName__c</members>\n        <members>Mass_Action_Configuration__c.Last_Run_Completed_Date__c</members>\n        <members>Mass_Action_Configuration__c.Last_Run_Completed_With_Errors__c</members>\n        <members>Mass_Action_Configuration__c.Named_Credential__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_Cron__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_DayOfMonth__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_DayOfWeek__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_Frequency__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_HourOfDay__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_MinuteOfHour__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_MonthOfYear__c</members>\n        <members>Mass_Action_Configuration__c.Schedule_SecondOfMinute__c</members>\n        <members>Mass_Action_Configuration__c.Source_Apex_Class__c</members>\n        <members>Mass_Action_Configuration__c.Source_List_View_ID__c</members>\n        <members>Mass_Action_Configuration__c.Source_Report_Column_Name__c</members>\n        <members>Mass_Action_Configuration__c.Source_Report_ID__c</members>\n        <members>Mass_Action_Configuration__c.Source_SOQL_Query__c</members>\n        <members>Mass_Action_Configuration__c.Source_Type__c</members>\n        <members>Mass_Action_Configuration__c.Target_Action_Name__c</members>\n        <members>Mass_Action_Configuration__c.Target_Apex_Script__c</members>\n        <members>Mass_Action_Configuration__c.Target_SObject_Type__c</members>\n        <members>Mass_Action_Configuration__c.Target_Type__c</members>\n        <members>Mass_Action_Job_Change_Event__e.Payload__c</members>\n        <members>Mass_Action_Log__c.Batch_Success_Percentage__c</members>\n        <members>Mass_Action_Log__c.Batch_Success_Rate__c</members>\n        <members>Mass_Action_Log__c.Failed_Batches__c</members>\n        <members>Mass_Action_Log__c.Job_ID__c</members>\n        <members>Mass_Action_Log__c.Job_Scope__c</members>\n        <members>Mass_Action_Log__c.Long_Message__c</members>\n        <members>Mass_Action_Log__c.Mass_Action_Configuration__c</members>\n        <members>Mass_Action_Log__c.Message_Type__c</members>\n        <members>Mass_Action_Log__c.Message__c</members>\n        <members>Mass_Action_Log__c.Parent_Log_Configuration__c</members>\n        <members>Mass_Action_Log__c.Parent_Log__c</members>\n        <members>Mass_Action_Log__c.Processed_Batches__c</members>\n        <members>Mass_Action_Log__c.Submitted_Date__c</members>\n        <members>Mass_Action_Log__c.Timestamp__c</members>\n        <members>Mass_Action_Log__c.Total_Batches__c</members>\n        <members>Mass_Action_Mapping__c.Mass_Action_Configuration__c</members>\n        <members>Mass_Action_Mapping__c.Source_Field_Name__c</members>\n        <members>Mass_Action_Mapping__c.Target_Field_Name__c</members>\n        <name>CustomField</name>\n    </types>\n    <types>\n        <members>Mass_Action_Notification</members>\n        <name>CustomNotificationType</name>\n    </types>\n    <types>\n        <members>Mass_Action_Batch_Apex_Status_Event__e</members>\n        <members>Mass_Action_Configuration__c</members>\n        <members>Mass_Action_Job_Change_Event__e</members>\n        <members>Mass_Action_Log__c</members>\n        <members>Mass_Action_Mapping__c</members>\n        <name>CustomObject</name>\n    </types>\n    <types>\n        <members>MA_SetupAuthWizardPageTab</members>\n        <members>Mass_Action_Configuration__c</members>\n        <members>Mass_Action_Log__c</members>\n        <name>CustomTab</name>\n    </types>\n    <types>\n        <members>Mass_Action_Configuration_Record_Page</members>\n        <members>Mass_Action_Configuration_Record_Page_One_Column</members>\n        <members>Mass_Action_Log_Record_Page</members>\n        <name>FlexiPage</name>\n    </types>\n    <types>\n        <members>MAS_Batch_Apex_Error_Event</members>\n        <members>MAS_Mass_Action_Configuration</members>\n        <members>MAS_Run_Mass_Action_Flow</members>\n        <name>Flow</name>\n    </types>\n    <types>\n        <members>Mass_Action_Configuration__c-Mass Action Configuration Layout</members>\n        <members>Mass_Action_Log__c-Mass Action Child Log Layout</members>\n        <members>Mass_Action_Log__c-Mass Action Log Layout</members>\n        <members>Mass_Action_Log__c-Mass Action Parent Log Layout</members>\n        <members>Mass_Action_Mapping__c-Mass Action Mapping Layout</members>\n        <name>Layout</name>\n    </types>\n    <types>\n        <members>Mass_Action_Configuration__c.All</members>\n        <members>Mass_Action_Log__c.All</members>\n        <members>Mass_Action_Log__c.All_Parent_Logs</members>\n        <name>ListView</name>\n    </types>\n    <types>\n        <members>Mass_Action_Test_Named_Credential</members>\n        <name>NamedCredential</name>\n    </types>\n    <types>\n        <members>Mass_Action_Admin</members>\n        <name>PermissionSet</name>\n    </types>\n    <types>\n        <members>Mass_Action_Configuration__c.Quick_Edit</members>\n        <members>Mass_Action_Configuration__c.Run</members>\n        <members>Mass_Action_Configuration__c.Run_via_Flow</members>\n        <name>QuickAction</name>\n    </types>\n    <types>\n        <members>Mass_Action_Log__c.Child_Log</members>\n        <members>Mass_Action_Log__c.Parent_Log</members>\n        <name>RecordType</name>\n    </types>\n    <types>\n        <members>Mass_Action_Test_Reports</members>\n        <members>Mass_Action_Test_Reports/MA_Test_Account_Report</members>\n        <name>Report</name>\n    </types>\n    <types>\n        <members>MA_SalesforceSecurityLogo</members>\n        <members>jquery</members>\n        <members>jsforce</members>\n        <members>penpal</members>\n        <name>StaticResource</name>\n    </types>\n    <version>54.0</version>\n</Package>\n"
  },
  {
    "path": "scripts/create-scratch-org.sh",
    "content": "#!/usr/bin/env bash\n\n# =========================================================================== #\n# USAGE\n# -----\n# create-scratch-org.sh [org alias]\n#\n# The $1 argument (optional) is what the alias should be.\n# Default name is mas-scratch\n# =========================================================================== #\n\n# Exit when any command fails\nset -e\n\n# Set CLI API version to match sfdx-project.json\n# https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_troubleshoot_api_sync.htm\necho \"Setting CLI API Version to match sfdx-project.json\"\napi_version=$(cat sfdx-project.json | jq -r '.sourceApiVersion')\nsfdx config:set apiVersion=$api_version\n\n# Alias for the scratch org\norg_alias=$1\nif [ -z \"$org_alias\" ]; then\n  org_alias=\"mas-scratch\"\nfi\n\necho \"Creating scratch org with alias: ${org_alias}\"\n\n# Create scratch org\nsfdx force:org:create -s -f config/project-scratch-def.json -d 30 -a $org_alias\n\n# Deploy the code\nsfdx force:source:deploy -p force-app -u $org_alias\n\n# Assign permission set\nsfdx force:user:permset:assign -n Mass_Action_Admin -u $org_alias\n\n# Create a test account, only required for the report tests\nsfdx force:data:record:create --sobjecttype Account --values \"Name='dca_mass_action: MA Test Account'\"\n\n# Reset source tracking\nsfdx force:source:tracking:reset --noprompt -u $org_alias\n\n# User convenience, make our app the first in the app launcher\nreorder_appmenu_apex=$(\n  cat <<EOL\n  List<AppMenuItem> menuItems = [\n    SELECT ApplicationId FROM AppMenuItem\n    WHERE Name = 'Mass_Action_Scheduler_Lightning'\n  ];\n  if (menuItems.size() > 0) {\n    AppLauncher.AppMenu.setUserSortOrder(\n      new List<ID> { menuItems[0].ApplicationId }\n    );\n  }\nEOL\n)\necho $reorder_appmenu_apex | sfdx force:apex:execute\n"
  },
  {
    "path": "scripts/recreate-manifest.sh",
    "content": "#!/usr/bin/env bash\n\n# Convert source format to mdapi format, which creates a package.xml\nsfdx force:source:convert -d mdapi\n\n# Replace the package.xml in the manifest folder\n# https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_develop_any_org.htm\n# http://www.illuminatedcloud.com/announcements/2061releasenotes\nrm manifest/package.xml || true\nmkdir -p manifest\nmv mdapi/package.xml manifest/package.xml\n\n# Delete the converted mdapi folder\nrm -rf mdapi\n"
  },
  {
    "path": "sfdx-project.json",
    "content": "{\n  \"packageDirectories\": [\n    {\n      \"path\": \"force-app\",\n      \"default\": true\n    }\n  ],\n  \"namespace\": \"\",\n  \"sfdcLoginUrl\": \"https://login.salesforce.com\",\n  \"sourceApiVersion\": \"54.0\"\n}\n"
  }
]