diff --git a/.eslintignore b/.eslintignore index d3e8a6328bc4..396bfd28c614 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ **/node_modules/* **/dist/* .github/actions/**/index.js" +docs/vendor/** diff --git a/.eslintrc.js b/.eslintrc.js index b76782af60f4..b71338d0c1a5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,6 +14,11 @@ const restrictedImportPaths = [ importNames: ['TouchableOpacity', 'TouchableWithoutFeedback', 'TouchableNativeFeedback', 'TouchableHighlight'], message: "Please use 'PressableWithFeedback' and/or 'PressableWithoutFeedback' from 'src/components/Pressable' instead.", }, + { + name: 'react-native-safe-area-context', + importNames: ['useSafeAreaInsets', 'SafeAreaConsumer', 'SafeAreaInsetsContext'], + message: "Please use 'useSafeAreaInsets' from 'src/hooks/useSafeAreaInset' and/or 'SafeAreaConsumer' from 'src/components/SafeAreaConsumer' instead.", + }, ]; const restrictedImportPatterns = [ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c106a25c8ab1..4f78ee6b69bf 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,2 @@ # Every PR gets a review from an internal Expensify engineer * @Expensify/pullerbear - -# Every PR that touches redirects gets reviewed by ring0 -docs/redirects.csv @Expensify/infra \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 351a11506d68..4f7d1c71553a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,8 +18,8 @@ $ https://github.com/Expensify/App/issues/ Do NOT only link the issue number like this: $ # ---> -$ -PROPOSAL: +$ +PROPOSAL: ### Tests @@ -98,7 +98,7 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c - [ ] The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory - [ ] If a new CSS style is added I verified that: - [ ] A similar style doesn't already exist - - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/StyleUtils.js) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)`) + - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/utils/index.ts) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)`) - [ ] If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic. - [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) - [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. diff --git a/.github/actions/composite/setupGitForOSBotifyApp/action.yml b/.github/actions/composite/setupGitForOSBotifyApp/action.yml index 52fb097d254e..7a90cc45257d 100644 --- a/.github/actions/composite/setupGitForOSBotifyApp/action.yml +++ b/.github/actions/composite/setupGitForOSBotifyApp/action.yml @@ -29,11 +29,11 @@ runs: shell: bash run: | if [[ -f .github/workflows/OSBotify-private-key.asc.gpg ]]; then - echo "::set-output name=key_exists::true" + echo "key_exists=true" >> "$GITHUB_OUTPUT" fi - + - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: steps.key_check.outputs.key_exists != 'true' with: sparse-checkout: | diff --git a/.github/actions/composite/setupNode/action.yml b/.github/actions/composite/setupNode/action.yml index 57c7e4d91379..7e1b5fbbae90 100644 --- a/.github/actions/composite/setupNode/action.yml +++ b/.github/actions/composite/setupNode/action.yml @@ -4,7 +4,7 @@ description: Set up Node runs: using: composite steps: - - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 + - uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/actions/javascript/authorChecklist/index.js b/.github/actions/javascript/authorChecklist/index.js index 12b9bd3b648e..bdb2b5b329d1 100644 --- a/.github/actions/javascript/authorChecklist/index.js +++ b/.github/actions/javascript/authorChecklist/index.js @@ -17,6 +17,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/awaitStagingDeploys/action.yml b/.github/actions/javascript/awaitStagingDeploys/action.yml index fdd0b940abaa..3499b4050de0 100644 --- a/.github/actions/javascript/awaitStagingDeploys/action.yml +++ b/.github/actions/javascript/awaitStagingDeploys/action.yml @@ -8,5 +8,5 @@ inputs: description: If provided, this action will only wait for a deploy matching this tag. required: false runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index 3fd3739c81d6..08468d9a06a5 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -129,6 +129,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/bumpVersion/action.yml b/.github/actions/javascript/bumpVersion/action.yml index d092821d96ac..dc4a75d6eb71 100644 --- a/.github/actions/javascript/bumpVersion/action.yml +++ b/.github/actions/javascript/bumpVersion/action.yml @@ -11,5 +11,5 @@ outputs: NEW_VERSION: description: The new semver version of the application, updated in the JS and native layers. runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/checkDeployBlockers/action.yml b/.github/actions/javascript/checkDeployBlockers/action.yml index ce0d19f2def1..c6c7b3954c89 100644 --- a/.github/actions/javascript/checkDeployBlockers/action.yml +++ b/.github/actions/javascript/checkDeployBlockers/action.yml @@ -11,5 +11,5 @@ outputs: HAS_DEPLOY_BLOCKERS: description: A true/false indicating whether or not a deploy blocker was found. runs: - using: 'node16' + using: 'node20' main: 'index.js' diff --git a/.github/actions/javascript/checkDeployBlockers/index.js b/.github/actions/javascript/checkDeployBlockers/index.js index c860977f790b..690018aa9367 100644 --- a/.github/actions/javascript/checkDeployBlockers/index.js +++ b/.github/actions/javascript/checkDeployBlockers/index.js @@ -96,6 +96,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/action.yml b/.github/actions/javascript/createOrUpdateStagingDeploy/action.yml index 870cab318d09..b228c694566c 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/action.yml +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/action.yml @@ -4,9 +4,7 @@ inputs: GITHUB_TOKEN: description: Auth token for New Expensify Github required: true - NPM_VERSION: - description: The new NPM version of the StagingDeployCash issue. - required: false + runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.js b/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.js index 82a79528ed09..f0e45257bbef 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.js +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.js @@ -1,13 +1,14 @@ +const fs = require('fs'); +const format = require('date-fns/format'); const _ = require('underscore'); const core = require('@actions/core'); -const moment = require('moment'); const CONST = require('../../../libs/CONST'); const GithubUtils = require('../../../libs/GithubUtils'); const GitUtils = require('../../../libs/GitUtils'); async function run() { - const newVersion = core.getInput('NPM_VERSION'); - console.log('New version found from action input:', newVersion); + // Note: require('package.json').version does not work because ncc will resolve that to a plain string at compile time + const newVersionTag = JSON.parse(fs.readFileSync('package.json')).version; try { // Start by fetching the list of recent StagingDeployCash issues, along with the list of open deploy blockers @@ -35,14 +36,12 @@ async function run() { const currentChecklistData = shouldCreateNewDeployChecklist ? {} : GithubUtils.getStagingDeployCashData(mostRecentChecklist); // Find the list of PRs merged between the current checklist and the previous checklist - // Note that any time we're creating a new checklist we MUST have `NPM_VERSION` passed in as an input - const newTag = newVersion || _.get(currentChecklistData, 'tag'); - const mergedPRs = await GitUtils.getPullRequestsMergedBetween(previousChecklistData.tag, newTag); + const mergedPRs = await GitUtils.getPullRequestsMergedBetween(previousChecklistData.tag, newVersionTag); // Next, we generate the checklist body let checklistBody = ''; if (shouldCreateNewDeployChecklist) { - checklistBody = await GithubUtils.generateStagingDeployCashBody(newTag, _.map(mergedPRs, GithubUtils.getPullRequestURLFromNumber)); + checklistBody = await GithubUtils.generateStagingDeployCashBody(newVersionTag, _.map(mergedPRs, GithubUtils.getPullRequestURLFromNumber)); } else { // Generate the updated PR list, preserving the previous state of `isVerified` for existing PRs const PRList = _.reduce( @@ -94,9 +93,9 @@ async function run() { }); } - const didVersionChange = newVersion ? newVersion !== currentChecklistData.tag : false; + const didVersionChange = newVersionTag !== currentChecklistData.tag; checklistBody = await GithubUtils.generateStagingDeployCashBody( - newTag, + newVersionTag, _.pluck(PRList, 'url'), _.pluck(_.where(PRList, {isVerified: true}), 'url'), _.pluck(deployBlockers, 'url'), @@ -118,7 +117,7 @@ async function run() { if (shouldCreateNewDeployChecklist) { const {data: newChecklist} = await GithubUtils.octokit.issues.create({ ...defaultPayload, - title: `Deploy Checklist: New Expensify ${moment().format('YYYY-MM-DD')}`, + title: `Deploy Checklist: New Expensify ${format(new Date(), CONST.DATE_FORMAT_STRING)}`, labels: [CONST.LABELS.STAGING_DEPLOY], assignees: [CONST.APPLAUSE_BOT], }); diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js index 8ea16c7d96b1..bf8214759c12 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js @@ -7,16 +7,17 @@ /***/ 3926: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +const fs = __nccwpck_require__(7147); +const format = __nccwpck_require__(2168); const _ = __nccwpck_require__(5067); const core = __nccwpck_require__(2186); -const moment = __nccwpck_require__(9623); const CONST = __nccwpck_require__(4097); const GithubUtils = __nccwpck_require__(7999); const GitUtils = __nccwpck_require__(669); async function run() { - const newVersion = core.getInput('NPM_VERSION'); - console.log('New version found from action input:', newVersion); + // Note: require('package.json').version does not work because ncc will resolve that to a plain string at compile time + const newVersionTag = JSON.parse(fs.readFileSync('package.json')).version; try { // Start by fetching the list of recent StagingDeployCash issues, along with the list of open deploy blockers @@ -44,14 +45,12 @@ async function run() { const currentChecklistData = shouldCreateNewDeployChecklist ? {} : GithubUtils.getStagingDeployCashData(mostRecentChecklist); // Find the list of PRs merged between the current checklist and the previous checklist - // Note that any time we're creating a new checklist we MUST have `NPM_VERSION` passed in as an input - const newTag = newVersion || _.get(currentChecklistData, 'tag'); - const mergedPRs = await GitUtils.getPullRequestsMergedBetween(previousChecklistData.tag, newTag); + const mergedPRs = await GitUtils.getPullRequestsMergedBetween(previousChecklistData.tag, newVersionTag); // Next, we generate the checklist body let checklistBody = ''; if (shouldCreateNewDeployChecklist) { - checklistBody = await GithubUtils.generateStagingDeployCashBody(newTag, _.map(mergedPRs, GithubUtils.getPullRequestURLFromNumber)); + checklistBody = await GithubUtils.generateStagingDeployCashBody(newVersionTag, _.map(mergedPRs, GithubUtils.getPullRequestURLFromNumber)); } else { // Generate the updated PR list, preserving the previous state of `isVerified` for existing PRs const PRList = _.reduce( @@ -103,9 +102,9 @@ async function run() { }); } - const didVersionChange = newVersion ? newVersion !== currentChecklistData.tag : false; + const didVersionChange = newVersionTag !== currentChecklistData.tag; checklistBody = await GithubUtils.generateStagingDeployCashBody( - newTag, + newVersionTag, _.pluck(PRList, 'url'), _.pluck(_.where(PRList, {isVerified: true}), 'url'), _.pluck(deployBlockers, 'url'), @@ -127,7 +126,7 @@ async function run() { if (shouldCreateNewDeployChecklist) { const {data: newChecklist} = await GithubUtils.octokit.issues.create({ ...defaultPayload, - title: `Deploy Checklist: New Expensify ${moment().format('YYYY-MM-DD')}`, + title: `Deploy Checklist: New Expensify ${format(new Date(), CONST.DATE_FORMAT_STRING)}`, labels: [CONST.LABELS.STAGING_DEPLOY], assignees: [CONST.APPLAUSE_BOT], }); @@ -169,6 +168,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; @@ -190,23 +190,42 @@ const {getPreviousVersion, SEMANTIC_VERSION_LEVELS} = __nccwpck_require__(8007); /** * @param {String} tag + * @param {String} [shallowExcludeTag] when fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) */ -function fetchTag(tag) { - const previousPatchVersion = getPreviousVersion(tag, SEMANTIC_VERSION_LEVELS.PATCH); - try { - let command = `git fetch origin tag ${tag} --no-tags`; +function fetchTag(tag, shallowExcludeTag = '') { + let shouldRetry = true; + let needsRepack = false; + while (shouldRetry) { + try { + let command = ''; + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + command = 'git repack -d'; + console.log(`Running command: ${command}`); + execSync(command); + } - // Exclude commits reachable from the previous patch version (i.e: previous checklist), - // so that we don't have to fetch the full history - // Note that this condition would only ever _not_ be true in the 1.0.0-0 edge case - if (previousPatchVersion !== tag) { - command += ` --shallow-exclude=${previousPatchVersion}`; - } + command = `git fetch origin tag ${tag} --no-tags`; - console.log(`Running command: ${command}`); - execSync(command); - } catch (e) { - console.error(e); + // Note that this condition is only ever NOT true in the 1.0.0-0 edge case + if (shallowExcludeTag && shallowExcludeTag !== tag) { + command += ` --shallow-exclude=${shallowExcludeTag}`; + } + + console.log(`Running command: ${command}`); + execSync(command); + shouldRetry = false; + } catch (e) { + console.error(e); + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } } } @@ -218,8 +237,10 @@ function fetchTag(tag) { * @returns {Promise>>} */ function getCommitHistoryAsJSON(fromTag, toTag) { - fetchTag(fromTag); - fetchTag(toTag); + // Fetch tags, exclude commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousVersion(fromTag, SEMANTIC_VERSION_LEVELS.PATCH); + fetchTag(fromTag, previousPatchVersion); + fetchTag(toTag, previousPatchVersion); console.log('Getting pull requests merged between the following tags:', fromTag, toTag); return new Promise((resolve, reject) => { @@ -296,16 +317,15 @@ function getValidMergedPRs(commits) { * @param {String} toTag * @returns {Promise>} – Pull request numbers */ -function getPullRequestsMergedBetween(fromTag, toTag) { +async function getPullRequestsMergedBetween(fromTag, toTag) { console.log(`Looking for commits made between ${fromTag} and ${toTag}...`); - return getCommitHistoryAsJSON(fromTag, toTag).then((commitList) => { - console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); + const commitList = await getCommitHistoryAsJSON(fromTag, toTag); + console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); - // Find which commit messages correspond to merged PR's - const pullRequestNumbers = getValidMergedPRs(commitList); - console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); - return _.map(pullRequestNumbers, (prNum) => Number.parseInt(prNum, 10)); - }); + // Find which commit messages correspond to merged PR's + const pullRequestNumbers = getValidMergedPRs(commitList).sort((a, b) => a - b); + console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); + return pullRequestNumbers; } module.exports = { @@ -7457,10425 +7477,7488 @@ function removeHook(state, name, method) { /***/ }), -/***/ 8932: -/***/ ((__unused_webpack_module, exports) => { +/***/ 8620: +/***/ ((module, exports) => { "use strict"; -Object.defineProperty(exports, "__esModule", ({ value: true })); - -class Deprecation extends Error { - constructor(message) { - super(message); // Maintains proper stack trace (only available on V8) - - /* istanbul ignore next */ +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = addLeadingZeros; +function addLeadingZeros(number, targetLength) { + var sign = number < 0 ? '-' : ''; + var output = Math.abs(number).toString(); + while (output.length < targetLength) { + output = '0' + output; + } + return sign + output; +} +module.exports = exports.default; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } +/***/ }), - this.name = 'Deprecation'; - } +/***/ 618: +/***/ ((module, exports, __nccwpck_require__) => { -} +"use strict"; -exports.Deprecation = Deprecation; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(1773)); +var _default = _index.default; +exports["default"] = _default; +module.exports = exports.default; /***/ }), -/***/ 8685: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 9307: +/***/ ((__unused_webpack_module, exports) => { "use strict"; -var iconvLite = __nccwpck_require__(9032); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.getDefaultOptions = getDefaultOptions; +exports.setDefaultOptions = setDefaultOptions; +var defaultOptions = {}; +function getDefaultOptions() { + return defaultOptions; +} +function setDefaultOptions(newOptions) { + defaultOptions = newOptions; +} -// Expose to the world -module.exports.O = convert; +/***/ }), -/** - * Convert encoding of an UTF-8 string or a buffer +/***/ 9257: +/***/ ((module, exports, __nccwpck_require__) => { + +"use strict"; + + +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(2966)); +var _index2 = _interopRequireDefault(__nccwpck_require__(8493)); +var _index3 = _interopRequireDefault(__nccwpck_require__(7170)); +var _index4 = _interopRequireDefault(__nccwpck_require__(8761)); +var _index5 = _interopRequireDefault(__nccwpck_require__(8050)); +var _index6 = _interopRequireDefault(__nccwpck_require__(8620)); +var _index7 = _interopRequireDefault(__nccwpck_require__(289)); +var dayPeriodEnum = { + am: 'am', + pm: 'pm', + midnight: 'midnight', + noon: 'noon', + morning: 'morning', + afternoon: 'afternoon', + evening: 'evening', + night: 'night' +}; +/* + * | | Unit | | Unit | + * |-----|--------------------------------|-----|--------------------------------| + * | a | AM, PM | A* | Milliseconds in day | + * | b | AM, PM, noon, midnight | B | Flexible day period | + * | c | Stand-alone local day of week | C* | Localized hour w/ day period | + * | d | Day of month | D | Day of year | + * | e | Local day of week | E | Day of week | + * | f | | F* | Day of week in month | + * | g* | Modified Julian day | G | Era | + * | h | Hour [1-12] | H | Hour [0-23] | + * | i! | ISO day of week | I! | ISO week of year | + * | j* | Localized hour w/ day period | J* | Localized hour w/o day period | + * | k | Hour [1-24] | K | Hour [0-11] | + * | l* | (deprecated) | L | Stand-alone month | + * | m | Minute | M | Month | + * | n | | N | | + * | o! | Ordinal number modifier | O | Timezone (GMT) | + * | p! | Long localized time | P! | Long localized date | + * | q | Stand-alone quarter | Q | Quarter | + * | r* | Related Gregorian year | R! | ISO week-numbering year | + * | s | Second | S | Fraction of second | + * | t! | Seconds timestamp | T! | Milliseconds timestamp | + * | u | Extended year | U* | Cyclic year | + * | v* | Timezone (generic non-locat.) | V* | Timezone (location) | + * | w | Local week of year | W* | Week of month | + * | x | Timezone (ISO-8601 w/o Z) | X | Timezone (ISO-8601) | + * | y | Year (abs) | Y | Local week-numbering year | + * | z | Timezone (specific non-locat.) | Z* | Timezone (aliases) | * - * @param {String|Buffer} str String to be converted - * @param {String} to Encoding to be converted to - * @param {String} [from='UTF-8'] Encoding to be converted from - * @return {Buffer} Encoded string + * Letters marked by * are not implemented but reserved by Unicode standard. + * + * Letters marked by ! are non-standard, but implemented by date-fns: + * - `o` modifies the previous token to turn it into an ordinal (see `format` docs) + * - `i` is ISO day of week. For `i` and `ii` is returns numeric ISO week days, + * i.e. 7 for Sunday, 1 for Monday, etc. + * - `I` is ISO week of year, as opposed to `w` which is local week of year. + * - `R` is ISO week-numbering year, as opposed to `Y` which is local week-numbering year. + * `R` is supposed to be used in conjunction with `I` and `i` + * for universal ISO week-numbering date, whereas + * `Y` is supposed to be used in conjunction with `w` and `e` + * for week-numbering date specific to the locale. + * - `P` is long localized date format + * - `p` is long localized time format */ -function convert(str, to, from) { - from = checkEncoding(from || 'UTF-8'); - to = checkEncoding(to || 'UTF-8'); - str = str || ''; - - var result; - if (from !== 'UTF-8' && typeof str === 'string') { - str = Buffer.from(str, 'binary'); +var formatters = { + // Era + G: function G(date, token, localize) { + var era = date.getUTCFullYear() > 0 ? 1 : 0; + switch (token) { + // AD, BC + case 'G': + case 'GG': + case 'GGG': + return localize.era(era, { + width: 'abbreviated' + }); + // A, B + case 'GGGGG': + return localize.era(era, { + width: 'narrow' + }); + // Anno Domini, Before Christ + case 'GGGG': + default: + return localize.era(era, { + width: 'wide' + }); } - - if (from === to) { - if (typeof str === 'string') { - result = Buffer.from(str); - } else { - result = str; - } - } else { - try { - result = convertIconvLite(str, to, from); - } catch (E) { - console.error(E); - result = str; - } + }, + // Year + y: function y(date, token, localize) { + // Ordinal number + if (token === 'yo') { + var signedYear = date.getUTCFullYear(); + // Returns 1 for 1 BC (which is year 0 in JavaScript) + var year = signedYear > 0 ? signedYear : 1 - signedYear; + return localize.ordinalNumber(year, { + unit: 'year' + }); } - - if (typeof result === 'string') { - result = Buffer.from(result, 'utf-8'); + return _index7.default.y(date, token); + }, + // Local week-numbering year + Y: function Y(date, token, localize, options) { + var signedWeekYear = (0, _index5.default)(date, options); + // Returns 1 for 1 BC (which is year 0 in JavaScript) + var weekYear = signedWeekYear > 0 ? signedWeekYear : 1 - signedWeekYear; + + // Two digit year + if (token === 'YY') { + var twoDigitYear = weekYear % 100; + return (0, _index6.default)(twoDigitYear, 2); + } + + // Ordinal number + if (token === 'Yo') { + return localize.ordinalNumber(weekYear, { + unit: 'year' + }); } - return result; -} + // Padding + return (0, _index6.default)(weekYear, token.length); + }, + // ISO week-numbering year + R: function R(date, token) { + var isoWeekYear = (0, _index3.default)(date); -/** - * Convert encoding of astring with iconv-lite - * - * @param {String|Buffer} str String to be converted - * @param {String} to Encoding to be converted to - * @param {String} [from='UTF-8'] Encoding to be converted from - * @return {Buffer} Encoded string - */ -function convertIconvLite(str, to, from) { - if (to === 'UTF-8') { - return iconvLite.decode(str, from); - } else if (from === 'UTF-8') { - return iconvLite.encode(str, to); + // Padding + return (0, _index6.default)(isoWeekYear, token.length); + }, + // Extended year. This is a single number designating the year of this calendar system. + // The main difference between `y` and `u` localizers are B.C. years: + // | Year | `y` | `u` | + // |------|-----|-----| + // | AC 1 | 1 | 1 | + // | BC 1 | 1 | 0 | + // | BC 2 | 2 | -1 | + // Also `yy` always returns the last two digits of a year, + // while `uu` pads single digit years to 2 characters and returns other years unchanged. + u: function u(date, token) { + var year = date.getUTCFullYear(); + return (0, _index6.default)(year, token.length); + }, + // Quarter + Q: function Q(date, token, localize) { + var quarter = Math.ceil((date.getUTCMonth() + 1) / 3); + switch (token) { + // 1, 2, 3, 4 + case 'Q': + return String(quarter); + // 01, 02, 03, 04 + case 'QQ': + return (0, _index6.default)(quarter, 2); + // 1st, 2nd, 3rd, 4th + case 'Qo': + return localize.ordinalNumber(quarter, { + unit: 'quarter' + }); + // Q1, Q2, Q3, Q4 + case 'QQQ': + return localize.quarter(quarter, { + width: 'abbreviated', + context: 'formatting' + }); + // 1, 2, 3, 4 (narrow quarter; could be not numerical) + case 'QQQQQ': + return localize.quarter(quarter, { + width: 'narrow', + context: 'formatting' + }); + // 1st quarter, 2nd quarter, ... + case 'QQQQ': + default: + return localize.quarter(quarter, { + width: 'wide', + context: 'formatting' + }); + } + }, + // Stand-alone quarter + q: function q(date, token, localize) { + var quarter = Math.ceil((date.getUTCMonth() + 1) / 3); + switch (token) { + // 1, 2, 3, 4 + case 'q': + return String(quarter); + // 01, 02, 03, 04 + case 'qq': + return (0, _index6.default)(quarter, 2); + // 1st, 2nd, 3rd, 4th + case 'qo': + return localize.ordinalNumber(quarter, { + unit: 'quarter' + }); + // Q1, Q2, Q3, Q4 + case 'qqq': + return localize.quarter(quarter, { + width: 'abbreviated', + context: 'standalone' + }); + // 1, 2, 3, 4 (narrow quarter; could be not numerical) + case 'qqqqq': + return localize.quarter(quarter, { + width: 'narrow', + context: 'standalone' + }); + // 1st quarter, 2nd quarter, ... + case 'qqqq': + default: + return localize.quarter(quarter, { + width: 'wide', + context: 'standalone' + }); + } + }, + // Month + M: function M(date, token, localize) { + var month = date.getUTCMonth(); + switch (token) { + case 'M': + case 'MM': + return _index7.default.M(date, token); + // 1st, 2nd, ..., 12th + case 'Mo': + return localize.ordinalNumber(month + 1, { + unit: 'month' + }); + // Jan, Feb, ..., Dec + case 'MMM': + return localize.month(month, { + width: 'abbreviated', + context: 'formatting' + }); + // J, F, ..., D + case 'MMMMM': + return localize.month(month, { + width: 'narrow', + context: 'formatting' + }); + // January, February, ..., December + case 'MMMM': + default: + return localize.month(month, { + width: 'wide', + context: 'formatting' + }); + } + }, + // Stand-alone month + L: function L(date, token, localize) { + var month = date.getUTCMonth(); + switch (token) { + // 1, 2, ..., 12 + case 'L': + return String(month + 1); + // 01, 02, ..., 12 + case 'LL': + return (0, _index6.default)(month + 1, 2); + // 1st, 2nd, ..., 12th + case 'Lo': + return localize.ordinalNumber(month + 1, { + unit: 'month' + }); + // Jan, Feb, ..., Dec + case 'LLL': + return localize.month(month, { + width: 'abbreviated', + context: 'standalone' + }); + // J, F, ..., D + case 'LLLLL': + return localize.month(month, { + width: 'narrow', + context: 'standalone' + }); + // January, February, ..., December + case 'LLLL': + default: + return localize.month(month, { + width: 'wide', + context: 'standalone' + }); + } + }, + // Local week of year + w: function w(date, token, localize, options) { + var week = (0, _index4.default)(date, options); + if (token === 'wo') { + return localize.ordinalNumber(week, { + unit: 'week' + }); + } + return (0, _index6.default)(week, token.length); + }, + // ISO week of year + I: function I(date, token, localize) { + var isoWeek = (0, _index2.default)(date); + if (token === 'Io') { + return localize.ordinalNumber(isoWeek, { + unit: 'week' + }); + } + return (0, _index6.default)(isoWeek, token.length); + }, + // Day of the month + d: function d(date, token, localize) { + if (token === 'do') { + return localize.ordinalNumber(date.getUTCDate(), { + unit: 'date' + }); + } + return _index7.default.d(date, token); + }, + // Day of year + D: function D(date, token, localize) { + var dayOfYear = (0, _index.default)(date); + if (token === 'Do') { + return localize.ordinalNumber(dayOfYear, { + unit: 'dayOfYear' + }); + } + return (0, _index6.default)(dayOfYear, token.length); + }, + // Day of week + E: function E(date, token, localize) { + var dayOfWeek = date.getUTCDay(); + switch (token) { + // Tue + case 'E': + case 'EE': + case 'EEE': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'formatting' + }); + // T + case 'EEEEE': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'formatting' + }); + // Tu + case 'EEEEEE': + return localize.day(dayOfWeek, { + width: 'short', + context: 'formatting' + }); + // Tuesday + case 'EEEE': + default: + return localize.day(dayOfWeek, { + width: 'wide', + context: 'formatting' + }); + } + }, + // Local day of week + e: function e(date, token, localize, options) { + var dayOfWeek = date.getUTCDay(); + var localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7; + switch (token) { + // Numerical value (Nth day of week with current locale or weekStartsOn) + case 'e': + return String(localDayOfWeek); + // Padded numerical value + case 'ee': + return (0, _index6.default)(localDayOfWeek, 2); + // 1st, 2nd, ..., 7th + case 'eo': + return localize.ordinalNumber(localDayOfWeek, { + unit: 'day' + }); + case 'eee': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'formatting' + }); + // T + case 'eeeee': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'formatting' + }); + // Tu + case 'eeeeee': + return localize.day(dayOfWeek, { + width: 'short', + context: 'formatting' + }); + // Tuesday + case 'eeee': + default: + return localize.day(dayOfWeek, { + width: 'wide', + context: 'formatting' + }); + } + }, + // Stand-alone local day of week + c: function c(date, token, localize, options) { + var dayOfWeek = date.getUTCDay(); + var localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7; + switch (token) { + // Numerical value (same as in `e`) + case 'c': + return String(localDayOfWeek); + // Padded numerical value + case 'cc': + return (0, _index6.default)(localDayOfWeek, token.length); + // 1st, 2nd, ..., 7th + case 'co': + return localize.ordinalNumber(localDayOfWeek, { + unit: 'day' + }); + case 'ccc': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'standalone' + }); + // T + case 'ccccc': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'standalone' + }); + // Tu + case 'cccccc': + return localize.day(dayOfWeek, { + width: 'short', + context: 'standalone' + }); + // Tuesday + case 'cccc': + default: + return localize.day(dayOfWeek, { + width: 'wide', + context: 'standalone' + }); + } + }, + // ISO day of week + i: function i(date, token, localize) { + var dayOfWeek = date.getUTCDay(); + var isoDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek; + switch (token) { + // 2 + case 'i': + return String(isoDayOfWeek); + // 02 + case 'ii': + return (0, _index6.default)(isoDayOfWeek, token.length); + // 2nd + case 'io': + return localize.ordinalNumber(isoDayOfWeek, { + unit: 'day' + }); + // Tue + case 'iii': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'formatting' + }); + // T + case 'iiiii': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'formatting' + }); + // Tu + case 'iiiiii': + return localize.day(dayOfWeek, { + width: 'short', + context: 'formatting' + }); + // Tuesday + case 'iiii': + default: + return localize.day(dayOfWeek, { + width: 'wide', + context: 'formatting' + }); + } + }, + // AM or PM + a: function a(date, token, localize) { + var hours = date.getUTCHours(); + var dayPeriodEnumValue = hours / 12 >= 1 ? 'pm' : 'am'; + switch (token) { + case 'a': + case 'aa': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }); + case 'aaa': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }).toLowerCase(); + case 'aaaaa': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'narrow', + context: 'formatting' + }); + case 'aaaa': + default: + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'wide', + context: 'formatting' + }); + } + }, + // AM, PM, midnight, noon + b: function b(date, token, localize) { + var hours = date.getUTCHours(); + var dayPeriodEnumValue; + if (hours === 12) { + dayPeriodEnumValue = dayPeriodEnum.noon; + } else if (hours === 0) { + dayPeriodEnumValue = dayPeriodEnum.midnight; } else { - return iconvLite.encode(iconvLite.decode(str, from), to); + dayPeriodEnumValue = hours / 12 >= 1 ? 'pm' : 'am'; + } + switch (token) { + case 'b': + case 'bb': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }); + case 'bbb': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }).toLowerCase(); + case 'bbbbb': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'narrow', + context: 'formatting' + }); + case 'bbbb': + default: + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'wide', + context: 'formatting' + }); + } + }, + // in the morning, in the afternoon, in the evening, at night + B: function B(date, token, localize) { + var hours = date.getUTCHours(); + var dayPeriodEnumValue; + if (hours >= 17) { + dayPeriodEnumValue = dayPeriodEnum.evening; + } else if (hours >= 12) { + dayPeriodEnumValue = dayPeriodEnum.afternoon; + } else if (hours >= 4) { + dayPeriodEnumValue = dayPeriodEnum.morning; + } else { + dayPeriodEnumValue = dayPeriodEnum.night; + } + switch (token) { + case 'B': + case 'BB': + case 'BBB': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }); + case 'BBBBB': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'narrow', + context: 'formatting' + }); + case 'BBBB': + default: + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'wide', + context: 'formatting' + }); + } + }, + // Hour [1-12] + h: function h(date, token, localize) { + if (token === 'ho') { + var hours = date.getUTCHours() % 12; + if (hours === 0) hours = 12; + return localize.ordinalNumber(hours, { + unit: 'hour' + }); + } + return _index7.default.h(date, token); + }, + // Hour [0-23] + H: function H(date, token, localize) { + if (token === 'Ho') { + return localize.ordinalNumber(date.getUTCHours(), { + unit: 'hour' + }); + } + return _index7.default.H(date, token); + }, + // Hour [0-11] + K: function K(date, token, localize) { + var hours = date.getUTCHours() % 12; + if (token === 'Ko') { + return localize.ordinalNumber(hours, { + unit: 'hour' + }); + } + return (0, _index6.default)(hours, token.length); + }, + // Hour [1-24] + k: function k(date, token, localize) { + var hours = date.getUTCHours(); + if (hours === 0) hours = 24; + if (token === 'ko') { + return localize.ordinalNumber(hours, { + unit: 'hour' + }); + } + return (0, _index6.default)(hours, token.length); + }, + // Minute + m: function m(date, token, localize) { + if (token === 'mo') { + return localize.ordinalNumber(date.getUTCMinutes(), { + unit: 'minute' + }); + } + return _index7.default.m(date, token); + }, + // Second + s: function s(date, token, localize) { + if (token === 'so') { + return localize.ordinalNumber(date.getUTCSeconds(), { + unit: 'second' + }); + } + return _index7.default.s(date, token); + }, + // Fraction of second + S: function S(date, token) { + return _index7.default.S(date, token); + }, + // Timezone (ISO-8601. If offset is 0, output is always `'Z'`) + X: function X(date, token, _localize, options) { + var originalDate = options._originalDate || date; + var timezoneOffset = originalDate.getTimezoneOffset(); + if (timezoneOffset === 0) { + return 'Z'; + } + switch (token) { + // Hours and optional minutes + case 'X': + return formatTimezoneWithOptionalMinutes(timezoneOffset); + + // Hours, minutes and optional seconds without `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `XX` + case 'XXXX': + case 'XX': + // Hours and minutes without `:` delimiter + return formatTimezone(timezoneOffset); + + // Hours, minutes and optional seconds with `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `XXX` + case 'XXXXX': + case 'XXX': // Hours and minutes with `:` delimiter + default: + return formatTimezone(timezoneOffset, ':'); + } + }, + // Timezone (ISO-8601. If offset is 0, output is `'+00:00'` or equivalent) + x: function x(date, token, _localize, options) { + var originalDate = options._originalDate || date; + var timezoneOffset = originalDate.getTimezoneOffset(); + switch (token) { + // Hours and optional minutes + case 'x': + return formatTimezoneWithOptionalMinutes(timezoneOffset); + + // Hours, minutes and optional seconds without `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `xx` + case 'xxxx': + case 'xx': + // Hours and minutes without `:` delimiter + return formatTimezone(timezoneOffset); + + // Hours, minutes and optional seconds with `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `xxx` + case 'xxxxx': + case 'xxx': // Hours and minutes with `:` delimiter + default: + return formatTimezone(timezoneOffset, ':'); + } + }, + // Timezone (GMT) + O: function O(date, token, _localize, options) { + var originalDate = options._originalDate || date; + var timezoneOffset = originalDate.getTimezoneOffset(); + switch (token) { + // Short + case 'O': + case 'OO': + case 'OOO': + return 'GMT' + formatTimezoneShort(timezoneOffset, ':'); + // Long + case 'OOOO': + default: + return 'GMT' + formatTimezone(timezoneOffset, ':'); + } + }, + // Timezone (specific non-location) + z: function z(date, token, _localize, options) { + var originalDate = options._originalDate || date; + var timezoneOffset = originalDate.getTimezoneOffset(); + switch (token) { + // Short + case 'z': + case 'zz': + case 'zzz': + return 'GMT' + formatTimezoneShort(timezoneOffset, ':'); + // Long + case 'zzzz': + default: + return 'GMT' + formatTimezone(timezoneOffset, ':'); } + }, + // Seconds timestamp + t: function t(date, token, _localize, options) { + var originalDate = options._originalDate || date; + var timestamp = Math.floor(originalDate.getTime() / 1000); + return (0, _index6.default)(timestamp, token.length); + }, + // Milliseconds timestamp + T: function T(date, token, _localize, options) { + var originalDate = options._originalDate || date; + var timestamp = originalDate.getTime(); + return (0, _index6.default)(timestamp, token.length); + } +}; +function formatTimezoneShort(offset, dirtyDelimiter) { + var sign = offset > 0 ? '-' : '+'; + var absOffset = Math.abs(offset); + var hours = Math.floor(absOffset / 60); + var minutes = absOffset % 60; + if (minutes === 0) { + return sign + String(hours); + } + var delimiter = dirtyDelimiter || ''; + return sign + String(hours) + delimiter + (0, _index6.default)(minutes, 2); } - -/** - * Converts charset name if needed - * - * @param {String} name Character set - * @return {String} Character set name - */ -function checkEncoding(name) { - return (name || '') - .toString() - .trim() - .replace(/^latin[\-_]?(\d+)$/i, 'ISO-8859-$1') - .replace(/^win(?:dows)?[\-_]?(\d+)$/i, 'WINDOWS-$1') - .replace(/^utf[\-_]?(\d+)$/i, 'UTF-$1') - .replace(/^ks_c_5601\-1987$/i, 'CP949') - .replace(/^us[\-_]?ascii$/i, 'ASCII') - .toUpperCase(); +function formatTimezoneWithOptionalMinutes(offset, dirtyDelimiter) { + if (offset % 60 === 0) { + var sign = offset > 0 ? '-' : '+'; + return sign + (0, _index6.default)(Math.abs(offset) / 60, 2); + } + return formatTimezone(offset, dirtyDelimiter); } - +function formatTimezone(offset, dirtyDelimiter) { + var delimiter = dirtyDelimiter || ''; + var sign = offset > 0 ? '-' : '+'; + var absOffset = Math.abs(offset); + var hours = (0, _index6.default)(Math.floor(absOffset / 60), 2); + var minutes = (0, _index6.default)(absOffset % 60, 2); + return sign + hours + delimiter + minutes; +} +var _default = formatters; +exports["default"] = _default; +module.exports = exports.default; /***/ }), -/***/ 9695: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { +/***/ 289: +/***/ ((module, exports, __nccwpck_require__) => { "use strict"; -var Buffer = (__nccwpck_require__(5118).Buffer); -// Multibyte codec. In this scheme, a character is represented by 1 or more bytes. -// Our codec supports UTF-16 surrogates, extensions for GB18030 and unicode sequences. -// To save memory and loading time, we read table files only when requested. +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(8620)); +/* + * | | Unit | | Unit | + * |-----|--------------------------------|-----|--------------------------------| + * | a | AM, PM | A* | | + * | d | Day of month | D | | + * | h | Hour [1-12] | H | Hour [0-23] | + * | m | Minute | M | Month | + * | s | Second | S | Fraction of second | + * | y | Year (abs) | Y | | + * + * Letters marked by * are not implemented but reserved by Unicode standard. + */ -exports._dbcs = DBCSCodec; +var formatters = { + // Year + y: function y(date, token) { + // From http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_tokens + // | Year | y | yy | yyy | yyyy | yyyyy | + // |----------|-------|----|-------|-------|-------| + // | AD 1 | 1 | 01 | 001 | 0001 | 00001 | + // | AD 12 | 12 | 12 | 012 | 0012 | 00012 | + // | AD 123 | 123 | 23 | 123 | 0123 | 00123 | + // | AD 1234 | 1234 | 34 | 1234 | 1234 | 01234 | + // | AD 12345 | 12345 | 45 | 12345 | 12345 | 12345 | + + var signedYear = date.getUTCFullYear(); + // Returns 1 for 1 BC (which is year 0 in JavaScript) + var year = signedYear > 0 ? signedYear : 1 - signedYear; + return (0, _index.default)(token === 'yy' ? year % 100 : year, token.length); + }, + // Month + M: function M(date, token) { + var month = date.getUTCMonth(); + return token === 'M' ? String(month + 1) : (0, _index.default)(month + 1, 2); + }, + // Day of the month + d: function d(date, token) { + return (0, _index.default)(date.getUTCDate(), token.length); + }, + // AM or PM + a: function a(date, token) { + var dayPeriodEnumValue = date.getUTCHours() / 12 >= 1 ? 'pm' : 'am'; + switch (token) { + case 'a': + case 'aa': + return dayPeriodEnumValue.toUpperCase(); + case 'aaa': + return dayPeriodEnumValue; + case 'aaaaa': + return dayPeriodEnumValue[0]; + case 'aaaa': + default: + return dayPeriodEnumValue === 'am' ? 'a.m.' : 'p.m.'; + } + }, + // Hour [1-12] + h: function h(date, token) { + return (0, _index.default)(date.getUTCHours() % 12 || 12, token.length); + }, + // Hour [0-23] + H: function H(date, token) { + return (0, _index.default)(date.getUTCHours(), token.length); + }, + // Minute + m: function m(date, token) { + return (0, _index.default)(date.getUTCMinutes(), token.length); + }, + // Second + s: function s(date, token) { + return (0, _index.default)(date.getUTCSeconds(), token.length); + }, + // Fraction of second + S: function S(date, token) { + var numberOfDigits = token.length; + var milliseconds = date.getUTCMilliseconds(); + var fractionalSeconds = Math.floor(milliseconds * Math.pow(10, numberOfDigits - 3)); + return (0, _index.default)(fractionalSeconds, token.length); + } +}; +var _default = formatters; +exports["default"] = _default; +module.exports = exports.default; -var UNASSIGNED = -1, - GB18030_CODE = -2, - SEQ_START = -10, - NODE_START = -1000, - UNASSIGNED_NODE = new Array(0x100), - DEF_CHAR = -1; +/***/ }), -for (var i = 0; i < 0x100; i++) - UNASSIGNED_NODE[i] = UNASSIGNED; +/***/ 8387: +/***/ ((module, exports) => { +"use strict"; -// Class DBCSCodec reads and initializes mapping tables. -function DBCSCodec(codecOptions, iconv) { - this.encodingName = codecOptions.encodingName; - if (!codecOptions) - throw new Error("DBCS codec is called without the data.") - if (!codecOptions.table) - throw new Error("Encoding '" + this.encodingName + "' has no data."); - // Load tables. - var mappingTable = codecOptions.table(); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var dateLongFormatter = function dateLongFormatter(pattern, formatLong) { + switch (pattern) { + case 'P': + return formatLong.date({ + width: 'short' + }); + case 'PP': + return formatLong.date({ + width: 'medium' + }); + case 'PPP': + return formatLong.date({ + width: 'long' + }); + case 'PPPP': + default: + return formatLong.date({ + width: 'full' + }); + } +}; +var timeLongFormatter = function timeLongFormatter(pattern, formatLong) { + switch (pattern) { + case 'p': + return formatLong.time({ + width: 'short' + }); + case 'pp': + return formatLong.time({ + width: 'medium' + }); + case 'ppp': + return formatLong.time({ + width: 'long' + }); + case 'pppp': + default: + return formatLong.time({ + width: 'full' + }); + } +}; +var dateTimeLongFormatter = function dateTimeLongFormatter(pattern, formatLong) { + var matchResult = pattern.match(/(P+)(p+)?/) || []; + var datePattern = matchResult[1]; + var timePattern = matchResult[2]; + if (!timePattern) { + return dateLongFormatter(pattern, formatLong); + } + var dateTimeFormat; + switch (datePattern) { + case 'P': + dateTimeFormat = formatLong.dateTime({ + width: 'short' + }); + break; + case 'PP': + dateTimeFormat = formatLong.dateTime({ + width: 'medium' + }); + break; + case 'PPP': + dateTimeFormat = formatLong.dateTime({ + width: 'long' + }); + break; + case 'PPPP': + default: + dateTimeFormat = formatLong.dateTime({ + width: 'full' + }); + break; + } + return dateTimeFormat.replace('{{date}}', dateLongFormatter(datePattern, formatLong)).replace('{{time}}', timeLongFormatter(timePattern, formatLong)); +}; +var longFormatters = { + p: timeLongFormatter, + P: dateTimeLongFormatter +}; +var _default = longFormatters; +exports["default"] = _default; +module.exports = exports.default; +/***/ }), - // Decode tables: MBCS -> Unicode. +/***/ 7032: +/***/ ((module, exports) => { - // decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256. - // Trie root is decodeTables[0]. - // Values: >= 0 -> unicode character code. can be > 0xFFFF - // == UNASSIGNED -> unknown/unassigned sequence. - // == GB18030_CODE -> this is the end of a GB18030 4-byte sequence. - // <= NODE_START -> index of the next node in our trie to process next byte. - // <= SEQ_START -> index of the start of a character code sequence, in decodeTableSeq. - this.decodeTables = []; - this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node. +"use strict"; - // Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here. - this.decodeTableSeq = []; - // Actual mapping tables consist of chunks. Use them to fill up decode tables. - for (var i = 0; i < mappingTable.length; i++) - this._addDecodeChunk(mappingTable[i]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = getTimezoneOffsetInMilliseconds; +/** + * Google Chrome as of 67.0.3396.87 introduced timezones with offset that includes seconds. + * They usually appear for dates that denote time before the timezones were introduced + * (e.g. for 'Europe/Prague' timezone the offset is GMT+00:57:44 before 1 October 1891 + * and GMT+01:00:00 after that date) + * + * Date#getTimezoneOffset returns the offset in minutes and would return 57 for the example above, + * which would lead to incorrect calculations. + * + * This function returns the timezone offset in milliseconds that takes seconds in account. + */ +function getTimezoneOffsetInMilliseconds(date) { + var utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())); + utcDate.setUTCFullYear(date.getFullYear()); + return date.getTime() - utcDate.getTime(); +} +module.exports = exports.default; - // Load & create GB18030 tables when needed. - if (typeof codecOptions.gb18030 === 'function') { - this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges. +/***/ }), - // Add GB18030 common decode nodes. - var commonThirdByteNodeIdx = this.decodeTables.length; - this.decodeTables.push(UNASSIGNED_NODE.slice(0)); +/***/ 2966: +/***/ ((module, exports, __nccwpck_require__) => { - var commonFourthByteNodeIdx = this.decodeTables.length; - this.decodeTables.push(UNASSIGNED_NODE.slice(0)); +"use strict"; - // Fill out the tree - var firstByteNode = this.decodeTables[0]; - for (var i = 0x81; i <= 0xFE; i++) { - var secondByteNode = this.decodeTables[NODE_START - firstByteNode[i]]; - for (var j = 0x30; j <= 0x39; j++) { - if (secondByteNode[j] === UNASSIGNED) { - secondByteNode[j] = NODE_START - commonThirdByteNodeIdx; - } else if (secondByteNode[j] > NODE_START) { - throw new Error("gb18030 decode tables conflict at byte 2"); - } - var thirdByteNode = this.decodeTables[NODE_START - secondByteNode[j]]; - for (var k = 0x81; k <= 0xFE; k++) { - if (thirdByteNode[k] === UNASSIGNED) { - thirdByteNode[k] = NODE_START - commonFourthByteNodeIdx; - } else if (thirdByteNode[k] === NODE_START - commonFourthByteNodeIdx) { - continue; - } else if (thirdByteNode[k] > NODE_START) { - throw new Error("gb18030 decode tables conflict at byte 3"); - } +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = getUTCDayOfYear; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +var MILLISECONDS_IN_DAY = 86400000; +function getUTCDayOfYear(dirtyDate) { + (0, _index2.default)(1, arguments); + var date = (0, _index.default)(dirtyDate); + var timestamp = date.getTime(); + date.setUTCMonth(0, 1); + date.setUTCHours(0, 0, 0, 0); + var startOfYearTimestamp = date.getTime(); + var difference = timestamp - startOfYearTimestamp; + return Math.floor(difference / MILLISECONDS_IN_DAY) + 1; +} +module.exports = exports.default; - var fourthByteNode = this.decodeTables[NODE_START - thirdByteNode[k]]; - for (var l = 0x30; l <= 0x39; l++) { - if (fourthByteNode[l] === UNASSIGNED) - fourthByteNode[l] = GB18030_CODE; - } - } - } - } - } +/***/ }), - this.defaultCharUnicode = iconv.defaultCharUnicode; +/***/ 8493: +/***/ ((module, exports, __nccwpck_require__) => { - - // Encode tables: Unicode -> DBCS. +"use strict"; - // `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance. - // Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null. - // Values: >= 0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.). - // == UNASSIGNED -> no conversion found. Output a default char. - // <= SEQ_START -> it's an index in encodeTableSeq, see below. The character starts a sequence. - this.encodeTable = []; - - // `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of - // objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key - // means end of sequence (needed when one sequence is a strict subsequence of another). - // Objects are kept separately from encodeTable to increase performance. - this.encodeTableSeq = []; - // Some chars can be decoded, but need not be encoded. - var skipEncodeChars = {}; - if (codecOptions.encodeSkipVals) - for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) { - var val = codecOptions.encodeSkipVals[i]; - if (typeof val === 'number') - skipEncodeChars[val] = true; - else - for (var j = val.from; j <= val.to; j++) - skipEncodeChars[j] = true; - } - - // Use decode trie to recursively fill out encode tables. - this._fillEncodeTable(0, 0, skipEncodeChars); +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = getUTCISOWeek; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(3061)); +var _index3 = _interopRequireDefault(__nccwpck_require__(1478)); +var _index4 = _interopRequireDefault(__nccwpck_require__(2063)); +var MILLISECONDS_IN_WEEK = 604800000; +function getUTCISOWeek(dirtyDate) { + (0, _index4.default)(1, arguments); + var date = (0, _index.default)(dirtyDate); + var diff = (0, _index2.default)(date).getTime() - (0, _index3.default)(date).getTime(); + + // Round the number of days to the nearest integer + // because the number of milliseconds in a week is not constant + // (e.g. it's different in the week of the daylight saving time clock shift) + return Math.round(diff / MILLISECONDS_IN_WEEK) + 1; +} +module.exports = exports.default; - // Add more encoding pairs when needed. - if (codecOptions.encodeAdd) { - for (var uChar in codecOptions.encodeAdd) - if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar)) - this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]); - } +/***/ }), - this.defCharSB = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)]; - if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?']; - if (this.defCharSB === UNASSIGNED) this.defCharSB = "?".charCodeAt(0); +/***/ 7170: +/***/ ((module, exports, __nccwpck_require__) => { + +"use strict"; + + +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = getUTCISOWeekYear; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +var _index3 = _interopRequireDefault(__nccwpck_require__(3061)); +function getUTCISOWeekYear(dirtyDate) { + (0, _index2.default)(1, arguments); + var date = (0, _index.default)(dirtyDate); + var year = date.getUTCFullYear(); + var fourthOfJanuaryOfNextYear = new Date(0); + fourthOfJanuaryOfNextYear.setUTCFullYear(year + 1, 0, 4); + fourthOfJanuaryOfNextYear.setUTCHours(0, 0, 0, 0); + var startOfNextYear = (0, _index3.default)(fourthOfJanuaryOfNextYear); + var fourthOfJanuaryOfThisYear = new Date(0); + fourthOfJanuaryOfThisYear.setUTCFullYear(year, 0, 4); + fourthOfJanuaryOfThisYear.setUTCHours(0, 0, 0, 0); + var startOfThisYear = (0, _index3.default)(fourthOfJanuaryOfThisYear); + if (date.getTime() >= startOfNextYear.getTime()) { + return year + 1; + } else if (date.getTime() >= startOfThisYear.getTime()) { + return year; + } else { + return year - 1; + } } +module.exports = exports.default; -DBCSCodec.prototype.encoder = DBCSEncoder; -DBCSCodec.prototype.decoder = DBCSDecoder; +/***/ }), -// Decoder helpers -DBCSCodec.prototype._getDecodeTrieNode = function(addr) { - var bytes = []; - for (; addr > 0; addr >>>= 8) - bytes.push(addr & 0xFF); - if (bytes.length == 0) - bytes.push(0); +/***/ 8761: +/***/ ((module, exports, __nccwpck_require__) => { - var node = this.decodeTables[0]; - for (var i = bytes.length-1; i > 0; i--) { // Traverse nodes deeper into the trie. - var val = node[bytes[i]]; +"use strict"; - if (val == UNASSIGNED) { // Create new node. - node[bytes[i]] = NODE_START - this.decodeTables.length; - this.decodeTables.push(node = UNASSIGNED_NODE.slice(0)); - } - else if (val <= NODE_START) { // Existing node. - node = this.decodeTables[NODE_START - val]; - } - else - throw new Error("Overwrite byte in " + this.encodingName + ", addr: " + addr.toString(16)); - } - return node; -} +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = getUTCWeek; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2258)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2629)); +var _index4 = _interopRequireDefault(__nccwpck_require__(2063)); +var MILLISECONDS_IN_WEEK = 604800000; +function getUTCWeek(dirtyDate, options) { + (0, _index4.default)(1, arguments); + var date = (0, _index.default)(dirtyDate); + var diff = (0, _index2.default)(date, options).getTime() - (0, _index3.default)(date, options).getTime(); + + // Round the number of days to the nearest integer + // because the number of milliseconds in a week is not constant + // (e.g. it's different in the week of the daylight saving time clock shift) + return Math.round(diff / MILLISECONDS_IN_WEEK) + 1; +} +module.exports = exports.default; -DBCSCodec.prototype._addDecodeChunk = function(chunk) { - // First element of chunk is the hex mbcs code where we start. - var curAddr = parseInt(chunk[0], 16); +/***/ }), - // Choose the decoding node where we'll write our chars. - var writeTable = this._getDecodeTrieNode(curAddr); - curAddr = curAddr & 0xFF; +/***/ 8050: +/***/ ((module, exports, __nccwpck_require__) => { - // Write all other elements of the chunk to the table. - for (var k = 1; k < chunk.length; k++) { - var part = chunk[k]; - if (typeof part === "string") { // String, write as-is. - for (var l = 0; l < part.length;) { - var code = part.charCodeAt(l++); - if (0xD800 <= code && code < 0xDC00) { // Decode surrogate - var codeTrail = part.charCodeAt(l++); - if (0xDC00 <= codeTrail && codeTrail < 0xE000) - writeTable[curAddr++] = 0x10000 + (code - 0xD800) * 0x400 + (codeTrail - 0xDC00); - else - throw new Error("Incorrect surrogate pair in " + this.encodingName + " at chunk " + chunk[0]); - } - else if (0x0FF0 < code && code <= 0x0FFF) { // Character sequence (our own encoding used) - var len = 0xFFF - code + 2; - var seq = []; - for (var m = 0; m < len; m++) - seq.push(part.charCodeAt(l++)); // Simple variation: don't support surrogates or subsequences in seq. +"use strict"; - writeTable[curAddr++] = SEQ_START - this.decodeTableSeq.length; - this.decodeTableSeq.push(seq); - } - else - writeTable[curAddr++] = code; // Basic char - } - } - else if (typeof part === "number") { // Integer, meaning increasing sequence starting with prev character. - var charCode = writeTable[curAddr - 1] + 1; - for (var l = 0; l < part; l++) - writeTable[curAddr++] = charCode++; - } - else - throw new Error("Incorrect type '" + typeof part + "' given in " + this.encodingName + " at chunk " + chunk[0]); - } - if (curAddr > 0xFF) - throw new Error("Incorrect chunk in " + this.encodingName + " at addr " + chunk[0] + ": too long" + curAddr); -} -// Encoder helpers -DBCSCodec.prototype._getEncodeBucket = function(uCode) { - var high = uCode >> 8; // This could be > 0xFF because of astral characters. - if (this.encodeTable[high] === undefined) - this.encodeTable[high] = UNASSIGNED_NODE.slice(0); // Create bucket on demand. - return this.encodeTable[high]; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = getUTCWeekYear; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2258)); +var _index4 = _interopRequireDefault(__nccwpck_require__(1985)); +var _index5 = __nccwpck_require__(9307); +function getUTCWeekYear(dirtyDate, options) { + var _ref, _ref2, _ref3, _options$firstWeekCon, _options$locale, _options$locale$optio, _defaultOptions$local, _defaultOptions$local2; + (0, _index2.default)(1, arguments); + var date = (0, _index.default)(dirtyDate); + var year = date.getUTCFullYear(); + var defaultOptions = (0, _index5.getDefaultOptions)(); + var firstWeekContainsDate = (0, _index4.default)((_ref = (_ref2 = (_ref3 = (_options$firstWeekCon = options === null || options === void 0 ? void 0 : options.firstWeekContainsDate) !== null && _options$firstWeekCon !== void 0 ? _options$firstWeekCon : options === null || options === void 0 ? void 0 : (_options$locale = options.locale) === null || _options$locale === void 0 ? void 0 : (_options$locale$optio = _options$locale.options) === null || _options$locale$optio === void 0 ? void 0 : _options$locale$optio.firstWeekContainsDate) !== null && _ref3 !== void 0 ? _ref3 : defaultOptions.firstWeekContainsDate) !== null && _ref2 !== void 0 ? _ref2 : (_defaultOptions$local = defaultOptions.locale) === null || _defaultOptions$local === void 0 ? void 0 : (_defaultOptions$local2 = _defaultOptions$local.options) === null || _defaultOptions$local2 === void 0 ? void 0 : _defaultOptions$local2.firstWeekContainsDate) !== null && _ref !== void 0 ? _ref : 1); + + // Test if weekStartsOn is between 1 and 7 _and_ is not NaN + if (!(firstWeekContainsDate >= 1 && firstWeekContainsDate <= 7)) { + throw new RangeError('firstWeekContainsDate must be between 1 and 7 inclusively'); + } + var firstWeekOfNextYear = new Date(0); + firstWeekOfNextYear.setUTCFullYear(year + 1, 0, firstWeekContainsDate); + firstWeekOfNextYear.setUTCHours(0, 0, 0, 0); + var startOfNextYear = (0, _index3.default)(firstWeekOfNextYear, options); + var firstWeekOfThisYear = new Date(0); + firstWeekOfThisYear.setUTCFullYear(year, 0, firstWeekContainsDate); + firstWeekOfThisYear.setUTCHours(0, 0, 0, 0); + var startOfThisYear = (0, _index3.default)(firstWeekOfThisYear, options); + if (date.getTime() >= startOfNextYear.getTime()) { + return year + 1; + } else if (date.getTime() >= startOfThisYear.getTime()) { + return year; + } else { + return year - 1; + } } +module.exports = exports.default; -DBCSCodec.prototype._setEncodeChar = function(uCode, dbcsCode) { - var bucket = this._getEncodeBucket(uCode); - var low = uCode & 0xFF; - if (bucket[low] <= SEQ_START) - this.encodeTableSeq[SEQ_START-bucket[low]][DEF_CHAR] = dbcsCode; // There's already a sequence, set a single-char subsequence of it. - else if (bucket[low] == UNASSIGNED) - bucket[low] = dbcsCode; -} +/***/ }), -DBCSCodec.prototype._setEncodeSequence = function(seq, dbcsCode) { - - // Get the root of character tree according to first character of the sequence. - var uCode = seq[0]; - var bucket = this._getEncodeBucket(uCode); - var low = uCode & 0xFF; +/***/ 2509: +/***/ ((__unused_webpack_module, exports) => { - var node; - if (bucket[low] <= SEQ_START) { - // There's already a sequence with - use it. - node = this.encodeTableSeq[SEQ_START-bucket[low]]; - } - else { - // There was no sequence object - allocate a new one. - node = {}; - if (bucket[low] !== UNASSIGNED) node[DEF_CHAR] = bucket[low]; // If a char was set before - make it a single-char subsequence. - bucket[low] = SEQ_START - this.encodeTableSeq.length; - this.encodeTableSeq.push(node); - } +"use strict"; - // Traverse the character tree, allocating new nodes as needed. - for (var j = 1; j < seq.length-1; j++) { - var oldVal = node[uCode]; - if (typeof oldVal === 'object') - node = oldVal; - else { - node = node[uCode] = {} - if (oldVal !== undefined) - node[DEF_CHAR] = oldVal - } - } - // Set the leaf to given dbcsCode. - uCode = seq[seq.length-1]; - node[uCode] = dbcsCode; +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports.isProtectedDayOfYearToken = isProtectedDayOfYearToken; +exports.isProtectedWeekYearToken = isProtectedWeekYearToken; +exports.throwProtectedError = throwProtectedError; +var protectedDayOfYearTokens = ['D', 'DD']; +var protectedWeekYearTokens = ['YY', 'YYYY']; +function isProtectedDayOfYearToken(token) { + return protectedDayOfYearTokens.indexOf(token) !== -1; +} +function isProtectedWeekYearToken(token) { + return protectedWeekYearTokens.indexOf(token) !== -1; +} +function throwProtectedError(token, format, input) { + if (token === 'YYYY') { + throw new RangeError("Use `yyyy` instead of `YYYY` (in `".concat(format, "`) for formatting years to the input `").concat(input, "`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md")); + } else if (token === 'YY') { + throw new RangeError("Use `yy` instead of `YY` (in `".concat(format, "`) for formatting years to the input `").concat(input, "`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md")); + } else if (token === 'D') { + throw new RangeError("Use `d` instead of `D` (in `".concat(format, "`) for formatting days of the month to the input `").concat(input, "`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md")); + } else if (token === 'DD') { + throw new RangeError("Use `dd` instead of `DD` (in `".concat(format, "`) for formatting days of the month to the input `").concat(input, "`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md")); + } } -DBCSCodec.prototype._fillEncodeTable = function(nodeIdx, prefix, skipEncodeChars) { - var node = this.decodeTables[nodeIdx]; - var hasValues = false; - var subNodeEmpty = {}; - for (var i = 0; i < 0x100; i++) { - var uCode = node[i]; - var mbCode = prefix + i; - if (skipEncodeChars[mbCode]) - continue; +/***/ }), - if (uCode >= 0) { - this._setEncodeChar(uCode, mbCode); - hasValues = true; - } else if (uCode <= NODE_START) { - var subNodeIdx = NODE_START - uCode; - if (!subNodeEmpty[subNodeIdx]) { // Skip empty subtrees (they are too large in gb18030). - var newPrefix = (mbCode << 8) >>> 0; // NOTE: '>>> 0' keeps 32-bit num positive. - if (this._fillEncodeTable(subNodeIdx, newPrefix, skipEncodeChars)) - hasValues = true; - else - subNodeEmpty[subNodeIdx] = true; - } - } else if (uCode <= SEQ_START) { - this._setEncodeSequence(this.decodeTableSeq[SEQ_START - uCode], mbCode); - hasValues = true; - } - } - return hasValues; +/***/ 2063: +/***/ ((module, exports) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = requiredArgs; +function requiredArgs(required, args) { + if (args.length < required) { + throw new TypeError(required + ' argument' + (required > 1 ? 's' : '') + ' required, but only ' + args.length + ' present'); + } } +module.exports = exports.default; +/***/ }), +/***/ 3061: +/***/ ((module, exports, __nccwpck_require__) => { -// == Encoder ================================================================== +"use strict"; -function DBCSEncoder(options, codec) { - // Encoder state - this.leadSurrogate = -1; - this.seqObj = undefined; - - // Static data - this.encodeTable = codec.encodeTable; - this.encodeTableSeq = codec.encodeTableSeq; - this.defaultCharSingleByte = codec.defCharSB; - this.gb18030 = codec.gb18030; -} -DBCSEncoder.prototype.write = function(str) { - var newBuf = Buffer.alloc(str.length * (this.gb18030 ? 4 : 3)), - leadSurrogate = this.leadSurrogate, - seqObj = this.seqObj, nextChar = -1, - i = 0, j = 0; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = startOfUTCISOWeek; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +function startOfUTCISOWeek(dirtyDate) { + (0, _index2.default)(1, arguments); + var weekStartsOn = 1; + var date = (0, _index.default)(dirtyDate); + var day = date.getUTCDay(); + var diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn; + date.setUTCDate(date.getUTCDate() - diff); + date.setUTCHours(0, 0, 0, 0); + return date; +} +module.exports = exports.default; - while (true) { - // 0. Get next character. - if (nextChar === -1) { - if (i == str.length) break; - var uCode = str.charCodeAt(i++); - } - else { - var uCode = nextChar; - nextChar = -1; - } +/***/ }), - // 1. Handle surrogates. - if (0xD800 <= uCode && uCode < 0xE000) { // Char is one of surrogates. - if (uCode < 0xDC00) { // We've got lead surrogate. - if (leadSurrogate === -1) { - leadSurrogate = uCode; - continue; - } else { - leadSurrogate = uCode; - // Double lead surrogate found. - uCode = UNASSIGNED; - } - } else { // We've got trail surrogate. - if (leadSurrogate !== -1) { - uCode = 0x10000 + (leadSurrogate - 0xD800) * 0x400 + (uCode - 0xDC00); - leadSurrogate = -1; - } else { - // Incomplete surrogate pair - only trail surrogate found. - uCode = UNASSIGNED; - } - - } - } - else if (leadSurrogate !== -1) { - // Incomplete surrogate pair - only lead surrogate found. - nextChar = uCode; uCode = UNASSIGNED; // Write an error, then current char. - leadSurrogate = -1; - } +/***/ 1478: +/***/ ((module, exports, __nccwpck_require__) => { - // 2. Convert uCode character. - var dbcsCode = UNASSIGNED; - if (seqObj !== undefined && uCode != UNASSIGNED) { // We are in the middle of the sequence - var resCode = seqObj[uCode]; - if (typeof resCode === 'object') { // Sequence continues. - seqObj = resCode; - continue; +"use strict"; - } else if (typeof resCode == 'number') { // Sequence finished. Write it. - dbcsCode = resCode; - } else if (resCode == undefined) { // Current character is not part of the sequence. +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = startOfUTCISOWeekYear; +var _index = _interopRequireDefault(__nccwpck_require__(7170)); +var _index2 = _interopRequireDefault(__nccwpck_require__(3061)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2063)); +function startOfUTCISOWeekYear(dirtyDate) { + (0, _index3.default)(1, arguments); + var year = (0, _index.default)(dirtyDate); + var fourthOfJanuary = new Date(0); + fourthOfJanuary.setUTCFullYear(year, 0, 4); + fourthOfJanuary.setUTCHours(0, 0, 0, 0); + var date = (0, _index2.default)(fourthOfJanuary); + return date; +} +module.exports = exports.default; - // Try default character for this sequence - resCode = seqObj[DEF_CHAR]; - if (resCode !== undefined) { - dbcsCode = resCode; // Found. Write it. - nextChar = uCode; // Current character will be written too in the next iteration. +/***/ }), - } else { - // TODO: What if we have no default? (resCode == undefined) - // Then, we should write first char of the sequence as-is and try the rest recursively. - // Didn't do it for now because no encoding has this situation yet. - // Currently, just skip the sequence and write current char. - } - } - seqObj = undefined; - } - else if (uCode >= 0) { // Regular character - var subtable = this.encodeTable[uCode >> 8]; - if (subtable !== undefined) - dbcsCode = subtable[uCode & 0xFF]; - - if (dbcsCode <= SEQ_START) { // Sequence start - seqObj = this.encodeTableSeq[SEQ_START-dbcsCode]; - continue; - } +/***/ 2258: +/***/ ((module, exports, __nccwpck_require__) => { - if (dbcsCode == UNASSIGNED && this.gb18030) { - // Use GB18030 algorithm to find character(s) to write. - var idx = findIdx(this.gb18030.uChars, uCode); - if (idx != -1) { - var dbcsCode = this.gb18030.gbChars[idx] + (uCode - this.gb18030.uChars[idx]); - newBuf[j++] = 0x81 + Math.floor(dbcsCode / 12600); dbcsCode = dbcsCode % 12600; - newBuf[j++] = 0x30 + Math.floor(dbcsCode / 1260); dbcsCode = dbcsCode % 1260; - newBuf[j++] = 0x81 + Math.floor(dbcsCode / 10); dbcsCode = dbcsCode % 10; - newBuf[j++] = 0x30 + dbcsCode; - continue; - } - } - } +"use strict"; - // 3. Write dbcsCode character. - if (dbcsCode === UNASSIGNED) - dbcsCode = this.defaultCharSingleByte; - - if (dbcsCode < 0x100) { - newBuf[j++] = dbcsCode; - } - else if (dbcsCode < 0x10000) { - newBuf[j++] = dbcsCode >> 8; // high byte - newBuf[j++] = dbcsCode & 0xFF; // low byte - } - else if (dbcsCode < 0x1000000) { - newBuf[j++] = dbcsCode >> 16; - newBuf[j++] = (dbcsCode >> 8) & 0xFF; - newBuf[j++] = dbcsCode & 0xFF; - } else { - newBuf[j++] = dbcsCode >>> 24; - newBuf[j++] = (dbcsCode >>> 16) & 0xFF; - newBuf[j++] = (dbcsCode >>> 8) & 0xFF; - newBuf[j++] = dbcsCode & 0xFF; - } - } - this.seqObj = seqObj; - this.leadSurrogate = leadSurrogate; - return newBuf.slice(0, j); +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = startOfUTCWeek; +var _index = _interopRequireDefault(__nccwpck_require__(6477)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +var _index3 = _interopRequireDefault(__nccwpck_require__(1985)); +var _index4 = __nccwpck_require__(9307); +function startOfUTCWeek(dirtyDate, options) { + var _ref, _ref2, _ref3, _options$weekStartsOn, _options$locale, _options$locale$optio, _defaultOptions$local, _defaultOptions$local2; + (0, _index2.default)(1, arguments); + var defaultOptions = (0, _index4.getDefaultOptions)(); + var weekStartsOn = (0, _index3.default)((_ref = (_ref2 = (_ref3 = (_options$weekStartsOn = options === null || options === void 0 ? void 0 : options.weekStartsOn) !== null && _options$weekStartsOn !== void 0 ? _options$weekStartsOn : options === null || options === void 0 ? void 0 : (_options$locale = options.locale) === null || _options$locale === void 0 ? void 0 : (_options$locale$optio = _options$locale.options) === null || _options$locale$optio === void 0 ? void 0 : _options$locale$optio.weekStartsOn) !== null && _ref3 !== void 0 ? _ref3 : defaultOptions.weekStartsOn) !== null && _ref2 !== void 0 ? _ref2 : (_defaultOptions$local = defaultOptions.locale) === null || _defaultOptions$local === void 0 ? void 0 : (_defaultOptions$local2 = _defaultOptions$local.options) === null || _defaultOptions$local2 === void 0 ? void 0 : _defaultOptions$local2.weekStartsOn) !== null && _ref !== void 0 ? _ref : 0); + + // Test if weekStartsOn is between 0 and 6 _and_ is not NaN + if (!(weekStartsOn >= 0 && weekStartsOn <= 6)) { + throw new RangeError('weekStartsOn must be between 0 and 6 inclusively'); + } + var date = (0, _index.default)(dirtyDate); + var day = date.getUTCDay(); + var diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn; + date.setUTCDate(date.getUTCDate() - diff); + date.setUTCHours(0, 0, 0, 0); + return date; } +module.exports = exports.default; -DBCSEncoder.prototype.end = function() { - if (this.leadSurrogate === -1 && this.seqObj === undefined) - return; // All clean. Most often case. +/***/ }), - var newBuf = Buffer.alloc(10), j = 0; +/***/ 2629: +/***/ ((module, exports, __nccwpck_require__) => { - if (this.seqObj) { // We're in the sequence. - var dbcsCode = this.seqObj[DEF_CHAR]; - if (dbcsCode !== undefined) { // Write beginning of the sequence. - if (dbcsCode < 0x100) { - newBuf[j++] = dbcsCode; - } - else { - newBuf[j++] = dbcsCode >> 8; // high byte - newBuf[j++] = dbcsCode & 0xFF; // low byte - } - } else { - // See todo above. - } - this.seqObj = undefined; - } +"use strict"; - if (this.leadSurrogate !== -1) { - // Incomplete surrogate pair - only lead surrogate found. - newBuf[j++] = this.defaultCharSingleByte; - this.leadSurrogate = -1; - } - - return newBuf.slice(0, j); + +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = startOfUTCWeekYear; +var _index = _interopRequireDefault(__nccwpck_require__(8050)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2258)); +var _index4 = _interopRequireDefault(__nccwpck_require__(1985)); +var _index5 = __nccwpck_require__(9307); +function startOfUTCWeekYear(dirtyDate, options) { + var _ref, _ref2, _ref3, _options$firstWeekCon, _options$locale, _options$locale$optio, _defaultOptions$local, _defaultOptions$local2; + (0, _index2.default)(1, arguments); + var defaultOptions = (0, _index5.getDefaultOptions)(); + var firstWeekContainsDate = (0, _index4.default)((_ref = (_ref2 = (_ref3 = (_options$firstWeekCon = options === null || options === void 0 ? void 0 : options.firstWeekContainsDate) !== null && _options$firstWeekCon !== void 0 ? _options$firstWeekCon : options === null || options === void 0 ? void 0 : (_options$locale = options.locale) === null || _options$locale === void 0 ? void 0 : (_options$locale$optio = _options$locale.options) === null || _options$locale$optio === void 0 ? void 0 : _options$locale$optio.firstWeekContainsDate) !== null && _ref3 !== void 0 ? _ref3 : defaultOptions.firstWeekContainsDate) !== null && _ref2 !== void 0 ? _ref2 : (_defaultOptions$local = defaultOptions.locale) === null || _defaultOptions$local === void 0 ? void 0 : (_defaultOptions$local2 = _defaultOptions$local.options) === null || _defaultOptions$local2 === void 0 ? void 0 : _defaultOptions$local2.firstWeekContainsDate) !== null && _ref !== void 0 ? _ref : 1); + var year = (0, _index.default)(dirtyDate, options); + var firstWeek = new Date(0); + firstWeek.setUTCFullYear(year, 0, firstWeekContainsDate); + firstWeek.setUTCHours(0, 0, 0, 0); + var date = (0, _index3.default)(firstWeek, options); + return date; +} +module.exports = exports.default; + +/***/ }), + +/***/ 1985: +/***/ ((module, exports) => { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = toInteger; +function toInteger(dirtyNumber) { + if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) { + return NaN; + } + var number = Number(dirtyNumber); + if (isNaN(number)) { + return number; + } + return number < 0 ? Math.ceil(number) : Math.floor(number); } +module.exports = exports.default; -// Export for testing -DBCSEncoder.prototype.findIdx = findIdx; +/***/ }), +/***/ 524: +/***/ ((module, exports, __nccwpck_require__) => { -// == Decoder ================================================================== +"use strict"; -function DBCSDecoder(options, codec) { - // Decoder state - this.nodeIdx = 0; - this.prevBytes = []; - // Static data - this.decodeTables = codec.decodeTables; - this.decodeTableSeq = codec.decodeTableSeq; - this.defaultCharUnicode = codec.defaultCharUnicode; - this.gb18030 = codec.gb18030; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = addMilliseconds; +var _index = _interopRequireDefault(__nccwpck_require__(1985)); +var _index2 = _interopRequireDefault(__nccwpck_require__(6477)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2063)); +/** + * @name addMilliseconds + * @category Millisecond Helpers + * @summary Add the specified number of milliseconds to the given date. + * + * @description + * Add the specified number of milliseconds to the given date. + * + * @param {Date|Number} date - the date to be changed + * @param {Number} amount - the amount of milliseconds to be added. Positive decimals will be rounded using `Math.floor`, decimals less than zero will be rounded using `Math.ceil`. + * @returns {Date} the new date with the milliseconds added + * @throws {TypeError} 2 arguments required + * + * @example + * // Add 750 milliseconds to 10 July 2014 12:45:30.000: + * const result = addMilliseconds(new Date(2014, 6, 10, 12, 45, 30, 0), 750) + * //=> Thu Jul 10 2014 12:45:30.750 + */ +function addMilliseconds(dirtyDate, dirtyAmount) { + (0, _index3.default)(2, arguments); + var timestamp = (0, _index2.default)(dirtyDate).getTime(); + var amount = (0, _index.default)(dirtyAmount); + return new Date(timestamp + amount); } +module.exports = exports.default; -DBCSDecoder.prototype.write = function(buf) { - var newBuf = Buffer.alloc(buf.length*2), - nodeIdx = this.nodeIdx, - prevBytes = this.prevBytes, prevOffset = this.prevBytes.length, - seqStart = -this.prevBytes.length, // idx of the start of current parsed sequence. - uCode; +/***/ }), - for (var i = 0, j = 0; i < buf.length; i++) { - var curByte = (i >= 0) ? buf[i] : prevBytes[i + prevOffset]; +/***/ 2168: +/***/ ((module, exports, __nccwpck_require__) => { - // Lookup in current trie node. - var uCode = this.decodeTables[nodeIdx][curByte]; +"use strict"; - if (uCode >= 0) { - // Normal character, just use it. - } - else if (uCode === UNASSIGNED) { // Unknown char. - // TODO: Callback with seq. - uCode = this.defaultCharUnicode.charCodeAt(0); - i = seqStart; // Skip one byte ('i' will be incremented by the for loop) and try to parse again. - } - else if (uCode === GB18030_CODE) { - if (i >= 3) { - var ptr = (buf[i-3]-0x81)*12600 + (buf[i-2]-0x30)*1260 + (buf[i-1]-0x81)*10 + (curByte-0x30); - } else { - var ptr = (prevBytes[i-3+prevOffset]-0x81)*12600 + - (((i-2 >= 0) ? buf[i-2] : prevBytes[i-2+prevOffset])-0x30)*1260 + - (((i-1 >= 0) ? buf[i-1] : prevBytes[i-1+prevOffset])-0x81)*10 + - (curByte-0x30); - } - var idx = findIdx(this.gb18030.gbChars, ptr); - uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx]; - } - else if (uCode <= NODE_START) { // Go to next trie node. - nodeIdx = NODE_START - uCode; - continue; - } - else if (uCode <= SEQ_START) { // Output a sequence of chars. - var seq = this.decodeTableSeq[SEQ_START - uCode]; - for (var k = 0; k < seq.length - 1; k++) { - uCode = seq[k]; - newBuf[j++] = uCode & 0xFF; - newBuf[j++] = uCode >> 8; - } - uCode = seq[seq.length-1]; - } - else - throw new Error("iconv-lite internal error: invalid decoding table value " + uCode + " at " + nodeIdx + "/" + curByte); - // Write the character to buffer, handling higher planes using surrogate pair. - if (uCode >= 0x10000) { - uCode -= 0x10000; - var uCodeLead = 0xD800 | (uCode >> 10); - newBuf[j++] = uCodeLead & 0xFF; - newBuf[j++] = uCodeLead >> 8; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = format; +var _index = _interopRequireDefault(__nccwpck_require__(9920)); +var _index2 = _interopRequireDefault(__nccwpck_require__(7923)); +var _index3 = _interopRequireDefault(__nccwpck_require__(6477)); +var _index4 = _interopRequireDefault(__nccwpck_require__(9257)); +var _index5 = _interopRequireDefault(__nccwpck_require__(8387)); +var _index6 = _interopRequireDefault(__nccwpck_require__(7032)); +var _index7 = __nccwpck_require__(2509); +var _index8 = _interopRequireDefault(__nccwpck_require__(1985)); +var _index9 = _interopRequireDefault(__nccwpck_require__(2063)); +var _index10 = __nccwpck_require__(9307); +var _index11 = _interopRequireDefault(__nccwpck_require__(618)); +// This RegExp consists of three parts separated by `|`: +// - [yYQqMLwIdDecihHKkms]o matches any available ordinal number token +// (one of the certain letters followed by `o`) +// - (\w)\1* matches any sequences of the same letter +// - '' matches two quote characters in a row +// - '(''|[^'])+('|$) matches anything surrounded by two quote characters ('), +// except a single quote symbol, which ends the sequence. +// Two quote characters do not end the sequence. +// If there is no matching single quote +// then the sequence will continue until the end of the string. +// - . matches any single character unmatched by previous parts of the RegExps +var formattingTokensRegExp = /[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g; + +// This RegExp catches symbols escaped by quotes, and also +// sequences of symbols P, p, and the combinations like `PPPPPPPppppp` +var longFormattingTokensRegExp = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g; +var escapedStringRegExp = /^'([^]*?)'?$/; +var doubleQuoteRegExp = /''/g; +var unescapedLatinCharacterRegExp = /[a-zA-Z]/; - uCode = 0xDC00 | (uCode & 0x3FF); - } - newBuf[j++] = uCode & 0xFF; - newBuf[j++] = uCode >> 8; +/** + * @name format + * @category Common Helpers + * @summary Format the date. + * + * @description + * Return the formatted date string in the given format. The result may vary by locale. + * + * > ⚠️ Please note that the `format` tokens differ from Moment.js and other libraries. + * > See: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * + * The characters wrapped between two single quotes characters (') are escaped. + * Two single quotes in a row, whether inside or outside a quoted sequence, represent a 'real' single quote. + * (see the last example) + * + * Format of the string is based on Unicode Technical Standard #35: + * https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table + * with a few additions (see note 7 below the table). + * + * Accepted patterns: + * | Unit | Pattern | Result examples | Notes | + * |---------------------------------|---------|-----------------------------------|-------| + * | Era | G..GGG | AD, BC | | + * | | GGGG | Anno Domini, Before Christ | 2 | + * | | GGGGG | A, B | | + * | Calendar year | y | 44, 1, 1900, 2017 | 5 | + * | | yo | 44th, 1st, 0th, 17th | 5,7 | + * | | yy | 44, 01, 00, 17 | 5 | + * | | yyy | 044, 001, 1900, 2017 | 5 | + * | | yyyy | 0044, 0001, 1900, 2017 | 5 | + * | | yyyyy | ... | 3,5 | + * | Local week-numbering year | Y | 44, 1, 1900, 2017 | 5 | + * | | Yo | 44th, 1st, 1900th, 2017th | 5,7 | + * | | YY | 44, 01, 00, 17 | 5,8 | + * | | YYY | 044, 001, 1900, 2017 | 5 | + * | | YYYY | 0044, 0001, 1900, 2017 | 5,8 | + * | | YYYYY | ... | 3,5 | + * | ISO week-numbering year | R | -43, 0, 1, 1900, 2017 | 5,7 | + * | | RR | -43, 00, 01, 1900, 2017 | 5,7 | + * | | RRR | -043, 000, 001, 1900, 2017 | 5,7 | + * | | RRRR | -0043, 0000, 0001, 1900, 2017 | 5,7 | + * | | RRRRR | ... | 3,5,7 | + * | Extended year | u | -43, 0, 1, 1900, 2017 | 5 | + * | | uu | -43, 01, 1900, 2017 | 5 | + * | | uuu | -043, 001, 1900, 2017 | 5 | + * | | uuuu | -0043, 0001, 1900, 2017 | 5 | + * | | uuuuu | ... | 3,5 | + * | Quarter (formatting) | Q | 1, 2, 3, 4 | | + * | | Qo | 1st, 2nd, 3rd, 4th | 7 | + * | | QQ | 01, 02, 03, 04 | | + * | | QQQ | Q1, Q2, Q3, Q4 | | + * | | QQQQ | 1st quarter, 2nd quarter, ... | 2 | + * | | QQQQQ | 1, 2, 3, 4 | 4 | + * | Quarter (stand-alone) | q | 1, 2, 3, 4 | | + * | | qo | 1st, 2nd, 3rd, 4th | 7 | + * | | qq | 01, 02, 03, 04 | | + * | | qqq | Q1, Q2, Q3, Q4 | | + * | | qqqq | 1st quarter, 2nd quarter, ... | 2 | + * | | qqqqq | 1, 2, 3, 4 | 4 | + * | Month (formatting) | M | 1, 2, ..., 12 | | + * | | Mo | 1st, 2nd, ..., 12th | 7 | + * | | MM | 01, 02, ..., 12 | | + * | | MMM | Jan, Feb, ..., Dec | | + * | | MMMM | January, February, ..., December | 2 | + * | | MMMMM | J, F, ..., D | | + * | Month (stand-alone) | L | 1, 2, ..., 12 | | + * | | Lo | 1st, 2nd, ..., 12th | 7 | + * | | LL | 01, 02, ..., 12 | | + * | | LLL | Jan, Feb, ..., Dec | | + * | | LLLL | January, February, ..., December | 2 | + * | | LLLLL | J, F, ..., D | | + * | Local week of year | w | 1, 2, ..., 53 | | + * | | wo | 1st, 2nd, ..., 53th | 7 | + * | | ww | 01, 02, ..., 53 | | + * | ISO week of year | I | 1, 2, ..., 53 | 7 | + * | | Io | 1st, 2nd, ..., 53th | 7 | + * | | II | 01, 02, ..., 53 | 7 | + * | Day of month | d | 1, 2, ..., 31 | | + * | | do | 1st, 2nd, ..., 31st | 7 | + * | | dd | 01, 02, ..., 31 | | + * | Day of year | D | 1, 2, ..., 365, 366 | 9 | + * | | Do | 1st, 2nd, ..., 365th, 366th | 7 | + * | | DD | 01, 02, ..., 365, 366 | 9 | + * | | DDD | 001, 002, ..., 365, 366 | | + * | | DDDD | ... | 3 | + * | Day of week (formatting) | E..EEE | Mon, Tue, Wed, ..., Sun | | + * | | EEEE | Monday, Tuesday, ..., Sunday | 2 | + * | | EEEEE | M, T, W, T, F, S, S | | + * | | EEEEEE | Mo, Tu, We, Th, Fr, Sa, Su | | + * | ISO day of week (formatting) | i | 1, 2, 3, ..., 7 | 7 | + * | | io | 1st, 2nd, ..., 7th | 7 | + * | | ii | 01, 02, ..., 07 | 7 | + * | | iii | Mon, Tue, Wed, ..., Sun | 7 | + * | | iiii | Monday, Tuesday, ..., Sunday | 2,7 | + * | | iiiii | M, T, W, T, F, S, S | 7 | + * | | iiiiii | Mo, Tu, We, Th, Fr, Sa, Su | 7 | + * | Local day of week (formatting) | e | 2, 3, 4, ..., 1 | | + * | | eo | 2nd, 3rd, ..., 1st | 7 | + * | | ee | 02, 03, ..., 01 | | + * | | eee | Mon, Tue, Wed, ..., Sun | | + * | | eeee | Monday, Tuesday, ..., Sunday | 2 | + * | | eeeee | M, T, W, T, F, S, S | | + * | | eeeeee | Mo, Tu, We, Th, Fr, Sa, Su | | + * | Local day of week (stand-alone) | c | 2, 3, 4, ..., 1 | | + * | | co | 2nd, 3rd, ..., 1st | 7 | + * | | cc | 02, 03, ..., 01 | | + * | | ccc | Mon, Tue, Wed, ..., Sun | | + * | | cccc | Monday, Tuesday, ..., Sunday | 2 | + * | | ccccc | M, T, W, T, F, S, S | | + * | | cccccc | Mo, Tu, We, Th, Fr, Sa, Su | | + * | AM, PM | a..aa | AM, PM | | + * | | aaa | am, pm | | + * | | aaaa | a.m., p.m. | 2 | + * | | aaaaa | a, p | | + * | AM, PM, noon, midnight | b..bb | AM, PM, noon, midnight | | + * | | bbb | am, pm, noon, midnight | | + * | | bbbb | a.m., p.m., noon, midnight | 2 | + * | | bbbbb | a, p, n, mi | | + * | Flexible day period | B..BBB | at night, in the morning, ... | | + * | | BBBB | at night, in the morning, ... | 2 | + * | | BBBBB | at night, in the morning, ... | | + * | Hour [1-12] | h | 1, 2, ..., 11, 12 | | + * | | ho | 1st, 2nd, ..., 11th, 12th | 7 | + * | | hh | 01, 02, ..., 11, 12 | | + * | Hour [0-23] | H | 0, 1, 2, ..., 23 | | + * | | Ho | 0th, 1st, 2nd, ..., 23rd | 7 | + * | | HH | 00, 01, 02, ..., 23 | | + * | Hour [0-11] | K | 1, 2, ..., 11, 0 | | + * | | Ko | 1st, 2nd, ..., 11th, 0th | 7 | + * | | KK | 01, 02, ..., 11, 00 | | + * | Hour [1-24] | k | 24, 1, 2, ..., 23 | | + * | | ko | 24th, 1st, 2nd, ..., 23rd | 7 | + * | | kk | 24, 01, 02, ..., 23 | | + * | Minute | m | 0, 1, ..., 59 | | + * | | mo | 0th, 1st, ..., 59th | 7 | + * | | mm | 00, 01, ..., 59 | | + * | Second | s | 0, 1, ..., 59 | | + * | | so | 0th, 1st, ..., 59th | 7 | + * | | ss | 00, 01, ..., 59 | | + * | Fraction of second | S | 0, 1, ..., 9 | | + * | | SS | 00, 01, ..., 99 | | + * | | SSS | 000, 001, ..., 999 | | + * | | SSSS | ... | 3 | + * | Timezone (ISO-8601 w/ Z) | X | -08, +0530, Z | | + * | | XX | -0800, +0530, Z | | + * | | XXX | -08:00, +05:30, Z | | + * | | XXXX | -0800, +0530, Z, +123456 | 2 | + * | | XXXXX | -08:00, +05:30, Z, +12:34:56 | | + * | Timezone (ISO-8601 w/o Z) | x | -08, +0530, +00 | | + * | | xx | -0800, +0530, +0000 | | + * | | xxx | -08:00, +05:30, +00:00 | 2 | + * | | xxxx | -0800, +0530, +0000, +123456 | | + * | | xxxxx | -08:00, +05:30, +00:00, +12:34:56 | | + * | Timezone (GMT) | O...OOO | GMT-8, GMT+5:30, GMT+0 | | + * | | OOOO | GMT-08:00, GMT+05:30, GMT+00:00 | 2 | + * | Timezone (specific non-locat.) | z...zzz | GMT-8, GMT+5:30, GMT+0 | 6 | + * | | zzzz | GMT-08:00, GMT+05:30, GMT+00:00 | 2,6 | + * | Seconds timestamp | t | 512969520 | 7 | + * | | tt | ... | 3,7 | + * | Milliseconds timestamp | T | 512969520900 | 7 | + * | | TT | ... | 3,7 | + * | Long localized date | P | 04/29/1453 | 7 | + * | | PP | Apr 29, 1453 | 7 | + * | | PPP | April 29th, 1453 | 7 | + * | | PPPP | Friday, April 29th, 1453 | 2,7 | + * | Long localized time | p | 12:00 AM | 7 | + * | | pp | 12:00:00 AM | 7 | + * | | ppp | 12:00:00 AM GMT+2 | 7 | + * | | pppp | 12:00:00 AM GMT+02:00 | 2,7 | + * | Combination of date and time | Pp | 04/29/1453, 12:00 AM | 7 | + * | | PPpp | Apr 29, 1453, 12:00:00 AM | 7 | + * | | PPPppp | April 29th, 1453 at ... | 7 | + * | | PPPPpppp| Friday, April 29th, 1453 at ... | 2,7 | + * Notes: + * 1. "Formatting" units (e.g. formatting quarter) in the default en-US locale + * are the same as "stand-alone" units, but are different in some languages. + * "Formatting" units are declined according to the rules of the language + * in the context of a date. "Stand-alone" units are always nominative singular: + * + * `format(new Date(2017, 10, 6), 'do LLLL', {locale: cs}) //=> '6. listopad'` + * + * `format(new Date(2017, 10, 6), 'do MMMM', {locale: cs}) //=> '6. listopadu'` + * + * 2. Any sequence of the identical letters is a pattern, unless it is escaped by + * the single quote characters (see below). + * If the sequence is longer than listed in table (e.g. `EEEEEEEEEEE`) + * the output will be the same as default pattern for this unit, usually + * the longest one (in case of ISO weekdays, `EEEE`). Default patterns for units + * are marked with "2" in the last column of the table. + * + * `format(new Date(2017, 10, 6), 'MMM') //=> 'Nov'` + * + * `format(new Date(2017, 10, 6), 'MMMM') //=> 'November'` + * + * `format(new Date(2017, 10, 6), 'MMMMM') //=> 'N'` + * + * `format(new Date(2017, 10, 6), 'MMMMMM') //=> 'November'` + * + * `format(new Date(2017, 10, 6), 'MMMMMMM') //=> 'November'` + * + * 3. Some patterns could be unlimited length (such as `yyyyyyyy`). + * The output will be padded with zeros to match the length of the pattern. + * + * `format(new Date(2017, 10, 6), 'yyyyyyyy') //=> '00002017'` + * + * 4. `QQQQQ` and `qqqqq` could be not strictly numerical in some locales. + * These tokens represent the shortest form of the quarter. + * + * 5. The main difference between `y` and `u` patterns are B.C. years: + * + * | Year | `y` | `u` | + * |------|-----|-----| + * | AC 1 | 1 | 1 | + * | BC 1 | 1 | 0 | + * | BC 2 | 2 | -1 | + * + * Also `yy` always returns the last two digits of a year, + * while `uu` pads single digit years to 2 characters and returns other years unchanged: + * + * | Year | `yy` | `uu` | + * |------|------|------| + * | 1 | 01 | 01 | + * | 14 | 14 | 14 | + * | 376 | 76 | 376 | + * | 1453 | 53 | 1453 | + * + * The same difference is true for local and ISO week-numbering years (`Y` and `R`), + * except local week-numbering years are dependent on `options.weekStartsOn` + * and `options.firstWeekContainsDate` (compare [getISOWeekYear]{@link https://date-fns.org/docs/getISOWeekYear} + * and [getWeekYear]{@link https://date-fns.org/docs/getWeekYear}). + * + * 6. Specific non-location timezones are currently unavailable in `date-fns`, + * so right now these tokens fall back to GMT timezones. + * + * 7. These patterns are not in the Unicode Technical Standard #35: + * - `i`: ISO day of week + * - `I`: ISO week of year + * - `R`: ISO week-numbering year + * - `t`: seconds timestamp + * - `T`: milliseconds timestamp + * - `o`: ordinal number modifier + * - `P`: long localized date + * - `p`: long localized time + * + * 8. `YY` and `YYYY` tokens represent week-numbering years but they are often confused with years. + * You should enable `options.useAdditionalWeekYearTokens` to use them. See: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * + * 9. `D` and `DD` tokens represent days of the year but they are often confused with days of the month. + * You should enable `options.useAdditionalDayOfYearTokens` to use them. See: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * + * @param {Date|Number} date - the original date + * @param {String} format - the string of tokens + * @param {Object} [options] - an object with options. + * @param {Locale} [options.locale=defaultLocale] - the locale object. See [Locale]{@link https://date-fns.org/docs/Locale} + * @param {0|1|2|3|4|5|6} [options.weekStartsOn=0] - the index of the first day of the week (0 - Sunday) + * @param {Number} [options.firstWeekContainsDate=1] - the day of January, which is + * @param {Boolean} [options.useAdditionalWeekYearTokens=false] - if true, allows usage of the week-numbering year tokens `YY` and `YYYY`; + * see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * @param {Boolean} [options.useAdditionalDayOfYearTokens=false] - if true, allows usage of the day of year tokens `D` and `DD`; + * see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * @returns {String} the formatted date string + * @throws {TypeError} 2 arguments required + * @throws {RangeError} `date` must not be Invalid Date + * @throws {RangeError} `options.locale` must contain `localize` property + * @throws {RangeError} `options.locale` must contain `formatLong` property + * @throws {RangeError} `options.weekStartsOn` must be between 0 and 6 + * @throws {RangeError} `options.firstWeekContainsDate` must be between 1 and 7 + * @throws {RangeError} use `yyyy` instead of `YYYY` for formatting years using [format provided] to the input [input provided]; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * @throws {RangeError} use `yy` instead of `YY` for formatting years using [format provided] to the input [input provided]; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * @throws {RangeError} use `d` instead of `D` for formatting days of the month using [format provided] to the input [input provided]; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * @throws {RangeError} use `dd` instead of `DD` for formatting days of the month using [format provided] to the input [input provided]; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md + * @throws {RangeError} format string contains an unescaped latin alphabet character + * + * @example + * // Represent 11 February 2014 in middle-endian format: + * const result = format(new Date(2014, 1, 11), 'MM/dd/yyyy') + * //=> '02/11/2014' + * + * @example + * // Represent 2 July 2014 in Esperanto: + * import { eoLocale } from 'date-fns/locale/eo' + * const result = format(new Date(2014, 6, 2), "do 'de' MMMM yyyy", { + * locale: eoLocale + * }) + * //=> '2-a de julio 2014' + * + * @example + * // Escape string by single quote characters: + * const result = format(new Date(2014, 6, 2, 15), "h 'o''clock'") + * //=> "3 o'clock" + */ - // Reset trie node. - nodeIdx = 0; seqStart = i+1; - } +function format(dirtyDate, dirtyFormatStr, options) { + var _ref, _options$locale, _ref2, _ref3, _ref4, _options$firstWeekCon, _options$locale2, _options$locale2$opti, _defaultOptions$local, _defaultOptions$local2, _ref5, _ref6, _ref7, _options$weekStartsOn, _options$locale3, _options$locale3$opti, _defaultOptions$local3, _defaultOptions$local4; + (0, _index9.default)(2, arguments); + var formatStr = String(dirtyFormatStr); + var defaultOptions = (0, _index10.getDefaultOptions)(); + var locale = (_ref = (_options$locale = options === null || options === void 0 ? void 0 : options.locale) !== null && _options$locale !== void 0 ? _options$locale : defaultOptions.locale) !== null && _ref !== void 0 ? _ref : _index11.default; + var firstWeekContainsDate = (0, _index8.default)((_ref2 = (_ref3 = (_ref4 = (_options$firstWeekCon = options === null || options === void 0 ? void 0 : options.firstWeekContainsDate) !== null && _options$firstWeekCon !== void 0 ? _options$firstWeekCon : options === null || options === void 0 ? void 0 : (_options$locale2 = options.locale) === null || _options$locale2 === void 0 ? void 0 : (_options$locale2$opti = _options$locale2.options) === null || _options$locale2$opti === void 0 ? void 0 : _options$locale2$opti.firstWeekContainsDate) !== null && _ref4 !== void 0 ? _ref4 : defaultOptions.firstWeekContainsDate) !== null && _ref3 !== void 0 ? _ref3 : (_defaultOptions$local = defaultOptions.locale) === null || _defaultOptions$local === void 0 ? void 0 : (_defaultOptions$local2 = _defaultOptions$local.options) === null || _defaultOptions$local2 === void 0 ? void 0 : _defaultOptions$local2.firstWeekContainsDate) !== null && _ref2 !== void 0 ? _ref2 : 1); + + // Test if weekStartsOn is between 1 and 7 _and_ is not NaN + if (!(firstWeekContainsDate >= 1 && firstWeekContainsDate <= 7)) { + throw new RangeError('firstWeekContainsDate must be between 1 and 7 inclusively'); + } + var weekStartsOn = (0, _index8.default)((_ref5 = (_ref6 = (_ref7 = (_options$weekStartsOn = options === null || options === void 0 ? void 0 : options.weekStartsOn) !== null && _options$weekStartsOn !== void 0 ? _options$weekStartsOn : options === null || options === void 0 ? void 0 : (_options$locale3 = options.locale) === null || _options$locale3 === void 0 ? void 0 : (_options$locale3$opti = _options$locale3.options) === null || _options$locale3$opti === void 0 ? void 0 : _options$locale3$opti.weekStartsOn) !== null && _ref7 !== void 0 ? _ref7 : defaultOptions.weekStartsOn) !== null && _ref6 !== void 0 ? _ref6 : (_defaultOptions$local3 = defaultOptions.locale) === null || _defaultOptions$local3 === void 0 ? void 0 : (_defaultOptions$local4 = _defaultOptions$local3.options) === null || _defaultOptions$local4 === void 0 ? void 0 : _defaultOptions$local4.weekStartsOn) !== null && _ref5 !== void 0 ? _ref5 : 0); - this.nodeIdx = nodeIdx; - this.prevBytes = (seqStart >= 0) - ? Array.prototype.slice.call(buf, seqStart) - : prevBytes.slice(seqStart + prevOffset).concat(Array.prototype.slice.call(buf)); + // Test if weekStartsOn is between 0 and 6 _and_ is not NaN + if (!(weekStartsOn >= 0 && weekStartsOn <= 6)) { + throw new RangeError('weekStartsOn must be between 0 and 6 inclusively'); + } + if (!locale.localize) { + throw new RangeError('locale must contain localize property'); + } + if (!locale.formatLong) { + throw new RangeError('locale must contain formatLong property'); + } + var originalDate = (0, _index3.default)(dirtyDate); + if (!(0, _index.default)(originalDate)) { + throw new RangeError('Invalid time value'); + } - return newBuf.slice(0, j).toString('ucs2'); + // Convert the date in system timezone to the same date in UTC+00:00 timezone. + // This ensures that when UTC functions will be implemented, locales will be compatible with them. + // See an issue about UTC functions: https://github.com/date-fns/date-fns/issues/376 + var timezoneOffset = (0, _index6.default)(originalDate); + var utcDate = (0, _index2.default)(originalDate, timezoneOffset); + var formatterOptions = { + firstWeekContainsDate: firstWeekContainsDate, + weekStartsOn: weekStartsOn, + locale: locale, + _originalDate: originalDate + }; + var result = formatStr.match(longFormattingTokensRegExp).map(function (substring) { + var firstCharacter = substring[0]; + if (firstCharacter === 'p' || firstCharacter === 'P') { + var longFormatter = _index5.default[firstCharacter]; + return longFormatter(substring, locale.formatLong); + } + return substring; + }).join('').match(formattingTokensRegExp).map(function (substring) { + // Replace two single quote characters with one single quote character + if (substring === "''") { + return "'"; + } + var firstCharacter = substring[0]; + if (firstCharacter === "'") { + return cleanEscapedString(substring); + } + var formatter = _index4.default[firstCharacter]; + if (formatter) { + if (!(options !== null && options !== void 0 && options.useAdditionalWeekYearTokens) && (0, _index7.isProtectedWeekYearToken)(substring)) { + (0, _index7.throwProtectedError)(substring, dirtyFormatStr, String(dirtyDate)); + } + if (!(options !== null && options !== void 0 && options.useAdditionalDayOfYearTokens) && (0, _index7.isProtectedDayOfYearToken)(substring)) { + (0, _index7.throwProtectedError)(substring, dirtyFormatStr, String(dirtyDate)); + } + return formatter(utcDate, substring, locale.localize, formatterOptions); + } + if (firstCharacter.match(unescapedLatinCharacterRegExp)) { + throw new RangeError('Format string contains an unescaped latin alphabet character `' + firstCharacter + '`'); + } + return substring; + }).join(''); + return result; +} +function cleanEscapedString(input) { + var matched = input.match(escapedStringRegExp); + if (!matched) { + return input; + } + return matched[1].replace(doubleQuoteRegExp, "'"); } +module.exports = exports.default; -DBCSDecoder.prototype.end = function() { - var ret = ''; +/***/ }), - // Try to parse all remaining chars. - while (this.prevBytes.length > 0) { - // Skip 1 character in the buffer. - ret += this.defaultCharUnicode; - var bytesArr = this.prevBytes.slice(1); +/***/ 6801: +/***/ ((module, exports, __nccwpck_require__) => { - // Parse remaining as usual. - this.prevBytes = []; - this.nodeIdx = 0; - if (bytesArr.length > 0) - ret += this.write(bytesArr); - } +"use strict"; - this.prevBytes = []; - this.nodeIdx = 0; - return ret; + +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = isDate; +var _typeof2 = _interopRequireDefault(__nccwpck_require__(5605)); +var _index = _interopRequireDefault(__nccwpck_require__(2063)); +/** + * @name isDate + * @category Common Helpers + * @summary Is the given value a date? + * + * @description + * Returns true if the given value is an instance of Date. The function works for dates transferred across iframes. + * + * @param {*} value - the value to check + * @returns {boolean} true if the given value is a date + * @throws {TypeError} 1 arguments required + * + * @example + * // For a valid date: + * const result = isDate(new Date()) + * //=> true + * + * @example + * // For an invalid date: + * const result = isDate(new Date(NaN)) + * //=> true + * + * @example + * // For some value: + * const result = isDate('2014-02-31') + * //=> false + * + * @example + * // For an object: + * const result = isDate({}) + * //=> false + */ +function isDate(value) { + (0, _index.default)(1, arguments); + return value instanceof Date || (0, _typeof2.default)(value) === 'object' && Object.prototype.toString.call(value) === '[object Date]'; } +module.exports = exports.default; -// Binary search for GB18030. Returns largest i such that table[i] <= val. -function findIdx(table, val) { - if (table[0] > val) - return -1; +/***/ }), - var l = 0, r = table.length; - while (l < r-1) { // always table[l] <= val < table[r] - var mid = l + ((r-l+1) >> 1); - if (table[mid] <= val) - l = mid; - else - r = mid; - } - return l; -} +/***/ 9920: +/***/ ((module, exports, __nccwpck_require__) => { + +"use strict"; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = isValid; +var _index = _interopRequireDefault(__nccwpck_require__(6801)); +var _index2 = _interopRequireDefault(__nccwpck_require__(6477)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2063)); +/** + * @name isValid + * @category Common Helpers + * @summary Is the given date valid? + * + * @description + * Returns false if argument is Invalid Date and true otherwise. + * Argument is converted to Date using `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate} + * Invalid Date is a Date, whose time value is NaN. + * + * Time value of Date: http://es5.github.io/#x15.9.1.1 + * + * @param {*} date - the date to check + * @returns {Boolean} the date is valid + * @throws {TypeError} 1 argument required + * + * @example + * // For the valid date: + * const result = isValid(new Date(2014, 1, 31)) + * //=> true + * + * @example + * // For the value, convertable into a date: + * const result = isValid(1393804800000) + * //=> true + * + * @example + * // For the invalid date: + * const result = isValid(new Date('')) + * //=> false + */ +function isValid(dirtyDate) { + (0, _index3.default)(1, arguments); + if (!(0, _index.default)(dirtyDate) && typeof dirtyDate !== 'number') { + return false; + } + var date = (0, _index2.default)(dirtyDate); + return !isNaN(Number(date)); +} +module.exports = exports.default; /***/ }), -/***/ 1386: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 1244: +/***/ ((module, exports) => { "use strict"; -// Description of supported double byte encodings and aliases. -// Tables are not require()-d until they are needed to speed up library load. -// require()-s are direct to support Browserify. - -module.exports = { - - // == Japanese/ShiftJIS ==================================================== - // All japanese encodings are based on JIS X set of standards: - // JIS X 0201 - Single-byte encoding of ASCII + ¥ + Kana chars at 0xA1-0xDF. - // JIS X 0208 - Main set of 6879 characters, placed in 94x94 plane, to be encoded by 2 bytes. - // Has several variations in 1978, 1983, 1990 and 1997. - // JIS X 0212 - Supplementary plane of 6067 chars in 94x94 plane. 1990. Effectively dead. - // JIS X 0213 - Extension and modern replacement of 0208 and 0212. Total chars: 11233. - // 2 planes, first is superset of 0208, second - revised 0212. - // Introduced in 2000, revised 2004. Some characters are in Unicode Plane 2 (0x2xxxx) +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = buildFormatLongFn; +function buildFormatLongFn(args) { + return function () { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + // TODO: Remove String() + var width = options.width ? String(options.width) : args.defaultWidth; + var format = args.formats[width] || args.formats[args.defaultWidth]; + return format; + }; +} +module.exports = exports.default; - // Byte encodings are: - // * Shift_JIS: Compatible with 0201, uses not defined chars in top half as lead bytes for double-byte - // encoding of 0208. Lead byte ranges: 0x81-0x9F, 0xE0-0xEF; Trail byte ranges: 0x40-0x7E, 0x80-0x9E, 0x9F-0xFC. - // Windows CP932 is a superset of Shift_JIS. Some companies added more chars, notably KDDI. - // * EUC-JP: Up to 3 bytes per character. Used mostly on *nixes. - // 0x00-0x7F - lower part of 0201 - // 0x8E, 0xA1-0xDF - upper part of 0201 - // (0xA1-0xFE)x2 - 0208 plane (94x94). - // 0x8F, (0xA1-0xFE)x2 - 0212 plane (94x94). - // * JIS X 208: 7-bit, direct encoding of 0208. Byte ranges: 0x21-0x7E (94 values). Uncommon. - // Used as-is in ISO2022 family. - // * ISO2022-JP: Stateful encoding, with escape sequences to switch between ASCII, - // 0201-1976 Roman, 0208-1978, 0208-1983. - // * ISO2022-JP-1: Adds esc seq for 0212-1990. - // * ISO2022-JP-2: Adds esc seq for GB2313-1980, KSX1001-1992, ISO8859-1, ISO8859-7. - // * ISO2022-JP-3: Adds esc seq for 0201-1976 Kana set, 0213-2000 Planes 1, 2. - // * ISO2022-JP-2004: Adds 0213-2004 Plane 1. - // - // After JIS X 0213 appeared, Shift_JIS-2004, EUC-JISX0213 and ISO2022-JP-2004 followed, with just changing the planes. - // - // Overall, it seems that it's a mess :( http://www8.plala.or.jp/tkubota1/unicode-symbols-map2.html +/***/ }), - 'shiftjis': { - type: '_dbcs', - table: function() { return __nccwpck_require__(7014) }, - encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E}, - encodeSkipVals: [{from: 0xED40, to: 0xF940}], - }, - 'csshiftjis': 'shiftjis', - 'mskanji': 'shiftjis', - 'sjis': 'shiftjis', - 'windows31j': 'shiftjis', - 'ms31j': 'shiftjis', - 'xsjis': 'shiftjis', - 'windows932': 'shiftjis', - 'ms932': 'shiftjis', - '932': 'shiftjis', - 'cp932': 'shiftjis', +/***/ 3647: +/***/ ((module, exports) => { - 'eucjp': { - type: '_dbcs', - table: function() { return __nccwpck_require__(1532) }, - encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E}, - }, +"use strict"; - // TODO: KDDI extension to Shift_JIS - // TODO: IBM CCSID 942 = CP932, but F0-F9 custom chars and other char changes. - // TODO: IBM CCSID 943 = Shift_JIS = CP932 with original Shift_JIS lower 128 chars. +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = buildLocalizeFn; +function buildLocalizeFn(args) { + return function (dirtyIndex, options) { + var context = options !== null && options !== void 0 && options.context ? String(options.context) : 'standalone'; + var valuesArray; + if (context === 'formatting' && args.formattingValues) { + var defaultWidth = args.defaultFormattingWidth || args.defaultWidth; + var width = options !== null && options !== void 0 && options.width ? String(options.width) : defaultWidth; + valuesArray = args.formattingValues[width] || args.formattingValues[defaultWidth]; + } else { + var _defaultWidth = args.defaultWidth; + var _width = options !== null && options !== void 0 && options.width ? String(options.width) : args.defaultWidth; + valuesArray = args.values[_width] || args.values[_defaultWidth]; + } + var index = args.argumentCallback ? args.argumentCallback(dirtyIndex) : dirtyIndex; + // @ts-ignore: For some reason TypeScript just don't want to match it, no matter how hard we try. I challenge you to try to remove it! + return valuesArray[index]; + }; +} +module.exports = exports.default; - // == Chinese/GBK ========================================================== - // http://en.wikipedia.org/wiki/GBK - // We mostly implement W3C recommendation: https://www.w3.org/TR/encoding/#gbk-encoder +/***/ }), - // Oldest GB2312 (1981, ~7600 chars) is a subset of CP936 - 'gb2312': 'cp936', - 'gb231280': 'cp936', - 'gb23121980': 'cp936', - 'csgb2312': 'cp936', - 'csiso58gb231280': 'cp936', - 'euccn': 'cp936', +/***/ 4029: +/***/ ((module, exports) => { - // Microsoft's CP936 is a subset and approximation of GBK. - 'windows936': 'cp936', - 'ms936': 'cp936', - '936': 'cp936', - 'cp936': { - type: '_dbcs', - table: function() { return __nccwpck_require__(3336) }, - }, +"use strict"; - // GBK (~22000 chars) is an extension of CP936 that added user-mapped chars and some other. - 'gbk': { - type: '_dbcs', - table: function() { return (__nccwpck_require__(3336).concat)(__nccwpck_require__(4346)) }, - }, - 'xgbk': 'gbk', - 'isoir58': 'gbk', - // GB18030 is an algorithmic extension of GBK. - // Main source: https://www.w3.org/TR/encoding/#gbk-encoder - // http://icu-project.org/docs/papers/gb18030.html - // http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/gb-18030-2000.xml - // http://www.khngai.com/chinese/charmap/tblgbk.php?page=0 - 'gb18030': { - type: '_dbcs', - table: function() { return (__nccwpck_require__(3336).concat)(__nccwpck_require__(4346)) }, - gb18030: function() { return __nccwpck_require__(6258) }, - encodeSkipVals: [0x80], - encodeAdd: {'€': 0xA2E3}, - }, +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = buildMatchFn; +function buildMatchFn(args) { + return function (string) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var width = options.width; + var matchPattern = width && args.matchPatterns[width] || args.matchPatterns[args.defaultMatchWidth]; + var matchResult = string.match(matchPattern); + if (!matchResult) { + return null; + } + var matchedString = matchResult[0]; + var parsePatterns = width && args.parsePatterns[width] || args.parsePatterns[args.defaultParseWidth]; + var key = Array.isArray(parsePatterns) ? findIndex(parsePatterns, function (pattern) { + return pattern.test(matchedString); + }) : findKey(parsePatterns, function (pattern) { + return pattern.test(matchedString); + }); + var value; + value = args.valueCallback ? args.valueCallback(key) : key; + value = options.valueCallback ? options.valueCallback(value) : value; + var rest = string.slice(matchedString.length); + return { + value: value, + rest: rest + }; + }; +} +function findKey(object, predicate) { + for (var key in object) { + if (object.hasOwnProperty(key) && predicate(object[key])) { + return key; + } + } + return undefined; +} +function findIndex(array, predicate) { + for (var key = 0; key < array.length; key++) { + if (predicate(array[key])) { + return key; + } + } + return undefined; +} +module.exports = exports.default; - 'chinese': 'gb18030', +/***/ }), +/***/ 3364: +/***/ ((module, exports) => { - // == Korean =============================================================== - // EUC-KR, KS_C_5601 and KS X 1001 are exactly the same. - 'windows949': 'cp949', - 'ms949': 'cp949', - '949': 'cp949', - 'cp949': { - type: '_dbcs', - table: function() { return __nccwpck_require__(7348) }, - }, +"use strict"; - 'cseuckr': 'cp949', - 'csksc56011987': 'cp949', - 'euckr': 'cp949', - 'isoir149': 'cp949', - 'korean': 'cp949', - 'ksc56011987': 'cp949', - 'ksc56011989': 'cp949', - 'ksc5601': 'cp949', +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = buildMatchPatternFn; +function buildMatchPatternFn(args) { + return function (string) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var matchResult = string.match(args.matchPattern); + if (!matchResult) return null; + var matchedString = matchResult[0]; + var parseResult = string.match(args.parsePattern); + if (!parseResult) return null; + var value = args.valueCallback ? args.valueCallback(parseResult[0]) : parseResult[0]; + value = options.valueCallback ? options.valueCallback(value) : value; + var rest = string.slice(matchedString.length); + return { + value: value, + rest: rest + }; + }; +} +module.exports = exports.default; - // == Big5/Taiwan/Hong Kong ================================================ - // There are lots of tables for Big5 and cp950. Please see the following links for history: - // http://moztw.org/docs/big5/ http://www.haible.de/bruno/charsets/conversion-tables/Big5.html - // Variations, in roughly number of defined chars: - // * Windows CP 950: Microsoft variant of Big5. Canonical: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT - // * Windows CP 951: Microsoft variant of Big5-HKSCS-2001. Seems to be never public. http://me.abelcheung.org/articles/research/what-is-cp951/ - // * Big5-2003 (Taiwan standard) almost superset of cp950. - // * Unicode-at-on (UAO) / Mozilla 1.8. Falling out of use on the Web. Not supported by other browsers. - // * Big5-HKSCS (-2001, -2004, -2008). Hong Kong standard. - // many unicode code points moved from PUA to Supplementary plane (U+2XXXX) over the years. - // Plus, it has 4 combining sequences. - // Seems that Mozilla refused to support it for 10 yrs. https://bugzilla.mozilla.org/show_bug.cgi?id=162431 https://bugzilla.mozilla.org/show_bug.cgi?id=310299 - // because big5-hkscs is the only encoding to include astral characters in non-algorithmic way. - // Implementations are not consistent within browsers; sometimes labeled as just big5. - // MS Internet Explorer switches from big5 to big5-hkscs when a patch applied. - // Great discussion & recap of what's going on https://bugzilla.mozilla.org/show_bug.cgi?id=912470#c31 - // In the encoder, it might make sense to support encoding old PUA mappings to Big5 bytes seq-s. - // Official spec: http://www.ogcio.gov.hk/en/business/tech_promotion/ccli/terms/doc/2003cmp_2008.txt - // http://www.ogcio.gov.hk/tc/business/tech_promotion/ccli/terms/doc/hkscs-2008-big5-iso.txt - // - // Current understanding of how to deal with Big5(-HKSCS) is in the Encoding Standard, http://encoding.spec.whatwg.org/#big5-encoder - // Unicode mapping (http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT) is said to be wrong. +/***/ }), - 'windows950': 'cp950', - 'ms950': 'cp950', - '950': 'cp950', - 'cp950': { - type: '_dbcs', - table: function() { return __nccwpck_require__(4284) }, - }, +/***/ 4846: +/***/ ((module, exports) => { - // Big5 has many variations and is an extension of cp950. We use Encoding Standard's as a consensus. - 'big5': 'big5hkscs', - 'big5hkscs': { - type: '_dbcs', - table: function() { return (__nccwpck_require__(4284).concat)(__nccwpck_require__(3480)) }, - encodeSkipVals: [ - // Although Encoding Standard says we should avoid encoding to HKSCS area (See Step 1 of - // https://encoding.spec.whatwg.org/#index-big5-pointer), we still do it to increase compatibility with ICU. - // But if a single unicode point can be encoded both as HKSCS and regular Big5, we prefer the latter. - 0x8e69, 0x8e6f, 0x8e7e, 0x8eab, 0x8eb4, 0x8ecd, 0x8ed0, 0x8f57, 0x8f69, 0x8f6e, 0x8fcb, 0x8ffe, - 0x906d, 0x907a, 0x90c4, 0x90dc, 0x90f1, 0x91bf, 0x92af, 0x92b0, 0x92b1, 0x92b2, 0x92d1, 0x9447, 0x94ca, - 0x95d9, 0x96fc, 0x9975, 0x9b76, 0x9b78, 0x9b7b, 0x9bc6, 0x9bde, 0x9bec, 0x9bf6, 0x9c42, 0x9c53, 0x9c62, - 0x9c68, 0x9c6b, 0x9c77, 0x9cbc, 0x9cbd, 0x9cd0, 0x9d57, 0x9d5a, 0x9dc4, 0x9def, 0x9dfb, 0x9ea9, 0x9eef, - 0x9efd, 0x9f60, 0x9fcb, 0xa077, 0xa0dc, 0xa0df, 0x8fcc, 0x92c8, 0x9644, 0x96ed, +"use strict"; - // Step 2 of https://encoding.spec.whatwg.org/#index-big5-pointer: Use last pointer for U+2550, U+255E, U+2561, U+256A, U+5341, or U+5345 - 0xa2a4, 0xa2a5, 0xa2a7, 0xa2a6, 0xa2cc, 0xa2ce, - ], - }, - 'cnbig5': 'big5hkscs', - 'csbig5': 'big5hkscs', - 'xxbig5': 'big5hkscs', +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var formatDistanceLocale = { + lessThanXSeconds: { + one: 'less than a second', + other: 'less than {{count}} seconds' + }, + xSeconds: { + one: '1 second', + other: '{{count}} seconds' + }, + halfAMinute: 'half a minute', + lessThanXMinutes: { + one: 'less than a minute', + other: 'less than {{count}} minutes' + }, + xMinutes: { + one: '1 minute', + other: '{{count}} minutes' + }, + aboutXHours: { + one: 'about 1 hour', + other: 'about {{count}} hours' + }, + xHours: { + one: '1 hour', + other: '{{count}} hours' + }, + xDays: { + one: '1 day', + other: '{{count}} days' + }, + aboutXWeeks: { + one: 'about 1 week', + other: 'about {{count}} weeks' + }, + xWeeks: { + one: '1 week', + other: '{{count}} weeks' + }, + aboutXMonths: { + one: 'about 1 month', + other: 'about {{count}} months' + }, + xMonths: { + one: '1 month', + other: '{{count}} months' + }, + aboutXYears: { + one: 'about 1 year', + other: 'about {{count}} years' + }, + xYears: { + one: '1 year', + other: '{{count}} years' + }, + overXYears: { + one: 'over 1 year', + other: 'over {{count}} years' + }, + almostXYears: { + one: 'almost 1 year', + other: 'almost {{count}} years' + } }; - +var formatDistance = function formatDistance(token, count, options) { + var result; + var tokenValue = formatDistanceLocale[token]; + if (typeof tokenValue === 'string') { + result = tokenValue; + } else if (count === 1) { + result = tokenValue.one; + } else { + result = tokenValue.other.replace('{{count}}', count.toString()); + } + if (options !== null && options !== void 0 && options.addSuffix) { + if (options.comparison && options.comparison > 0) { + return 'in ' + result; + } else { + return result + ' ago'; + } + } + return result; +}; +var _default = formatDistance; +exports["default"] = _default; +module.exports = exports.default; /***/ }), -/***/ 2733: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { +/***/ 368: +/***/ ((module, exports, __nccwpck_require__) => { "use strict"; -// Update this array if you add/rename/remove files in this directory. -// We support Browserify by skipping automatic module discovery and requiring modules directly. -var modules = [ - __nccwpck_require__(2376), - __nccwpck_require__(9557), - __nccwpck_require__(1155), - __nccwpck_require__(1644), - __nccwpck_require__(373), - __nccwpck_require__(1080), - __nccwpck_require__(1012), - __nccwpck_require__(9695), - __nccwpck_require__(1386), -]; - -// Put all encoding/alias/codec definitions to single object and export it. -for (var i = 0; i < modules.length; i++) { - var module = modules[i]; - for (var enc in module) - if (Object.prototype.hasOwnProperty.call(module, enc)) - exports[enc] = module[enc]; -} - +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(1244)); +var dateFormats = { + full: 'EEEE, MMMM do, y', + long: 'MMMM do, y', + medium: 'MMM d, y', + short: 'MM/dd/yyyy' +}; +var timeFormats = { + full: 'h:mm:ss a zzzz', + long: 'h:mm:ss a z', + medium: 'h:mm:ss a', + short: 'h:mm a' +}; +var dateTimeFormats = { + full: "{{date}} 'at' {{time}}", + long: "{{date}} 'at' {{time}}", + medium: '{{date}}, {{time}}', + short: '{{date}}, {{time}}' +}; +var formatLong = { + date: (0, _index.default)({ + formats: dateFormats, + defaultWidth: 'full' + }), + time: (0, _index.default)({ + formats: timeFormats, + defaultWidth: 'full' + }), + dateTime: (0, _index.default)({ + formats: dateTimeFormats, + defaultWidth: 'full' + }) +}; +var _default = formatLong; +exports["default"] = _default; +module.exports = exports.default; /***/ }), -/***/ 2376: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 2430: +/***/ ((module, exports) => { "use strict"; -var Buffer = (__nccwpck_require__(5118).Buffer); -// Export Node.js internal encodings. +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var formatRelativeLocale = { + lastWeek: "'last' eeee 'at' p", + yesterday: "'yesterday at' p", + today: "'today at' p", + tomorrow: "'tomorrow at' p", + nextWeek: "eeee 'at' p", + other: 'P' +}; +var formatRelative = function formatRelative(token, _date, _baseDate, _options) { + return formatRelativeLocale[token]; +}; +var _default = formatRelative; +exports["default"] = _default; +module.exports = exports.default; -module.exports = { - // Encodings - utf8: { type: "_internal", bomAware: true}, - cesu8: { type: "_internal", bomAware: true}, - unicode11utf8: "utf8", +/***/ }), - ucs2: { type: "_internal", bomAware: true}, - utf16le: "ucs2", +/***/ 5474: +/***/ ((module, exports, __nccwpck_require__) => { - binary: { type: "_internal" }, - base64: { type: "_internal" }, - hex: { type: "_internal" }, +"use strict"; - // Codec. - _internal: InternalCodec, + +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(3647)); +var eraValues = { + narrow: ['B', 'A'], + abbreviated: ['BC', 'AD'], + wide: ['Before Christ', 'Anno Domini'] +}; +var quarterValues = { + narrow: ['1', '2', '3', '4'], + abbreviated: ['Q1', 'Q2', 'Q3', 'Q4'], + wide: ['1st quarter', '2nd quarter', '3rd quarter', '4th quarter'] }; -//------------------------------------------------------------------------------ +// Note: in English, the names of days of the week and months are capitalized. +// If you are making a new locale based on this one, check if the same is true for the language you're working on. +// Generally, formatted dates should look like they are in the middle of a sentence, +// e.g. in Spanish language the weekdays and months should be in the lowercase. +var monthValues = { + narrow: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'], + abbreviated: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + wide: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] +}; +var dayValues = { + narrow: ['S', 'M', 'T', 'W', 'T', 'F', 'S'], + short: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + abbreviated: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + wide: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] +}; +var dayPeriodValues = { + narrow: { + am: 'a', + pm: 'p', + midnight: 'mi', + noon: 'n', + morning: 'morning', + afternoon: 'afternoon', + evening: 'evening', + night: 'night' + }, + abbreviated: { + am: 'AM', + pm: 'PM', + midnight: 'midnight', + noon: 'noon', + morning: 'morning', + afternoon: 'afternoon', + evening: 'evening', + night: 'night' + }, + wide: { + am: 'a.m.', + pm: 'p.m.', + midnight: 'midnight', + noon: 'noon', + morning: 'morning', + afternoon: 'afternoon', + evening: 'evening', + night: 'night' + } +}; +var formattingDayPeriodValues = { + narrow: { + am: 'a', + pm: 'p', + midnight: 'mi', + noon: 'n', + morning: 'in the morning', + afternoon: 'in the afternoon', + evening: 'in the evening', + night: 'at night' + }, + abbreviated: { + am: 'AM', + pm: 'PM', + midnight: 'midnight', + noon: 'noon', + morning: 'in the morning', + afternoon: 'in the afternoon', + evening: 'in the evening', + night: 'at night' + }, + wide: { + am: 'a.m.', + pm: 'p.m.', + midnight: 'midnight', + noon: 'noon', + morning: 'in the morning', + afternoon: 'in the afternoon', + evening: 'in the evening', + night: 'at night' + } +}; +var ordinalNumber = function ordinalNumber(dirtyNumber, _options) { + var number = Number(dirtyNumber); + + // If ordinal numbers depend on context, for example, + // if they are different for different grammatical genders, + // use `options.unit`. + // + // `unit` can be 'year', 'quarter', 'month', 'week', 'date', 'dayOfYear', + // 'day', 'hour', 'minute', 'second'. + + var rem100 = number % 100; + if (rem100 > 20 || rem100 < 10) { + switch (rem100 % 10) { + case 1: + return number + 'st'; + case 2: + return number + 'nd'; + case 3: + return number + 'rd'; + } + } + return number + 'th'; +}; +var localize = { + ordinalNumber: ordinalNumber, + era: (0, _index.default)({ + values: eraValues, + defaultWidth: 'wide' + }), + quarter: (0, _index.default)({ + values: quarterValues, + defaultWidth: 'wide', + argumentCallback: function argumentCallback(quarter) { + return quarter - 1; + } + }), + month: (0, _index.default)({ + values: monthValues, + defaultWidth: 'wide' + }), + day: (0, _index.default)({ + values: dayValues, + defaultWidth: 'wide' + }), + dayPeriod: (0, _index.default)({ + values: dayPeriodValues, + defaultWidth: 'wide', + formattingValues: formattingDayPeriodValues, + defaultFormattingWidth: 'wide' + }) +}; +var _default = localize; +exports["default"] = _default; +module.exports = exports.default; -function InternalCodec(codecOptions, iconv) { - this.enc = codecOptions.encodingName; - this.bomAware = codecOptions.bomAware; +/***/ }), - if (this.enc === "base64") - this.encoder = InternalEncoderBase64; - else if (this.enc === "cesu8") { - this.enc = "utf8"; // Use utf8 for decoding. - this.encoder = InternalEncoderCesu8; +/***/ 1338: +/***/ ((module, exports, __nccwpck_require__) => { - // Add decoder for versions of Node not supporting CESU-8 - if (Buffer.from('eda0bdedb2a9', 'hex').toString() !== '💩') { - this.decoder = InternalDecoderCesu8; - this.defaultCharUnicode = iconv.defaultCharUnicode; - } - } -} +"use strict"; -InternalCodec.prototype.encoder = InternalEncoder; -InternalCodec.prototype.decoder = InternalDecoder; -//------------------------------------------------------------------------------ +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(4029)); +var _index2 = _interopRequireDefault(__nccwpck_require__(3364)); +var matchOrdinalNumberPattern = /^(\d+)(th|st|nd|rd)?/i; +var parseOrdinalNumberPattern = /\d+/i; +var matchEraPatterns = { + narrow: /^(b|a)/i, + abbreviated: /^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i, + wide: /^(before christ|before common era|anno domini|common era)/i +}; +var parseEraPatterns = { + any: [/^b/i, /^(a|c)/i] +}; +var matchQuarterPatterns = { + narrow: /^[1234]/i, + abbreviated: /^q[1234]/i, + wide: /^[1234](th|st|nd|rd)? quarter/i +}; +var parseQuarterPatterns = { + any: [/1/i, /2/i, /3/i, /4/i] +}; +var matchMonthPatterns = { + narrow: /^[jfmasond]/i, + abbreviated: /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i, + wide: /^(january|february|march|april|may|june|july|august|september|october|november|december)/i +}; +var parseMonthPatterns = { + narrow: [/^j/i, /^f/i, /^m/i, /^a/i, /^m/i, /^j/i, /^j/i, /^a/i, /^s/i, /^o/i, /^n/i, /^d/i], + any: [/^ja/i, /^f/i, /^mar/i, /^ap/i, /^may/i, /^jun/i, /^jul/i, /^au/i, /^s/i, /^o/i, /^n/i, /^d/i] +}; +var matchDayPatterns = { + narrow: /^[smtwf]/i, + short: /^(su|mo|tu|we|th|fr|sa)/i, + abbreviated: /^(sun|mon|tue|wed|thu|fri|sat)/i, + wide: /^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i +}; +var parseDayPatterns = { + narrow: [/^s/i, /^m/i, /^t/i, /^w/i, /^t/i, /^f/i, /^s/i], + any: [/^su/i, /^m/i, /^tu/i, /^w/i, /^th/i, /^f/i, /^sa/i] +}; +var matchDayPeriodPatterns = { + narrow: /^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i, + any: /^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i +}; +var parseDayPeriodPatterns = { + any: { + am: /^a/i, + pm: /^p/i, + midnight: /^mi/i, + noon: /^no/i, + morning: /morning/i, + afternoon: /afternoon/i, + evening: /evening/i, + night: /night/i + } +}; +var match = { + ordinalNumber: (0, _index2.default)({ + matchPattern: matchOrdinalNumberPattern, + parsePattern: parseOrdinalNumberPattern, + valueCallback: function valueCallback(value) { + return parseInt(value, 10); + } + }), + era: (0, _index.default)({ + matchPatterns: matchEraPatterns, + defaultMatchWidth: 'wide', + parsePatterns: parseEraPatterns, + defaultParseWidth: 'any' + }), + quarter: (0, _index.default)({ + matchPatterns: matchQuarterPatterns, + defaultMatchWidth: 'wide', + parsePatterns: parseQuarterPatterns, + defaultParseWidth: 'any', + valueCallback: function valueCallback(index) { + return index + 1; + } + }), + month: (0, _index.default)({ + matchPatterns: matchMonthPatterns, + defaultMatchWidth: 'wide', + parsePatterns: parseMonthPatterns, + defaultParseWidth: 'any' + }), + day: (0, _index.default)({ + matchPatterns: matchDayPatterns, + defaultMatchWidth: 'wide', + parsePatterns: parseDayPatterns, + defaultParseWidth: 'any' + }), + dayPeriod: (0, _index.default)({ + matchPatterns: matchDayPeriodPatterns, + defaultMatchWidth: 'any', + parsePatterns: parseDayPeriodPatterns, + defaultParseWidth: 'any' + }) +}; +var _default = match; +exports["default"] = _default; +module.exports = exports.default; -// We use node.js internal decoder. Its signature is the same as ours. -var StringDecoder = (__nccwpck_require__(1576).StringDecoder); +/***/ }), -if (!StringDecoder.prototype.end) // Node v0.8 doesn't have this method. - StringDecoder.prototype.end = function() {}; +/***/ 1773: +/***/ ((module, exports, __nccwpck_require__) => { +"use strict"; -function InternalDecoder(options, codec) { - this.decoder = new StringDecoder(codec.enc); -} -InternalDecoder.prototype.write = function(buf) { - if (!Buffer.isBuffer(buf)) { - buf = Buffer.from(buf); - } +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = void 0; +var _index = _interopRequireDefault(__nccwpck_require__(4846)); +var _index2 = _interopRequireDefault(__nccwpck_require__(368)); +var _index3 = _interopRequireDefault(__nccwpck_require__(2430)); +var _index4 = _interopRequireDefault(__nccwpck_require__(5474)); +var _index5 = _interopRequireDefault(__nccwpck_require__(1338)); +/** + * @type {Locale} + * @category Locales + * @summary English locale (United States). + * @language English + * @iso-639-2 eng + * @author Sasha Koss [@kossnocorp]{@link https://github.com/kossnocorp} + * @author Lesha Koss [@leshakoss]{@link https://github.com/leshakoss} + */ +var locale = { + code: 'en-US', + formatDistance: _index.default, + formatLong: _index2.default, + formatRelative: _index3.default, + localize: _index4.default, + match: _index5.default, + options: { + weekStartsOn: 0 /* Sunday */, + firstWeekContainsDate: 1 + } +}; +var _default = locale; +exports["default"] = _default; +module.exports = exports.default; - return this.decoder.write(buf); -} +/***/ }), -InternalDecoder.prototype.end = function() { - return this.decoder.end(); -} +/***/ 7923: +/***/ ((module, exports, __nccwpck_require__) => { +"use strict"; -//------------------------------------------------------------------------------ -// Encoder is mostly trivial -function InternalEncoder(options, codec) { - this.enc = codec.enc; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = subMilliseconds; +var _index = _interopRequireDefault(__nccwpck_require__(524)); +var _index2 = _interopRequireDefault(__nccwpck_require__(2063)); +var _index3 = _interopRequireDefault(__nccwpck_require__(1985)); +/** + * @name subMilliseconds + * @category Millisecond Helpers + * @summary Subtract the specified number of milliseconds from the given date. + * + * @description + * Subtract the specified number of milliseconds from the given date. + * + * @param {Date|Number} date - the date to be changed + * @param {Number} amount - the amount of milliseconds to be subtracted. Positive decimals will be rounded using `Math.floor`, decimals less than zero will be rounded using `Math.ceil`. + * @returns {Date} the new date with the milliseconds subtracted + * @throws {TypeError} 2 arguments required + * + * @example + * // Subtract 750 milliseconds from 10 July 2014 12:45:30.000: + * const result = subMilliseconds(new Date(2014, 6, 10, 12, 45, 30, 0), 750) + * //=> Thu Jul 10 2014 12:45:29.250 + */ +function subMilliseconds(dirtyDate, dirtyAmount) { + (0, _index2.default)(2, arguments); + var amount = (0, _index3.default)(dirtyAmount); + return (0, _index.default)(dirtyDate, -amount); } +module.exports = exports.default; -InternalEncoder.prototype.write = function(str) { - return Buffer.from(str, this.enc); -} +/***/ }), -InternalEncoder.prototype.end = function() { -} +/***/ 6477: +/***/ ((module, exports, __nccwpck_require__) => { +"use strict"; -//------------------------------------------------------------------------------ -// Except base64 encoder, which must keep its state. -function InternalEncoderBase64(options, codec) { - this.prevStr = ''; +var _interopRequireDefault = (__nccwpck_require__(3286)["default"]); +Object.defineProperty(exports, "__esModule", ({ + value: true +})); +exports["default"] = toDate; +var _typeof2 = _interopRequireDefault(__nccwpck_require__(5605)); +var _index = _interopRequireDefault(__nccwpck_require__(2063)); +/** + * @name toDate + * @category Common Helpers + * @summary Convert the given argument to an instance of Date. + * + * @description + * Convert the given argument to an instance of Date. + * + * If the argument is an instance of Date, the function returns its clone. + * + * If the argument is a number, it is treated as a timestamp. + * + * If the argument is none of the above, the function returns Invalid Date. + * + * **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`. + * + * @param {Date|Number} argument - the value to convert + * @returns {Date} the parsed date in the local time zone + * @throws {TypeError} 1 argument required + * + * @example + * // Clone the date: + * const result = toDate(new Date(2014, 1, 11, 11, 30, 30)) + * //=> Tue Feb 11 2014 11:30:30 + * + * @example + * // Convert the timestamp to date: + * const result = toDate(1392098430000) + * //=> Tue Feb 11 2014 11:30:30 + */ +function toDate(argument) { + (0, _index.default)(1, arguments); + var argStr = Object.prototype.toString.call(argument); + + // Clone the date + if (argument instanceof Date || (0, _typeof2.default)(argument) === 'object' && argStr === '[object Date]') { + // Prevent the date to lose the milliseconds when passed to new Date() in IE10 + return new Date(argument.getTime()); + } else if (typeof argument === 'number' || argStr === '[object Number]') { + return new Date(argument); + } else { + if ((typeof argument === 'string' || argStr === '[object String]') && typeof console !== 'undefined') { + // eslint-disable-next-line no-console + console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#string-arguments"); + // eslint-disable-next-line no-console + console.warn(new Error().stack); + } + return new Date(NaN); + } } +module.exports = exports.default; -InternalEncoderBase64.prototype.write = function(str) { - str = this.prevStr + str; - var completeQuads = str.length - (str.length % 4); - this.prevStr = str.slice(completeQuads); - str = str.slice(0, completeQuads); +/***/ }), - return Buffer.from(str, "base64"); -} +/***/ 8932: +/***/ ((__unused_webpack_module, exports) => { -InternalEncoderBase64.prototype.end = function() { - return Buffer.from(this.prevStr, "base64"); -} +"use strict"; -//------------------------------------------------------------------------------ -// CESU-8 encoder is also special. +Object.defineProperty(exports, "__esModule", ({ value: true })); -function InternalEncoderCesu8(options, codec) { -} +class Deprecation extends Error { + constructor(message) { + super(message); // Maintains proper stack trace (only available on V8) -InternalEncoderCesu8.prototype.write = function(str) { - var buf = Buffer.alloc(str.length * 3), bufIdx = 0; - for (var i = 0; i < str.length; i++) { - var charCode = str.charCodeAt(i); - // Naive implementation, but it works because CESU-8 is especially easy - // to convert from UTF-16 (which all JS strings are encoded in). - if (charCode < 0x80) - buf[bufIdx++] = charCode; - else if (charCode < 0x800) { - buf[bufIdx++] = 0xC0 + (charCode >>> 6); - buf[bufIdx++] = 0x80 + (charCode & 0x3f); - } - else { // charCode will always be < 0x10000 in javascript. - buf[bufIdx++] = 0xE0 + (charCode >>> 12); - buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f); - buf[bufIdx++] = 0x80 + (charCode & 0x3f); - } + /* istanbul ignore next */ + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); } - return buf.slice(0, bufIdx); -} -InternalEncoderCesu8.prototype.end = function() { + this.name = 'Deprecation'; + } + } -//------------------------------------------------------------------------------ -// CESU-8 decoder is not implemented in Node v4.0+ +exports.Deprecation = Deprecation; -function InternalDecoderCesu8(options, codec) { - this.acc = 0; - this.contBytes = 0; - this.accBytes = 0; - this.defaultCharUnicode = codec.defaultCharUnicode; -} -InternalDecoderCesu8.prototype.write = function(buf) { - var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes, - res = ''; - for (var i = 0; i < buf.length; i++) { - var curByte = buf[i]; - if ((curByte & 0xC0) !== 0x80) { // Leading byte - if (contBytes > 0) { // Previous code is invalid - res += this.defaultCharUnicode; - contBytes = 0; - } +/***/ }), - if (curByte < 0x80) { // Single-byte code - res += String.fromCharCode(curByte); - } else if (curByte < 0xE0) { // Two-byte code - acc = curByte & 0x1F; - contBytes = 1; accBytes = 1; - } else if (curByte < 0xF0) { // Three-byte code - acc = curByte & 0x0F; - contBytes = 2; accBytes = 1; - } else { // Four or more are not supported for CESU-8. - res += this.defaultCharUnicode; - } - } else { // Continuation byte - if (contBytes > 0) { // We're waiting for it. - acc = (acc << 6) | (curByte & 0x3f); - contBytes--; accBytes++; - if (contBytes === 0) { - // Check for overlong encoding, but support Modified UTF-8 (encoding NULL as C0 80) - if (accBytes === 2 && acc < 0x80 && acc > 0) - res += this.defaultCharUnicode; - else if (accBytes === 3 && acc < 0x800) - res += this.defaultCharUnicode; - else - // Actually add character. - res += String.fromCharCode(acc); - } - } else { // Unexpected continuation byte - res += this.defaultCharUnicode; - } +/***/ 8685: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; + + +var iconvLite = __nccwpck_require__(9032); + +// Expose to the world +module.exports.O = convert; + +/** + * Convert encoding of an UTF-8 string or a buffer + * + * @param {String|Buffer} str String to be converted + * @param {String} to Encoding to be converted to + * @param {String} [from='UTF-8'] Encoding to be converted from + * @return {Buffer} Encoded string + */ +function convert(str, to, from) { + from = checkEncoding(from || 'UTF-8'); + to = checkEncoding(to || 'UTF-8'); + str = str || ''; + + var result; + + if (from !== 'UTF-8' && typeof str === 'string') { + str = Buffer.from(str, 'binary'); + } + + if (from === to) { + if (typeof str === 'string') { + result = Buffer.from(str); + } else { + result = str; + } + } else { + try { + result = convertIconvLite(str, to, from); + } catch (E) { + console.error(E); + result = str; } } - this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes; - return res; + + if (typeof result === 'string') { + result = Buffer.from(result, 'utf-8'); + } + + return result; } -InternalDecoderCesu8.prototype.end = function() { - var res = 0; - if (this.contBytes > 0) - res += this.defaultCharUnicode; - return res; +/** + * Convert encoding of astring with iconv-lite + * + * @param {String|Buffer} str String to be converted + * @param {String} to Encoding to be converted to + * @param {String} [from='UTF-8'] Encoding to be converted from + * @return {Buffer} Encoded string + */ +function convertIconvLite(str, to, from) { + if (to === 'UTF-8') { + return iconvLite.decode(str, from); + } else if (from === 'UTF-8') { + return iconvLite.encode(str, to); + } else { + return iconvLite.encode(iconvLite.decode(str, from), to); + } +} + +/** + * Converts charset name if needed + * + * @param {String} name Character set + * @return {String} Character set name + */ +function checkEncoding(name) { + return (name || '') + .toString() + .trim() + .replace(/^latin[\-_]?(\d+)$/i, 'ISO-8859-$1') + .replace(/^win(?:dows)?[\-_]?(\d+)$/i, 'WINDOWS-$1') + .replace(/^utf[\-_]?(\d+)$/i, 'UTF-$1') + .replace(/^ks_c_5601\-1987$/i, 'CP949') + .replace(/^us[\-_]?ascii$/i, 'ASCII') + .toUpperCase(); } /***/ }), -/***/ 373: +/***/ 9695: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; var Buffer = (__nccwpck_require__(5118).Buffer); -// Single-byte codec. Needs a 'chars' string parameter that contains 256 or 128 chars that -// correspond to encoded bytes (if 128 - then lower half is ASCII). +// Multibyte codec. In this scheme, a character is represented by 1 or more bytes. +// Our codec supports UTF-16 surrogates, extensions for GB18030 and unicode sequences. +// To save memory and loading time, we read table files only when requested. -exports._sbcs = SBCSCodec; -function SBCSCodec(codecOptions, iconv) { - if (!codecOptions) - throw new Error("SBCS codec is called without the data.") - - // Prepare char buffer for decoding. - if (!codecOptions.chars || (codecOptions.chars.length !== 128 && codecOptions.chars.length !== 256)) - throw new Error("Encoding '"+codecOptions.type+"' has incorrect 'chars' (must be of len 128 or 256)"); - - if (codecOptions.chars.length === 128) { - var asciiString = ""; - for (var i = 0; i < 128; i++) - asciiString += String.fromCharCode(i); - codecOptions.chars = asciiString + codecOptions.chars; - } +exports._dbcs = DBCSCodec; - this.decodeBuf = Buffer.from(codecOptions.chars, 'ucs2'); - - // Encoding buffer. - var encodeBuf = Buffer.alloc(65536, iconv.defaultCharSingleByte.charCodeAt(0)); +var UNASSIGNED = -1, + GB18030_CODE = -2, + SEQ_START = -10, + NODE_START = -1000, + UNASSIGNED_NODE = new Array(0x100), + DEF_CHAR = -1; - for (var i = 0; i < codecOptions.chars.length; i++) - encodeBuf[codecOptions.chars.charCodeAt(i)] = i; +for (var i = 0; i < 0x100; i++) + UNASSIGNED_NODE[i] = UNASSIGNED; - this.encodeBuf = encodeBuf; -} -SBCSCodec.prototype.encoder = SBCSEncoder; -SBCSCodec.prototype.decoder = SBCSDecoder; +// Class DBCSCodec reads and initializes mapping tables. +function DBCSCodec(codecOptions, iconv) { + this.encodingName = codecOptions.encodingName; + if (!codecOptions) + throw new Error("DBCS codec is called without the data.") + if (!codecOptions.table) + throw new Error("Encoding '" + this.encodingName + "' has no data."); + // Load tables. + var mappingTable = codecOptions.table(); -function SBCSEncoder(options, codec) { - this.encodeBuf = codec.encodeBuf; -} -SBCSEncoder.prototype.write = function(str) { - var buf = Buffer.alloc(str.length); - for (var i = 0; i < str.length; i++) - buf[i] = this.encodeBuf[str.charCodeAt(i)]; - - return buf; -} + // Decode tables: MBCS -> Unicode. -SBCSEncoder.prototype.end = function() { -} + // decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256. + // Trie root is decodeTables[0]. + // Values: >= 0 -> unicode character code. can be > 0xFFFF + // == UNASSIGNED -> unknown/unassigned sequence. + // == GB18030_CODE -> this is the end of a GB18030 4-byte sequence. + // <= NODE_START -> index of the next node in our trie to process next byte. + // <= SEQ_START -> index of the start of a character code sequence, in decodeTableSeq. + this.decodeTables = []; + this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node. + // Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here. + this.decodeTableSeq = []; -function SBCSDecoder(options, codec) { - this.decodeBuf = codec.decodeBuf; -} + // Actual mapping tables consist of chunks. Use them to fill up decode tables. + for (var i = 0; i < mappingTable.length; i++) + this._addDecodeChunk(mappingTable[i]); -SBCSDecoder.prototype.write = function(buf) { - // Strings are immutable in JS -> we use ucs2 buffer to speed up computations. - var decodeBuf = this.decodeBuf; - var newBuf = Buffer.alloc(buf.length*2); - var idx1 = 0, idx2 = 0; - for (var i = 0; i < buf.length; i++) { - idx1 = buf[i]*2; idx2 = i*2; - newBuf[idx2] = decodeBuf[idx1]; - newBuf[idx2+1] = decodeBuf[idx1+1]; - } - return newBuf.toString('ucs2'); -} + // Load & create GB18030 tables when needed. + if (typeof codecOptions.gb18030 === 'function') { + this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges. -SBCSDecoder.prototype.end = function() { -} + // Add GB18030 common decode nodes. + var commonThirdByteNodeIdx = this.decodeTables.length; + this.decodeTables.push(UNASSIGNED_NODE.slice(0)); + var commonFourthByteNodeIdx = this.decodeTables.length; + this.decodeTables.push(UNASSIGNED_NODE.slice(0)); -/***/ }), + // Fill out the tree + var firstByteNode = this.decodeTables[0]; + for (var i = 0x81; i <= 0xFE; i++) { + var secondByteNode = this.decodeTables[NODE_START - firstByteNode[i]]; + for (var j = 0x30; j <= 0x39; j++) { + if (secondByteNode[j] === UNASSIGNED) { + secondByteNode[j] = NODE_START - commonThirdByteNodeIdx; + } else if (secondByteNode[j] > NODE_START) { + throw new Error("gb18030 decode tables conflict at byte 2"); + } -/***/ 1012: -/***/ ((module) => { + var thirdByteNode = this.decodeTables[NODE_START - secondByteNode[j]]; + for (var k = 0x81; k <= 0xFE; k++) { + if (thirdByteNode[k] === UNASSIGNED) { + thirdByteNode[k] = NODE_START - commonFourthByteNodeIdx; + } else if (thirdByteNode[k] === NODE_START - commonFourthByteNodeIdx) { + continue; + } else if (thirdByteNode[k] > NODE_START) { + throw new Error("gb18030 decode tables conflict at byte 3"); + } -"use strict"; + var fourthByteNode = this.decodeTables[NODE_START - thirdByteNode[k]]; + for (var l = 0x30; l <= 0x39; l++) { + if (fourthByteNode[l] === UNASSIGNED) + fourthByteNode[l] = GB18030_CODE; + } + } + } + } + } + this.defaultCharUnicode = iconv.defaultCharUnicode; -// Generated data for sbcs codec. Don't edit manually. Regenerate using generation/gen-sbcs.js script. -module.exports = { - "437": "cp437", - "737": "cp737", - "775": "cp775", - "850": "cp850", - "852": "cp852", - "855": "cp855", - "856": "cp856", - "857": "cp857", - "858": "cp858", - "860": "cp860", - "861": "cp861", - "862": "cp862", - "863": "cp863", - "864": "cp864", - "865": "cp865", - "866": "cp866", - "869": "cp869", - "874": "windows874", - "922": "cp922", - "1046": "cp1046", - "1124": "cp1124", - "1125": "cp1125", - "1129": "cp1129", - "1133": "cp1133", - "1161": "cp1161", - "1162": "cp1162", - "1163": "cp1163", - "1250": "windows1250", - "1251": "windows1251", - "1252": "windows1252", - "1253": "windows1253", - "1254": "windows1254", - "1255": "windows1255", - "1256": "windows1256", - "1257": "windows1257", - "1258": "windows1258", - "28591": "iso88591", - "28592": "iso88592", - "28593": "iso88593", - "28594": "iso88594", - "28595": "iso88595", - "28596": "iso88596", - "28597": "iso88597", - "28598": "iso88598", - "28599": "iso88599", - "28600": "iso885910", - "28601": "iso885911", - "28603": "iso885913", - "28604": "iso885914", - "28605": "iso885915", - "28606": "iso885916", - "windows874": { - "type": "_sbcs", - "chars": "€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" - }, - "win874": "windows874", - "cp874": "windows874", - "windows1250": { - "type": "_sbcs", - "chars": "€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙" - }, - "win1250": "windows1250", - "cp1250": "windows1250", - "windows1251": { - "type": "_sbcs", - "chars": "ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя" - }, - "win1251": "windows1251", - "cp1251": "windows1251", - "windows1252": { - "type": "_sbcs", - "chars": "€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" - }, - "win1252": "windows1252", - "cp1252": "windows1252", - "windows1253": { - "type": "_sbcs", - "chars": "€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬­®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�" - }, - "win1253": "windows1253", - "cp1253": "windows1253", - "windows1254": { - "type": "_sbcs", - "chars": "€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ" - }, - "win1254": "windows1254", - "cp1254": "windows1254", - "windows1255": { - "type": "_sbcs", - "chars": "€�‚ƒ„…†‡ˆ‰�‹�����‘’“”•–—˜™�›���� ¡¢£₪¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾¿ְֱֲֳִֵֶַָֹֺֻּֽ־ֿ׀ׁׂ׃װױײ׳״�������אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�" - }, - "win1255": "windows1255", - "cp1255": "windows1255", - "windows1256": { - "type": "_sbcs", - "chars": "€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهوçèéêëىيîïًٌٍَôُِ÷ّùْûü‎‏ے" - }, - "win1256": "windows1256", - "cp1256": "windows1256", - "windows1257": { - "type": "_sbcs", - "chars": "€�‚�„…†‡�‰�‹�¨ˇ¸�‘’“”•–—�™�›�¯˛� �¢£¤�¦§Ø©Ŗ«¬­®Æ°±²³´µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž˙" - }, - "win1257": "windows1257", - "cp1257": "windows1257", - "windows1258": { - "type": "_sbcs", - "chars": "€�‚ƒ„…†‡ˆ‰�‹Œ����‘’“”•–—˜™�›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ" - }, - "win1258": "windows1258", - "cp1258": "windows1258", - "iso88591": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" - }, - "cp28591": "iso88591", - "iso88592": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ Ą˘Ł¤ĽŚ§¨ŠŞŤŹ­ŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙" - }, - "cp28592": "iso88592", - "iso88593": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ Ħ˘£¤�Ĥ§¨İŞĞĴ­�Ż°ħ²³´µĥ·¸ışğĵ½�żÀÁÂ�ÄĊĈÇÈÉÊËÌÍÎÏ�ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâ�äċĉçèéêëìíîï�ñòóôġö÷ĝùúûüŭŝ˙" - }, - "cp28593": "iso88593", - "iso88594": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ĄĸŖ¤ĨĻ§¨ŠĒĢŦ­Ž¯°ą˛ŗ´ĩļˇ¸šēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖ×ØŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙" - }, - "cp28594": "iso88594", - "iso88595": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ" - }, - "cp28595": "iso88595", - "iso88596": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ���¤�������،­�������������؛���؟�ءآأؤإئابةتثجحخدذرزسشصضطظعغ�����ـفقكلمنهوىيًٌٍَُِّْ�������������" - }, - "cp28596": "iso88596", - "iso88597": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ‘’£€₯¦§¨©ͺ«¬­�―°±²³΄΅Ά·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�" - }, - "cp28597": "iso88597", - "iso88598": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ �¢£¤¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾��������������������������������‗אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�" - }, - "cp28598": "iso88598", - "iso88599": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ" - }, - "cp28599": "iso88599", - "iso885910": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ĄĒĢĪĨĶ§ĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ" - }, - "cp28600": "iso885910", - "iso885911": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" - }, - "cp28601": "iso885911", - "iso885913": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’" - }, - "cp28603": "iso885913", - "iso885914": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ Ḃḃ£ĊċḊ§Ẁ©ẂḋỲ­®ŸḞḟĠġṀṁ¶ṖẁṗẃṠỳẄẅṡÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŴÑÒÓÔÕÖṪØÙÚÛÜÝŶßàáâãäåæçèéêëìíîïŵñòóôõöṫøùúûüýŷÿ" - }, - "cp28604": "iso885914", - "iso885915": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" - }, - "cp28605": "iso885915", - "iso885916": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ĄąŁ€„Š§š©Ș«Ź­źŻ°±ČłŽ”¶·žčș»ŒœŸżÀÁÂĂÄĆÆÇÈÉÊËÌÍÎÏĐŃÒÓÔŐÖŚŰÙÚÛÜĘȚßàáâăäćæçèéêëìíîïđńòóôőöśűùúûüęțÿ" - }, - "cp28606": "iso885916", - "cp437": { - "type": "_sbcs", - "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - "ibm437": "cp437", - "csibm437": "cp437", - "cp737": { - "type": "_sbcs", - "chars": "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ " - }, - "ibm737": "cp737", - "csibm737": "cp737", - "cp775": { - "type": "_sbcs", - "chars": "ĆüéāäģåćłēŖŗīŹÄÅÉæÆōöĢ¢ŚśÖÜø£ØפĀĪóŻżź”¦©®¬½¼Ł«»░▒▓│┤ĄČĘĖ╣║╗╝ĮŠ┐└┴┬├─┼ŲŪ╚╔╩╦╠═╬Žąčęėįšųūž┘┌█▄▌▐▀ÓßŌŃõÕµńĶķĻļņĒŅ’­±“¾¶§÷„°∙·¹³²■ " - }, - "ibm775": "cp775", - "csibm775": "cp775", - "cp850": { - "type": "_sbcs", - "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´­±‗¾¶§÷¸°¨·¹³²■ " - }, - "ibm850": "cp850", - "csibm850": "cp850", - "cp852": { - "type": "_sbcs", - "chars": "ÇüéâäůćçłëŐőîŹÄĆÉĹĺôöĽľŚśÖÜŤťŁ×čáíóúĄąŽžĘ꬟Ⱥ«»░▒▓│┤ÁÂĚŞ╣║╗╝Żż┐└┴┬├─┼Ăă╚╔╩╦╠═╬¤đĐĎËďŇÍÎě┘┌█▄ŢŮ▀ÓßÔŃńňŠšŔÚŕŰýÝţ´­˝˛ˇ˘§÷¸°¨˙űŘř■ " - }, - "ibm852": "cp852", - "csibm852": "cp852", - "cp855": { - "type": "_sbcs", - "chars": "ђЂѓЃёЁєЄѕЅіІїЇјЈљЉњЊћЋќЌўЎџЏюЮъЪаАбБцЦдДеЕфФгГ«»░▒▓│┤хХиИ╣║╗╝йЙ┐└┴┬├─┼кК╚╔╩╦╠═╬¤лЛмМнНоОп┘┌█▄Пя▀ЯрРсСтТуУжЖвВьЬ№­ыЫзЗшШэЭщЩчЧ§■ " - }, - "ibm855": "cp855", - "csibm855": "cp855", - "cp856": { - "type": "_sbcs", - "chars": "אבגדהוזחטיךכלםמןנסעףפץצקרשת�£�×����������®¬½¼�«»░▒▓│┤���©╣║╗╝¢¥┐└┴┬├─┼��╚╔╩╦╠═╬¤���������┘┌█▄¦�▀������µ�������¯´­±‗¾¶§÷¸°¨·¹³²■ " - }, - "ibm856": "cp856", - "csibm856": "cp856", - "cp857": { - "type": "_sbcs", - "chars": "ÇüéâäàåçêëèïîıÄÅÉæÆôöòûùİÖÜø£ØŞşáíóúñÑĞ𿮬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ºªÊËÈ�ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµ�×ÚÛÙìÿ¯´­±�¾¶§÷¸°¨·¹³²■ " - }, - "ibm857": "cp857", - "csibm857": "cp857", - "cp858": { - "type": "_sbcs", - "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈ€ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´­±‗¾¶§÷¸°¨·¹³²■ " - }, - "ibm858": "cp858", - "csibm858": "cp858", - "cp860": { - "type": "_sbcs", - "chars": "ÇüéâãàÁçêÊèÍÔìÃÂÉÀÈôõòÚùÌÕÜ¢£Ù₧ÓáíóúñѪº¿Ò¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - "ibm860": "cp860", - "csibm860": "cp860", - "cp861": { - "type": "_sbcs", - "chars": "ÇüéâäàåçêëèÐðÞÄÅÉæÆôöþûÝýÖÜø£Ø₧ƒáíóúÁÍÓÚ¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - "ibm861": "cp861", - "csibm861": "cp861", - "cp862": { - "type": "_sbcs", - "chars": "אבגדהוזחטיךכלםמןנסעףפץצקרשת¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - "ibm862": "cp862", - "csibm862": "cp862", - "cp863": { - "type": "_sbcs", - "chars": "ÇüéâÂà¶çêëèïî‗À§ÉÈÊôËÏûù¤ÔÜ¢£ÙÛƒ¦´óú¨¸³¯Î⌐¬½¼¾«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - "ibm863": "cp863", - "csibm863": "cp863", - "cp864": { - "type": "_sbcs", - "chars": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$٪&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~°·∙√▒─│┼┤┬├┴┐┌└┘β∞φ±½¼≈«»ﻷﻸ��ﻻﻼ� ­ﺂ£¤ﺄ��ﺎﺏﺕﺙ،ﺝﺡﺥ٠١٢٣٤٥٦٧٨٩ﻑ؛ﺱﺵﺹ؟¢ﺀﺁﺃﺅﻊﺋﺍﺑﺓﺗﺛﺟﺣﺧﺩﺫﺭﺯﺳﺷﺻﺿﻁﻅﻋﻏ¦¬÷×ﻉـﻓﻗﻛﻟﻣﻧﻫﻭﻯﻳﺽﻌﻎﻍﻡﹽّﻥﻩﻬﻰﻲﻐﻕﻵﻶﻝﻙﻱ■�" - }, - "ibm864": "cp864", - "csibm864": "cp864", - "cp865": { - "type": "_sbcs", - "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø₧ƒáíóúñѪº¿⌐¬½¼¡«¤░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - "ibm865": "cp865", - "csibm865": "cp865", - "cp866": { - "type": "_sbcs", - "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ " - }, - "ibm866": "cp866", - "csibm866": "cp866", - "cp869": { - "type": "_sbcs", - "chars": "������Ά�·¬¦‘’Έ―ΉΊΪΌ��ΎΫ©Ώ²³ά£έήίϊΐόύΑΒΓΔΕΖΗ½ΘΙ«»░▒▓│┤ΚΛΜΝ╣║╗╝ΞΟ┐└┴┬├─┼ΠΡ╚╔╩╦╠═╬ΣΤΥΦΧΨΩαβγ┘┌█▄δε▀ζηθικλμνξοπρσςτ΄­±υφχ§ψ΅°¨ωϋΰώ■ " - }, - "ibm869": "cp869", - "csibm869": "cp869", - "cp922": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®‾°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŠÑÒÓÔÕÖ×ØÙÚÛÜÝŽßàáâãäåæçèéêëìíîïšñòóôõö÷øùúûüýžÿ" - }, - "ibm922": "cp922", - "csibm922": "cp922", - "cp1046": { - "type": "_sbcs", - "chars": "ﺈ×÷ﹱˆ■│─┐┌└┘ﹹﹻﹽﹿﹷﺊﻰﻳﻲﻎﻏﻐﻶﻸﻺﻼ ¤ﺋﺑﺗﺛﺟﺣ،­ﺧﺳ٠١٢٣٤٥٦٧٨٩ﺷ؛ﺻﺿﻊ؟ﻋءآأؤإئابةتثجحخدذرزسشصضطﻇعغﻌﺂﺄﺎﻓـفقكلمنهوىيًٌٍَُِّْﻗﻛﻟﻵﻷﻹﻻﻣﻧﻬﻩ�" - }, - "ibm1046": "cp1046", - "csibm1046": "cp1046", - "cp1124": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ЁЂҐЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђґєѕіїјљњћќ§ўџ" - }, - "ibm1124": "cp1124", - "csibm1124": "cp1124", - "cp1125": { - "type": "_sbcs", - "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёҐґЄєІіЇї·√№¤■ " - }, - "ibm1125": "cp1125", - "csibm1125": "cp1125", - "cp1129": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ" - }, - "ibm1129": "cp1129", - "csibm1129": "cp1129", - "cp1133": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ກຂຄງຈສຊຍດຕຖທນບປຜຝພຟມຢຣລວຫອຮ���ຯະາຳິີຶືຸູຼັົຽ���ເແໂໃໄ່້໊໋໌ໍໆ�ໜໝ₭����������������໐໑໒໓໔໕໖໗໘໙��¢¬¦�" - }, - "ibm1133": "cp1133", - "csibm1133": "cp1133", - "cp1161": { - "type": "_sbcs", - "chars": "��������������������������������่กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู้๊๋€฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛¢¬¦ " - }, - "ibm1161": "cp1161", - "csibm1161": "cp1161", - "cp1162": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" - }, - "ibm1162": "cp1162", - "csibm1162": "cp1162", - "cp1163": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£€¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ" - }, - "ibm1163": "cp1163", - "csibm1163": "cp1163", - "maccroatian": { - "type": "_sbcs", - "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊�©⁄¤‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ" - }, - "maccyrillic": { - "type": "_sbcs", - "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°¢£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµ∂ЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤" - }, - "macgreek": { - "type": "_sbcs", - "chars": "Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦­ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ�" - }, - "maciceland": { - "type": "_sbcs", - "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" - }, - "macroman": { - "type": "_sbcs", - "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" - }, - "macromania": { - "type": "_sbcs", - "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂŞ∞±≤≥¥µ∂∑∏π∫ªºΩăş¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›Ţţ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" - }, - "macthai": { - "type": "_sbcs", - "chars": "«»…“”�•‘’� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู​–—฿เแโใไๅๆ็่้๊๋์ํ™๏๐๑๒๓๔๕๖๗๘๙®©����" - }, - "macturkish": { - "type": "_sbcs", - "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙ�ˆ˜¯˘˙˚¸˝˛ˇ" - }, - "macukraine": { - "type": "_sbcs", - "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤" - }, - "koi8r": { - "type": "_sbcs", - "chars": "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" - }, - "koi8u": { - "type": "_sbcs", - "chars": "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґ╝╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪Ґ╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" - }, - "koi8ru": { - "type": "_sbcs", - "chars": "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" - }, - "koi8t": { - "type": "_sbcs", - "chars": "қғ‚Ғ„…†‡�‰ҳ‹ҲҷҶ�Қ‘’“”•–—�™�›�����ӯӮё¤ӣ¦§���«¬­®�°±²Ё�Ӣ¶·�№�»���©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" - }, - "armscii8": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ �և։)(»«—.՝,-֊…՜՛՞ԱաԲբԳգԴդԵեԶզԷէԸըԹթԺժԻիԼլԽխԾծԿկՀհՁձՂղՃճՄմՅյՆնՇշՈոՉչՊպՋջՌռՍսՎվՏտՐրՑցՒւՓփՔքՕօՖֆ՚�" - }, - "rk1048": { - "type": "_sbcs", - "chars": "ЂЃ‚ѓ„…†‡€‰Љ‹ЊҚҺЏђ‘’“”•–—�™љ›њқһџ ҰұӘ¤Ө¦§Ё©Ғ«¬­®Ү°±Ііөµ¶·ё№ғ»әҢңүАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя" - }, - "tcvn": { - "type": "_sbcs", - "chars": "\u0000ÚỤ\u0003ỪỬỮ\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010ỨỰỲỶỸÝỴ\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÀẢÃÁẠẶẬÈẺẼÉẸỆÌỈĨÍỊÒỎÕÓỌỘỜỞỠỚỢÙỦŨ ĂÂÊÔƠƯĐăâêôơưđẶ̀̀̉̃́àảãáạẲằẳẵắẴẮẦẨẪẤỀặầẩẫấậèỂẻẽéẹềểễếệìỉỄẾỒĩíịòỔỏõóọồổỗốộờởỡớợùỖủũúụừửữứựỳỷỹýỵỐ" - }, - "georgianacademy": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶçèéêëìíîïðñòóôõö÷øùúûüýþÿ" - }, - "georgianps": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზჱთიკლმნჲოპჟრსტჳუფქღყშჩცძწჭხჴჯჰჵæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" - }, - "pt154": { - "type": "_sbcs", - "chars": "ҖҒӮғ„…ҶҮҲүҠӢҢҚҺҸҗ‘’“”•–—ҳҷҡӣңқһҹ ЎўЈӨҘҰ§Ё©Ә«¬ӯ®Ҝ°ұІіҙө¶·ё№ә»јҪҫҝАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя" - }, - "viscii": { - "type": "_sbcs", - "chars": "\u0000\u0001Ẳ\u0003\u0004ẴẪ\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013Ỷ\u0015\u0016\u0017\u0018Ỹ\u001a\u001b\u001c\u001dỴ\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ẠẮẰẶẤẦẨẬẼẸẾỀỂỄỆỐỒỔỖỘỢỚỜỞỊỎỌỈỦŨỤỲÕắằặấầẩậẽẹếềểễệốồổỗỠƠộờởịỰỨỪỬơớƯÀÁÂÃẢĂẳẵÈÉÊẺÌÍĨỳĐứÒÓÔạỷừửÙÚỹỵÝỡưàáâãảăữẫèéêẻìíĩỉđựòóôõỏọụùúũủýợỮ" - }, - "iso646cn": { - "type": "_sbcs", - "chars": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������" - }, - "iso646jp": { - "type": "_sbcs", - "chars": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������" - }, - "hproman8": { - "type": "_sbcs", - "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ÀÂÈÊËÎÏ´ˋˆ¨˜ÙÛ₤¯Ýý°ÇçÑñ¡¿¤£¥§ƒ¢âêôûáéóúàèòùäëöüÅîØÆåíøæÄìÖÜÉïßÔÁÃãÐðÍÌÓÒÕõŠšÚŸÿÞþ·µ¶¾—¼½ªº«■»±�" - }, - "macintosh": { - "type": "_sbcs", - "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" - }, - "ascii": { - "type": "_sbcs", - "chars": "��������������������������������������������������������������������������������������������������������������������������������" - }, - "tis620": { - "type": "_sbcs", - "chars": "���������������������������������กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" - } -} - -/***/ }), - -/***/ 1080: -/***/ ((module) => { - -"use strict"; - - -// Manually added data to be used by sbcs codec in addition to generated one. - -module.exports = { - // Not supported by iconv, not sure why. - "10029": "maccenteuro", - "maccenteuro": { - "type": "_sbcs", - "chars": "ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ" - }, - - "808": "cp808", - "ibm808": "cp808", - "cp808": { - "type": "_sbcs", - "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№€■ " - }, - - "mik": { - "type": "_sbcs", - "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя└┴┬├─┼╣║╚╔╩╦╠═╬┐░▒▓│┤№§╗╝┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " - }, - - "cp720": { - "type": "_sbcs", - "chars": "\x80\x81éâ\x84à\x86çêëèïî\x8d\x8e\x8f\x90\u0651\u0652ô¤ـûùءآأؤ£إئابةتثجحخدذرزسشص«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ضطظعغفµقكلمنهوىي≡\u064b\u064c\u064d\u064e\u064f\u0650≈°∙·√ⁿ²■\u00a0" - }, - - // Aliases of generated encodings. - "ascii8bit": "ascii", - "usascii": "ascii", - "ansix34": "ascii", - "ansix341968": "ascii", - "ansix341986": "ascii", - "csascii": "ascii", - "cp367": "ascii", - "ibm367": "ascii", - "isoir6": "ascii", - "iso646us": "ascii", - "iso646irv": "ascii", - "us": "ascii", - - "latin1": "iso88591", - "latin2": "iso88592", - "latin3": "iso88593", - "latin4": "iso88594", - "latin5": "iso88599", - "latin6": "iso885910", - "latin7": "iso885913", - "latin8": "iso885914", - "latin9": "iso885915", - "latin10": "iso885916", - - "csisolatin1": "iso88591", - "csisolatin2": "iso88592", - "csisolatin3": "iso88593", - "csisolatin4": "iso88594", - "csisolatincyrillic": "iso88595", - "csisolatinarabic": "iso88596", - "csisolatingreek" : "iso88597", - "csisolatinhebrew": "iso88598", - "csisolatin5": "iso88599", - "csisolatin6": "iso885910", - - "l1": "iso88591", - "l2": "iso88592", - "l3": "iso88593", - "l4": "iso88594", - "l5": "iso88599", - "l6": "iso885910", - "l7": "iso885913", - "l8": "iso885914", - "l9": "iso885915", - "l10": "iso885916", - - "isoir14": "iso646jp", - "isoir57": "iso646cn", - "isoir100": "iso88591", - "isoir101": "iso88592", - "isoir109": "iso88593", - "isoir110": "iso88594", - "isoir144": "iso88595", - "isoir127": "iso88596", - "isoir126": "iso88597", - "isoir138": "iso88598", - "isoir148": "iso88599", - "isoir157": "iso885910", - "isoir166": "tis620", - "isoir179": "iso885913", - "isoir199": "iso885914", - "isoir203": "iso885915", - "isoir226": "iso885916", - - "cp819": "iso88591", - "ibm819": "iso88591", - - "cyrillic": "iso88595", - - "arabic": "iso88596", - "arabic8": "iso88596", - "ecma114": "iso88596", - "asmo708": "iso88596", - - "greek" : "iso88597", - "greek8" : "iso88597", - "ecma118" : "iso88597", - "elot928" : "iso88597", - - "hebrew": "iso88598", - "hebrew8": "iso88598", - - "turkish": "iso88599", - "turkish8": "iso88599", - - "thai": "iso885911", - "thai8": "iso885911", - - "celtic": "iso885914", - "celtic8": "iso885914", - "isoceltic": "iso885914", - - "tis6200": "tis620", - "tis62025291": "tis620", - "tis62025330": "tis620", - - "10000": "macroman", - "10006": "macgreek", - "10007": "maccyrillic", - "10079": "maciceland", - "10081": "macturkish", - - "cspc8codepage437": "cp437", - "cspc775baltic": "cp775", - "cspc850multilingual": "cp850", - "cspcp852": "cp852", - "cspc862latinhebrew": "cp862", - "cpgr": "cp869", - - "msee": "cp1250", - "mscyrl": "cp1251", - "msansi": "cp1252", - "msgreek": "cp1253", - "msturk": "cp1254", - "mshebr": "cp1255", - "msarab": "cp1256", - "winbaltrim": "cp1257", - - "cp20866": "koi8r", - "20866": "koi8r", - "ibm878": "koi8r", - "cskoi8r": "koi8r", - - "cp21866": "koi8u", - "21866": "koi8u", - "ibm1168": "koi8u", - - "strk10482002": "rk1048", - - "tcvn5712": "tcvn", - "tcvn57121": "tcvn", - - "gb198880": "iso646cn", - "cn": "iso646cn", - - "csiso14jisc6220ro": "iso646jp", - "jisc62201969ro": "iso646jp", - "jp": "iso646jp", - - "cshproman8": "hproman8", - "r8": "hproman8", - "roman8": "hproman8", - "xroman8": "hproman8", - "ibm1051": "hproman8", - - "mac": "macintosh", - "csmacintosh": "macintosh", -}; - - - -/***/ }), - -/***/ 1155: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -var Buffer = (__nccwpck_require__(5118).Buffer); - -// Note: UTF16-LE (or UCS2) codec is Node.js native. See encodings/internal.js - -// == UTF16-BE codec. ========================================================== - -exports.utf16be = Utf16BECodec; -function Utf16BECodec() { -} - -Utf16BECodec.prototype.encoder = Utf16BEEncoder; -Utf16BECodec.prototype.decoder = Utf16BEDecoder; -Utf16BECodec.prototype.bomAware = true; - - -// -- Encoding - -function Utf16BEEncoder() { -} - -Utf16BEEncoder.prototype.write = function(str) { - var buf = Buffer.from(str, 'ucs2'); - for (var i = 0; i < buf.length; i += 2) { - var tmp = buf[i]; buf[i] = buf[i+1]; buf[i+1] = tmp; - } - return buf; -} - -Utf16BEEncoder.prototype.end = function() { -} - - -// -- Decoding - -function Utf16BEDecoder() { - this.overflowByte = -1; -} - -Utf16BEDecoder.prototype.write = function(buf) { - if (buf.length == 0) - return ''; - - var buf2 = Buffer.alloc(buf.length + 1), - i = 0, j = 0; - - if (this.overflowByte !== -1) { - buf2[0] = buf[0]; - buf2[1] = this.overflowByte; - i = 1; j = 2; - } - - for (; i < buf.length-1; i += 2, j+= 2) { - buf2[j] = buf[i+1]; - buf2[j+1] = buf[i]; - } - - this.overflowByte = (i == buf.length-1) ? buf[buf.length-1] : -1; - - return buf2.slice(0, j).toString('ucs2'); -} - -Utf16BEDecoder.prototype.end = function() { - this.overflowByte = -1; -} - - -// == UTF-16 codec ============================================================= -// Decoder chooses automatically from UTF-16LE and UTF-16BE using BOM and space-based heuristic. -// Defaults to UTF-16LE, as it's prevalent and default in Node. -// http://en.wikipedia.org/wiki/UTF-16 and http://encoding.spec.whatwg.org/#utf-16le -// Decoder default can be changed: iconv.decode(buf, 'utf16', {defaultEncoding: 'utf-16be'}); - -// Encoder uses UTF-16LE and prepends BOM (which can be overridden with addBOM: false). - -exports.utf16 = Utf16Codec; -function Utf16Codec(codecOptions, iconv) { - this.iconv = iconv; -} - -Utf16Codec.prototype.encoder = Utf16Encoder; -Utf16Codec.prototype.decoder = Utf16Decoder; - - -// -- Encoding (pass-through) - -function Utf16Encoder(options, codec) { - options = options || {}; - if (options.addBOM === undefined) - options.addBOM = true; - this.encoder = codec.iconv.getEncoder('utf-16le', options); -} - -Utf16Encoder.prototype.write = function(str) { - return this.encoder.write(str); -} - -Utf16Encoder.prototype.end = function() { - return this.encoder.end(); -} - - -// -- Decoding - -function Utf16Decoder(options, codec) { - this.decoder = null; - this.initialBufs = []; - this.initialBufsLen = 0; - - this.options = options || {}; - this.iconv = codec.iconv; -} - -Utf16Decoder.prototype.write = function(buf) { - if (!this.decoder) { - // Codec is not chosen yet. Accumulate initial bytes. - this.initialBufs.push(buf); - this.initialBufsLen += buf.length; - - if (this.initialBufsLen < 16) // We need more bytes to use space heuristic (see below) - return ''; - - // We have enough bytes -> detect endianness. - var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); - this.decoder = this.iconv.getDecoder(encoding, this.options); - - var resStr = ''; - for (var i = 0; i < this.initialBufs.length; i++) - resStr += this.decoder.write(this.initialBufs[i]); - - this.initialBufs.length = this.initialBufsLen = 0; - return resStr; - } - - return this.decoder.write(buf); -} - -Utf16Decoder.prototype.end = function() { - if (!this.decoder) { - var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); - this.decoder = this.iconv.getDecoder(encoding, this.options); - - var resStr = ''; - for (var i = 0; i < this.initialBufs.length; i++) - resStr += this.decoder.write(this.initialBufs[i]); - - var trail = this.decoder.end(); - if (trail) - resStr += trail; - - this.initialBufs.length = this.initialBufsLen = 0; - return resStr; - } - return this.decoder.end(); -} - -function detectEncoding(bufs, defaultEncoding) { - var b = []; - var charsProcessed = 0; - var asciiCharsLE = 0, asciiCharsBE = 0; // Number of ASCII chars when decoded as LE or BE. - - outer_loop: - for (var i = 0; i < bufs.length; i++) { - var buf = bufs[i]; - for (var j = 0; j < buf.length; j++) { - b.push(buf[j]); - if (b.length === 2) { - if (charsProcessed === 0) { - // Check BOM first. - if (b[0] === 0xFF && b[1] === 0xFE) return 'utf-16le'; - if (b[0] === 0xFE && b[1] === 0xFF) return 'utf-16be'; - } - - if (b[0] === 0 && b[1] !== 0) asciiCharsBE++; - if (b[0] !== 0 && b[1] === 0) asciiCharsLE++; - - b.length = 0; - charsProcessed++; - - if (charsProcessed >= 100) { - break outer_loop; - } - } - } - } - - // Make decisions. - // Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon. - // So, we count ASCII as if it was LE or BE, and decide from that. - if (asciiCharsBE > asciiCharsLE) return 'utf-16be'; - if (asciiCharsBE < asciiCharsLE) return 'utf-16le'; - - // Couldn't decide (likely all zeros or not enough data). - return defaultEncoding || 'utf-16le'; -} - - - - -/***/ }), - -/***/ 9557: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -var Buffer = (__nccwpck_require__(5118).Buffer); - -// == UTF32-LE/BE codec. ========================================================== - -exports._utf32 = Utf32Codec; - -function Utf32Codec(codecOptions, iconv) { - this.iconv = iconv; - this.bomAware = true; - this.isLE = codecOptions.isLE; -} - -exports.utf32le = { type: '_utf32', isLE: true }; -exports.utf32be = { type: '_utf32', isLE: false }; - -// Aliases -exports.ucs4le = 'utf32le'; -exports.ucs4be = 'utf32be'; - -Utf32Codec.prototype.encoder = Utf32Encoder; -Utf32Codec.prototype.decoder = Utf32Decoder; - -// -- Encoding - -function Utf32Encoder(options, codec) { - this.isLE = codec.isLE; - this.highSurrogate = 0; -} - -Utf32Encoder.prototype.write = function(str) { - var src = Buffer.from(str, 'ucs2'); - var dst = Buffer.alloc(src.length * 2); - var write32 = this.isLE ? dst.writeUInt32LE : dst.writeUInt32BE; - var offset = 0; - - for (var i = 0; i < src.length; i += 2) { - var code = src.readUInt16LE(i); - var isHighSurrogate = (0xD800 <= code && code < 0xDC00); - var isLowSurrogate = (0xDC00 <= code && code < 0xE000); - - if (this.highSurrogate) { - if (isHighSurrogate || !isLowSurrogate) { - // There shouldn't be two high surrogates in a row, nor a high surrogate which isn't followed by a low - // surrogate. If this happens, keep the pending high surrogate as a stand-alone semi-invalid character - // (technically wrong, but expected by some applications, like Windows file names). - write32.call(dst, this.highSurrogate, offset); - offset += 4; - } - else { - // Create 32-bit value from high and low surrogates; - var codepoint = (((this.highSurrogate - 0xD800) << 10) | (code - 0xDC00)) + 0x10000; - - write32.call(dst, codepoint, offset); - offset += 4; - this.highSurrogate = 0; - - continue; - } - } - - if (isHighSurrogate) - this.highSurrogate = code; - else { - // Even if the current character is a low surrogate, with no previous high surrogate, we'll - // encode it as a semi-invalid stand-alone character for the same reasons expressed above for - // unpaired high surrogates. - write32.call(dst, code, offset); - offset += 4; - this.highSurrogate = 0; - } - } - - if (offset < dst.length) - dst = dst.slice(0, offset); - - return dst; -}; - -Utf32Encoder.prototype.end = function() { - // Treat any leftover high surrogate as a semi-valid independent character. - if (!this.highSurrogate) - return; - - var buf = Buffer.alloc(4); - - if (this.isLE) - buf.writeUInt32LE(this.highSurrogate, 0); - else - buf.writeUInt32BE(this.highSurrogate, 0); - - this.highSurrogate = 0; - - return buf; -}; - -// -- Decoding - -function Utf32Decoder(options, codec) { - this.isLE = codec.isLE; - this.badChar = codec.iconv.defaultCharUnicode.charCodeAt(0); - this.overflow = []; -} - -Utf32Decoder.prototype.write = function(src) { - if (src.length === 0) - return ''; - - var i = 0; - var codepoint = 0; - var dst = Buffer.alloc(src.length + 4); - var offset = 0; - var isLE = this.isLE; - var overflow = this.overflow; - var badChar = this.badChar; - - if (overflow.length > 0) { - for (; i < src.length && overflow.length < 4; i++) - overflow.push(src[i]); - - if (overflow.length === 4) { - // NOTE: codepoint is a signed int32 and can be negative. - // NOTE: We copied this block from below to help V8 optimize it (it works with array, not buffer). - if (isLE) { - codepoint = overflow[i] | (overflow[i+1] << 8) | (overflow[i+2] << 16) | (overflow[i+3] << 24); - } else { - codepoint = overflow[i+3] | (overflow[i+2] << 8) | (overflow[i+1] << 16) | (overflow[i] << 24); - } - overflow.length = 0; - - offset = _writeCodepoint(dst, offset, codepoint, badChar); - } - } - - // Main loop. Should be as optimized as possible. - for (; i < src.length - 3; i += 4) { - // NOTE: codepoint is a signed int32 and can be negative. - if (isLE) { - codepoint = src[i] | (src[i+1] << 8) | (src[i+2] << 16) | (src[i+3] << 24); - } else { - codepoint = src[i+3] | (src[i+2] << 8) | (src[i+1] << 16) | (src[i] << 24); - } - offset = _writeCodepoint(dst, offset, codepoint, badChar); - } - - // Keep overflowing bytes. - for (; i < src.length; i++) { - overflow.push(src[i]); - } - - return dst.slice(0, offset).toString('ucs2'); -}; - -function _writeCodepoint(dst, offset, codepoint, badChar) { - // NOTE: codepoint is signed int32 and can be negative. We keep it that way to help V8 with optimizations. - if (codepoint < 0 || codepoint > 0x10FFFF) { - // Not a valid Unicode codepoint - codepoint = badChar; - } - - // Ephemeral Planes: Write high surrogate. - if (codepoint >= 0x10000) { - codepoint -= 0x10000; - - var high = 0xD800 | (codepoint >> 10); - dst[offset++] = high & 0xff; - dst[offset++] = high >> 8; - - // Low surrogate is written below. - var codepoint = 0xDC00 | (codepoint & 0x3FF); - } - - // Write BMP char or low surrogate. - dst[offset++] = codepoint & 0xff; - dst[offset++] = codepoint >> 8; - - return offset; -}; - -Utf32Decoder.prototype.end = function() { - this.overflow.length = 0; -}; - -// == UTF-32 Auto codec ============================================================= -// Decoder chooses automatically from UTF-32LE and UTF-32BE using BOM and space-based heuristic. -// Defaults to UTF-32LE. http://en.wikipedia.org/wiki/UTF-32 -// Encoder/decoder default can be changed: iconv.decode(buf, 'utf32', {defaultEncoding: 'utf-32be'}); - -// Encoder prepends BOM (which can be overridden with (addBOM: false}). - -exports.utf32 = Utf32AutoCodec; -exports.ucs4 = 'utf32'; - -function Utf32AutoCodec(options, iconv) { - this.iconv = iconv; -} - -Utf32AutoCodec.prototype.encoder = Utf32AutoEncoder; -Utf32AutoCodec.prototype.decoder = Utf32AutoDecoder; - -// -- Encoding - -function Utf32AutoEncoder(options, codec) { - options = options || {}; - - if (options.addBOM === undefined) - options.addBOM = true; - - this.encoder = codec.iconv.getEncoder(options.defaultEncoding || 'utf-32le', options); -} - -Utf32AutoEncoder.prototype.write = function(str) { - return this.encoder.write(str); -}; - -Utf32AutoEncoder.prototype.end = function() { - return this.encoder.end(); -}; - -// -- Decoding - -function Utf32AutoDecoder(options, codec) { - this.decoder = null; - this.initialBufs = []; - this.initialBufsLen = 0; - this.options = options || {}; - this.iconv = codec.iconv; -} - -Utf32AutoDecoder.prototype.write = function(buf) { - if (!this.decoder) { - // Codec is not chosen yet. Accumulate initial bytes. - this.initialBufs.push(buf); - this.initialBufsLen += buf.length; - - if (this.initialBufsLen < 32) // We need more bytes to use space heuristic (see below) - return ''; - - // We have enough bytes -> detect endianness. - var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); - this.decoder = this.iconv.getDecoder(encoding, this.options); - - var resStr = ''; - for (var i = 0; i < this.initialBufs.length; i++) - resStr += this.decoder.write(this.initialBufs[i]); - - this.initialBufs.length = this.initialBufsLen = 0; - return resStr; - } - - return this.decoder.write(buf); -}; - -Utf32AutoDecoder.prototype.end = function() { - if (!this.decoder) { - var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); - this.decoder = this.iconv.getDecoder(encoding, this.options); - - var resStr = ''; - for (var i = 0; i < this.initialBufs.length; i++) - resStr += this.decoder.write(this.initialBufs[i]); - - var trail = this.decoder.end(); - if (trail) - resStr += trail; - - this.initialBufs.length = this.initialBufsLen = 0; - return resStr; - } - - return this.decoder.end(); -}; - -function detectEncoding(bufs, defaultEncoding) { - var b = []; - var charsProcessed = 0; - var invalidLE = 0, invalidBE = 0; // Number of invalid chars when decoded as LE or BE. - var bmpCharsLE = 0, bmpCharsBE = 0; // Number of BMP chars when decoded as LE or BE. - - outer_loop: - for (var i = 0; i < bufs.length; i++) { - var buf = bufs[i]; - for (var j = 0; j < buf.length; j++) { - b.push(buf[j]); - if (b.length === 4) { - if (charsProcessed === 0) { - // Check BOM first. - if (b[0] === 0xFF && b[1] === 0xFE && b[2] === 0 && b[3] === 0) { - return 'utf-32le'; - } - if (b[0] === 0 && b[1] === 0 && b[2] === 0xFE && b[3] === 0xFF) { - return 'utf-32be'; - } - } - - if (b[0] !== 0 || b[1] > 0x10) invalidBE++; - if (b[3] !== 0 || b[2] > 0x10) invalidLE++; - - if (b[0] === 0 && b[1] === 0 && (b[2] !== 0 || b[3] !== 0)) bmpCharsBE++; - if ((b[0] !== 0 || b[1] !== 0) && b[2] === 0 && b[3] === 0) bmpCharsLE++; - - b.length = 0; - charsProcessed++; - - if (charsProcessed >= 100) { - break outer_loop; - } - } - } - } - - // Make decisions. - if (bmpCharsBE - invalidBE > bmpCharsLE - invalidLE) return 'utf-32be'; - if (bmpCharsBE - invalidBE < bmpCharsLE - invalidLE) return 'utf-32le'; - - // Couldn't decide (likely all zeros or not enough data). - return defaultEncoding || 'utf-32le'; -} - - -/***/ }), - -/***/ 1644: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -var Buffer = (__nccwpck_require__(5118).Buffer); - -// UTF-7 codec, according to https://tools.ietf.org/html/rfc2152 -// See also below a UTF-7-IMAP codec, according to http://tools.ietf.org/html/rfc3501#section-5.1.3 - -exports.utf7 = Utf7Codec; -exports.unicode11utf7 = 'utf7'; // Alias UNICODE-1-1-UTF-7 -function Utf7Codec(codecOptions, iconv) { - this.iconv = iconv; -}; - -Utf7Codec.prototype.encoder = Utf7Encoder; -Utf7Codec.prototype.decoder = Utf7Decoder; -Utf7Codec.prototype.bomAware = true; - - -// -- Encoding - -var nonDirectChars = /[^A-Za-z0-9'\(\),-\.\/:\? \n\r\t]+/g; - -function Utf7Encoder(options, codec) { - this.iconv = codec.iconv; -} - -Utf7Encoder.prototype.write = function(str) { - // Naive implementation. - // Non-direct chars are encoded as "+-"; single "+" char is encoded as "+-". - return Buffer.from(str.replace(nonDirectChars, function(chunk) { - return "+" + (chunk === '+' ? '' : - this.iconv.encode(chunk, 'utf16-be').toString('base64').replace(/=+$/, '')) - + "-"; - }.bind(this))); -} - -Utf7Encoder.prototype.end = function() { -} - - -// -- Decoding - -function Utf7Decoder(options, codec) { - this.iconv = codec.iconv; - this.inBase64 = false; - this.base64Accum = ''; -} - -var base64Regex = /[A-Za-z0-9\/+]/; -var base64Chars = []; -for (var i = 0; i < 256; i++) - base64Chars[i] = base64Regex.test(String.fromCharCode(i)); - -var plusChar = '+'.charCodeAt(0), - minusChar = '-'.charCodeAt(0), - andChar = '&'.charCodeAt(0); - -Utf7Decoder.prototype.write = function(buf) { - var res = "", lastI = 0, - inBase64 = this.inBase64, - base64Accum = this.base64Accum; - - // The decoder is more involved as we must handle chunks in stream. - - for (var i = 0; i < buf.length; i++) { - if (!inBase64) { // We're in direct mode. - // Write direct chars until '+' - if (buf[i] == plusChar) { - res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars. - lastI = i+1; - inBase64 = true; - } - } else { // We decode base64. - if (!base64Chars[buf[i]]) { // Base64 ended. - if (i == lastI && buf[i] == minusChar) {// "+-" -> "+" - res += "+"; - } else { - var b64str = base64Accum + this.iconv.decode(buf.slice(lastI, i), "ascii"); - res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); - } - - if (buf[i] != minusChar) // Minus is absorbed after base64. - i--; - - lastI = i+1; - inBase64 = false; - base64Accum = ''; - } - } - } - - if (!inBase64) { - res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars. - } else { - var b64str = base64Accum + this.iconv.decode(buf.slice(lastI), "ascii"); - - var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars. - base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future. - b64str = b64str.slice(0, canBeDecoded); - - res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); - } - - this.inBase64 = inBase64; - this.base64Accum = base64Accum; - - return res; -} - -Utf7Decoder.prototype.end = function() { - var res = ""; - if (this.inBase64 && this.base64Accum.length > 0) - res = this.iconv.decode(Buffer.from(this.base64Accum, 'base64'), "utf16-be"); - - this.inBase64 = false; - this.base64Accum = ''; - return res; -} - - -// UTF-7-IMAP codec. -// RFC3501 Sec. 5.1.3 Modified UTF-7 (http://tools.ietf.org/html/rfc3501#section-5.1.3) -// Differences: -// * Base64 part is started by "&" instead of "+" -// * Direct characters are 0x20-0x7E, except "&" (0x26) -// * In Base64, "," is used instead of "/" -// * Base64 must not be used to represent direct characters. -// * No implicit shift back from Base64 (should always end with '-') -// * String must end in non-shifted position. -// * "-&" while in base64 is not allowed. - - -exports.utf7imap = Utf7IMAPCodec; -function Utf7IMAPCodec(codecOptions, iconv) { - this.iconv = iconv; -}; - -Utf7IMAPCodec.prototype.encoder = Utf7IMAPEncoder; -Utf7IMAPCodec.prototype.decoder = Utf7IMAPDecoder; -Utf7IMAPCodec.prototype.bomAware = true; - - -// -- Encoding - -function Utf7IMAPEncoder(options, codec) { - this.iconv = codec.iconv; - this.inBase64 = false; - this.base64Accum = Buffer.alloc(6); - this.base64AccumIdx = 0; -} - -Utf7IMAPEncoder.prototype.write = function(str) { - var inBase64 = this.inBase64, - base64Accum = this.base64Accum, - base64AccumIdx = this.base64AccumIdx, - buf = Buffer.alloc(str.length*5 + 10), bufIdx = 0; - - for (var i = 0; i < str.length; i++) { - var uChar = str.charCodeAt(i); - if (0x20 <= uChar && uChar <= 0x7E) { // Direct character or '&'. - if (inBase64) { - if (base64AccumIdx > 0) { - bufIdx += buf.write(base64Accum.slice(0, base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx); - base64AccumIdx = 0; - } - - buf[bufIdx++] = minusChar; // Write '-', then go to direct mode. - inBase64 = false; - } - - if (!inBase64) { - buf[bufIdx++] = uChar; // Write direct character - - if (uChar === andChar) // Ampersand -> '&-' - buf[bufIdx++] = minusChar; - } - - } else { // Non-direct character - if (!inBase64) { - buf[bufIdx++] = andChar; // Write '&', then go to base64 mode. - inBase64 = true; - } - if (inBase64) { - base64Accum[base64AccumIdx++] = uChar >> 8; - base64Accum[base64AccumIdx++] = uChar & 0xFF; - - if (base64AccumIdx == base64Accum.length) { - bufIdx += buf.write(base64Accum.toString('base64').replace(/\//g, ','), bufIdx); - base64AccumIdx = 0; - } - } - } - } - - this.inBase64 = inBase64; - this.base64AccumIdx = base64AccumIdx; - - return buf.slice(0, bufIdx); -} - -Utf7IMAPEncoder.prototype.end = function() { - var buf = Buffer.alloc(10), bufIdx = 0; - if (this.inBase64) { - if (this.base64AccumIdx > 0) { - bufIdx += buf.write(this.base64Accum.slice(0, this.base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx); - this.base64AccumIdx = 0; - } - - buf[bufIdx++] = minusChar; // Write '-', then go to direct mode. - this.inBase64 = false; - } - - return buf.slice(0, bufIdx); -} - - -// -- Decoding - -function Utf7IMAPDecoder(options, codec) { - this.iconv = codec.iconv; - this.inBase64 = false; - this.base64Accum = ''; -} - -var base64IMAPChars = base64Chars.slice(); -base64IMAPChars[','.charCodeAt(0)] = true; - -Utf7IMAPDecoder.prototype.write = function(buf) { - var res = "", lastI = 0, - inBase64 = this.inBase64, - base64Accum = this.base64Accum; - - // The decoder is more involved as we must handle chunks in stream. - // It is forgiving, closer to standard UTF-7 (for example, '-' is optional at the end). - - for (var i = 0; i < buf.length; i++) { - if (!inBase64) { // We're in direct mode. - // Write direct chars until '&' - if (buf[i] == andChar) { - res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars. - lastI = i+1; - inBase64 = true; - } - } else { // We decode base64. - if (!base64IMAPChars[buf[i]]) { // Base64 ended. - if (i == lastI && buf[i] == minusChar) { // "&-" -> "&" - res += "&"; - } else { - var b64str = base64Accum + this.iconv.decode(buf.slice(lastI, i), "ascii").replace(/,/g, '/'); - res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); - } - - if (buf[i] != minusChar) // Minus may be absorbed after base64. - i--; - - lastI = i+1; - inBase64 = false; - base64Accum = ''; - } - } - } - - if (!inBase64) { - res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars. - } else { - var b64str = base64Accum + this.iconv.decode(buf.slice(lastI), "ascii").replace(/,/g, '/'); - - var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars. - base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future. - b64str = b64str.slice(0, canBeDecoded); - - res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); - } - - this.inBase64 = inBase64; - this.base64Accum = base64Accum; - - return res; -} - -Utf7IMAPDecoder.prototype.end = function() { - var res = ""; - if (this.inBase64 && this.base64Accum.length > 0) - res = this.iconv.decode(Buffer.from(this.base64Accum, 'base64'), "utf16-be"); - - this.inBase64 = false; - this.base64Accum = ''; - return res; -} - - - - -/***/ }), - -/***/ 7961: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - - -var BOMChar = '\uFEFF'; - -exports.PrependBOM = PrependBOMWrapper -function PrependBOMWrapper(encoder, options) { - this.encoder = encoder; - this.addBOM = true; -} - -PrependBOMWrapper.prototype.write = function(str) { - if (this.addBOM) { - str = BOMChar + str; - this.addBOM = false; - } - - return this.encoder.write(str); -} - -PrependBOMWrapper.prototype.end = function() { - return this.encoder.end(); -} - - -//------------------------------------------------------------------------------ - -exports.StripBOM = StripBOMWrapper; -function StripBOMWrapper(decoder, options) { - this.decoder = decoder; - this.pass = false; - this.options = options || {}; -} - -StripBOMWrapper.prototype.write = function(buf) { - var res = this.decoder.write(buf); - if (this.pass || !res) - return res; - - if (res[0] === BOMChar) { - res = res.slice(1); - if (typeof this.options.stripBOM === 'function') - this.options.stripBOM(); - } - - this.pass = true; - return res; -} - -StripBOMWrapper.prototype.end = function() { - return this.decoder.end(); -} - - - -/***/ }), - -/***/ 9032: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -var Buffer = (__nccwpck_require__(5118).Buffer); - -var bomHandling = __nccwpck_require__(7961), - iconv = module.exports; - -// All codecs and aliases are kept here, keyed by encoding name/alias. -// They are lazy loaded in `iconv.getCodec` from `encodings/index.js`. -iconv.encodings = null; - -// Characters emitted in case of error. -iconv.defaultCharUnicode = '�'; -iconv.defaultCharSingleByte = '?'; - -// Public API. -iconv.encode = function encode(str, encoding, options) { - str = "" + (str || ""); // Ensure string. - - var encoder = iconv.getEncoder(encoding, options); - - var res = encoder.write(str); - var trail = encoder.end(); - - return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res; -} - -iconv.decode = function decode(buf, encoding, options) { - if (typeof buf === 'string') { - if (!iconv.skipDecodeWarning) { - console.error('Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding'); - iconv.skipDecodeWarning = true; - } - - buf = Buffer.from("" + (buf || ""), "binary"); // Ensure buffer. - } - - var decoder = iconv.getDecoder(encoding, options); - - var res = decoder.write(buf); - var trail = decoder.end(); - - return trail ? (res + trail) : res; -} - -iconv.encodingExists = function encodingExists(enc) { - try { - iconv.getCodec(enc); - return true; - } catch (e) { - return false; - } -} - -// Legacy aliases to convert functions -iconv.toEncoding = iconv.encode; -iconv.fromEncoding = iconv.decode; - -// Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache. -iconv._codecDataCache = {}; -iconv.getCodec = function getCodec(encoding) { - if (!iconv.encodings) - iconv.encodings = __nccwpck_require__(2733); // Lazy load all encoding definitions. - - // Canonicalize encoding name: strip all non-alphanumeric chars and appended year. - var enc = iconv._canonicalizeEncoding(encoding); - - // Traverse iconv.encodings to find actual codec. - var codecOptions = {}; - while (true) { - var codec = iconv._codecDataCache[enc]; - if (codec) - return codec; - - var codecDef = iconv.encodings[enc]; - - switch (typeof codecDef) { - case "string": // Direct alias to other encoding. - enc = codecDef; - break; - - case "object": // Alias with options. Can be layered. - for (var key in codecDef) - codecOptions[key] = codecDef[key]; - - if (!codecOptions.encodingName) - codecOptions.encodingName = enc; - - enc = codecDef.type; - break; - - case "function": // Codec itself. - if (!codecOptions.encodingName) - codecOptions.encodingName = enc; - - // The codec function must load all tables and return object with .encoder and .decoder methods. - // It'll be called only once (for each different options object). - codec = new codecDef(codecOptions, iconv); - - iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later. - return codec; - - default: - throw new Error("Encoding not recognized: '" + encoding + "' (searched as: '"+enc+"')"); - } - } -} - -iconv._canonicalizeEncoding = function(encoding) { - // Canonicalize encoding name: strip all non-alphanumeric chars and appended year. - return (''+encoding).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, ""); -} - -iconv.getEncoder = function getEncoder(encoding, options) { - var codec = iconv.getCodec(encoding), - encoder = new codec.encoder(options, codec); - - if (codec.bomAware && options && options.addBOM) - encoder = new bomHandling.PrependBOM(encoder, options); - - return encoder; -} - -iconv.getDecoder = function getDecoder(encoding, options) { - var codec = iconv.getCodec(encoding), - decoder = new codec.decoder(options, codec); - - if (codec.bomAware && !(options && options.stripBOM === false)) - decoder = new bomHandling.StripBOM(decoder, options); - - return decoder; -} - -// Streaming API -// NOTE: Streaming API naturally depends on 'stream' module from Node.js. Unfortunately in browser environments this module can add -// up to 100Kb to the output bundle. To avoid unnecessary code bloat, we don't enable Streaming API in browser by default. -// If you would like to enable it explicitly, please add the following code to your app: -// > iconv.enableStreamingAPI(require('stream')); -iconv.enableStreamingAPI = function enableStreamingAPI(stream_module) { - if (iconv.supportsStreams) - return; - - // Dependency-inject stream module to create IconvLite stream classes. - var streams = __nccwpck_require__(6869)(stream_module); - - // Not public API yet, but expose the stream classes. - iconv.IconvLiteEncoderStream = streams.IconvLiteEncoderStream; - iconv.IconvLiteDecoderStream = streams.IconvLiteDecoderStream; - - // Streaming API. - iconv.encodeStream = function encodeStream(encoding, options) { - return new iconv.IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options); - } - - iconv.decodeStream = function decodeStream(encoding, options) { - return new iconv.IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options); - } - - iconv.supportsStreams = true; -} - -// Enable Streaming API automatically if 'stream' module is available and non-empty (the majority of environments). -var stream_module; -try { - stream_module = __nccwpck_require__(2781); -} catch (e) {} - -if (stream_module && stream_module.Transform) { - iconv.enableStreamingAPI(stream_module); - -} else { - // In rare cases where 'stream' module is not available by default, throw a helpful exception. - iconv.encodeStream = iconv.decodeStream = function() { - throw new Error("iconv-lite Streaming API is not enabled. Use iconv.enableStreamingAPI(require('stream')); to enable it."); - }; -} - -if (false) {} - - -/***/ }), - -/***/ 6869: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -var Buffer = (__nccwpck_require__(5118).Buffer); - -// NOTE: Due to 'stream' module being pretty large (~100Kb, significant in browser environments), -// we opt to dependency-inject it instead of creating a hard dependency. -module.exports = function(stream_module) { - var Transform = stream_module.Transform; - - // == Encoder stream ======================================================= - - function IconvLiteEncoderStream(conv, options) { - this.conv = conv; - options = options || {}; - options.decodeStrings = false; // We accept only strings, so we don't need to decode them. - Transform.call(this, options); - } - - IconvLiteEncoderStream.prototype = Object.create(Transform.prototype, { - constructor: { value: IconvLiteEncoderStream } - }); - - IconvLiteEncoderStream.prototype._transform = function(chunk, encoding, done) { - if (typeof chunk != 'string') - return done(new Error("Iconv encoding stream needs strings as its input.")); - try { - var res = this.conv.write(chunk); - if (res && res.length) this.push(res); - done(); - } - catch (e) { - done(e); - } - } - - IconvLiteEncoderStream.prototype._flush = function(done) { - try { - var res = this.conv.end(); - if (res && res.length) this.push(res); - done(); - } - catch (e) { - done(e); - } - } - - IconvLiteEncoderStream.prototype.collect = function(cb) { - var chunks = []; - this.on('error', cb); - this.on('data', function(chunk) { chunks.push(chunk); }); - this.on('end', function() { - cb(null, Buffer.concat(chunks)); - }); - return this; - } - - - // == Decoder stream ======================================================= - - function IconvLiteDecoderStream(conv, options) { - this.conv = conv; - options = options || {}; - options.encoding = this.encoding = 'utf8'; // We output strings. - Transform.call(this, options); - } - - IconvLiteDecoderStream.prototype = Object.create(Transform.prototype, { - constructor: { value: IconvLiteDecoderStream } - }); - - IconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) { - if (!Buffer.isBuffer(chunk) && !(chunk instanceof Uint8Array)) - return done(new Error("Iconv decoding stream needs buffers as its input.")); - try { - var res = this.conv.write(chunk); - if (res && res.length) this.push(res, this.encoding); - done(); - } - catch (e) { - done(e); - } - } - - IconvLiteDecoderStream.prototype._flush = function(done) { - try { - var res = this.conv.end(); - if (res && res.length) this.push(res, this.encoding); - done(); - } - catch (e) { - done(e); - } - } - - IconvLiteDecoderStream.prototype.collect = function(cb) { - var res = ''; - this.on('error', cb); - this.on('data', function(chunk) { res += chunk; }); - this.on('end', function() { - cb(null, res); - }); - return this; - } - - return { - IconvLiteEncoderStream: IconvLiteEncoderStream, - IconvLiteDecoderStream: IconvLiteDecoderStream, - }; -}; - - -/***/ }), - -/***/ 3287: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ value: true })); - -/*! - * is-plain-object - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - -function isObject(o) { - return Object.prototype.toString.call(o) === '[object Object]'; -} - -function isPlainObject(o) { - var ctor,prot; - - if (isObject(o) === false) return false; - - // If has modified constructor - ctor = o.constructor; - if (ctor === undefined) return true; - - // If has modified prototype - prot = ctor.prototype; - if (isObject(prot) === false) return false; - - // If constructor does not have an Object-specific method - if (prot.hasOwnProperty('isPrototypeOf') === false) { - return false; - } - - // Most likely a plain Object - return true; -} - -exports.isPlainObject = isPlainObject; - - -/***/ }), - -/***/ 5902: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var hashClear = __nccwpck_require__(1789), - hashDelete = __nccwpck_require__(712), - hashGet = __nccwpck_require__(5395), - hashHas = __nccwpck_require__(5232), - hashSet = __nccwpck_require__(7320); - -/** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function Hash(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -// Add methods to `Hash`. -Hash.prototype.clear = hashClear; -Hash.prototype['delete'] = hashDelete; -Hash.prototype.get = hashGet; -Hash.prototype.has = hashHas; -Hash.prototype.set = hashSet; - -module.exports = Hash; - - -/***/ }), - -/***/ 6608: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var listCacheClear = __nccwpck_require__(9792), - listCacheDelete = __nccwpck_require__(7716), - listCacheGet = __nccwpck_require__(5789), - listCacheHas = __nccwpck_require__(9386), - listCacheSet = __nccwpck_require__(7399); - -/** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -// Add methods to `ListCache`. -ListCache.prototype.clear = listCacheClear; -ListCache.prototype['delete'] = listCacheDelete; -ListCache.prototype.get = listCacheGet; -ListCache.prototype.has = listCacheHas; -ListCache.prototype.set = listCacheSet; - -module.exports = ListCache; - - -/***/ }), - -/***/ 881: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var getNative = __nccwpck_require__(4479), - root = __nccwpck_require__(9882); - -/* Built-in method references that are verified to be native. */ -var Map = getNative(root, 'Map'); - -module.exports = Map; - - -/***/ }), - -/***/ 938: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var mapCacheClear = __nccwpck_require__(1610), - mapCacheDelete = __nccwpck_require__(6657), - mapCacheGet = __nccwpck_require__(1372), - mapCacheHas = __nccwpck_require__(609), - mapCacheSet = __nccwpck_require__(5582); - -/** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ -function MapCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } -} - -// Add methods to `MapCache`. -MapCache.prototype.clear = mapCacheClear; -MapCache.prototype['delete'] = mapCacheDelete; -MapCache.prototype.get = mapCacheGet; -MapCache.prototype.has = mapCacheHas; -MapCache.prototype.set = mapCacheSet; - -module.exports = MapCache; - - -/***/ }), - -/***/ 9213: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var root = __nccwpck_require__(9882); - -/** Built-in value references. */ -var Symbol = root.Symbol; - -module.exports = Symbol; - - -/***/ }), - -/***/ 4356: -/***/ ((module) => { - -/** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ -function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; -} - -module.exports = arrayMap; - - -/***/ }), - -/***/ 6752: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var eq = __nccwpck_require__(1901); - -/** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ -function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; -} - -module.exports = assocIndexOf; - - -/***/ }), - -/***/ 5758: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var castPath = __nccwpck_require__(2688), - toKey = __nccwpck_require__(9071); - -/** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ -function baseGet(object, path) { - path = castPath(path, object); - - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; -} - -module.exports = baseGet; - - -/***/ }), - -/***/ 7497: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var Symbol = __nccwpck_require__(9213), - getRawTag = __nccwpck_require__(923), - objectToString = __nccwpck_require__(4200); - -/** `Object#toString` result references. */ -var nullTag = '[object Null]', - undefinedTag = '[object Undefined]'; - -/** Built-in value references. */ -var symToStringTag = Symbol ? Symbol.toStringTag : undefined; - -/** - * The base implementation of `getTag` without fallbacks for buggy environments. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ -function baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); -} - -module.exports = baseGetTag; - - -/***/ }), - -/***/ 411: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var isFunction = __nccwpck_require__(7799), - isMasked = __nccwpck_require__(9058), - isObject = __nccwpck_require__(3334), - toSource = __nccwpck_require__(6928); - -/** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ -var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - -/** Used to detect host constructors (Safari). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; - -/** Used for built-in method references. */ -var funcProto = Function.prototype, - objectProto = Object.prototype; - -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); - -/** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ -function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); -} - -module.exports = baseIsNative; - - -/***/ }), - -/***/ 6792: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var Symbol = __nccwpck_require__(9213), - arrayMap = __nccwpck_require__(4356), - isArray = __nccwpck_require__(4869), - isSymbol = __nccwpck_require__(6403); - -/** Used as references for various `Number` constants. */ -var INFINITY = 1 / 0; - -/** Used to convert symbols to primitives and strings. */ -var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - -/** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ -function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; -} - -module.exports = baseToString; - - -/***/ }), - -/***/ 2688: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var isArray = __nccwpck_require__(4869), - isKey = __nccwpck_require__(9084), - stringToPath = __nccwpck_require__(1853), - toString = __nccwpck_require__(2931); - -/** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ -function castPath(value, object) { - if (isArray(value)) { - return value; - } - return isKey(value, object) ? [value] : stringToPath(toString(value)); -} - -module.exports = castPath; - - -/***/ }), - -/***/ 8380: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var root = __nccwpck_require__(9882); - -/** Used to detect overreaching core-js shims. */ -var coreJsData = root['__core-js_shared__']; - -module.exports = coreJsData; - - -/***/ }), - -/***/ 2085: -/***/ ((module) => { - -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -module.exports = freeGlobal; - - -/***/ }), - -/***/ 9980: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var isKeyable = __nccwpck_require__(3308); - -/** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ -function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; -} - -module.exports = getMapData; - - -/***/ }), - -/***/ 4479: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var baseIsNative = __nccwpck_require__(411), - getValue = __nccwpck_require__(3542); - -/** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ -function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; -} - -module.exports = getNative; - - -/***/ }), - -/***/ 923: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var Symbol = __nccwpck_require__(9213); - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var nativeObjectToString = objectProto.toString; - -/** Built-in value references. */ -var symToStringTag = Symbol ? Symbol.toStringTag : undefined; - -/** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. - */ -function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), - tag = value[symToStringTag]; - - try { - value[symToStringTag] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; -} - -module.exports = getRawTag; - - -/***/ }), - -/***/ 3542: -/***/ ((module) => { - -/** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ -function getValue(object, key) { - return object == null ? undefined : object[key]; -} - -module.exports = getValue; - - -/***/ }), - -/***/ 1789: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var nativeCreate = __nccwpck_require__(3041); - -/** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ -function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; -} - -module.exports = hashClear; - - -/***/ }), - -/***/ 712: -/***/ ((module) => { - -/** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; -} - -module.exports = hashDelete; - - -/***/ }), - -/***/ 5395: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var nativeCreate = __nccwpck_require__(3041); - -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED = '__lodash_hash_undefined__'; - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; -} - -module.exports = hashGet; - - -/***/ }), - -/***/ 5232: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var nativeCreate = __nccwpck_require__(3041); - -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); -} - -module.exports = hashHas; - - -/***/ }), - -/***/ 7320: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var nativeCreate = __nccwpck_require__(3041); - -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED = '__lodash_hash_undefined__'; - -/** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ -function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; -} - -module.exports = hashSet; - - -/***/ }), - -/***/ 9084: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var isArray = __nccwpck_require__(4869), - isSymbol = __nccwpck_require__(6403); - -/** Used to match property names within property paths. */ -var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/; - -/** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ -function isKey(value, object) { - if (isArray(value)) { - return false; - } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); -} - -module.exports = isKey; - - -/***/ }), - -/***/ 3308: -/***/ ((module) => { - -/** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ -function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); -} - -module.exports = isKeyable; - - -/***/ }), + + // Encode tables: Unicode -> DBCS. -/***/ 9058: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance. + // Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null. + // Values: >= 0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.). + // == UNASSIGNED -> no conversion found. Output a default char. + // <= SEQ_START -> it's an index in encodeTableSeq, see below. The character starts a sequence. + this.encodeTable = []; + + // `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of + // objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key + // means end of sequence (needed when one sequence is a strict subsequence of another). + // Objects are kept separately from encodeTable to increase performance. + this.encodeTableSeq = []; -var coreJsData = __nccwpck_require__(8380); + // Some chars can be decoded, but need not be encoded. + var skipEncodeChars = {}; + if (codecOptions.encodeSkipVals) + for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) { + var val = codecOptions.encodeSkipVals[i]; + if (typeof val === 'number') + skipEncodeChars[val] = true; + else + for (var j = val.from; j <= val.to; j++) + skipEncodeChars[j] = true; + } + + // Use decode trie to recursively fill out encode tables. + this._fillEncodeTable(0, 0, skipEncodeChars); -/** Used to detect methods masquerading as native. */ -var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; -}()); + // Add more encoding pairs when needed. + if (codecOptions.encodeAdd) { + for (var uChar in codecOptions.encodeAdd) + if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar)) + this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]); + } -/** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ -function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); + this.defCharSB = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)]; + if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?']; + if (this.defCharSB === UNASSIGNED) this.defCharSB = "?".charCodeAt(0); } -module.exports = isMasked; - +DBCSCodec.prototype.encoder = DBCSEncoder; +DBCSCodec.prototype.decoder = DBCSDecoder; -/***/ }), +// Decoder helpers +DBCSCodec.prototype._getDecodeTrieNode = function(addr) { + var bytes = []; + for (; addr > 0; addr >>>= 8) + bytes.push(addr & 0xFF); + if (bytes.length == 0) + bytes.push(0); -/***/ 9792: -/***/ ((module) => { + var node = this.decodeTables[0]; + for (var i = bytes.length-1; i > 0; i--) { // Traverse nodes deeper into the trie. + var val = node[bytes[i]]; -/** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ -function listCacheClear() { - this.__data__ = []; - this.size = 0; + if (val == UNASSIGNED) { // Create new node. + node[bytes[i]] = NODE_START - this.decodeTables.length; + this.decodeTables.push(node = UNASSIGNED_NODE.slice(0)); + } + else if (val <= NODE_START) { // Existing node. + node = this.decodeTables[NODE_START - val]; + } + else + throw new Error("Overwrite byte in " + this.encodingName + ", addr: " + addr.toString(16)); + } + return node; } -module.exports = listCacheClear; - - -/***/ }), -/***/ 7716: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var assocIndexOf = __nccwpck_require__(6752); +DBCSCodec.prototype._addDecodeChunk = function(chunk) { + // First element of chunk is the hex mbcs code where we start. + var curAddr = parseInt(chunk[0], 16); -/** Used for built-in method references. */ -var arrayProto = Array.prototype; + // Choose the decoding node where we'll write our chars. + var writeTable = this._getDecodeTrieNode(curAddr); + curAddr = curAddr & 0xFF; -/** Built-in value references. */ -var splice = arrayProto.splice; + // Write all other elements of the chunk to the table. + for (var k = 1; k < chunk.length; k++) { + var part = chunk[k]; + if (typeof part === "string") { // String, write as-is. + for (var l = 0; l < part.length;) { + var code = part.charCodeAt(l++); + if (0xD800 <= code && code < 0xDC00) { // Decode surrogate + var codeTrail = part.charCodeAt(l++); + if (0xDC00 <= codeTrail && codeTrail < 0xE000) + writeTable[curAddr++] = 0x10000 + (code - 0xD800) * 0x400 + (codeTrail - 0xDC00); + else + throw new Error("Incorrect surrogate pair in " + this.encodingName + " at chunk " + chunk[0]); + } + else if (0x0FF0 < code && code <= 0x0FFF) { // Character sequence (our own encoding used) + var len = 0xFFF - code + 2; + var seq = []; + for (var m = 0; m < len; m++) + seq.push(part.charCodeAt(l++)); // Simple variation: don't support surrogates or subsequences in seq. -/** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); + writeTable[curAddr++] = SEQ_START - this.decodeTableSeq.length; + this.decodeTableSeq.push(seq); + } + else + writeTable[curAddr++] = code; // Basic char + } + } + else if (typeof part === "number") { // Integer, meaning increasing sequence starting with prev character. + var charCode = writeTable[curAddr - 1] + 1; + for (var l = 0; l < part; l++) + writeTable[curAddr++] = charCode++; + } + else + throw new Error("Incorrect type '" + typeof part + "' given in " + this.encodingName + " at chunk " + chunk[0]); + } + if (curAddr > 0xFF) + throw new Error("Incorrect chunk in " + this.encodingName + " at addr " + chunk[0] + ": too long" + curAddr); +} - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; +// Encoder helpers +DBCSCodec.prototype._getEncodeBucket = function(uCode) { + var high = uCode >> 8; // This could be > 0xFF because of astral characters. + if (this.encodeTable[high] === undefined) + this.encodeTable[high] = UNASSIGNED_NODE.slice(0); // Create bucket on demand. + return this.encodeTable[high]; } -module.exports = listCacheDelete; +DBCSCodec.prototype._setEncodeChar = function(uCode, dbcsCode) { + var bucket = this._getEncodeBucket(uCode); + var low = uCode & 0xFF; + if (bucket[low] <= SEQ_START) + this.encodeTableSeq[SEQ_START-bucket[low]][DEF_CHAR] = dbcsCode; // There's already a sequence, set a single-char subsequence of it. + else if (bucket[low] == UNASSIGNED) + bucket[low] = dbcsCode; +} +DBCSCodec.prototype._setEncodeSequence = function(seq, dbcsCode) { + + // Get the root of character tree according to first character of the sequence. + var uCode = seq[0]; + var bucket = this._getEncodeBucket(uCode); + var low = uCode & 0xFF; -/***/ }), + var node; + if (bucket[low] <= SEQ_START) { + // There's already a sequence with - use it. + node = this.encodeTableSeq[SEQ_START-bucket[low]]; + } + else { + // There was no sequence object - allocate a new one. + node = {}; + if (bucket[low] !== UNASSIGNED) node[DEF_CHAR] = bucket[low]; // If a char was set before - make it a single-char subsequence. + bucket[low] = SEQ_START - this.encodeTableSeq.length; + this.encodeTableSeq.push(node); + } -/***/ 5789: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // Traverse the character tree, allocating new nodes as needed. + for (var j = 1; j < seq.length-1; j++) { + var oldVal = node[uCode]; + if (typeof oldVal === 'object') + node = oldVal; + else { + node = node[uCode] = {} + if (oldVal !== undefined) + node[DEF_CHAR] = oldVal + } + } -var assocIndexOf = __nccwpck_require__(6752); + // Set the leaf to given dbcsCode. + uCode = seq[seq.length-1]; + node[uCode] = dbcsCode; +} -/** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); +DBCSCodec.prototype._fillEncodeTable = function(nodeIdx, prefix, skipEncodeChars) { + var node = this.decodeTables[nodeIdx]; + var hasValues = false; + var subNodeEmpty = {}; + for (var i = 0; i < 0x100; i++) { + var uCode = node[i]; + var mbCode = prefix + i; + if (skipEncodeChars[mbCode]) + continue; - return index < 0 ? undefined : data[index][1]; + if (uCode >= 0) { + this._setEncodeChar(uCode, mbCode); + hasValues = true; + } else if (uCode <= NODE_START) { + var subNodeIdx = NODE_START - uCode; + if (!subNodeEmpty[subNodeIdx]) { // Skip empty subtrees (they are too large in gb18030). + var newPrefix = (mbCode << 8) >>> 0; // NOTE: '>>> 0' keeps 32-bit num positive. + if (this._fillEncodeTable(subNodeIdx, newPrefix, skipEncodeChars)) + hasValues = true; + else + subNodeEmpty[subNodeIdx] = true; + } + } else if (uCode <= SEQ_START) { + this._setEncodeSequence(this.decodeTableSeq[SEQ_START - uCode], mbCode); + hasValues = true; + } + } + return hasValues; } -module.exports = listCacheGet; -/***/ }), +// == Encoder ================================================================== -/***/ 9386: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +function DBCSEncoder(options, codec) { + // Encoder state + this.leadSurrogate = -1; + this.seqObj = undefined; + + // Static data + this.encodeTable = codec.encodeTable; + this.encodeTableSeq = codec.encodeTableSeq; + this.defaultCharSingleByte = codec.defCharSB; + this.gb18030 = codec.gb18030; +} -var assocIndexOf = __nccwpck_require__(6752); +DBCSEncoder.prototype.write = function(str) { + var newBuf = Buffer.alloc(str.length * (this.gb18030 ? 4 : 3)), + leadSurrogate = this.leadSurrogate, + seqObj = this.seqObj, nextChar = -1, + i = 0, j = 0; -/** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; -} + while (true) { + // 0. Get next character. + if (nextChar === -1) { + if (i == str.length) break; + var uCode = str.charCodeAt(i++); + } + else { + var uCode = nextChar; + nextChar = -1; + } -module.exports = listCacheHas; + // 1. Handle surrogates. + if (0xD800 <= uCode && uCode < 0xE000) { // Char is one of surrogates. + if (uCode < 0xDC00) { // We've got lead surrogate. + if (leadSurrogate === -1) { + leadSurrogate = uCode; + continue; + } else { + leadSurrogate = uCode; + // Double lead surrogate found. + uCode = UNASSIGNED; + } + } else { // We've got trail surrogate. + if (leadSurrogate !== -1) { + uCode = 0x10000 + (leadSurrogate - 0xD800) * 0x400 + (uCode - 0xDC00); + leadSurrogate = -1; + } else { + // Incomplete surrogate pair - only trail surrogate found. + uCode = UNASSIGNED; + } + + } + } + else if (leadSurrogate !== -1) { + // Incomplete surrogate pair - only lead surrogate found. + nextChar = uCode; uCode = UNASSIGNED; // Write an error, then current char. + leadSurrogate = -1; + } + + // 2. Convert uCode character. + var dbcsCode = UNASSIGNED; + if (seqObj !== undefined && uCode != UNASSIGNED) { // We are in the middle of the sequence + var resCode = seqObj[uCode]; + if (typeof resCode === 'object') { // Sequence continues. + seqObj = resCode; + continue; + } else if (typeof resCode == 'number') { // Sequence finished. Write it. + dbcsCode = resCode; -/***/ }), + } else if (resCode == undefined) { // Current character is not part of the sequence. -/***/ 7399: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // Try default character for this sequence + resCode = seqObj[DEF_CHAR]; + if (resCode !== undefined) { + dbcsCode = resCode; // Found. Write it. + nextChar = uCode; // Current character will be written too in the next iteration. -var assocIndexOf = __nccwpck_require__(6752); + } else { + // TODO: What if we have no default? (resCode == undefined) + // Then, we should write first char of the sequence as-is and try the rest recursively. + // Didn't do it for now because no encoding has this situation yet. + // Currently, just skip the sequence and write current char. + } + } + seqObj = undefined; + } + else if (uCode >= 0) { // Regular character + var subtable = this.encodeTable[uCode >> 8]; + if (subtable !== undefined) + dbcsCode = subtable[uCode & 0xFF]; + + if (dbcsCode <= SEQ_START) { // Sequence start + seqObj = this.encodeTableSeq[SEQ_START-dbcsCode]; + continue; + } -/** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ -function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); + if (dbcsCode == UNASSIGNED && this.gb18030) { + // Use GB18030 algorithm to find character(s) to write. + var idx = findIdx(this.gb18030.uChars, uCode); + if (idx != -1) { + var dbcsCode = this.gb18030.gbChars[idx] + (uCode - this.gb18030.uChars[idx]); + newBuf[j++] = 0x81 + Math.floor(dbcsCode / 12600); dbcsCode = dbcsCode % 12600; + newBuf[j++] = 0x30 + Math.floor(dbcsCode / 1260); dbcsCode = dbcsCode % 1260; + newBuf[j++] = 0x81 + Math.floor(dbcsCode / 10); dbcsCode = dbcsCode % 10; + newBuf[j++] = 0x30 + dbcsCode; + continue; + } + } + } + + // 3. Write dbcsCode character. + if (dbcsCode === UNASSIGNED) + dbcsCode = this.defaultCharSingleByte; + + if (dbcsCode < 0x100) { + newBuf[j++] = dbcsCode; + } + else if (dbcsCode < 0x10000) { + newBuf[j++] = dbcsCode >> 8; // high byte + newBuf[j++] = dbcsCode & 0xFF; // low byte + } + else if (dbcsCode < 0x1000000) { + newBuf[j++] = dbcsCode >> 16; + newBuf[j++] = (dbcsCode >> 8) & 0xFF; + newBuf[j++] = dbcsCode & 0xFF; + } else { + newBuf[j++] = dbcsCode >>> 24; + newBuf[j++] = (dbcsCode >>> 16) & 0xFF; + newBuf[j++] = (dbcsCode >>> 8) & 0xFF; + newBuf[j++] = dbcsCode & 0xFF; + } + } - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; + this.seqObj = seqObj; + this.leadSurrogate = leadSurrogate; + return newBuf.slice(0, j); } -module.exports = listCacheSet; +DBCSEncoder.prototype.end = function() { + if (this.leadSurrogate === -1 && this.seqObj === undefined) + return; // All clean. Most often case. + var newBuf = Buffer.alloc(10), j = 0; -/***/ }), + if (this.seqObj) { // We're in the sequence. + var dbcsCode = this.seqObj[DEF_CHAR]; + if (dbcsCode !== undefined) { // Write beginning of the sequence. + if (dbcsCode < 0x100) { + newBuf[j++] = dbcsCode; + } + else { + newBuf[j++] = dbcsCode >> 8; // high byte + newBuf[j++] = dbcsCode & 0xFF; // low byte + } + } else { + // See todo above. + } + this.seqObj = undefined; + } -/***/ 1610: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + if (this.leadSurrogate !== -1) { + // Incomplete surrogate pair - only lead surrogate found. + newBuf[j++] = this.defaultCharSingleByte; + this.leadSurrogate = -1; + } + + return newBuf.slice(0, j); +} -var Hash = __nccwpck_require__(5902), - ListCache = __nccwpck_require__(6608), - Map = __nccwpck_require__(881); +// Export for testing +DBCSEncoder.prototype.findIdx = findIdx; -/** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ -function mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; -} -module.exports = mapCacheClear; +// == Decoder ================================================================== +function DBCSDecoder(options, codec) { + // Decoder state + this.nodeIdx = 0; + this.prevBytes = []; -/***/ }), + // Static data + this.decodeTables = codec.decodeTables; + this.decodeTableSeq = codec.decodeTableSeq; + this.defaultCharUnicode = codec.defaultCharUnicode; + this.gb18030 = codec.gb18030; +} -/***/ 6657: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +DBCSDecoder.prototype.write = function(buf) { + var newBuf = Buffer.alloc(buf.length*2), + nodeIdx = this.nodeIdx, + prevBytes = this.prevBytes, prevOffset = this.prevBytes.length, + seqStart = -this.prevBytes.length, // idx of the start of current parsed sequence. + uCode; -var getMapData = __nccwpck_require__(9980); + for (var i = 0, j = 0; i < buf.length; i++) { + var curByte = (i >= 0) ? buf[i] : prevBytes[i + prevOffset]; -/** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ -function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; -} + // Lookup in current trie node. + var uCode = this.decodeTables[nodeIdx][curByte]; -module.exports = mapCacheDelete; + if (uCode >= 0) { + // Normal character, just use it. + } + else if (uCode === UNASSIGNED) { // Unknown char. + // TODO: Callback with seq. + uCode = this.defaultCharUnicode.charCodeAt(0); + i = seqStart; // Skip one byte ('i' will be incremented by the for loop) and try to parse again. + } + else if (uCode === GB18030_CODE) { + if (i >= 3) { + var ptr = (buf[i-3]-0x81)*12600 + (buf[i-2]-0x30)*1260 + (buf[i-1]-0x81)*10 + (curByte-0x30); + } else { + var ptr = (prevBytes[i-3+prevOffset]-0x81)*12600 + + (((i-2 >= 0) ? buf[i-2] : prevBytes[i-2+prevOffset])-0x30)*1260 + + (((i-1 >= 0) ? buf[i-1] : prevBytes[i-1+prevOffset])-0x81)*10 + + (curByte-0x30); + } + var idx = findIdx(this.gb18030.gbChars, ptr); + uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx]; + } + else if (uCode <= NODE_START) { // Go to next trie node. + nodeIdx = NODE_START - uCode; + continue; + } + else if (uCode <= SEQ_START) { // Output a sequence of chars. + var seq = this.decodeTableSeq[SEQ_START - uCode]; + for (var k = 0; k < seq.length - 1; k++) { + uCode = seq[k]; + newBuf[j++] = uCode & 0xFF; + newBuf[j++] = uCode >> 8; + } + uCode = seq[seq.length-1]; + } + else + throw new Error("iconv-lite internal error: invalid decoding table value " + uCode + " at " + nodeIdx + "/" + curByte); + // Write the character to buffer, handling higher planes using surrogate pair. + if (uCode >= 0x10000) { + uCode -= 0x10000; + var uCodeLead = 0xD800 | (uCode >> 10); + newBuf[j++] = uCodeLead & 0xFF; + newBuf[j++] = uCodeLead >> 8; -/***/ }), + uCode = 0xDC00 | (uCode & 0x3FF); + } + newBuf[j++] = uCode & 0xFF; + newBuf[j++] = uCode >> 8; -/***/ 1372: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // Reset trie node. + nodeIdx = 0; seqStart = i+1; + } -var getMapData = __nccwpck_require__(9980); + this.nodeIdx = nodeIdx; + this.prevBytes = (seqStart >= 0) + ? Array.prototype.slice.call(buf, seqStart) + : prevBytes.slice(seqStart + prevOffset).concat(Array.prototype.slice.call(buf)); -/** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ -function mapCacheGet(key) { - return getMapData(this, key).get(key); + return newBuf.slice(0, j).toString('ucs2'); } -module.exports = mapCacheGet; +DBCSDecoder.prototype.end = function() { + var ret = ''; + // Try to parse all remaining chars. + while (this.prevBytes.length > 0) { + // Skip 1 character in the buffer. + ret += this.defaultCharUnicode; + var bytesArr = this.prevBytes.slice(1); -/***/ }), + // Parse remaining as usual. + this.prevBytes = []; + this.nodeIdx = 0; + if (bytesArr.length > 0) + ret += this.write(bytesArr); + } -/***/ 609: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + this.prevBytes = []; + this.nodeIdx = 0; + return ret; +} -var getMapData = __nccwpck_require__(9980); +// Binary search for GB18030. Returns largest i such that table[i] <= val. +function findIdx(table, val) { + if (table[0] > val) + return -1; -/** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ -function mapCacheHas(key) { - return getMapData(this, key).has(key); + var l = 0, r = table.length; + while (l < r-1) { // always table[l] <= val < table[r] + var mid = l + ((r-l+1) >> 1); + if (table[mid] <= val) + l = mid; + else + r = mid; + } + return l; } -module.exports = mapCacheHas; /***/ }), -/***/ 5582: +/***/ 1386: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -var getMapData = __nccwpck_require__(9980); - -/** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ -function mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; -} - -module.exports = mapCacheSet; +"use strict"; -/***/ }), +// Description of supported double byte encodings and aliases. +// Tables are not require()-d until they are needed to speed up library load. +// require()-s are direct to support Browserify. -/***/ 9422: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +module.exports = { + + // == Japanese/ShiftJIS ==================================================== + // All japanese encodings are based on JIS X set of standards: + // JIS X 0201 - Single-byte encoding of ASCII + ¥ + Kana chars at 0xA1-0xDF. + // JIS X 0208 - Main set of 6879 characters, placed in 94x94 plane, to be encoded by 2 bytes. + // Has several variations in 1978, 1983, 1990 and 1997. + // JIS X 0212 - Supplementary plane of 6067 chars in 94x94 plane. 1990. Effectively dead. + // JIS X 0213 - Extension and modern replacement of 0208 and 0212. Total chars: 11233. + // 2 planes, first is superset of 0208, second - revised 0212. + // Introduced in 2000, revised 2004. Some characters are in Unicode Plane 2 (0x2xxxx) -var memoize = __nccwpck_require__(9885); + // Byte encodings are: + // * Shift_JIS: Compatible with 0201, uses not defined chars in top half as lead bytes for double-byte + // encoding of 0208. Lead byte ranges: 0x81-0x9F, 0xE0-0xEF; Trail byte ranges: 0x40-0x7E, 0x80-0x9E, 0x9F-0xFC. + // Windows CP932 is a superset of Shift_JIS. Some companies added more chars, notably KDDI. + // * EUC-JP: Up to 3 bytes per character. Used mostly on *nixes. + // 0x00-0x7F - lower part of 0201 + // 0x8E, 0xA1-0xDF - upper part of 0201 + // (0xA1-0xFE)x2 - 0208 plane (94x94). + // 0x8F, (0xA1-0xFE)x2 - 0212 plane (94x94). + // * JIS X 208: 7-bit, direct encoding of 0208. Byte ranges: 0x21-0x7E (94 values). Uncommon. + // Used as-is in ISO2022 family. + // * ISO2022-JP: Stateful encoding, with escape sequences to switch between ASCII, + // 0201-1976 Roman, 0208-1978, 0208-1983. + // * ISO2022-JP-1: Adds esc seq for 0212-1990. + // * ISO2022-JP-2: Adds esc seq for GB2313-1980, KSX1001-1992, ISO8859-1, ISO8859-7. + // * ISO2022-JP-3: Adds esc seq for 0201-1976 Kana set, 0213-2000 Planes 1, 2. + // * ISO2022-JP-2004: Adds 0213-2004 Plane 1. + // + // After JIS X 0213 appeared, Shift_JIS-2004, EUC-JISX0213 and ISO2022-JP-2004 followed, with just changing the planes. + // + // Overall, it seems that it's a mess :( http://www8.plala.or.jp/tkubota1/unicode-symbols-map2.html -/** Used as the maximum memoize cache size. */ -var MAX_MEMOIZE_SIZE = 500; + 'shiftjis': { + type: '_dbcs', + table: function() { return __nccwpck_require__(7014) }, + encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E}, + encodeSkipVals: [{from: 0xED40, to: 0xF940}], + }, + 'csshiftjis': 'shiftjis', + 'mskanji': 'shiftjis', + 'sjis': 'shiftjis', + 'windows31j': 'shiftjis', + 'ms31j': 'shiftjis', + 'xsjis': 'shiftjis', + 'windows932': 'shiftjis', + 'ms932': 'shiftjis', + '932': 'shiftjis', + 'cp932': 'shiftjis', -/** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. - * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. - */ -function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; - }); + 'eucjp': { + type: '_dbcs', + table: function() { return __nccwpck_require__(1532) }, + encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E}, + }, - var cache = result.cache; - return result; -} + // TODO: KDDI extension to Shift_JIS + // TODO: IBM CCSID 942 = CP932, but F0-F9 custom chars and other char changes. + // TODO: IBM CCSID 943 = Shift_JIS = CP932 with original Shift_JIS lower 128 chars. -module.exports = memoizeCapped; + // == Chinese/GBK ========================================================== + // http://en.wikipedia.org/wiki/GBK + // We mostly implement W3C recommendation: https://www.w3.org/TR/encoding/#gbk-encoder -/***/ }), + // Oldest GB2312 (1981, ~7600 chars) is a subset of CP936 + 'gb2312': 'cp936', + 'gb231280': 'cp936', + 'gb23121980': 'cp936', + 'csgb2312': 'cp936', + 'csiso58gb231280': 'cp936', + 'euccn': 'cp936', -/***/ 3041: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + // Microsoft's CP936 is a subset and approximation of GBK. + 'windows936': 'cp936', + 'ms936': 'cp936', + '936': 'cp936', + 'cp936': { + type: '_dbcs', + table: function() { return __nccwpck_require__(3336) }, + }, -var getNative = __nccwpck_require__(4479); + // GBK (~22000 chars) is an extension of CP936 that added user-mapped chars and some other. + 'gbk': { + type: '_dbcs', + table: function() { return (__nccwpck_require__(3336).concat)(__nccwpck_require__(4346)) }, + }, + 'xgbk': 'gbk', + 'isoir58': 'gbk', -/* Built-in method references that are verified to be native. */ -var nativeCreate = getNative(Object, 'create'); + // GB18030 is an algorithmic extension of GBK. + // Main source: https://www.w3.org/TR/encoding/#gbk-encoder + // http://icu-project.org/docs/papers/gb18030.html + // http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/gb-18030-2000.xml + // http://www.khngai.com/chinese/charmap/tblgbk.php?page=0 + 'gb18030': { + type: '_dbcs', + table: function() { return (__nccwpck_require__(3336).concat)(__nccwpck_require__(4346)) }, + gb18030: function() { return __nccwpck_require__(6258) }, + encodeSkipVals: [0x80], + encodeAdd: {'€': 0xA2E3}, + }, -module.exports = nativeCreate; + 'chinese': 'gb18030', -/***/ }), + // == Korean =============================================================== + // EUC-KR, KS_C_5601 and KS X 1001 are exactly the same. + 'windows949': 'cp949', + 'ms949': 'cp949', + '949': 'cp949', + 'cp949': { + type: '_dbcs', + table: function() { return __nccwpck_require__(7348) }, + }, -/***/ 4200: -/***/ ((module) => { + 'cseuckr': 'cp949', + 'csksc56011987': 'cp949', + 'euckr': 'cp949', + 'isoir149': 'cp949', + 'korean': 'cp949', + 'ksc56011987': 'cp949', + 'ksc56011989': 'cp949', + 'ksc5601': 'cp949', -/** Used for built-in method references. */ -var objectProto = Object.prototype; -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var nativeObjectToString = objectProto.toString; + // == Big5/Taiwan/Hong Kong ================================================ + // There are lots of tables for Big5 and cp950. Please see the following links for history: + // http://moztw.org/docs/big5/ http://www.haible.de/bruno/charsets/conversion-tables/Big5.html + // Variations, in roughly number of defined chars: + // * Windows CP 950: Microsoft variant of Big5. Canonical: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT + // * Windows CP 951: Microsoft variant of Big5-HKSCS-2001. Seems to be never public. http://me.abelcheung.org/articles/research/what-is-cp951/ + // * Big5-2003 (Taiwan standard) almost superset of cp950. + // * Unicode-at-on (UAO) / Mozilla 1.8. Falling out of use on the Web. Not supported by other browsers. + // * Big5-HKSCS (-2001, -2004, -2008). Hong Kong standard. + // many unicode code points moved from PUA to Supplementary plane (U+2XXXX) over the years. + // Plus, it has 4 combining sequences. + // Seems that Mozilla refused to support it for 10 yrs. https://bugzilla.mozilla.org/show_bug.cgi?id=162431 https://bugzilla.mozilla.org/show_bug.cgi?id=310299 + // because big5-hkscs is the only encoding to include astral characters in non-algorithmic way. + // Implementations are not consistent within browsers; sometimes labeled as just big5. + // MS Internet Explorer switches from big5 to big5-hkscs when a patch applied. + // Great discussion & recap of what's going on https://bugzilla.mozilla.org/show_bug.cgi?id=912470#c31 + // In the encoder, it might make sense to support encoding old PUA mappings to Big5 bytes seq-s. + // Official spec: http://www.ogcio.gov.hk/en/business/tech_promotion/ccli/terms/doc/2003cmp_2008.txt + // http://www.ogcio.gov.hk/tc/business/tech_promotion/ccli/terms/doc/hkscs-2008-big5-iso.txt + // + // Current understanding of how to deal with Big5(-HKSCS) is in the Encoding Standard, http://encoding.spec.whatwg.org/#big5-encoder + // Unicode mapping (http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT) is said to be wrong. -/** - * Converts `value` to a string using `Object.prototype.toString`. - * - * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - */ -function objectToString(value) { - return nativeObjectToString.call(value); -} + 'windows950': 'cp950', + 'ms950': 'cp950', + '950': 'cp950', + 'cp950': { + type: '_dbcs', + table: function() { return __nccwpck_require__(4284) }, + }, -module.exports = objectToString; + // Big5 has many variations and is an extension of cp950. We use Encoding Standard's as a consensus. + 'big5': 'big5hkscs', + 'big5hkscs': { + type: '_dbcs', + table: function() { return (__nccwpck_require__(4284).concat)(__nccwpck_require__(3480)) }, + encodeSkipVals: [ + // Although Encoding Standard says we should avoid encoding to HKSCS area (See Step 1 of + // https://encoding.spec.whatwg.org/#index-big5-pointer), we still do it to increase compatibility with ICU. + // But if a single unicode point can be encoded both as HKSCS and regular Big5, we prefer the latter. + 0x8e69, 0x8e6f, 0x8e7e, 0x8eab, 0x8eb4, 0x8ecd, 0x8ed0, 0x8f57, 0x8f69, 0x8f6e, 0x8fcb, 0x8ffe, + 0x906d, 0x907a, 0x90c4, 0x90dc, 0x90f1, 0x91bf, 0x92af, 0x92b0, 0x92b1, 0x92b2, 0x92d1, 0x9447, 0x94ca, + 0x95d9, 0x96fc, 0x9975, 0x9b76, 0x9b78, 0x9b7b, 0x9bc6, 0x9bde, 0x9bec, 0x9bf6, 0x9c42, 0x9c53, 0x9c62, + 0x9c68, 0x9c6b, 0x9c77, 0x9cbc, 0x9cbd, 0x9cd0, 0x9d57, 0x9d5a, 0x9dc4, 0x9def, 0x9dfb, 0x9ea9, 0x9eef, + 0x9efd, 0x9f60, 0x9fcb, 0xa077, 0xa0dc, 0xa0df, 0x8fcc, 0x92c8, 0x9644, 0x96ed, + + // Step 2 of https://encoding.spec.whatwg.org/#index-big5-pointer: Use last pointer for U+2550, U+255E, U+2561, U+256A, U+5341, or U+5345 + 0xa2a4, 0xa2a5, 0xa2a7, 0xa2a6, 0xa2cc, 0xa2ce, + ], + }, + + 'cnbig5': 'big5hkscs', + 'csbig5': 'big5hkscs', + 'xxbig5': 'big5hkscs', +}; /***/ }), -/***/ 9882: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ 2733: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { -var freeGlobal = __nccwpck_require__(2085); +"use strict"; -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); +// Update this array if you add/rename/remove files in this directory. +// We support Browserify by skipping automatic module discovery and requiring modules directly. +var modules = [ + __nccwpck_require__(2376), + __nccwpck_require__(9557), + __nccwpck_require__(1155), + __nccwpck_require__(1644), + __nccwpck_require__(373), + __nccwpck_require__(1080), + __nccwpck_require__(1012), + __nccwpck_require__(9695), + __nccwpck_require__(1386), +]; -module.exports = root; +// Put all encoding/alias/codec definitions to single object and export it. +for (var i = 0; i < modules.length; i++) { + var module = modules[i]; + for (var enc in module) + if (Object.prototype.hasOwnProperty.call(module, enc)) + exports[enc] = module[enc]; +} /***/ }), -/***/ 1853: +/***/ 2376: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -var memoizeCapped = __nccwpck_require__(9422); +"use strict"; -/** Used to match property names within property paths. */ -var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; +var Buffer = (__nccwpck_require__(5118).Buffer); -/** Used to match backslashes in property paths. */ -var reEscapeChar = /\\(\\)?/g; +// Export Node.js internal encodings. -/** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ -var stringToPath = memoizeCapped(function(string) { - var result = []; - if (string.charCodeAt(0) === 46 /* . */) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, subString) { - result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; -}); +module.exports = { + // Encodings + utf8: { type: "_internal", bomAware: true}, + cesu8: { type: "_internal", bomAware: true}, + unicode11utf8: "utf8", -module.exports = stringToPath; + ucs2: { type: "_internal", bomAware: true}, + utf16le: "ucs2", + binary: { type: "_internal" }, + base64: { type: "_internal" }, + hex: { type: "_internal" }, -/***/ }), + // Codec. + _internal: InternalCodec, +}; -/***/ 9071: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +//------------------------------------------------------------------------------ -var isSymbol = __nccwpck_require__(6403); +function InternalCodec(codecOptions, iconv) { + this.enc = codecOptions.encodingName; + this.bomAware = codecOptions.bomAware; -/** Used as references for various `Number` constants. */ -var INFINITY = 1 / 0; + if (this.enc === "base64") + this.encoder = InternalEncoderBase64; + else if (this.enc === "cesu8") { + this.enc = "utf8"; // Use utf8 for decoding. + this.encoder = InternalEncoderCesu8; -/** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ -function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + // Add decoder for versions of Node not supporting CESU-8 + if (Buffer.from('eda0bdedb2a9', 'hex').toString() !== '💩') { + this.decoder = InternalDecoderCesu8; + this.defaultCharUnicode = iconv.defaultCharUnicode; + } + } } -module.exports = toKey; - +InternalCodec.prototype.encoder = InternalEncoder; +InternalCodec.prototype.decoder = InternalDecoder; -/***/ }), +//------------------------------------------------------------------------------ -/***/ 6928: -/***/ ((module) => { +// We use node.js internal decoder. Its signature is the same as ours. +var StringDecoder = (__nccwpck_require__(1576).StringDecoder); -/** Used for built-in method references. */ -var funcProto = Function.prototype; +if (!StringDecoder.prototype.end) // Node v0.8 doesn't have this method. + StringDecoder.prototype.end = function() {}; -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; -/** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. - */ -function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; +function InternalDecoder(options, codec) { + this.decoder = new StringDecoder(codec.enc); } -module.exports = toSource; +InternalDecoder.prototype.write = function(buf) { + if (!Buffer.isBuffer(buf)) { + buf = Buffer.from(buf); + } + return this.decoder.write(buf); +} -/***/ }), +InternalDecoder.prototype.end = function() { + return this.decoder.end(); +} -/***/ 1901: -/***/ ((module) => { -/** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ -function eq(value, other) { - return value === other || (value !== value && other !== other); -} +//------------------------------------------------------------------------------ +// Encoder is mostly trivial -module.exports = eq; +function InternalEncoder(options, codec) { + this.enc = codec.enc; +} +InternalEncoder.prototype.write = function(str) { + return Buffer.from(str, this.enc); +} -/***/ }), +InternalEncoder.prototype.end = function() { +} -/***/ 6908: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -var baseGet = __nccwpck_require__(5758); +//------------------------------------------------------------------------------ +// Except base64 encoder, which must keep its state. -/** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ -function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); - return result === undefined ? defaultValue : result; +function InternalEncoderBase64(options, codec) { + this.prevStr = ''; } -module.exports = get; +InternalEncoderBase64.prototype.write = function(str) { + str = this.prevStr + str; + var completeQuads = str.length - (str.length % 4); + this.prevStr = str.slice(completeQuads); + str = str.slice(0, completeQuads); + return Buffer.from(str, "base64"); +} -/***/ }), +InternalEncoderBase64.prototype.end = function() { + return Buffer.from(this.prevStr, "base64"); +} -/***/ 4869: -/***/ ((module) => { -/** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ -var isArray = Array.isArray; +//------------------------------------------------------------------------------ +// CESU-8 encoder is also special. -module.exports = isArray; +function InternalEncoderCesu8(options, codec) { +} +InternalEncoderCesu8.prototype.write = function(str) { + var buf = Buffer.alloc(str.length * 3), bufIdx = 0; + for (var i = 0; i < str.length; i++) { + var charCode = str.charCodeAt(i); + // Naive implementation, but it works because CESU-8 is especially easy + // to convert from UTF-16 (which all JS strings are encoded in). + if (charCode < 0x80) + buf[bufIdx++] = charCode; + else if (charCode < 0x800) { + buf[bufIdx++] = 0xC0 + (charCode >>> 6); + buf[bufIdx++] = 0x80 + (charCode & 0x3f); + } + else { // charCode will always be < 0x10000 in javascript. + buf[bufIdx++] = 0xE0 + (charCode >>> 12); + buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f); + buf[bufIdx++] = 0x80 + (charCode & 0x3f); + } + } + return buf.slice(0, bufIdx); +} -/***/ }), +InternalEncoderCesu8.prototype.end = function() { +} -/***/ 7799: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +//------------------------------------------------------------------------------ +// CESU-8 decoder is not implemented in Node v4.0+ -var baseGetTag = __nccwpck_require__(7497), - isObject = __nccwpck_require__(3334); +function InternalDecoderCesu8(options, codec) { + this.acc = 0; + this.contBytes = 0; + this.accBytes = 0; + this.defaultCharUnicode = codec.defaultCharUnicode; +} -/** `Object#toString` result references. */ -var asyncTag = '[object AsyncFunction]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - proxyTag = '[object Proxy]'; +InternalDecoderCesu8.prototype.write = function(buf) { + var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes, + res = ''; + for (var i = 0; i < buf.length; i++) { + var curByte = buf[i]; + if ((curByte & 0xC0) !== 0x80) { // Leading byte + if (contBytes > 0) { // Previous code is invalid + res += this.defaultCharUnicode; + contBytes = 0; + } -/** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ -function isFunction(value) { - if (!isObject(value)) { - return false; - } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + if (curByte < 0x80) { // Single-byte code + res += String.fromCharCode(curByte); + } else if (curByte < 0xE0) { // Two-byte code + acc = curByte & 0x1F; + contBytes = 1; accBytes = 1; + } else if (curByte < 0xF0) { // Three-byte code + acc = curByte & 0x0F; + contBytes = 2; accBytes = 1; + } else { // Four or more are not supported for CESU-8. + res += this.defaultCharUnicode; + } + } else { // Continuation byte + if (contBytes > 0) { // We're waiting for it. + acc = (acc << 6) | (curByte & 0x3f); + contBytes--; accBytes++; + if (contBytes === 0) { + // Check for overlong encoding, but support Modified UTF-8 (encoding NULL as C0 80) + if (accBytes === 2 && acc < 0x80 && acc > 0) + res += this.defaultCharUnicode; + else if (accBytes === 3 && acc < 0x800) + res += this.defaultCharUnicode; + else + // Actually add character. + res += String.fromCharCode(acc); + } + } else { // Unexpected continuation byte + res += this.defaultCharUnicode; + } + } + } + this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes; + return res; } -module.exports = isFunction; +InternalDecoderCesu8.prototype.end = function() { + var res = 0; + if (this.contBytes > 0) + res += this.defaultCharUnicode; + return res; +} /***/ }), -/***/ 3334: -/***/ ((module) => { +/***/ 373: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { -/** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ -function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); -} +"use strict"; -module.exports = isObject; +var Buffer = (__nccwpck_require__(5118).Buffer); +// Single-byte codec. Needs a 'chars' string parameter that contains 256 or 128 chars that +// correspond to encoded bytes (if 128 - then lower half is ASCII). -/***/ }), +exports._sbcs = SBCSCodec; +function SBCSCodec(codecOptions, iconv) { + if (!codecOptions) + throw new Error("SBCS codec is called without the data.") + + // Prepare char buffer for decoding. + if (!codecOptions.chars || (codecOptions.chars.length !== 128 && codecOptions.chars.length !== 256)) + throw new Error("Encoding '"+codecOptions.type+"' has incorrect 'chars' (must be of len 128 or 256)"); + + if (codecOptions.chars.length === 128) { + var asciiString = ""; + for (var i = 0; i < 128; i++) + asciiString += String.fromCharCode(i); + codecOptions.chars = asciiString + codecOptions.chars; + } -/***/ 5926: -/***/ ((module) => { + this.decodeBuf = Buffer.from(codecOptions.chars, 'ucs2'); + + // Encoding buffer. + var encodeBuf = Buffer.alloc(65536, iconv.defaultCharSingleByte.charCodeAt(0)); -/** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ -function isObjectLike(value) { - return value != null && typeof value == 'object'; + for (var i = 0; i < codecOptions.chars.length; i++) + encodeBuf[codecOptions.chars.charCodeAt(i)] = i; + + this.encodeBuf = encodeBuf; } -module.exports = isObjectLike; +SBCSCodec.prototype.encoder = SBCSEncoder; +SBCSCodec.prototype.decoder = SBCSDecoder; -/***/ }), +function SBCSEncoder(options, codec) { + this.encodeBuf = codec.encodeBuf; +} -/***/ 6403: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +SBCSEncoder.prototype.write = function(str) { + var buf = Buffer.alloc(str.length); + for (var i = 0; i < str.length; i++) + buf[i] = this.encodeBuf[str.charCodeAt(i)]; + + return buf; +} -var baseGetTag = __nccwpck_require__(7497), - isObjectLike = __nccwpck_require__(5926); +SBCSEncoder.prototype.end = function() { +} -/** `Object#toString` result references. */ -var symbolTag = '[object Symbol]'; -/** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ -function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); +function SBCSDecoder(options, codec) { + this.decodeBuf = codec.decodeBuf; } -module.exports = isSymbol; +SBCSDecoder.prototype.write = function(buf) { + // Strings are immutable in JS -> we use ucs2 buffer to speed up computations. + var decodeBuf = this.decodeBuf; + var newBuf = Buffer.alloc(buf.length*2); + var idx1 = 0, idx2 = 0; + for (var i = 0; i < buf.length; i++) { + idx1 = buf[i]*2; idx2 = i*2; + newBuf[idx2] = decodeBuf[idx1]; + newBuf[idx2+1] = decodeBuf[idx1+1]; + } + return newBuf.toString('ucs2'); +} +SBCSDecoder.prototype.end = function() { +} -/***/ }), -/***/ 9885: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { +/***/ }), -var MapCache = __nccwpck_require__(938); +/***/ 1012: +/***/ ((module) => { -/** Error message constants. */ -var FUNC_ERROR_TEXT = 'Expected a function'; +"use strict"; -/** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoized function. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] - * - * object.a = 2; - * values(object); - * // => [1, 2] - * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] - * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ -function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; +// Generated data for sbcs codec. Don't edit manually. Regenerate using generation/gen-sbcs.js script. +module.exports = { + "437": "cp437", + "737": "cp737", + "775": "cp775", + "850": "cp850", + "852": "cp852", + "855": "cp855", + "856": "cp856", + "857": "cp857", + "858": "cp858", + "860": "cp860", + "861": "cp861", + "862": "cp862", + "863": "cp863", + "864": "cp864", + "865": "cp865", + "866": "cp866", + "869": "cp869", + "874": "windows874", + "922": "cp922", + "1046": "cp1046", + "1124": "cp1124", + "1125": "cp1125", + "1129": "cp1129", + "1133": "cp1133", + "1161": "cp1161", + "1162": "cp1162", + "1163": "cp1163", + "1250": "windows1250", + "1251": "windows1251", + "1252": "windows1252", + "1253": "windows1253", + "1254": "windows1254", + "1255": "windows1255", + "1256": "windows1256", + "1257": "windows1257", + "1258": "windows1258", + "28591": "iso88591", + "28592": "iso88592", + "28593": "iso88593", + "28594": "iso88594", + "28595": "iso88595", + "28596": "iso88596", + "28597": "iso88597", + "28598": "iso88598", + "28599": "iso88599", + "28600": "iso885910", + "28601": "iso885911", + "28603": "iso885913", + "28604": "iso885914", + "28605": "iso885915", + "28606": "iso885916", + "windows874": { + "type": "_sbcs", + "chars": "€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" + }, + "win874": "windows874", + "cp874": "windows874", + "windows1250": { + "type": "_sbcs", + "chars": "€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙" + }, + "win1250": "windows1250", + "cp1250": "windows1250", + "windows1251": { + "type": "_sbcs", + "chars": "ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя" + }, + "win1251": "windows1251", + "cp1251": "windows1251", + "windows1252": { + "type": "_sbcs", + "chars": "€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + }, + "win1252": "windows1252", + "cp1252": "windows1252", + "windows1253": { + "type": "_sbcs", + "chars": "€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬­®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�" + }, + "win1253": "windows1253", + "cp1253": "windows1253", + "windows1254": { + "type": "_sbcs", + "chars": "€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ" + }, + "win1254": "windows1254", + "cp1254": "windows1254", + "windows1255": { + "type": "_sbcs", + "chars": "€�‚ƒ„…†‡ˆ‰�‹�����‘’“”•–—˜™�›���� ¡¢£₪¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾¿ְֱֲֳִֵֶַָֹֺֻּֽ־ֿ׀ׁׂ׃װױײ׳״�������אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�" + }, + "win1255": "windows1255", + "cp1255": "windows1255", + "windows1256": { + "type": "_sbcs", + "chars": "€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهوçèéêëىيîïًٌٍَôُِ÷ّùْûü‎‏ے" + }, + "win1256": "windows1256", + "cp1256": "windows1256", + "windows1257": { + "type": "_sbcs", + "chars": "€�‚�„…†‡�‰�‹�¨ˇ¸�‘’“”•–—�™�›�¯˛� �¢£¤�¦§Ø©Ŗ«¬­®Æ°±²³´µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž˙" + }, + "win1257": "windows1257", + "cp1257": "windows1257", + "windows1258": { + "type": "_sbcs", + "chars": "€�‚ƒ„…†‡ˆ‰�‹Œ����‘’“”•–—˜™�›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ" + }, + "win1258": "windows1258", + "cp1258": "windows1258", + "iso88591": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + }, + "cp28591": "iso88591", + "iso88592": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ Ą˘Ł¤ĽŚ§¨ŠŞŤŹ­ŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙" + }, + "cp28592": "iso88592", + "iso88593": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ Ħ˘£¤�Ĥ§¨İŞĞĴ­�Ż°ħ²³´µĥ·¸ışğĵ½�żÀÁÂ�ÄĊĈÇÈÉÊËÌÍÎÏ�ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâ�äċĉçèéêëìíîï�ñòóôġö÷ĝùúûüŭŝ˙" + }, + "cp28593": "iso88593", + "iso88594": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ĄĸŖ¤ĨĻ§¨ŠĒĢŦ­Ž¯°ą˛ŗ´ĩļˇ¸šēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖ×ØŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙" + }, + "cp28594": "iso88594", + "iso88595": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ" + }, + "cp28595": "iso88595", + "iso88596": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ���¤�������،­�������������؛���؟�ءآأؤإئابةتثجحخدذرزسشصضطظعغ�����ـفقكلمنهوىيًٌٍَُِّْ�������������" + }, + "cp28596": "iso88596", + "iso88597": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ‘’£€₯¦§¨©ͺ«¬­�―°±²³΄΅Ά·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�" + }, + "cp28597": "iso88597", + "iso88598": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ �¢£¤¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾��������������������������������‗אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�" + }, + "cp28598": "iso88598", + "iso88599": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ" + }, + "cp28599": "iso88599", + "iso885910": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ĄĒĢĪĨĶ§ĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ" + }, + "cp28600": "iso885910", + "iso885911": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" + }, + "cp28601": "iso885911", + "iso885913": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’" + }, + "cp28603": "iso885913", + "iso885914": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ Ḃḃ£ĊċḊ§Ẁ©ẂḋỲ­®ŸḞḟĠġṀṁ¶ṖẁṗẃṠỳẄẅṡÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŴÑÒÓÔÕÖṪØÙÚÛÜÝŶßàáâãäåæçèéêëìíîïŵñòóôõöṫøùúûüýŷÿ" + }, + "cp28604": "iso885914", + "iso885915": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + }, + "cp28605": "iso885915", + "iso885916": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ĄąŁ€„Š§š©Ș«Ź­źŻ°±ČłŽ”¶·žčș»ŒœŸżÀÁÂĂÄĆÆÇÈÉÊËÌÍÎÏĐŃÒÓÔŐÖŚŰÙÚÛÜĘȚßàáâăäćæçèéêëìíîïđńòóôőöśűùúûüęțÿ" + }, + "cp28606": "iso885916", + "cp437": { + "type": "_sbcs", + "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, + "ibm437": "cp437", + "csibm437": "cp437", + "cp737": { + "type": "_sbcs", + "chars": "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ " + }, + "ibm737": "cp737", + "csibm737": "cp737", + "cp775": { + "type": "_sbcs", + "chars": "ĆüéāäģåćłēŖŗīŹÄÅÉæÆōöĢ¢ŚśÖÜø£ØפĀĪóŻżź”¦©®¬½¼Ł«»░▒▓│┤ĄČĘĖ╣║╗╝ĮŠ┐└┴┬├─┼ŲŪ╚╔╩╦╠═╬Žąčęėįšųūž┘┌█▄▌▐▀ÓßŌŃõÕµńĶķĻļņĒŅ’­±“¾¶§÷„°∙·¹³²■ " + }, + "ibm775": "cp775", + "csibm775": "cp775", + "cp850": { + "type": "_sbcs", + "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´­±‗¾¶§÷¸°¨·¹³²■ " + }, + "ibm850": "cp850", + "csibm850": "cp850", + "cp852": { + "type": "_sbcs", + "chars": "ÇüéâäůćçłëŐőîŹÄĆÉĹĺôöĽľŚśÖÜŤťŁ×čáíóúĄąŽžĘ꬟Ⱥ«»░▒▓│┤ÁÂĚŞ╣║╗╝Żż┐└┴┬├─┼Ăă╚╔╩╦╠═╬¤đĐĎËďŇÍÎě┘┌█▄ŢŮ▀ÓßÔŃńňŠšŔÚŕŰýÝţ´­˝˛ˇ˘§÷¸°¨˙űŘř■ " + }, + "ibm852": "cp852", + "csibm852": "cp852", + "cp855": { + "type": "_sbcs", + "chars": "ђЂѓЃёЁєЄѕЅіІїЇјЈљЉњЊћЋќЌўЎџЏюЮъЪаАбБцЦдДеЕфФгГ«»░▒▓│┤хХиИ╣║╗╝йЙ┐└┴┬├─┼кК╚╔╩╦╠═╬¤лЛмМнНоОп┘┌█▄Пя▀ЯрРсСтТуУжЖвВьЬ№­ыЫзЗшШэЭщЩчЧ§■ " + }, + "ibm855": "cp855", + "csibm855": "cp855", + "cp856": { + "type": "_sbcs", + "chars": "אבגדהוזחטיךכלםמןנסעףפץצקרשת�£�×����������®¬½¼�«»░▒▓│┤���©╣║╗╝¢¥┐└┴┬├─┼��╚╔╩╦╠═╬¤���������┘┌█▄¦�▀������µ�������¯´­±‗¾¶§÷¸°¨·¹³²■ " + }, + "ibm856": "cp856", + "csibm856": "cp856", + "cp857": { + "type": "_sbcs", + "chars": "ÇüéâäàåçêëèïîıÄÅÉæÆôöòûùİÖÜø£ØŞşáíóúñÑĞ𿮬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ºªÊËÈ�ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµ�×ÚÛÙìÿ¯´­±�¾¶§÷¸°¨·¹³²■ " + }, + "ibm857": "cp857", + "csibm857": "cp857", + "cp858": { + "type": "_sbcs", + "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø׃áíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈ€ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´­±‗¾¶§÷¸°¨·¹³²■ " + }, + "ibm858": "cp858", + "csibm858": "cp858", + "cp860": { + "type": "_sbcs", + "chars": "ÇüéâãàÁçêÊèÍÔìÃÂÉÀÈôõòÚùÌÕÜ¢£Ù₧ÓáíóúñѪº¿Ò¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, + "ibm860": "cp860", + "csibm860": "cp860", + "cp861": { + "type": "_sbcs", + "chars": "ÇüéâäàåçêëèÐðÞÄÅÉæÆôöþûÝýÖÜø£Ø₧ƒáíóúÁÍÓÚ¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, + "ibm861": "cp861", + "csibm861": "cp861", + "cp862": { + "type": "_sbcs", + "chars": "אבגדהוזחטיךכלםמןנסעףפץצקרשת¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, + "ibm862": "cp862", + "csibm862": "cp862", + "cp863": { + "type": "_sbcs", + "chars": "ÇüéâÂà¶çêëèïî‗À§ÉÈÊôËÏûù¤ÔÜ¢£ÙÛƒ¦´óú¨¸³¯Î⌐¬½¼¾«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, + "ibm863": "cp863", + "csibm863": "cp863", + "cp864": { + "type": "_sbcs", + "chars": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$٪&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~°·∙√▒─│┼┤┬├┴┐┌└┘β∞φ±½¼≈«»ﻷﻸ��ﻻﻼ� ­ﺂ£¤ﺄ��ﺎﺏﺕﺙ،ﺝﺡﺥ٠١٢٣٤٥٦٧٨٩ﻑ؛ﺱﺵﺹ؟¢ﺀﺁﺃﺅﻊﺋﺍﺑﺓﺗﺛﺟﺣﺧﺩﺫﺭﺯﺳﺷﺻﺿﻁﻅﻋﻏ¦¬÷×ﻉـﻓﻗﻛﻟﻣﻧﻫﻭﻯﻳﺽﻌﻎﻍﻡﹽّﻥﻩﻬﻰﻲﻐﻕﻵﻶﻝﻙﻱ■�" + }, + "ibm864": "cp864", + "csibm864": "cp864", + "cp865": { + "type": "_sbcs", + "chars": "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø₧ƒáíóúñѪº¿⌐¬½¼¡«¤░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, + "ibm865": "cp865", + "csibm865": "cp865", + "cp866": { + "type": "_sbcs", + "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ " + }, + "ibm866": "cp866", + "csibm866": "cp866", + "cp869": { + "type": "_sbcs", + "chars": "������Ά�·¬¦‘’Έ―ΉΊΪΌ��ΎΫ©Ώ²³ά£έήίϊΐόύΑΒΓΔΕΖΗ½ΘΙ«»░▒▓│┤ΚΛΜΝ╣║╗╝ΞΟ┐└┴┬├─┼ΠΡ╚╔╩╦╠═╬ΣΤΥΦΧΨΩαβγ┘┌█▄δε▀ζηθικλμνξοπρσςτ΄­±υφχ§ψ΅°¨ωϋΰώ■ " + }, + "ibm869": "cp869", + "csibm869": "cp869", + "cp922": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®‾°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŠÑÒÓÔÕÖ×ØÙÚÛÜÝŽßàáâãäåæçèéêëìíîïšñòóôõö÷øùúûüýžÿ" + }, + "ibm922": "cp922", + "csibm922": "cp922", + "cp1046": { + "type": "_sbcs", + "chars": "ﺈ×÷ﹱˆ■│─┐┌└┘ﹹﹻﹽﹿﹷﺊﻰﻳﻲﻎﻏﻐﻶﻸﻺﻼ ¤ﺋﺑﺗﺛﺟﺣ،­ﺧﺳ٠١٢٣٤٥٦٧٨٩ﺷ؛ﺻﺿﻊ؟ﻋءآأؤإئابةتثجحخدذرزسشصضطﻇعغﻌﺂﺄﺎﻓـفقكلمنهوىيًٌٍَُِّْﻗﻛﻟﻵﻷﻹﻻﻣﻧﻬﻩ�" + }, + "ibm1046": "cp1046", + "csibm1046": "cp1046", + "cp1124": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ЁЂҐЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђґєѕіїјљњћќ§ўџ" + }, + "ibm1124": "cp1124", + "csibm1124": "cp1124", + "cp1125": { + "type": "_sbcs", + "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёҐґЄєІіЇї·√№¤■ " + }, + "ibm1125": "cp1125", + "csibm1125": "cp1125", + "cp1129": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ" + }, + "ibm1129": "cp1129", + "csibm1129": "cp1129", + "cp1133": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ກຂຄງຈສຊຍດຕຖທນບປຜຝພຟມຢຣລວຫອຮ���ຯະາຳິີຶືຸູຼັົຽ���ເແໂໃໄ່້໊໋໌ໍໆ�ໜໝ₭����������������໐໑໒໓໔໕໖໗໘໙��¢¬¦�" + }, + "ibm1133": "cp1133", + "csibm1133": "cp1133", + "cp1161": { + "type": "_sbcs", + "chars": "��������������������������������่กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู้๊๋€฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛¢¬¦ " + }, + "ibm1161": "cp1161", + "csibm1161": "cp1161", + "cp1162": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" + }, + "ibm1162": "cp1162", + "csibm1162": "cp1162", + "cp1163": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£€¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ" + }, + "ibm1163": "cp1163", + "csibm1163": "cp1163", + "maccroatian": { + "type": "_sbcs", + "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊�©⁄¤‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ" + }, + "maccyrillic": { + "type": "_sbcs", + "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°¢£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµ∂ЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤" + }, + "macgreek": { + "type": "_sbcs", + "chars": "Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦­ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ�" + }, + "maciceland": { + "type": "_sbcs", + "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" + }, + "macroman": { + "type": "_sbcs", + "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" + }, + "macromania": { + "type": "_sbcs", + "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂŞ∞±≤≥¥µ∂∑∏π∫ªºΩăş¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›Ţţ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" + }, + "macthai": { + "type": "_sbcs", + "chars": "«»…“”�•‘’� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู​–—฿เแโใไๅๆ็่้๊๋์ํ™๏๐๑๒๓๔๕๖๗๘๙®©����" + }, + "macturkish": { + "type": "_sbcs", + "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙ�ˆ˜¯˘˙˚¸˝˛ˇ" + }, + "macukraine": { + "type": "_sbcs", + "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤" + }, + "koi8r": { + "type": "_sbcs", + "chars": "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" + }, + "koi8u": { + "type": "_sbcs", + "chars": "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґ╝╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪Ґ╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" + }, + "koi8ru": { + "type": "_sbcs", + "chars": "─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" + }, + "koi8t": { + "type": "_sbcs", + "chars": "қғ‚Ғ„…†‡�‰ҳ‹ҲҷҶ�Қ‘’“”•–—�™�›�����ӯӮё¤ӣ¦§���«¬­®�°±²Ё�Ӣ¶·�№�»���©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ" + }, + "armscii8": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ �և։)(»«—.՝,-֊…՜՛՞ԱաԲբԳգԴդԵեԶզԷէԸըԹթԺժԻիԼլԽխԾծԿկՀհՁձՂղՃճՄմՅյՆնՇշՈոՉչՊպՋջՌռՍսՎվՏտՐրՑցՒւՓփՔքՕօՖֆ՚�" + }, + "rk1048": { + "type": "_sbcs", + "chars": "ЂЃ‚ѓ„…†‡€‰Љ‹ЊҚҺЏђ‘’“”•–—�™љ›њқһџ ҰұӘ¤Ө¦§Ё©Ғ«¬­®Ү°±Ііөµ¶·ё№ғ»әҢңүАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя" + }, + "tcvn": { + "type": "_sbcs", + "chars": "\u0000ÚỤ\u0003ỪỬỮ\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010ỨỰỲỶỸÝỴ\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÀẢÃÁẠẶẬÈẺẼÉẸỆÌỈĨÍỊÒỎÕÓỌỘỜỞỠỚỢÙỦŨ ĂÂÊÔƠƯĐăâêôơưđẶ̀̀̉̃́àảãáạẲằẳẵắẴẮẦẨẪẤỀặầẩẫấậèỂẻẽéẹềểễếệìỉỄẾỒĩíịòỔỏõóọồổỗốộờởỡớợùỖủũúụừửữứựỳỷỹýỵỐ" + }, + "georgianacademy": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + }, + "georgianps": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზჱთიკლმნჲოპჟრსტჳუფქღყშჩცძწჭხჴჯჰჵæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" + }, + "pt154": { + "type": "_sbcs", + "chars": "ҖҒӮғ„…ҶҮҲүҠӢҢҚҺҸҗ‘’“”•–—ҳҷҡӣңқһҹ ЎўЈӨҘҰ§Ё©Ә«¬ӯ®Ҝ°ұІіҙө¶·ё№ә»јҪҫҝАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя" + }, + "viscii": { + "type": "_sbcs", + "chars": "\u0000\u0001Ẳ\u0003\u0004ẴẪ\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013Ỷ\u0015\u0016\u0017\u0018Ỹ\u001a\u001b\u001c\u001dỴ\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ẠẮẰẶẤẦẨẬẼẸẾỀỂỄỆỐỒỔỖỘỢỚỜỞỊỎỌỈỦŨỤỲÕắằặấầẩậẽẹếềểễệốồổỗỠƠộờởịỰỨỪỬơớƯÀÁÂÃẢĂẳẵÈÉÊẺÌÍĨỳĐứÒÓÔạỷừửÙÚỹỵÝỡưàáâãảăữẫèéêẻìíĩỉđựòóôõỏọụùúũủýợỮ" + }, + "iso646cn": { + "type": "_sbcs", + "chars": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������" + }, + "iso646jp": { + "type": "_sbcs", + "chars": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������" + }, + "hproman8": { + "type": "_sbcs", + "chars": "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ÀÂÈÊËÎÏ´ˋˆ¨˜ÙÛ₤¯Ýý°ÇçÑñ¡¿¤£¥§ƒ¢âêôûáéóúàèòùäëöüÅîØÆåíøæÄìÖÜÉïßÔÁÃãÐðÍÌÓÒÕõŠšÚŸÿÞþ·µ¶¾—¼½ªº«■»±�" + }, + "macintosh": { + "type": "_sbcs", + "chars": "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ" + }, + "ascii": { + "type": "_sbcs", + "chars": "��������������������������������������������������������������������������������������������������������������������������������" + }, + "tis620": { + "type": "_sbcs", + "chars": "���������������������������������กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����" + } } -// Expose `MapCache`. -memoize.Cache = MapCache; - -module.exports = memoize; - - /***/ }), -/***/ 2931: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -var baseToString = __nccwpck_require__(6792); - -/** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ -function toString(value) { - return value == null ? '' : baseToString(value); -} +/***/ 1080: +/***/ ((module) => { -module.exports = toString; +"use strict"; -/***/ }), +// Manually added data to be used by sbcs codec in addition to generated one. -/***/ 9623: -/***/ (function(module, __unused_webpack_exports, __nccwpck_require__) { +module.exports = { + // Not supported by iconv, not sure why. + "10029": "maccenteuro", + "maccenteuro": { + "type": "_sbcs", + "chars": "ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ" + }, -/* module decorator */ module = __nccwpck_require__.nmd(module); -//! moment.js -//! version : 2.29.4 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com + "808": "cp808", + "ibm808": "cp808", + "cp808": { + "type": "_sbcs", + "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№€■ " + }, -;(function (global, factory) { - true ? module.exports = factory() : - 0 -}(this, (function () { 'use strict'; + "mik": { + "type": "_sbcs", + "chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя└┴┬├─┼╣║╚╔╩╦╠═╬┐░▒▓│┤№§╗╝┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ " + }, - var hookCallback; + "cp720": { + "type": "_sbcs", + "chars": "\x80\x81éâ\x84à\x86çêëèïî\x8d\x8e\x8f\x90\u0651\u0652ô¤ـûùءآأؤ£إئابةتثجحخدذرزسشص«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ضطظعغفµقكلمنهوىي≡\u064b\u064c\u064d\u064e\u064f\u0650≈°∙·√ⁿ²■\u00a0" + }, - function hooks() { - return hookCallback.apply(null, arguments); - } + // Aliases of generated encodings. + "ascii8bit": "ascii", + "usascii": "ascii", + "ansix34": "ascii", + "ansix341968": "ascii", + "ansix341986": "ascii", + "csascii": "ascii", + "cp367": "ascii", + "ibm367": "ascii", + "isoir6": "ascii", + "iso646us": "ascii", + "iso646irv": "ascii", + "us": "ascii", - // This is done to register the method called with moment() - // without creating circular dependencies. - function setHookCallback(callback) { - hookCallback = callback; - } + "latin1": "iso88591", + "latin2": "iso88592", + "latin3": "iso88593", + "latin4": "iso88594", + "latin5": "iso88599", + "latin6": "iso885910", + "latin7": "iso885913", + "latin8": "iso885914", + "latin9": "iso885915", + "latin10": "iso885916", - function isArray(input) { - return ( - input instanceof Array || - Object.prototype.toString.call(input) === '[object Array]' - ); - } + "csisolatin1": "iso88591", + "csisolatin2": "iso88592", + "csisolatin3": "iso88593", + "csisolatin4": "iso88594", + "csisolatincyrillic": "iso88595", + "csisolatinarabic": "iso88596", + "csisolatingreek" : "iso88597", + "csisolatinhebrew": "iso88598", + "csisolatin5": "iso88599", + "csisolatin6": "iso885910", - function isObject(input) { - // IE8 will treat undefined and null as object if it wasn't for - // input != null - return ( - input != null && - Object.prototype.toString.call(input) === '[object Object]' - ); - } + "l1": "iso88591", + "l2": "iso88592", + "l3": "iso88593", + "l4": "iso88594", + "l5": "iso88599", + "l6": "iso885910", + "l7": "iso885913", + "l8": "iso885914", + "l9": "iso885915", + "l10": "iso885916", - function hasOwnProp(a, b) { - return Object.prototype.hasOwnProperty.call(a, b); - } + "isoir14": "iso646jp", + "isoir57": "iso646cn", + "isoir100": "iso88591", + "isoir101": "iso88592", + "isoir109": "iso88593", + "isoir110": "iso88594", + "isoir144": "iso88595", + "isoir127": "iso88596", + "isoir126": "iso88597", + "isoir138": "iso88598", + "isoir148": "iso88599", + "isoir157": "iso885910", + "isoir166": "tis620", + "isoir179": "iso885913", + "isoir199": "iso885914", + "isoir203": "iso885915", + "isoir226": "iso885916", - function isObjectEmpty(obj) { - if (Object.getOwnPropertyNames) { - return Object.getOwnPropertyNames(obj).length === 0; - } else { - var k; - for (k in obj) { - if (hasOwnProp(obj, k)) { - return false; - } - } - return true; - } - } + "cp819": "iso88591", + "ibm819": "iso88591", - function isUndefined(input) { - return input === void 0; - } + "cyrillic": "iso88595", - function isNumber(input) { - return ( - typeof input === 'number' || - Object.prototype.toString.call(input) === '[object Number]' - ); - } + "arabic": "iso88596", + "arabic8": "iso88596", + "ecma114": "iso88596", + "asmo708": "iso88596", - function isDate(input) { - return ( - input instanceof Date || - Object.prototype.toString.call(input) === '[object Date]' - ); - } + "greek" : "iso88597", + "greek8" : "iso88597", + "ecma118" : "iso88597", + "elot928" : "iso88597", - function map(arr, fn) { - var res = [], - i, - arrLen = arr.length; - for (i = 0; i < arrLen; ++i) { - res.push(fn(arr[i], i)); - } - return res; - } + "hebrew": "iso88598", + "hebrew8": "iso88598", - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } - } + "turkish": "iso88599", + "turkish8": "iso88599", - if (hasOwnProp(b, 'toString')) { - a.toString = b.toString; - } + "thai": "iso885911", + "thai8": "iso885911", - if (hasOwnProp(b, 'valueOf')) { - a.valueOf = b.valueOf; - } + "celtic": "iso885914", + "celtic8": "iso885914", + "isoceltic": "iso885914", - return a; - } + "tis6200": "tis620", + "tis62025291": "tis620", + "tis62025330": "tis620", - function createUTC(input, format, locale, strict) { - return createLocalOrUTC(input, format, locale, strict, true).utc(); - } + "10000": "macroman", + "10006": "macgreek", + "10007": "maccyrillic", + "10079": "maciceland", + "10081": "macturkish", - function defaultParsingFlags() { - // We need to deep clone this object. - return { - empty: false, - unusedTokens: [], - unusedInput: [], - overflow: -2, - charsLeftOver: 0, - nullInput: false, - invalidEra: null, - invalidMonth: null, - invalidFormat: false, - userInvalidated: false, - iso: false, - parsedDateParts: [], - era: null, - meridiem: null, - rfc2822: false, - weekdayMismatch: false, - }; - } + "cspc8codepage437": "cp437", + "cspc775baltic": "cp775", + "cspc850multilingual": "cp850", + "cspcp852": "cp852", + "cspc862latinhebrew": "cp862", + "cpgr": "cp869", - function getParsingFlags(m) { - if (m._pf == null) { - m._pf = defaultParsingFlags(); - } - return m._pf; - } + "msee": "cp1250", + "mscyrl": "cp1251", + "msansi": "cp1252", + "msgreek": "cp1253", + "msturk": "cp1254", + "mshebr": "cp1255", + "msarab": "cp1256", + "winbaltrim": "cp1257", - var some; - if (Array.prototype.some) { - some = Array.prototype.some; - } else { - some = function (fun) { - var t = Object(this), - len = t.length >>> 0, - i; - - for (i = 0; i < len; i++) { - if (i in t && fun.call(this, t[i], i, t)) { - return true; - } - } + "cp20866": "koi8r", + "20866": "koi8r", + "ibm878": "koi8r", + "cskoi8r": "koi8r", - return false; - }; - } + "cp21866": "koi8u", + "21866": "koi8u", + "ibm1168": "koi8u", - function isValid(m) { - if (m._isValid == null) { - var flags = getParsingFlags(m), - parsedParts = some.call(flags.parsedDateParts, function (i) { - return i != null; - }), - isNowValid = - !isNaN(m._d.getTime()) && - flags.overflow < 0 && - !flags.empty && - !flags.invalidEra && - !flags.invalidMonth && - !flags.invalidWeekday && - !flags.weekdayMismatch && - !flags.nullInput && - !flags.invalidFormat && - !flags.userInvalidated && - (!flags.meridiem || (flags.meridiem && parsedParts)); - - if (m._strict) { - isNowValid = - isNowValid && - flags.charsLeftOver === 0 && - flags.unusedTokens.length === 0 && - flags.bigHour === undefined; - } + "strk10482002": "rk1048", - if (Object.isFrozen == null || !Object.isFrozen(m)) { - m._isValid = isNowValid; - } else { - return isNowValid; - } - } - return m._isValid; - } + "tcvn5712": "tcvn", + "tcvn57121": "tcvn", - function createInvalid(flags) { - var m = createUTC(NaN); - if (flags != null) { - extend(getParsingFlags(m), flags); - } else { - getParsingFlags(m).userInvalidated = true; - } + "gb198880": "iso646cn", + "cn": "iso646cn", - return m; - } + "csiso14jisc6220ro": "iso646jp", + "jisc62201969ro": "iso646jp", + "jp": "iso646jp", - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - var momentProperties = (hooks.momentProperties = []), - updateInProgress = false; + "cshproman8": "hproman8", + "r8": "hproman8", + "roman8": "hproman8", + "xroman8": "hproman8", + "ibm1051": "hproman8", - function copyConfig(to, from) { - var i, - prop, - val, - momentPropertiesLen = momentProperties.length; + "mac": "macintosh", + "csmacintosh": "macintosh", +}; - if (!isUndefined(from._isAMomentObject)) { - to._isAMomentObject = from._isAMomentObject; - } - if (!isUndefined(from._i)) { - to._i = from._i; - } - if (!isUndefined(from._f)) { - to._f = from._f; - } - if (!isUndefined(from._l)) { - to._l = from._l; - } - if (!isUndefined(from._strict)) { - to._strict = from._strict; - } - if (!isUndefined(from._tzm)) { - to._tzm = from._tzm; - } - if (!isUndefined(from._isUTC)) { - to._isUTC = from._isUTC; - } - if (!isUndefined(from._offset)) { - to._offset = from._offset; - } - if (!isUndefined(from._pf)) { - to._pf = getParsingFlags(from); - } - if (!isUndefined(from._locale)) { - to._locale = from._locale; - } - if (momentPropertiesLen > 0) { - for (i = 0; i < momentPropertiesLen; i++) { - prop = momentProperties[i]; - val = from[prop]; - if (!isUndefined(val)) { - to[prop] = val; - } - } - } - return to; - } +/***/ }), - // Moment prototype object - function Moment(config) { - copyConfig(this, config); - this._d = new Date(config._d != null ? config._d.getTime() : NaN); - if (!this.isValid()) { - this._d = new Date(NaN); - } - // Prevent infinite loop in case updateOffset creates new moment - // objects. - if (updateInProgress === false) { - updateInProgress = true; - hooks.updateOffset(this); - updateInProgress = false; - } - } +/***/ 1155: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - function isMoment(obj) { - return ( - obj instanceof Moment || (obj != null && obj._isAMomentObject != null) - ); - } +"use strict"; - function warn(msg) { - if ( - hooks.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && - console.warn - ) { - console.warn('Deprecation warning: ' + msg); - } - } +var Buffer = (__nccwpck_require__(5118).Buffer); - function deprecate(msg, fn) { - var firstTime = true; +// Note: UTF16-LE (or UCS2) codec is Node.js native. See encodings/internal.js - return extend(function () { - if (hooks.deprecationHandler != null) { - hooks.deprecationHandler(null, msg); - } - if (firstTime) { - var args = [], - arg, - i, - key, - argLen = arguments.length; - for (i = 0; i < argLen; i++) { - arg = ''; - if (typeof arguments[i] === 'object') { - arg += '\n[' + i + '] '; - for (key in arguments[0]) { - if (hasOwnProp(arguments[0], key)) { - arg += key + ': ' + arguments[0][key] + ', '; - } - } - arg = arg.slice(0, -2); // Remove trailing comma and space - } else { - arg = arguments[i]; - } - args.push(arg); - } - warn( - msg + - '\nArguments: ' + - Array.prototype.slice.call(args).join('') + - '\n' + - new Error().stack - ); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); - } +// == UTF16-BE codec. ========================================================== - var deprecations = {}; +exports.utf16be = Utf16BECodec; +function Utf16BECodec() { +} - function deprecateSimple(name, msg) { - if (hooks.deprecationHandler != null) { - hooks.deprecationHandler(name, msg); - } - if (!deprecations[name]) { - warn(msg); - deprecations[name] = true; - } - } +Utf16BECodec.prototype.encoder = Utf16BEEncoder; +Utf16BECodec.prototype.decoder = Utf16BEDecoder; +Utf16BECodec.prototype.bomAware = true; - hooks.suppressDeprecationWarnings = false; - hooks.deprecationHandler = null; - function isFunction(input) { - return ( - (typeof Function !== 'undefined' && input instanceof Function) || - Object.prototype.toString.call(input) === '[object Function]' - ); - } +// -- Encoding - function set(config) { - var prop, i; - for (i in config) { - if (hasOwnProp(config, i)) { - prop = config[i]; - if (isFunction(prop)) { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - } - this._config = config; - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _dayOfMonthOrdinalParse. - // TODO: Remove "ordinalParse" fallback in next major release. - this._dayOfMonthOrdinalParseLenient = new RegExp( - (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + - '|' + - /\d{1,2}/.source - ); - } +function Utf16BEEncoder() { +} - function mergeConfigs(parentConfig, childConfig) { - var res = extend({}, parentConfig), - prop; - for (prop in childConfig) { - if (hasOwnProp(childConfig, prop)) { - if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { - res[prop] = {}; - extend(res[prop], parentConfig[prop]); - extend(res[prop], childConfig[prop]); - } else if (childConfig[prop] != null) { - res[prop] = childConfig[prop]; - } else { - delete res[prop]; - } - } - } - for (prop in parentConfig) { - if ( - hasOwnProp(parentConfig, prop) && - !hasOwnProp(childConfig, prop) && - isObject(parentConfig[prop]) - ) { - // make sure changes to properties don't modify parent config - res[prop] = extend({}, res[prop]); - } - } - return res; +Utf16BEEncoder.prototype.write = function(str) { + var buf = Buffer.from(str, 'ucs2'); + for (var i = 0; i < buf.length; i += 2) { + var tmp = buf[i]; buf[i] = buf[i+1]; buf[i+1] = tmp; } + return buf; +} - function Locale(config) { - if (config != null) { - this.set(config); - } - } +Utf16BEEncoder.prototype.end = function() { +} - var keys; - if (Object.keys) { - keys = Object.keys; - } else { - keys = function (obj) { - var i, - res = []; - for (i in obj) { - if (hasOwnProp(obj, i)) { - res.push(i); - } - } - return res; - }; - } +// -- Decoding - var defaultCalendar = { - sameDay: '[Today at] LT', - nextDay: '[Tomorrow at] LT', - nextWeek: 'dddd [at] LT', - lastDay: '[Yesterday at] LT', - lastWeek: '[Last] dddd [at] LT', - sameElse: 'L', - }; +function Utf16BEDecoder() { + this.overflowByte = -1; +} - function calendar(key, mom, now) { - var output = this._calendar[key] || this._calendar['sameElse']; - return isFunction(output) ? output.call(mom, now) : output; - } +Utf16BEDecoder.prototype.write = function(buf) { + if (buf.length == 0) + return ''; - function zeroFill(number, targetLength, forceSign) { - var absNumber = '' + Math.abs(number), - zerosToFill = targetLength - absNumber.length, - sign = number >= 0; - return ( - (sign ? (forceSign ? '+' : '') : '-') + - Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + - absNumber - ); - } + var buf2 = Buffer.alloc(buf.length + 1), + i = 0, j = 0; - var formattingTokens = - /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, - formatFunctions = {}, - formatTokenFunctions = {}; - - // token: 'M' - // padded: ['MM', 2] - // ordinal: 'Mo' - // callback: function () { this.month() + 1 } - function addFormatToken(token, padded, ordinal, callback) { - var func = callback; - if (typeof callback === 'string') { - func = function () { - return this[callback](); - }; - } - if (token) { - formatTokenFunctions[token] = func; - } - if (padded) { - formatTokenFunctions[padded[0]] = function () { - return zeroFill(func.apply(this, arguments), padded[1], padded[2]); - }; - } - if (ordinal) { - formatTokenFunctions[ordinal] = function () { - return this.localeData().ordinal( - func.apply(this, arguments), - token - ); - }; - } + if (this.overflowByte !== -1) { + buf2[0] = buf[0]; + buf2[1] = this.overflowByte; + i = 1; j = 2; } - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); + for (; i < buf.length-1; i += 2, j+= 2) { + buf2[j] = buf[i+1]; + buf2[j+1] = buf[i]; } - function makeFormatFunction(format) { - var array = format.match(formattingTokens), - i, - length; + this.overflowByte = (i == buf.length-1) ? buf[buf.length-1] : -1; - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } + return buf2.slice(0, j).toString('ucs2'); +} - return function (mom) { - var output = '', - i; - for (i = 0; i < length; i++) { - output += isFunction(array[i]) - ? array[i].call(mom, format) - : array[i]; - } - return output; - }; - } +Utf16BEDecoder.prototype.end = function() { + this.overflowByte = -1; +} - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - format = expandFormat(format, m.localeData()); - formatFunctions[format] = - formatFunctions[format] || makeFormatFunction(format); +// == UTF-16 codec ============================================================= +// Decoder chooses automatically from UTF-16LE and UTF-16BE using BOM and space-based heuristic. +// Defaults to UTF-16LE, as it's prevalent and default in Node. +// http://en.wikipedia.org/wiki/UTF-16 and http://encoding.spec.whatwg.org/#utf-16le +// Decoder default can be changed: iconv.decode(buf, 'utf16', {defaultEncoding: 'utf-16be'}); - return formatFunctions[format](m); - } +// Encoder uses UTF-16LE and prepends BOM (which can be overridden with addBOM: false). - function expandFormat(format, locale) { - var i = 5; +exports.utf16 = Utf16Codec; +function Utf16Codec(codecOptions, iconv) { + this.iconv = iconv; +} - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } +Utf16Codec.prototype.encoder = Utf16Encoder; +Utf16Codec.prototype.decoder = Utf16Decoder; - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace( - localFormattingTokens, - replaceLongDateFormatTokens - ); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - return format; - } +// -- Encoding (pass-through) - var defaultLongDateFormat = { - LTS: 'h:mm:ss A', - LT: 'h:mm A', - L: 'MM/DD/YYYY', - LL: 'MMMM D, YYYY', - LLL: 'MMMM D, YYYY h:mm A', - LLLL: 'dddd, MMMM D, YYYY h:mm A', - }; +function Utf16Encoder(options, codec) { + options = options || {}; + if (options.addBOM === undefined) + options.addBOM = true; + this.encoder = codec.iconv.getEncoder('utf-16le', options); +} - function longDateFormat(key) { - var format = this._longDateFormat[key], - formatUpper = this._longDateFormat[key.toUpperCase()]; +Utf16Encoder.prototype.write = function(str) { + return this.encoder.write(str); +} - if (format || !formatUpper) { - return format; - } +Utf16Encoder.prototype.end = function() { + return this.encoder.end(); +} - this._longDateFormat[key] = formatUpper - .match(formattingTokens) - .map(function (tok) { - if ( - tok === 'MMMM' || - tok === 'MM' || - tok === 'DD' || - tok === 'dddd' - ) { - return tok.slice(1); - } - return tok; - }) - .join(''); - return this._longDateFormat[key]; - } +// -- Decoding - var defaultInvalidDate = 'Invalid date'; +function Utf16Decoder(options, codec) { + this.decoder = null; + this.initialBufs = []; + this.initialBufsLen = 0; - function invalidDate() { - return this._invalidDate; - } + this.options = options || {}; + this.iconv = codec.iconv; +} - var defaultOrdinal = '%d', - defaultDayOfMonthOrdinalParse = /\d{1,2}/; +Utf16Decoder.prototype.write = function(buf) { + if (!this.decoder) { + // Codec is not chosen yet. Accumulate initial bytes. + this.initialBufs.push(buf); + this.initialBufsLen += buf.length; + + if (this.initialBufsLen < 16) // We need more bytes to use space heuristic (see below) + return ''; - function ordinal(number) { - return this._ordinal.replace('%d', number); - } + // We have enough bytes -> detect endianness. + var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); + this.decoder = this.iconv.getDecoder(encoding, this.options); - var defaultRelativeTime = { - future: 'in %s', - past: '%s ago', - s: 'a few seconds', - ss: '%d seconds', - m: 'a minute', - mm: '%d minutes', - h: 'an hour', - hh: '%d hours', - d: 'a day', - dd: '%d days', - w: 'a week', - ww: '%d weeks', - M: 'a month', - MM: '%d months', - y: 'a year', - yy: '%d years', - }; + var resStr = ''; + for (var i = 0; i < this.initialBufs.length; i++) + resStr += this.decoder.write(this.initialBufs[i]); - function relativeTime(number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return isFunction(output) - ? output(number, withoutSuffix, string, isFuture) - : output.replace(/%d/i, number); + this.initialBufs.length = this.initialBufsLen = 0; + return resStr; } - function pastFuture(diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return isFunction(format) ? format(output) : format.replace(/%s/i, output); - } + return this.decoder.write(buf); +} + +Utf16Decoder.prototype.end = function() { + if (!this.decoder) { + var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); + this.decoder = this.iconv.getDecoder(encoding, this.options); - var aliases = {}; + var resStr = ''; + for (var i = 0; i < this.initialBufs.length; i++) + resStr += this.decoder.write(this.initialBufs[i]); - function addUnitAlias(unit, shorthand) { - var lowerCase = unit.toLowerCase(); - aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; - } + var trail = this.decoder.end(); + if (trail) + resStr += trail; - function normalizeUnits(units) { - return typeof units === 'string' - ? aliases[units] || aliases[units.toLowerCase()] - : undefined; + this.initialBufs.length = this.initialBufsLen = 0; + return resStr; } + return this.decoder.end(); +} - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; +function detectEncoding(bufs, defaultEncoding) { + var b = []; + var charsProcessed = 0; + var asciiCharsLE = 0, asciiCharsBE = 0; // Number of ASCII chars when decoded as LE or BE. - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; + outer_loop: + for (var i = 0; i < bufs.length; i++) { + var buf = bufs[i]; + for (var j = 0; j < buf.length; j++) { + b.push(buf[j]); + if (b.length === 2) { + if (charsProcessed === 0) { + // Check BOM first. + if (b[0] === 0xFF && b[1] === 0xFE) return 'utf-16le'; + if (b[0] === 0xFE && b[1] === 0xFF) return 'utf-16be'; } - } - } - - return normalizedInput; - } - var priorities = {}; + if (b[0] === 0 && b[1] !== 0) asciiCharsBE++; + if (b[0] !== 0 && b[1] === 0) asciiCharsLE++; - function addUnitPriority(unit, priority) { - priorities[unit] = priority; - } + b.length = 0; + charsProcessed++; - function getPrioritizedUnits(unitsObj) { - var units = [], - u; - for (u in unitsObj) { - if (hasOwnProp(unitsObj, u)) { - units.push({ unit: u, priority: priorities[u] }); + if (charsProcessed >= 100) { + break outer_loop; + } } } - units.sort(function (a, b) { - return a.priority - b.priority; - }); - return units; } - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } + // Make decisions. + // Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon. + // So, we count ASCII as if it was LE or BE, and decide from that. + if (asciiCharsBE > asciiCharsLE) return 'utf-16be'; + if (asciiCharsBE < asciiCharsLE) return 'utf-16le'; - function absFloor(number) { - if (number < 0) { - // -0 -> 0 - return Math.ceil(number) || 0; - } else { - return Math.floor(number); - } - } + // Couldn't decide (likely all zeros or not enough data). + return defaultEncoding || 'utf-16le'; +} - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - value = absFloor(coercedNumber); - } - return value; - } - function makeGetSet(unit, keepTime) { - return function (value) { - if (value != null) { - set$1(this, unit, value); - hooks.updateOffset(this, keepTime); - return this; - } else { - return get(this, unit); - } - }; - } +/***/ }), - function get(mom, unit) { - return mom.isValid() - ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() - : NaN; - } - - function set$1(mom, unit, value) { - if (mom.isValid() && !isNaN(value)) { - if ( - unit === 'FullYear' && - isLeapYear(mom.year()) && - mom.month() === 1 && - mom.date() === 29 - ) { - value = toInt(value); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit]( - value, - mom.month(), - daysInMonth(value, mom.month()) - ); - } else { - mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } - } +/***/ 9557: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - // MOMENTS +"use strict"; - function stringGet(units) { - units = normalizeUnits(units); - if (isFunction(this[units])) { - return this[units](); - } - return this; - } - function stringSet(units, value) { - if (typeof units === 'object') { - units = normalizeObjectUnits(units); - var prioritized = getPrioritizedUnits(units), - i, - prioritizedLen = prioritized.length; - for (i = 0; i < prioritizedLen; i++) { - this[prioritized[i].unit](units[prioritized[i].unit]); - } - } else { - units = normalizeUnits(units); - if (isFunction(this[units])) { - return this[units](value); - } - } - return this; - } +var Buffer = (__nccwpck_require__(5118).Buffer); - var match1 = /\d/, // 0 - 9 - match2 = /\d\d/, // 00 - 99 - match3 = /\d{3}/, // 000 - 999 - match4 = /\d{4}/, // 0000 - 9999 - match6 = /[+-]?\d{6}/, // -999999 - 999999 - match1to2 = /\d\d?/, // 0 - 99 - match3to4 = /\d\d\d\d?/, // 999 - 9999 - match5to6 = /\d\d\d\d\d\d?/, // 99999 - 999999 - match1to3 = /\d{1,3}/, // 0 - 999 - match1to4 = /\d{1,4}/, // 0 - 9999 - match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999 - matchUnsigned = /\d+/, // 0 - inf - matchSigned = /[+-]?\d+/, // -inf - inf - matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z - matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - // any word (or two) characters or numbers including two/three word month in arabic. - // includes scottish gaelic two word and hyphenated months - matchWord = - /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, - regexes; - - regexes = {}; - - function addRegexToken(token, regex, strictRegex) { - regexes[token] = isFunction(regex) - ? regex - : function (isStrict, localeData) { - return isStrict && strictRegex ? strictRegex : regex; - }; - } - - function getParseRegexForToken(token, config) { - if (!hasOwnProp(regexes, token)) { - return new RegExp(unescapeFormat(token)); - } +// == UTF32-LE/BE codec. ========================================================== - return regexes[token](config._strict, config._locale); - } +exports._utf32 = Utf32Codec; + +function Utf32Codec(codecOptions, iconv) { + this.iconv = iconv; + this.bomAware = true; + this.isLE = codecOptions.isLE; +} - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function unescapeFormat(s) { - return regexEscape( - s - .replace('\\', '') - .replace( - /\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, - function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - } - ) - ); - } +exports.utf32le = { type: '_utf32', isLE: true }; +exports.utf32be = { type: '_utf32', isLE: false }; - function regexEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } +// Aliases +exports.ucs4le = 'utf32le'; +exports.ucs4be = 'utf32be'; - var tokens = {}; +Utf32Codec.prototype.encoder = Utf32Encoder; +Utf32Codec.prototype.decoder = Utf32Decoder; - function addParseToken(token, callback) { - var i, - func = callback, - tokenLen; - if (typeof token === 'string') { - token = [token]; - } - if (isNumber(callback)) { - func = function (input, array) { - array[callback] = toInt(input); - }; - } - tokenLen = token.length; - for (i = 0; i < tokenLen; i++) { - tokens[token[i]] = func; - } - } +// -- Encoding - function addWeekParseToken(token, callback) { - addParseToken(token, function (input, array, config, token) { - config._w = config._w || {}; - callback(input, config._w, config, token); - }); - } +function Utf32Encoder(options, codec) { + this.isLE = codec.isLE; + this.highSurrogate = 0; +} - function addTimeToArrayFromToken(token, input, config) { - if (input != null && hasOwnProp(tokens, token)) { - tokens[token](input, config._a, config, token); - } - } +Utf32Encoder.prototype.write = function(str) { + var src = Buffer.from(str, 'ucs2'); + var dst = Buffer.alloc(src.length * 2); + var write32 = this.isLE ? dst.writeUInt32LE : dst.writeUInt32BE; + var offset = 0; - var YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - WEEK = 7, - WEEKDAY = 8; + for (var i = 0; i < src.length; i += 2) { + var code = src.readUInt16LE(i); + var isHighSurrogate = (0xD800 <= code && code < 0xDC00); + var isLowSurrogate = (0xDC00 <= code && code < 0xE000); - function mod(n, x) { - return ((n % x) + x) % x; - } + if (this.highSurrogate) { + if (isHighSurrogate || !isLowSurrogate) { + // There shouldn't be two high surrogates in a row, nor a high surrogate which isn't followed by a low + // surrogate. If this happens, keep the pending high surrogate as a stand-alone semi-invalid character + // (technically wrong, but expected by some applications, like Windows file names). + write32.call(dst, this.highSurrogate, offset); + offset += 4; + } + else { + // Create 32-bit value from high and low surrogates; + var codepoint = (((this.highSurrogate - 0xD800) << 10) | (code - 0xDC00)) + 0x10000; - var indexOf; + write32.call(dst, codepoint, offset); + offset += 4; + this.highSurrogate = 0; - if (Array.prototype.indexOf) { - indexOf = Array.prototype.indexOf; - } else { - indexOf = function (o) { - // I know - var i; - for (i = 0; i < this.length; ++i) { - if (this[i] === o) { - return i; - } + continue; } - return -1; - }; - } + } - function daysInMonth(year, month) { - if (isNaN(year) || isNaN(month)) { - return NaN; + if (isHighSurrogate) + this.highSurrogate = code; + else { + // Even if the current character is a low surrogate, with no previous high surrogate, we'll + // encode it as a semi-invalid stand-alone character for the same reasons expressed above for + // unpaired high surrogates. + write32.call(dst, code, offset); + offset += 4; + this.highSurrogate = 0; } - var modMonth = mod(month, 12); - year += (month - modMonth) / 12; - return modMonth === 1 - ? isLeapYear(year) - ? 29 - : 28 - : 31 - ((modMonth % 7) % 2); } - // FORMATTING - - addFormatToken('M', ['MM', 2], 'Mo', function () { - return this.month() + 1; - }); + if (offset < dst.length) + dst = dst.slice(0, offset); - addFormatToken('MMM', 0, 0, function (format) { - return this.localeData().monthsShort(this, format); - }); + return dst; +}; - addFormatToken('MMMM', 0, 0, function (format) { - return this.localeData().months(this, format); - }); +Utf32Encoder.prototype.end = function() { + // Treat any leftover high surrogate as a semi-valid independent character. + if (!this.highSurrogate) + return; - // ALIASES + var buf = Buffer.alloc(4); - addUnitAlias('month', 'M'); + if (this.isLE) + buf.writeUInt32LE(this.highSurrogate, 0); + else + buf.writeUInt32BE(this.highSurrogate, 0); - // PRIORITY + this.highSurrogate = 0; - addUnitPriority('month', 8); + return buf; +}; - // PARSING +// -- Decoding - addRegexToken('M', match1to2); - addRegexToken('MM', match1to2, match2); - addRegexToken('MMM', function (isStrict, locale) { - return locale.monthsShortRegex(isStrict); - }); - addRegexToken('MMMM', function (isStrict, locale) { - return locale.monthsRegex(isStrict); - }); +function Utf32Decoder(options, codec) { + this.isLE = codec.isLE; + this.badChar = codec.iconv.defaultCharUnicode.charCodeAt(0); + this.overflow = []; +} - addParseToken(['M', 'MM'], function (input, array) { - array[MONTH] = toInt(input) - 1; - }); +Utf32Decoder.prototype.write = function(src) { + if (src.length === 0) + return ''; - addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { - var month = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (month != null) { - array[MONTH] = month; - } else { - getParsingFlags(config).invalidMonth = input; - } - }); + var i = 0; + var codepoint = 0; + var dst = Buffer.alloc(src.length + 4); + var offset = 0; + var isLE = this.isLE; + var overflow = this.overflow; + var badChar = this.badChar; - // LOCALES - - var defaultLocaleMonths = - 'January_February_March_April_May_June_July_August_September_October_November_December'.split( - '_' - ), - defaultLocaleMonthsShort = - 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, - defaultMonthsShortRegex = matchWord, - defaultMonthsRegex = matchWord; - - function localeMonths(m, format) { - if (!m) { - return isArray(this._months) - ? this._months - : this._months['standalone']; - } - return isArray(this._months) - ? this._months[m.month()] - : this._months[ - (this._months.isFormat || MONTHS_IN_FORMAT).test(format) - ? 'format' - : 'standalone' - ][m.month()]; - } - - function localeMonthsShort(m, format) { - if (!m) { - return isArray(this._monthsShort) - ? this._monthsShort - : this._monthsShort['standalone']; - } - return isArray(this._monthsShort) - ? this._monthsShort[m.month()] - : this._monthsShort[ - MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone' - ][m.month()]; - } - - function handleStrictParse(monthName, format, strict) { - var i, - ii, - mom, - llc = monthName.toLocaleLowerCase(); - if (!this._monthsParse) { - // this is not used - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - for (i = 0; i < 12; ++i) { - mom = createUTC([2000, i]); - this._shortMonthsParse[i] = this.monthsShort( - mom, - '' - ).toLocaleLowerCase(); - this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); + if (overflow.length > 0) { + for (; i < src.length && overflow.length < 4; i++) + overflow.push(src[i]); + + if (overflow.length === 4) { + // NOTE: codepoint is a signed int32 and can be negative. + // NOTE: We copied this block from below to help V8 optimize it (it works with array, not buffer). + if (isLE) { + codepoint = overflow[i] | (overflow[i+1] << 8) | (overflow[i+2] << 16) | (overflow[i+3] << 24); + } else { + codepoint = overflow[i+3] | (overflow[i+2] << 8) | (overflow[i+1] << 16) | (overflow[i] << 24); } + overflow.length = 0; + + offset = _writeCodepoint(dst, offset, codepoint, badChar); } + } - if (strict) { - if (format === 'MMM') { - ii = indexOf.call(this._shortMonthsParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._longMonthsParse, llc); - return ii !== -1 ? ii : null; - } + // Main loop. Should be as optimized as possible. + for (; i < src.length - 3; i += 4) { + // NOTE: codepoint is a signed int32 and can be negative. + if (isLE) { + codepoint = src[i] | (src[i+1] << 8) | (src[i+2] << 16) | (src[i+3] << 24); } else { - if (format === 'MMM') { - ii = indexOf.call(this._shortMonthsParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._longMonthsParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._longMonthsParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._shortMonthsParse, llc); - return ii !== -1 ? ii : null; - } + codepoint = src[i+3] | (src[i+2] << 8) | (src[i+1] << 16) | (src[i] << 24); } + offset = _writeCodepoint(dst, offset, codepoint, badChar); } - function localeMonthsParse(monthName, format, strict) { - var i, mom, regex; + // Keep overflowing bytes. + for (; i < src.length; i++) { + overflow.push(src[i]); + } - if (this._monthsParseExact) { - return handleStrictParse.call(this, monthName, format, strict); - } + return dst.slice(0, offset).toString('ucs2'); +}; - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } +function _writeCodepoint(dst, offset, codepoint, badChar) { + // NOTE: codepoint is signed int32 and can be negative. We keep it that way to help V8 with optimizations. + if (codepoint < 0 || codepoint > 0x10FFFF) { + // Not a valid Unicode codepoint + codepoint = badChar; + } - // TODO: add sorting - // Sorting makes sure if one month (or abbr) is a prefix of another - // see sorting in computeMonthsParse - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = createUTC([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp( - '^' + this.months(mom, '').replace('.', '') + '$', - 'i' - ); - this._shortMonthsParse[i] = new RegExp( - '^' + this.monthsShort(mom, '').replace('.', '') + '$', - 'i' - ); - } - if (!strict && !this._monthsParse[i]) { - regex = - '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if ( - strict && - format === 'MMMM' && - this._longMonthsParse[i].test(monthName) - ) { - return i; - } else if ( - strict && - format === 'MMM' && - this._shortMonthsParse[i].test(monthName) - ) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } + // Ephemeral Planes: Write high surrogate. + if (codepoint >= 0x10000) { + codepoint -= 0x10000; + + var high = 0xD800 | (codepoint >> 10); + dst[offset++] = high & 0xff; + dst[offset++] = high >> 8; + + // Low surrogate is written below. + var codepoint = 0xDC00 | (codepoint & 0x3FF); } - // MOMENTS + // Write BMP char or low surrogate. + dst[offset++] = codepoint & 0xff; + dst[offset++] = codepoint >> 8; - function setMonth(mom, value) { - var dayOfMonth; + return offset; +}; - if (!mom.isValid()) { - // No op - return mom; - } +Utf32Decoder.prototype.end = function() { + this.overflow.length = 0; +}; - if (typeof value === 'string') { - if (/^\d+$/.test(value)) { - value = toInt(value); - } else { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (!isNumber(value)) { - return mom; - } - } - } +// == UTF-32 Auto codec ============================================================= +// Decoder chooses automatically from UTF-32LE and UTF-32BE using BOM and space-based heuristic. +// Defaults to UTF-32LE. http://en.wikipedia.org/wiki/UTF-32 +// Encoder/decoder default can be changed: iconv.decode(buf, 'utf32', {defaultEncoding: 'utf-32be'}); - dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } +// Encoder prepends BOM (which can be overridden with (addBOM: false}). - function getSetMonth(value) { - if (value != null) { - setMonth(this, value); - hooks.updateOffset(this, true); - return this; - } else { - return get(this, 'Month'); - } - } +exports.utf32 = Utf32AutoCodec; +exports.ucs4 = 'utf32'; - function getDaysInMonth() { - return daysInMonth(this.year(), this.month()); - } +function Utf32AutoCodec(options, iconv) { + this.iconv = iconv; +} - function monthsShortRegex(isStrict) { - if (this._monthsParseExact) { - if (!hasOwnProp(this, '_monthsRegex')) { - computeMonthsParse.call(this); - } - if (isStrict) { - return this._monthsShortStrictRegex; - } else { - return this._monthsShortRegex; - } - } else { - if (!hasOwnProp(this, '_monthsShortRegex')) { - this._monthsShortRegex = defaultMonthsShortRegex; - } - return this._monthsShortStrictRegex && isStrict - ? this._monthsShortStrictRegex - : this._monthsShortRegex; - } - } +Utf32AutoCodec.prototype.encoder = Utf32AutoEncoder; +Utf32AutoCodec.prototype.decoder = Utf32AutoDecoder; - function monthsRegex(isStrict) { - if (this._monthsParseExact) { - if (!hasOwnProp(this, '_monthsRegex')) { - computeMonthsParse.call(this); - } - if (isStrict) { - return this._monthsStrictRegex; - } else { - return this._monthsRegex; - } - } else { - if (!hasOwnProp(this, '_monthsRegex')) { - this._monthsRegex = defaultMonthsRegex; - } - return this._monthsStrictRegex && isStrict - ? this._monthsStrictRegex - : this._monthsRegex; - } - } +// -- Encoding - function computeMonthsParse() { - function cmpLenRev(a, b) { - return b.length - a.length; - } +function Utf32AutoEncoder(options, codec) { + options = options || {}; - var shortPieces = [], - longPieces = [], - mixedPieces = [], - i, - mom; - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = createUTC([2000, i]); - shortPieces.push(this.monthsShort(mom, '')); - longPieces.push(this.months(mom, '')); - mixedPieces.push(this.months(mom, '')); - mixedPieces.push(this.monthsShort(mom, '')); - } - // Sorting makes sure if one month (or abbr) is a prefix of another it - // will match the longer piece. - shortPieces.sort(cmpLenRev); - longPieces.sort(cmpLenRev); - mixedPieces.sort(cmpLenRev); - for (i = 0; i < 12; i++) { - shortPieces[i] = regexEscape(shortPieces[i]); - longPieces[i] = regexEscape(longPieces[i]); - } - for (i = 0; i < 24; i++) { - mixedPieces[i] = regexEscape(mixedPieces[i]); - } + if (options.addBOM === undefined) + options.addBOM = true; - this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); - this._monthsShortRegex = this._monthsRegex; - this._monthsStrictRegex = new RegExp( - '^(' + longPieces.join('|') + ')', - 'i' - ); - this._monthsShortStrictRegex = new RegExp( - '^(' + shortPieces.join('|') + ')', - 'i' - ); - } + this.encoder = codec.iconv.getEncoder(options.defaultEncoding || 'utf-32le', options); +} - // FORMATTING +Utf32AutoEncoder.prototype.write = function(str) { + return this.encoder.write(str); +}; - addFormatToken('Y', 0, 0, function () { - var y = this.year(); - return y <= 9999 ? zeroFill(y, 4) : '+' + y; - }); +Utf32AutoEncoder.prototype.end = function() { + return this.encoder.end(); +}; - addFormatToken(0, ['YY', 2], 0, function () { - return this.year() % 100; - }); +// -- Decoding + +function Utf32AutoDecoder(options, codec) { + this.decoder = null; + this.initialBufs = []; + this.initialBufsLen = 0; + this.options = options || {}; + this.iconv = codec.iconv; +} - addFormatToken(0, ['YYYY', 4], 0, 'year'); - addFormatToken(0, ['YYYYY', 5], 0, 'year'); - addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); +Utf32AutoDecoder.prototype.write = function(buf) { + if (!this.decoder) { + // Codec is not chosen yet. Accumulate initial bytes. + this.initialBufs.push(buf); + this.initialBufsLen += buf.length; - // ALIASES + if (this.initialBufsLen < 32) // We need more bytes to use space heuristic (see below) + return ''; - addUnitAlias('year', 'y'); + // We have enough bytes -> detect endianness. + var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); + this.decoder = this.iconv.getDecoder(encoding, this.options); - // PRIORITIES + var resStr = ''; + for (var i = 0; i < this.initialBufs.length; i++) + resStr += this.decoder.write(this.initialBufs[i]); - addUnitPriority('year', 1); + this.initialBufs.length = this.initialBufsLen = 0; + return resStr; + } - // PARSING + return this.decoder.write(buf); +}; - addRegexToken('Y', matchSigned); - addRegexToken('YY', match1to2, match2); - addRegexToken('YYYY', match1to4, match4); - addRegexToken('YYYYY', match1to6, match6); - addRegexToken('YYYYYY', match1to6, match6); +Utf32AutoDecoder.prototype.end = function() { + if (!this.decoder) { + var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding); + this.decoder = this.iconv.getDecoder(encoding, this.options); - addParseToken(['YYYYY', 'YYYYYY'], YEAR); - addParseToken('YYYY', function (input, array) { - array[YEAR] = - input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); - }); - addParseToken('YY', function (input, array) { - array[YEAR] = hooks.parseTwoDigitYear(input); - }); - addParseToken('Y', function (input, array) { - array[YEAR] = parseInt(input, 10); - }); + var resStr = ''; + for (var i = 0; i < this.initialBufs.length; i++) + resStr += this.decoder.write(this.initialBufs[i]); - // HELPERS + var trail = this.decoder.end(); + if (trail) + resStr += trail; - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; + this.initialBufs.length = this.initialBufsLen = 0; + return resStr; } - // HOOKS - - hooks.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; + return this.decoder.end(); +}; - // MOMENTS +function detectEncoding(bufs, defaultEncoding) { + var b = []; + var charsProcessed = 0; + var invalidLE = 0, invalidBE = 0; // Number of invalid chars when decoded as LE or BE. + var bmpCharsLE = 0, bmpCharsBE = 0; // Number of BMP chars when decoded as LE or BE. - var getSetYear = makeGetSet('FullYear', true); + outer_loop: + for (var i = 0; i < bufs.length; i++) { + var buf = bufs[i]; + for (var j = 0; j < buf.length; j++) { + b.push(buf[j]); + if (b.length === 4) { + if (charsProcessed === 0) { + // Check BOM first. + if (b[0] === 0xFF && b[1] === 0xFE && b[2] === 0 && b[3] === 0) { + return 'utf-32le'; + } + if (b[0] === 0 && b[1] === 0 && b[2] === 0xFE && b[3] === 0xFF) { + return 'utf-32be'; + } + } - function getIsLeapYear() { - return isLeapYear(this.year()); - } + if (b[0] !== 0 || b[1] > 0x10) invalidBE++; + if (b[3] !== 0 || b[2] > 0x10) invalidLE++; - function createDate(y, m, d, h, M, s, ms) { - // can't just apply() to create a date: - // https://stackoverflow.com/q/181348 - var date; - // the date constructor remaps years 0-99 to 1900-1999 - if (y < 100 && y >= 0) { - // preserve leap years using a full 400 year cycle, then reset - date = new Date(y + 400, m, d, h, M, s, ms); - if (isFinite(date.getFullYear())) { - date.setFullYear(y); - } - } else { - date = new Date(y, m, d, h, M, s, ms); - } + if (b[0] === 0 && b[1] === 0 && (b[2] !== 0 || b[3] !== 0)) bmpCharsBE++; + if ((b[0] !== 0 || b[1] !== 0) && b[2] === 0 && b[3] === 0) bmpCharsLE++; - return date; - } + b.length = 0; + charsProcessed++; - function createUTCDate(y) { - var date, args; - // the Date.UTC function remaps years 0-99 to 1900-1999 - if (y < 100 && y >= 0) { - args = Array.prototype.slice.call(arguments); - // preserve leap years using a full 400 year cycle, then reset - args[0] = y + 400; - date = new Date(Date.UTC.apply(null, args)); - if (isFinite(date.getUTCFullYear())) { - date.setUTCFullYear(y); + if (charsProcessed >= 100) { + break outer_loop; + } } - } else { - date = new Date(Date.UTC.apply(null, arguments)); } - - return date; } - // start-of-first-week - start-of-year - function firstWeekOffset(year, dow, doy) { - var // first-week day -- which january is always in the first week (4 for iso, 1 for other) - fwd = 7 + dow - doy, - // first-week day local weekday -- which local weekday is fwd - fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + // Make decisions. + if (bmpCharsBE - invalidBE > bmpCharsLE - invalidLE) return 'utf-32be'; + if (bmpCharsBE - invalidBE < bmpCharsLE - invalidLE) return 'utf-32le'; - return -fwdlw + fwd - 1; - } + // Couldn't decide (likely all zeros or not enough data). + return defaultEncoding || 'utf-32le'; +} - // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, dow, doy) { - var localWeekday = (7 + weekday - dow) % 7, - weekOffset = firstWeekOffset(year, dow, doy), - dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, - resYear, - resDayOfYear; - if (dayOfYear <= 0) { - resYear = year - 1; - resDayOfYear = daysInYear(resYear) + dayOfYear; - } else if (dayOfYear > daysInYear(year)) { - resYear = year + 1; - resDayOfYear = dayOfYear - daysInYear(year); - } else { - resYear = year; - resDayOfYear = dayOfYear; - } +/***/ }), - return { - year: resYear, - dayOfYear: resDayOfYear, - }; - } +/***/ 1644: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - function weekOfYear(mom, dow, doy) { - var weekOffset = firstWeekOffset(mom.year(), dow, doy), - week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, - resWeek, - resYear; +"use strict"; - if (week < 1) { - resYear = mom.year() - 1; - resWeek = week + weeksInYear(resYear, dow, doy); - } else if (week > weeksInYear(mom.year(), dow, doy)) { - resWeek = week - weeksInYear(mom.year(), dow, doy); - resYear = mom.year() + 1; - } else { - resYear = mom.year(); - resWeek = week; - } +var Buffer = (__nccwpck_require__(5118).Buffer); - return { - week: resWeek, - year: resYear, - }; - } +// UTF-7 codec, according to https://tools.ietf.org/html/rfc2152 +// See also below a UTF-7-IMAP codec, according to http://tools.ietf.org/html/rfc3501#section-5.1.3 - function weeksInYear(year, dow, doy) { - var weekOffset = firstWeekOffset(year, dow, doy), - weekOffsetNext = firstWeekOffset(year + 1, dow, doy); - return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; - } +exports.utf7 = Utf7Codec; +exports.unicode11utf7 = 'utf7'; // Alias UNICODE-1-1-UTF-7 +function Utf7Codec(codecOptions, iconv) { + this.iconv = iconv; +}; - // FORMATTING +Utf7Codec.prototype.encoder = Utf7Encoder; +Utf7Codec.prototype.decoder = Utf7Decoder; +Utf7Codec.prototype.bomAware = true; - addFormatToken('w', ['ww', 2], 'wo', 'week'); - addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); - // ALIASES +// -- Encoding - addUnitAlias('week', 'w'); - addUnitAlias('isoWeek', 'W'); +var nonDirectChars = /[^A-Za-z0-9'\(\),-\.\/:\? \n\r\t]+/g; - // PRIORITIES +function Utf7Encoder(options, codec) { + this.iconv = codec.iconv; +} - addUnitPriority('week', 5); - addUnitPriority('isoWeek', 5); +Utf7Encoder.prototype.write = function(str) { + // Naive implementation. + // Non-direct chars are encoded as "+-"; single "+" char is encoded as "+-". + return Buffer.from(str.replace(nonDirectChars, function(chunk) { + return "+" + (chunk === '+' ? '' : + this.iconv.encode(chunk, 'utf16-be').toString('base64').replace(/=+$/, '')) + + "-"; + }.bind(this))); +} - // PARSING +Utf7Encoder.prototype.end = function() { +} - addRegexToken('w', match1to2); - addRegexToken('ww', match1to2, match2); - addRegexToken('W', match1to2); - addRegexToken('WW', match1to2, match2); - addWeekParseToken( - ['w', 'ww', 'W', 'WW'], - function (input, week, config, token) { - week[token.substr(0, 1)] = toInt(input); - } - ); +// -- Decoding - // HELPERS +function Utf7Decoder(options, codec) { + this.iconv = codec.iconv; + this.inBase64 = false; + this.base64Accum = ''; +} - // LOCALES +var base64Regex = /[A-Za-z0-9\/+]/; +var base64Chars = []; +for (var i = 0; i < 256; i++) + base64Chars[i] = base64Regex.test(String.fromCharCode(i)); - function localeWeek(mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - } +var plusChar = '+'.charCodeAt(0), + minusChar = '-'.charCodeAt(0), + andChar = '&'.charCodeAt(0); - var defaultLocaleWeek = { - dow: 0, // Sunday is the first day of the week. - doy: 6, // The week that contains Jan 6th is the first week of the year. - }; +Utf7Decoder.prototype.write = function(buf) { + var res = "", lastI = 0, + inBase64 = this.inBase64, + base64Accum = this.base64Accum; - function localeFirstDayOfWeek() { - return this._week.dow; - } + // The decoder is more involved as we must handle chunks in stream. - function localeFirstDayOfYear() { - return this._week.doy; - } + for (var i = 0; i < buf.length; i++) { + if (!inBase64) { // We're in direct mode. + // Write direct chars until '+' + if (buf[i] == plusChar) { + res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars. + lastI = i+1; + inBase64 = true; + } + } else { // We decode base64. + if (!base64Chars[buf[i]]) { // Base64 ended. + if (i == lastI && buf[i] == minusChar) {// "+-" -> "+" + res += "+"; + } else { + var b64str = base64Accum + this.iconv.decode(buf.slice(lastI, i), "ascii"); + res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); + } - // MOMENTS + if (buf[i] != minusChar) // Minus is absorbed after base64. + i--; - function getSetWeek(input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); + lastI = i+1; + inBase64 = false; + base64Accum = ''; + } + } } - function getSetISOWeek(input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - } + if (!inBase64) { + res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars. + } else { + var b64str = base64Accum + this.iconv.decode(buf.slice(lastI), "ascii"); - // FORMATTING + var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars. + base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future. + b64str = b64str.slice(0, canBeDecoded); - addFormatToken('d', 0, 'do', 'day'); + res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); + } - addFormatToken('dd', 0, 0, function (format) { - return this.localeData().weekdaysMin(this, format); - }); + this.inBase64 = inBase64; + this.base64Accum = base64Accum; - addFormatToken('ddd', 0, 0, function (format) { - return this.localeData().weekdaysShort(this, format); - }); + return res; +} - addFormatToken('dddd', 0, 0, function (format) { - return this.localeData().weekdays(this, format); - }); +Utf7Decoder.prototype.end = function() { + var res = ""; + if (this.inBase64 && this.base64Accum.length > 0) + res = this.iconv.decode(Buffer.from(this.base64Accum, 'base64'), "utf16-be"); - addFormatToken('e', 0, 0, 'weekday'); - addFormatToken('E', 0, 0, 'isoWeekday'); + this.inBase64 = false; + this.base64Accum = ''; + return res; +} - // ALIASES - addUnitAlias('day', 'd'); - addUnitAlias('weekday', 'e'); - addUnitAlias('isoWeekday', 'E'); +// UTF-7-IMAP codec. +// RFC3501 Sec. 5.1.3 Modified UTF-7 (http://tools.ietf.org/html/rfc3501#section-5.1.3) +// Differences: +// * Base64 part is started by "&" instead of "+" +// * Direct characters are 0x20-0x7E, except "&" (0x26) +// * In Base64, "," is used instead of "/" +// * Base64 must not be used to represent direct characters. +// * No implicit shift back from Base64 (should always end with '-') +// * String must end in non-shifted position. +// * "-&" while in base64 is not allowed. - // PRIORITY - addUnitPriority('day', 11); - addUnitPriority('weekday', 11); - addUnitPriority('isoWeekday', 11); - // PARSING +exports.utf7imap = Utf7IMAPCodec; +function Utf7IMAPCodec(codecOptions, iconv) { + this.iconv = iconv; +}; - addRegexToken('d', match1to2); - addRegexToken('e', match1to2); - addRegexToken('E', match1to2); - addRegexToken('dd', function (isStrict, locale) { - return locale.weekdaysMinRegex(isStrict); - }); - addRegexToken('ddd', function (isStrict, locale) { - return locale.weekdaysShortRegex(isStrict); - }); - addRegexToken('dddd', function (isStrict, locale) { - return locale.weekdaysRegex(isStrict); - }); +Utf7IMAPCodec.prototype.encoder = Utf7IMAPEncoder; +Utf7IMAPCodec.prototype.decoder = Utf7IMAPDecoder; +Utf7IMAPCodec.prototype.bomAware = true; - addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { - var weekday = config._locale.weekdaysParse(input, token, config._strict); - // if we didn't get a weekday name, mark the date as invalid - if (weekday != null) { - week.d = weekday; - } else { - getParsingFlags(config).invalidWeekday = input; - } - }); - addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { - week[token] = toInt(input); - }); +// -- Encoding - // HELPERS +function Utf7IMAPEncoder(options, codec) { + this.iconv = codec.iconv; + this.inBase64 = false; + this.base64Accum = Buffer.alloc(6); + this.base64AccumIdx = 0; +} - function parseWeekday(input, locale) { - if (typeof input !== 'string') { - return input; - } +Utf7IMAPEncoder.prototype.write = function(str) { + var inBase64 = this.inBase64, + base64Accum = this.base64Accum, + base64AccumIdx = this.base64AccumIdx, + buf = Buffer.alloc(str.length*5 + 10), bufIdx = 0; - if (!isNaN(input)) { - return parseInt(input, 10); - } + for (var i = 0; i < str.length; i++) { + var uChar = str.charCodeAt(i); + if (0x20 <= uChar && uChar <= 0x7E) { // Direct character or '&'. + if (inBase64) { + if (base64AccumIdx > 0) { + bufIdx += buf.write(base64Accum.slice(0, base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx); + base64AccumIdx = 0; + } - input = locale.weekdaysParse(input); - if (typeof input === 'number') { - return input; - } + buf[bufIdx++] = minusChar; // Write '-', then go to direct mode. + inBase64 = false; + } - return null; - } + if (!inBase64) { + buf[bufIdx++] = uChar; // Write direct character - function parseIsoWeekday(input, locale) { - if (typeof input === 'string') { - return locale.weekdaysParse(input) % 7 || 7; - } - return isNaN(input) ? null : input; - } - - // LOCALES - function shiftWeekdays(ws, n) { - return ws.slice(n, 7).concat(ws.slice(0, n)); - } - - var defaultLocaleWeekdays = - 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - defaultWeekdaysRegex = matchWord, - defaultWeekdaysShortRegex = matchWord, - defaultWeekdaysMinRegex = matchWord; - - function localeWeekdays(m, format) { - var weekdays = isArray(this._weekdays) - ? this._weekdays - : this._weekdays[ - m && m !== true && this._weekdays.isFormat.test(format) - ? 'format' - : 'standalone' - ]; - return m === true - ? shiftWeekdays(weekdays, this._week.dow) - : m - ? weekdays[m.day()] - : weekdays; - } - - function localeWeekdaysShort(m) { - return m === true - ? shiftWeekdays(this._weekdaysShort, this._week.dow) - : m - ? this._weekdaysShort[m.day()] - : this._weekdaysShort; - } - - function localeWeekdaysMin(m) { - return m === true - ? shiftWeekdays(this._weekdaysMin, this._week.dow) - : m - ? this._weekdaysMin[m.day()] - : this._weekdaysMin; - } - - function handleStrictParse$1(weekdayName, format, strict) { - var i, - ii, - mom, - llc = weekdayName.toLocaleLowerCase(); - if (!this._weekdaysParse) { - this._weekdaysParse = []; - this._shortWeekdaysParse = []; - this._minWeekdaysParse = []; - - for (i = 0; i < 7; ++i) { - mom = createUTC([2000, 1]).day(i); - this._minWeekdaysParse[i] = this.weekdaysMin( - mom, - '' - ).toLocaleLowerCase(); - this._shortWeekdaysParse[i] = this.weekdaysShort( - mom, - '' - ).toLocaleLowerCase(); - this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); + if (uChar === andChar) // Ampersand -> '&-' + buf[bufIdx++] = minusChar; } - } - if (strict) { - if (format === 'dddd') { - ii = indexOf.call(this._weekdaysParse, llc); - return ii !== -1 ? ii : null; - } else if (format === 'ddd') { - ii = indexOf.call(this._shortWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._minWeekdaysParse, llc); - return ii !== -1 ? ii : null; + } else { // Non-direct character + if (!inBase64) { + buf[bufIdx++] = andChar; // Write '&', then go to base64 mode. + inBase64 = true; } - } else { - if (format === 'dddd') { - ii = indexOf.call(this._weekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._shortWeekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._minWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } else if (format === 'ddd') { - ii = indexOf.call(this._shortWeekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._weekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._minWeekdaysParse, llc); - return ii !== -1 ? ii : null; - } else { - ii = indexOf.call(this._minWeekdaysParse, llc); - if (ii !== -1) { - return ii; - } - ii = indexOf.call(this._weekdaysParse, llc); - if (ii !== -1) { - return ii; + if (inBase64) { + base64Accum[base64AccumIdx++] = uChar >> 8; + base64Accum[base64AccumIdx++] = uChar & 0xFF; + + if (base64AccumIdx == base64Accum.length) { + bufIdx += buf.write(base64Accum.toString('base64').replace(/\//g, ','), bufIdx); + base64AccumIdx = 0; } - ii = indexOf.call(this._shortWeekdaysParse, llc); - return ii !== -1 ? ii : null; } } } - function localeWeekdaysParse(weekdayName, format, strict) { - var i, mom, regex; + this.inBase64 = inBase64; + this.base64AccumIdx = base64AccumIdx; - if (this._weekdaysParseExact) { - return handleStrictParse$1.call(this, weekdayName, format, strict); - } + return buf.slice(0, bufIdx); +} - if (!this._weekdaysParse) { - this._weekdaysParse = []; - this._minWeekdaysParse = []; - this._shortWeekdaysParse = []; - this._fullWeekdaysParse = []; +Utf7IMAPEncoder.prototype.end = function() { + var buf = Buffer.alloc(10), bufIdx = 0; + if (this.inBase64) { + if (this.base64AccumIdx > 0) { + bufIdx += buf.write(this.base64Accum.slice(0, this.base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx); + this.base64AccumIdx = 0; } - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - - mom = createUTC([2000, 1]).day(i); - if (strict && !this._fullWeekdaysParse[i]) { - this._fullWeekdaysParse[i] = new RegExp( - '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', - 'i' - ); - this._shortWeekdaysParse[i] = new RegExp( - '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', - 'i' - ); - this._minWeekdaysParse[i] = new RegExp( - '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', - 'i' - ); - } - if (!this._weekdaysParse[i]) { - regex = - '^' + - this.weekdays(mom, '') + - '|^' + - this.weekdaysShort(mom, '') + - '|^' + - this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if ( - strict && - format === 'dddd' && - this._fullWeekdaysParse[i].test(weekdayName) - ) { - return i; - } else if ( - strict && - format === 'ddd' && - this._shortWeekdaysParse[i].test(weekdayName) - ) { - return i; - } else if ( - strict && - format === 'dd' && - this._minWeekdaysParse[i].test(weekdayName) - ) { - return i; - } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } + buf[bufIdx++] = minusChar; // Write '-', then go to direct mode. + this.inBase64 = false; } - // MOMENTS + return buf.slice(0, bufIdx); +} - function getSetDayOfWeek(input) { - if (!this.isValid()) { - return input != null ? this : NaN; - } - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - } - function getSetLocaleDayOfWeek(input) { - if (!this.isValid()) { - return input != null ? this : NaN; - } - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - } +// -- Decoding - function getSetISODayOfWeek(input) { - if (!this.isValid()) { - return input != null ? this : NaN; - } +function Utf7IMAPDecoder(options, codec) { + this.iconv = codec.iconv; + this.inBase64 = false; + this.base64Accum = ''; +} - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. +var base64IMAPChars = base64Chars.slice(); +base64IMAPChars[','.charCodeAt(0)] = true; - if (input != null) { - var weekday = parseIsoWeekday(input, this.localeData()); - return this.day(this.day() % 7 ? weekday : weekday - 7); - } else { - return this.day() || 7; - } - } +Utf7IMAPDecoder.prototype.write = function(buf) { + var res = "", lastI = 0, + inBase64 = this.inBase64, + base64Accum = this.base64Accum; - function weekdaysRegex(isStrict) { - if (this._weekdaysParseExact) { - if (!hasOwnProp(this, '_weekdaysRegex')) { - computeWeekdaysParse.call(this); - } - if (isStrict) { - return this._weekdaysStrictRegex; - } else { - return this._weekdaysRegex; - } - } else { - if (!hasOwnProp(this, '_weekdaysRegex')) { - this._weekdaysRegex = defaultWeekdaysRegex; - } - return this._weekdaysStrictRegex && isStrict - ? this._weekdaysStrictRegex - : this._weekdaysRegex; - } - } + // The decoder is more involved as we must handle chunks in stream. + // It is forgiving, closer to standard UTF-7 (for example, '-' is optional at the end). - function weekdaysShortRegex(isStrict) { - if (this._weekdaysParseExact) { - if (!hasOwnProp(this, '_weekdaysRegex')) { - computeWeekdaysParse.call(this); - } - if (isStrict) { - return this._weekdaysShortStrictRegex; - } else { - return this._weekdaysShortRegex; - } - } else { - if (!hasOwnProp(this, '_weekdaysShortRegex')) { - this._weekdaysShortRegex = defaultWeekdaysShortRegex; + for (var i = 0; i < buf.length; i++) { + if (!inBase64) { // We're in direct mode. + // Write direct chars until '&' + if (buf[i] == andChar) { + res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars. + lastI = i+1; + inBase64 = true; } - return this._weekdaysShortStrictRegex && isStrict - ? this._weekdaysShortStrictRegex - : this._weekdaysShortRegex; - } - } + } else { // We decode base64. + if (!base64IMAPChars[buf[i]]) { // Base64 ended. + if (i == lastI && buf[i] == minusChar) { // "&-" -> "&" + res += "&"; + } else { + var b64str = base64Accum + this.iconv.decode(buf.slice(lastI, i), "ascii").replace(/,/g, '/'); + res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); + } - function weekdaysMinRegex(isStrict) { - if (this._weekdaysParseExact) { - if (!hasOwnProp(this, '_weekdaysRegex')) { - computeWeekdaysParse.call(this); - } - if (isStrict) { - return this._weekdaysMinStrictRegex; - } else { - return this._weekdaysMinRegex; - } - } else { - if (!hasOwnProp(this, '_weekdaysMinRegex')) { - this._weekdaysMinRegex = defaultWeekdaysMinRegex; + if (buf[i] != minusChar) // Minus may be absorbed after base64. + i--; + + lastI = i+1; + inBase64 = false; + base64Accum = ''; } - return this._weekdaysMinStrictRegex && isStrict - ? this._weekdaysMinStrictRegex - : this._weekdaysMinRegex; } } - function computeWeekdaysParse() { - function cmpLenRev(a, b) { - return b.length - a.length; - } + if (!inBase64) { + res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars. + } else { + var b64str = base64Accum + this.iconv.decode(buf.slice(lastI), "ascii").replace(/,/g, '/'); - var minPieces = [], - shortPieces = [], - longPieces = [], - mixedPieces = [], - i, - mom, - minp, - shortp, - longp; - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - mom = createUTC([2000, 1]).day(i); - minp = regexEscape(this.weekdaysMin(mom, '')); - shortp = regexEscape(this.weekdaysShort(mom, '')); - longp = regexEscape(this.weekdays(mom, '')); - minPieces.push(minp); - shortPieces.push(shortp); - longPieces.push(longp); - mixedPieces.push(minp); - mixedPieces.push(shortp); - mixedPieces.push(longp); - } - // Sorting makes sure if one weekday (or abbr) is a prefix of another it - // will match the longer piece. - minPieces.sort(cmpLenRev); - shortPieces.sort(cmpLenRev); - longPieces.sort(cmpLenRev); - mixedPieces.sort(cmpLenRev); - - this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); - this._weekdaysShortRegex = this._weekdaysRegex; - this._weekdaysMinRegex = this._weekdaysRegex; - - this._weekdaysStrictRegex = new RegExp( - '^(' + longPieces.join('|') + ')', - 'i' - ); - this._weekdaysShortStrictRegex = new RegExp( - '^(' + shortPieces.join('|') + ')', - 'i' - ); - this._weekdaysMinStrictRegex = new RegExp( - '^(' + minPieces.join('|') + ')', - 'i' - ); + var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars. + base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future. + b64str = b64str.slice(0, canBeDecoded); + + res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be"); } - // FORMATTING + this.inBase64 = inBase64; + this.base64Accum = base64Accum; - function hFormat() { - return this.hours() % 12 || 12; - } + return res; +} - function kFormat() { - return this.hours() || 24; - } +Utf7IMAPDecoder.prototype.end = function() { + var res = ""; + if (this.inBase64 && this.base64Accum.length > 0) + res = this.iconv.decode(Buffer.from(this.base64Accum, 'base64'), "utf16-be"); + + this.inBase64 = false; + this.base64Accum = ''; + return res; +} - addFormatToken('H', ['HH', 2], 0, 'hour'); - addFormatToken('h', ['hh', 2], 0, hFormat); - addFormatToken('k', ['kk', 2], 0, kFormat); - addFormatToken('hmm', 0, 0, function () { - return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); - }); - addFormatToken('hmmss', 0, 0, function () { - return ( - '' + - hFormat.apply(this) + - zeroFill(this.minutes(), 2) + - zeroFill(this.seconds(), 2) - ); - }); - addFormatToken('Hmm', 0, 0, function () { - return '' + this.hours() + zeroFill(this.minutes(), 2); - }); +/***/ }), - addFormatToken('Hmmss', 0, 0, function () { - return ( - '' + - this.hours() + - zeroFill(this.minutes(), 2) + - zeroFill(this.seconds(), 2) - ); - }); +/***/ 7961: +/***/ ((__unused_webpack_module, exports) => { - function meridiem(token, lowercase) { - addFormatToken(token, 0, 0, function () { - return this.localeData().meridiem( - this.hours(), - this.minutes(), - lowercase - ); - }); +"use strict"; + + +var BOMChar = '\uFEFF'; + +exports.PrependBOM = PrependBOMWrapper +function PrependBOMWrapper(encoder, options) { + this.encoder = encoder; + this.addBOM = true; +} + +PrependBOMWrapper.prototype.write = function(str) { + if (this.addBOM) { + str = BOMChar + str; + this.addBOM = false; } - meridiem('a', true); - meridiem('A', false); + return this.encoder.write(str); +} + +PrependBOMWrapper.prototype.end = function() { + return this.encoder.end(); +} - // ALIASES - addUnitAlias('hour', 'h'); +//------------------------------------------------------------------------------ - // PRIORITY - addUnitPriority('hour', 13); +exports.StripBOM = StripBOMWrapper; +function StripBOMWrapper(decoder, options) { + this.decoder = decoder; + this.pass = false; + this.options = options || {}; +} - // PARSING +StripBOMWrapper.prototype.write = function(buf) { + var res = this.decoder.write(buf); + if (this.pass || !res) + return res; - function matchMeridiem(isStrict, locale) { - return locale._meridiemParse; + if (res[0] === BOMChar) { + res = res.slice(1); + if (typeof this.options.stripBOM === 'function') + this.options.stripBOM(); } - addRegexToken('a', matchMeridiem); - addRegexToken('A', matchMeridiem); - addRegexToken('H', match1to2); - addRegexToken('h', match1to2); - addRegexToken('k', match1to2); - addRegexToken('HH', match1to2, match2); - addRegexToken('hh', match1to2, match2); - addRegexToken('kk', match1to2, match2); + this.pass = true; + return res; +} - addRegexToken('hmm', match3to4); - addRegexToken('hmmss', match5to6); - addRegexToken('Hmm', match3to4); - addRegexToken('Hmmss', match5to6); +StripBOMWrapper.prototype.end = function() { + return this.decoder.end(); +} - addParseToken(['H', 'HH'], HOUR); - addParseToken(['k', 'kk'], function (input, array, config) { - var kInput = toInt(input); - array[HOUR] = kInput === 24 ? 0 : kInput; - }); - addParseToken(['a', 'A'], function (input, array, config) { - config._isPm = config._locale.isPM(input); - config._meridiem = input; - }); - addParseToken(['h', 'hh'], function (input, array, config) { - array[HOUR] = toInt(input); - getParsingFlags(config).bigHour = true; - }); - addParseToken('hmm', function (input, array, config) { - var pos = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos)); - array[MINUTE] = toInt(input.substr(pos)); - getParsingFlags(config).bigHour = true; - }); - addParseToken('hmmss', function (input, array, config) { - var pos1 = input.length - 4, - pos2 = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos1)); - array[MINUTE] = toInt(input.substr(pos1, 2)); - array[SECOND] = toInt(input.substr(pos2)); - getParsingFlags(config).bigHour = true; - }); - addParseToken('Hmm', function (input, array, config) { - var pos = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos)); - array[MINUTE] = toInt(input.substr(pos)); - }); - addParseToken('Hmmss', function (input, array, config) { - var pos1 = input.length - 4, - pos2 = input.length - 2; - array[HOUR] = toInt(input.substr(0, pos1)); - array[MINUTE] = toInt(input.substr(pos1, 2)); - array[SECOND] = toInt(input.substr(pos2)); - }); - // LOCALES - function localeIsPM(input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return (input + '').toLowerCase().charAt(0) === 'p'; - } +/***/ }), - var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i, - // Setting the hour should keep the time, because the user explicitly - // specified which hour they want. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - getSetHour = makeGetSet('Hours', true); +/***/ 9032: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function localeMeridiem(hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - } +"use strict"; - var baseConfig = { - calendar: defaultCalendar, - longDateFormat: defaultLongDateFormat, - invalidDate: defaultInvalidDate, - ordinal: defaultOrdinal, - dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, - relativeTime: defaultRelativeTime, - months: defaultLocaleMonths, - monthsShort: defaultLocaleMonthsShort, +var Buffer = (__nccwpck_require__(5118).Buffer); - week: defaultLocaleWeek, +var bomHandling = __nccwpck_require__(7961), + iconv = module.exports; - weekdays: defaultLocaleWeekdays, - weekdaysMin: defaultLocaleWeekdaysMin, - weekdaysShort: defaultLocaleWeekdaysShort, +// All codecs and aliases are kept here, keyed by encoding name/alias. +// They are lazy loaded in `iconv.getCodec` from `encodings/index.js`. +iconv.encodings = null; - meridiemParse: defaultLocaleMeridiemParse, - }; +// Characters emitted in case of error. +iconv.defaultCharUnicode = '�'; +iconv.defaultCharSingleByte = '?'; - // internal storage for locale config files - var locales = {}, - localeFamilies = {}, - globalLocale; - - function commonPrefix(arr1, arr2) { - var i, - minl = Math.min(arr1.length, arr2.length); - for (i = 0; i < minl; i += 1) { - if (arr1[i] !== arr2[i]) { - return i; - } - } - return minl; - } - - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // pick the locale from the array - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { - var i = 0, - j, - next, - locale, - split; - - while (i < names.length) { - split = normalizeLocale(names[i]).split('-'); - j = split.length; - next = normalizeLocale(names[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - locale = loadLocale(split.slice(0, j).join('-')); - if (locale) { - return locale; - } - if ( - next && - next.length >= j && - commonPrefix(split, next) >= j - 1 - ) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; +// Public API. +iconv.encode = function encode(str, encoding, options) { + str = "" + (str || ""); // Ensure string. + + var encoder = iconv.getEncoder(encoding, options); + + var res = encoder.write(str); + var trail = encoder.end(); + + return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res; +} + +iconv.decode = function decode(buf, encoding, options) { + if (typeof buf === 'string') { + if (!iconv.skipDecodeWarning) { + console.error('Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding'); + iconv.skipDecodeWarning = true; } - return globalLocale; - } - function isLocaleNameSane(name) { - // Prevent names that look like filesystem paths, i.e contain '/' or '\' - return name.match('^[^/\\\\]*$') != null; + buf = Buffer.from("" + (buf || ""), "binary"); // Ensure buffer. } - function loadLocale(name) { - var oldLocale = null, - aliasedRequire; - // TODO: Find a better way to register and load all the locales in Node - if ( - locales[name] === undefined && - "object" !== 'undefined' && - module && - module.exports && - isLocaleNameSane(name) - ) { - try { - oldLocale = globalLocale._abbr; - aliasedRequire = require; - aliasedRequire('./locale/' + name); - getSetGlobalLocale(oldLocale); - } catch (e) { - // mark as not found to avoid repeating expensive file require call causing high CPU - // when trying to find en-US, en_US, en-us for every format call - locales[name] = null; // null means not found - } - } - return locales[name]; + var decoder = iconv.getDecoder(encoding, options); + + var res = decoder.write(buf); + var trail = decoder.end(); + + return trail ? (res + trail) : res; +} + +iconv.encodingExists = function encodingExists(enc) { + try { + iconv.getCodec(enc); + return true; + } catch (e) { + return false; } +} - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - function getSetGlobalLocale(key, values) { - var data; - if (key) { - if (isUndefined(values)) { - data = getLocale(key); - } else { - data = defineLocale(key, values); - } +// Legacy aliases to convert functions +iconv.toEncoding = iconv.encode; +iconv.fromEncoding = iconv.decode; - if (data) { - // moment.duration._locale = moment._locale = data; - globalLocale = data; - } else { - if (typeof console !== 'undefined' && console.warn) { - //warn user if arguments are passed but the locale could not be set - console.warn( - 'Locale ' + key + ' not found. Did you forget to load it?' - ); - } - } - } +// Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache. +iconv._codecDataCache = {}; +iconv.getCodec = function getCodec(encoding) { + if (!iconv.encodings) + iconv.encodings = __nccwpck_require__(2733); // Lazy load all encoding definitions. + + // Canonicalize encoding name: strip all non-alphanumeric chars and appended year. + var enc = iconv._canonicalizeEncoding(encoding); + + // Traverse iconv.encodings to find actual codec. + var codecOptions = {}; + while (true) { + var codec = iconv._codecDataCache[enc]; + if (codec) + return codec; - return globalLocale._abbr; - } - - function defineLocale(name, config) { - if (config !== null) { - var locale, - parentConfig = baseConfig; - config.abbr = name; - if (locales[name] != null) { - deprecateSimple( - 'defineLocaleOverride', - 'use moment.updateLocale(localeName, config) to change ' + - 'an existing locale. moment.defineLocale(localeName, ' + - 'config) should only be used for creating a new locale ' + - 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.' - ); - parentConfig = locales[name]._config; - } else if (config.parentLocale != null) { - if (locales[config.parentLocale] != null) { - parentConfig = locales[config.parentLocale]._config; - } else { - locale = loadLocale(config.parentLocale); - if (locale != null) { - parentConfig = locale._config; - } else { - if (!localeFamilies[config.parentLocale]) { - localeFamilies[config.parentLocale] = []; - } - localeFamilies[config.parentLocale].push({ - name: name, - config: config, - }); - return null; - } - } - } - locales[name] = new Locale(mergeConfigs(parentConfig, config)); + var codecDef = iconv.encodings[enc]; - if (localeFamilies[name]) { - localeFamilies[name].forEach(function (x) { - defineLocale(x.name, x.config); - }); - } + switch (typeof codecDef) { + case "string": // Direct alias to other encoding. + enc = codecDef; + break; - // backwards compat for now: also set the locale - // make sure we set the locale AFTER all child locales have been - // created, so we won't end up with the child locale set. - getSetGlobalLocale(name); + case "object": // Alias with options. Can be layered. + for (var key in codecDef) + codecOptions[key] = codecDef[key]; - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - } + if (!codecOptions.encodingName) + codecOptions.encodingName = enc; + + enc = codecDef.type; + break; - function updateLocale(name, config) { - if (config != null) { - var locale, - tmpLocale, - parentConfig = baseConfig; + case "function": // Codec itself. + if (!codecOptions.encodingName) + codecOptions.encodingName = enc; - if (locales[name] != null && locales[name].parentLocale != null) { - // Update existing child locale in-place to avoid memory-leaks - locales[name].set(mergeConfigs(locales[name]._config, config)); - } else { - // MERGE - tmpLocale = loadLocale(name); - if (tmpLocale != null) { - parentConfig = tmpLocale._config; - } - config = mergeConfigs(parentConfig, config); - if (tmpLocale == null) { - // updateLocale is called for creating a new locale - // Set abbr so it will have a name (getters return - // undefined otherwise). - config.abbr = name; - } - locale = new Locale(config); - locale.parentLocale = locales[name]; - locales[name] = locale; - } + // The codec function must load all tables and return object with .encoder and .decoder methods. + // It'll be called only once (for each different options object). + codec = new codecDef(codecOptions, iconv); - // backwards compat for now: also set the locale - getSetGlobalLocale(name); - } else { - // pass null for config to unupdate, useful for tests - if (locales[name] != null) { - if (locales[name].parentLocale != null) { - locales[name] = locales[name].parentLocale; - if (name === getSetGlobalLocale()) { - getSetGlobalLocale(name); - } - } else if (locales[name] != null) { - delete locales[name]; - } - } + iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later. + return codec; + + default: + throw new Error("Encoding not recognized: '" + encoding + "' (searched as: '"+enc+"')"); } - return locales[name]; } +} - // returns locale data - function getLocale(key) { - var locale; +iconv._canonicalizeEncoding = function(encoding) { + // Canonicalize encoding name: strip all non-alphanumeric chars and appended year. + return (''+encoding).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, ""); +} - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } +iconv.getEncoder = function getEncoder(encoding, options) { + var codec = iconv.getCodec(encoding), + encoder = new codec.encoder(options, codec); - if (!key) { - return globalLocale; - } + if (codec.bomAware && options && options.addBOM) + encoder = new bomHandling.PrependBOM(encoder, options); - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } + return encoder; +} - return chooseLocale(key); - } - - function listLocales() { - return keys(locales); - } - - function checkOverflow(m) { - var overflow, - a = m._a; - - if (a && getParsingFlags(m).overflow === -2) { - overflow = - a[MONTH] < 0 || a[MONTH] > 11 - ? MONTH - : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) - ? DATE - : a[HOUR] < 0 || - a[HOUR] > 24 || - (a[HOUR] === 24 && - (a[MINUTE] !== 0 || - a[SECOND] !== 0 || - a[MILLISECOND] !== 0)) - ? HOUR - : a[MINUTE] < 0 || a[MINUTE] > 59 - ? MINUTE - : a[SECOND] < 0 || a[SECOND] > 59 - ? SECOND - : a[MILLISECOND] < 0 || a[MILLISECOND] > 999 - ? MILLISECOND - : -1; - - if ( - getParsingFlags(m)._overflowDayOfYear && - (overflow < YEAR || overflow > DATE) - ) { - overflow = DATE; - } - if (getParsingFlags(m)._overflowWeeks && overflow === -1) { - overflow = WEEK; - } - if (getParsingFlags(m)._overflowWeekday && overflow === -1) { - overflow = WEEKDAY; - } +iconv.getDecoder = function getDecoder(encoding, options) { + var codec = iconv.getCodec(encoding), + decoder = new codec.decoder(options, codec); - getParsingFlags(m).overflow = overflow; - } + if (codec.bomAware && !(options && options.stripBOM === false)) + decoder = new bomHandling.StripBOM(decoder, options); - return m; - } - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - var extendedIsoRegex = - /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - basicIsoRegex = - /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - tzRegex = /Z|[+-]\d\d(?::?\d\d)?/, - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], - ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], - ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], - ['GGGG-[W]WW', /\d{4}-W\d\d/, false], - ['YYYY-DDD', /\d{4}-\d{3}/], - ['YYYY-MM', /\d{4}-\d\d/, false], - ['YYYYYYMMDD', /[+-]\d{10}/], - ['YYYYMMDD', /\d{8}/], - ['GGGG[W]WWE', /\d{4}W\d{3}/], - ['GGGG[W]WW', /\d{4}W\d{2}/, false], - ['YYYYDDD', /\d{7}/], - ['YYYYMM', /\d{6}/, false], - ['YYYY', /\d{4}/, false], - ], - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], - ['HH:mm:ss', /\d\d:\d\d:\d\d/], - ['HH:mm', /\d\d:\d\d/], - ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], - ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], - ['HHmmss', /\d\d\d\d\d\d/], - ['HHmm', /\d\d\d\d/], - ['HH', /\d\d/], - ], - aspNetJsonRegex = /^\/?Date\((-?\d+)/i, - // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 - rfc2822 = - /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, - obsOffsets = { - UT: 0, - GMT: 0, - EDT: -4 * 60, - EST: -5 * 60, - CDT: -5 * 60, - CST: -6 * 60, - MDT: -6 * 60, - MST: -7 * 60, - PDT: -7 * 60, - PST: -8 * 60, - }; + return decoder; +} - // date from iso format - function configFromISO(config) { - var i, - l, - string = config._i, - match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), - allowTime, - dateFormat, - timeFormat, - tzFormat, - isoDatesLen = isoDates.length, - isoTimesLen = isoTimes.length; - - if (match) { - getParsingFlags(config).iso = true; - for (i = 0, l = isoDatesLen; i < l; i++) { - if (isoDates[i][1].exec(match[1])) { - dateFormat = isoDates[i][0]; - allowTime = isoDates[i][2] !== false; - break; - } - } - if (dateFormat == null) { - config._isValid = false; - return; - } - if (match[3]) { - for (i = 0, l = isoTimesLen; i < l; i++) { - if (isoTimes[i][1].exec(match[3])) { - // match[2] should be 'T' or space - timeFormat = (match[2] || ' ') + isoTimes[i][0]; - break; - } - } - if (timeFormat == null) { - config._isValid = false; - return; - } - } - if (!allowTime && timeFormat != null) { - config._isValid = false; - return; - } - if (match[4]) { - if (tzRegex.exec(match[4])) { - tzFormat = 'Z'; - } else { - config._isValid = false; - return; - } - } - config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); - configFromStringAndFormat(config); - } else { - config._isValid = false; - } - } +// Streaming API +// NOTE: Streaming API naturally depends on 'stream' module from Node.js. Unfortunately in browser environments this module can add +// up to 100Kb to the output bundle. To avoid unnecessary code bloat, we don't enable Streaming API in browser by default. +// If you would like to enable it explicitly, please add the following code to your app: +// > iconv.enableStreamingAPI(require('stream')); +iconv.enableStreamingAPI = function enableStreamingAPI(stream_module) { + if (iconv.supportsStreams) + return; - function extractFromRFC2822Strings( - yearStr, - monthStr, - dayStr, - hourStr, - minuteStr, - secondStr - ) { - var result = [ - untruncateYear(yearStr), - defaultLocaleMonthsShort.indexOf(monthStr), - parseInt(dayStr, 10), - parseInt(hourStr, 10), - parseInt(minuteStr, 10), - ]; - - if (secondStr) { - result.push(parseInt(secondStr, 10)); - } + // Dependency-inject stream module to create IconvLite stream classes. + var streams = __nccwpck_require__(6869)(stream_module); - return result; - } + // Not public API yet, but expose the stream classes. + iconv.IconvLiteEncoderStream = streams.IconvLiteEncoderStream; + iconv.IconvLiteDecoderStream = streams.IconvLiteDecoderStream; - function untruncateYear(yearStr) { - var year = parseInt(yearStr, 10); - if (year <= 49) { - return 2000 + year; - } else if (year <= 999) { - return 1900 + year; - } - return year; - } - - function preprocessRFC2822(s) { - // Remove comments and folding whitespace and replace multiple-spaces with a single space - return s - .replace(/\([^()]*\)|[\n\t]/g, ' ') - .replace(/(\s\s+)/g, ' ') - .replace(/^\s\s*/, '') - .replace(/\s\s*$/, ''); - } - - function checkWeekday(weekdayStr, parsedInput, config) { - if (weekdayStr) { - // TODO: Replace the vanilla JS Date object with an independent day-of-week check. - var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), - weekdayActual = new Date( - parsedInput[0], - parsedInput[1], - parsedInput[2] - ).getDay(); - if (weekdayProvided !== weekdayActual) { - getParsingFlags(config).weekdayMismatch = true; - config._isValid = false; - return false; - } - } - return true; + // Streaming API. + iconv.encodeStream = function encodeStream(encoding, options) { + return new iconv.IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options); } - function calculateOffset(obsOffset, militaryOffset, numOffset) { - if (obsOffset) { - return obsOffsets[obsOffset]; - } else if (militaryOffset) { - // the only allowed military tz is Z - return 0; - } else { - var hm = parseInt(numOffset, 10), - m = hm % 100, - h = (hm - m) / 100; - return h * 60 + m; - } + iconv.decodeStream = function decodeStream(encoding, options) { + return new iconv.IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options); } - // date and time from ref 2822 format - function configFromRFC2822(config) { - var match = rfc2822.exec(preprocessRFC2822(config._i)), - parsedArray; - if (match) { - parsedArray = extractFromRFC2822Strings( - match[4], - match[3], - match[2], - match[5], - match[6], - match[7] - ); - if (!checkWeekday(match[1], parsedArray, config)) { - return; - } - - config._a = parsedArray; - config._tzm = calculateOffset(match[8], match[9], match[10]); - - config._d = createUTCDate.apply(null, config._a); - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + iconv.supportsStreams = true; +} - getParsingFlags(config).rfc2822 = true; - } else { - config._isValid = false; - } - } +// Enable Streaming API automatically if 'stream' module is available and non-empty (the majority of environments). +var stream_module; +try { + stream_module = __nccwpck_require__(2781); +} catch (e) {} - // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict - function configFromString(config) { - var matched = aspNetJsonRegex.exec(config._i); - if (matched !== null) { - config._d = new Date(+matched[1]); - return; - } +if (stream_module && stream_module.Transform) { + iconv.enableStreamingAPI(stream_module); - configFromISO(config); - if (config._isValid === false) { - delete config._isValid; - } else { - return; - } +} else { + // In rare cases where 'stream' module is not available by default, throw a helpful exception. + iconv.encodeStream = iconv.decodeStream = function() { + throw new Error("iconv-lite Streaming API is not enabled. Use iconv.enableStreamingAPI(require('stream')); to enable it."); + }; +} - configFromRFC2822(config); - if (config._isValid === false) { - delete config._isValid; - } else { - return; - } +if (false) {} - if (config._strict) { - config._isValid = false; - } else { - // Final attempt, use Input Fallback - hooks.createFromInputFallback(config); - } - } - hooks.createFromInputFallback = deprecate( - 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + - 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + - 'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.', - function (config) { - config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); - } - ); +/***/ }), - // Pick the first defined of two or three arguments. - function defaults(a, b, c) { - if (a != null) { - return a; - } - if (b != null) { - return b; - } - return c; - } - - function currentDateArray(config) { - // hooks is actually the exported moment object - var nowValue = new Date(hooks.now()); - if (config._useUTC) { - return [ - nowValue.getUTCFullYear(), - nowValue.getUTCMonth(), - nowValue.getUTCDate(), - ]; - } - return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function configFromArray(config) { - var i, - date, - input = [], - currentDate, - expectedWeekday, - yearToUse; - - if (config._d) { - return; - } +/***/ 6869: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - currentDate = currentDateArray(config); +"use strict"; - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } - //if the day of the year is set, figure out what it is - if (config._dayOfYear != null) { - yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); +var Buffer = (__nccwpck_require__(5118).Buffer); - if ( - config._dayOfYear > daysInYear(yearToUse) || - config._dayOfYear === 0 - ) { - getParsingFlags(config)._overflowDayOfYear = true; - } +// NOTE: Due to 'stream' module being pretty large (~100Kb, significant in browser environments), +// we opt to dependency-inject it instead of creating a hard dependency. +module.exports = function(stream_module) { + var Transform = stream_module.Transform; - date = createUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } + // == Encoder stream ======================================================= - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } + function IconvLiteEncoderStream(conv, options) { + this.conv = conv; + options = options || {}; + options.decodeStrings = false; // We accept only strings, so we don't need to decode them. + Transform.call(this, options); + } - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = - config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i]; - } + IconvLiteEncoderStream.prototype = Object.create(Transform.prototype, { + constructor: { value: IconvLiteEncoderStream } + }); - // Check for 24:00:00.000 - if ( - config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0 - ) { - config._nextDay = true; - config._a[HOUR] = 0; + IconvLiteEncoderStream.prototype._transform = function(chunk, encoding, done) { + if (typeof chunk != 'string') + return done(new Error("Iconv encoding stream needs strings as its input.")); + try { + var res = this.conv.write(chunk); + if (res && res.length) this.push(res); + done(); } - - config._d = (config._useUTC ? createUTCDate : createDate).apply( - null, - input - ); - expectedWeekday = config._useUTC - ? config._d.getUTCDay() - : config._d.getDay(); - - // Apply timezone offset from input. The actual utcOffset can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + catch (e) { + done(e); } + } - if (config._nextDay) { - config._a[HOUR] = 24; + IconvLiteEncoderStream.prototype._flush = function(done) { + try { + var res = this.conv.end(); + if (res && res.length) this.push(res); + done(); } - - // check for mismatching day of week - if ( - config._w && - typeof config._w.d !== 'undefined' && - config._w.d !== expectedWeekday - ) { - getParsingFlags(config).weekdayMismatch = true; + catch (e) { + done(e); } } - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; - - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = defaults( - w.GG, - config._a[YEAR], - weekOfYear(createLocal(), 1, 4).year - ); - week = defaults(w.W, 1); - weekday = defaults(w.E, 1); - if (weekday < 1 || weekday > 7) { - weekdayOverflow = true; - } - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; - - curWeek = weekOfYear(createLocal(), dow, doy); - - weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); - - // Default to current week. - week = defaults(w.w, curWeek.week); - - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < 0 || weekday > 6) { - weekdayOverflow = true; - } - } else if (w.e != null) { - // local weekday -- counting starts from beginning of week - weekday = w.e + dow; - if (w.e < 0 || w.e > 6) { - weekdayOverflow = true; - } - } else { - // default to beginning of week - weekday = dow; - } - } - if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { - getParsingFlags(config)._overflowWeeks = true; - } else if (weekdayOverflow != null) { - getParsingFlags(config)._overflowWeekday = true; - } else { - temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } + IconvLiteEncoderStream.prototype.collect = function(cb) { + var chunks = []; + this.on('error', cb); + this.on('data', function(chunk) { chunks.push(chunk); }); + this.on('end', function() { + cb(null, Buffer.concat(chunks)); + }); + return this; } - // constant that refers to the ISO standard - hooks.ISO_8601 = function () {}; - // constant that refers to the RFC 2822 form - hooks.RFC_2822 = function () {}; + // == Decoder stream ======================================================= - // date from string and format string - function configFromStringAndFormat(config) { - // TODO: Move this to another part of the creation flow to prevent circular deps - if (config._f === hooks.ISO_8601) { - configFromISO(config); - return; - } - if (config._f === hooks.RFC_2822) { - configFromRFC2822(config); - return; - } - config._a = []; - getParsingFlags(config).empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, - parsedInput, - tokens, - token, - skipped, - stringLength = string.length, - totalParsedInputLength = 0, - era, - tokenLen; - - tokens = - expandFormat(config._f, config._locale).match(formattingTokens) || []; - tokenLen = tokens.length; - for (i = 0; i < tokenLen; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || - [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - getParsingFlags(config).unusedInput.push(skipped); - } - string = string.slice( - string.indexOf(parsedInput) + parsedInput.length - ); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - getParsingFlags(config).empty = false; - } else { - getParsingFlags(config).unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } else if (config._strict && !parsedInput) { - getParsingFlags(config).unusedTokens.push(token); - } - } + function IconvLiteDecoderStream(conv, options) { + this.conv = conv; + options = options || {}; + options.encoding = this.encoding = 'utf8'; // We output strings. + Transform.call(this, options); + } - // add remaining unparsed input length to the string - getParsingFlags(config).charsLeftOver = - stringLength - totalParsedInputLength; - if (string.length > 0) { - getParsingFlags(config).unusedInput.push(string); - } + IconvLiteDecoderStream.prototype = Object.create(Transform.prototype, { + constructor: { value: IconvLiteDecoderStream } + }); - // clear _12h flag if hour is <= 12 - if ( - config._a[HOUR] <= 12 && - getParsingFlags(config).bigHour === true && - config._a[HOUR] > 0 - ) { - getParsingFlags(config).bigHour = undefined; + IconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) { + if (!Buffer.isBuffer(chunk) && !(chunk instanceof Uint8Array)) + return done(new Error("Iconv decoding stream needs buffers as its input.")); + try { + var res = this.conv.write(chunk); + if (res && res.length) this.push(res, this.encoding); + done(); } - - getParsingFlags(config).parsedDateParts = config._a.slice(0); - getParsingFlags(config).meridiem = config._meridiem; - // handle meridiem - config._a[HOUR] = meridiemFixWrap( - config._locale, - config._a[HOUR], - config._meridiem - ); - - // handle era - era = getParsingFlags(config).era; - if (era !== null) { - config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]); + catch (e) { + done(e); } - - configFromArray(config); - checkOverflow(config); } - function meridiemFixWrap(locale, hour, meridiem) { - var isPm; - - if (meridiem == null) { - // nothing to do - return hour; + IconvLiteDecoderStream.prototype._flush = function(done) { + try { + var res = this.conv.end(); + if (res && res.length) this.push(res, this.encoding); + done(); } - if (locale.meridiemHour != null) { - return locale.meridiemHour(hour, meridiem); - } else if (locale.isPM != null) { - // Fallback - isPm = locale.isPM(meridiem); - if (isPm && hour < 12) { - hour += 12; - } - if (!isPm && hour === 12) { - hour = 0; - } - return hour; - } else { - // this is not supposed to happen - return hour; + catch (e) { + done(e); } } - // date from string and array of format strings - function configFromStringAndArray(config) { - var tempConfig, - bestMoment, - scoreToBeat, - i, - currentScore, - validFormatFound, - bestFormatIsValid = false, - configfLen = config._f.length; - - if (configfLen === 0) { - getParsingFlags(config).invalidFormat = true; - config._d = new Date(NaN); - return; - } + IconvLiteDecoderStream.prototype.collect = function(cb) { + var res = ''; + this.on('error', cb); + this.on('data', function(chunk) { res += chunk; }); + this.on('end', function() { + cb(null, res); + }); + return this; + } - for (i = 0; i < configfLen; i++) { - currentScore = 0; - validFormatFound = false; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._f = config._f[i]; - configFromStringAndFormat(tempConfig); + return { + IconvLiteEncoderStream: IconvLiteEncoderStream, + IconvLiteDecoderStream: IconvLiteDecoderStream, + }; +}; - if (isValid(tempConfig)) { - validFormatFound = true; - } - // if there is any input that was not parsed add a penalty for that format - currentScore += getParsingFlags(tempConfig).charsLeftOver; +/***/ }), - //or tokens - currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; +/***/ 3287: +/***/ ((__unused_webpack_module, exports) => { - getParsingFlags(tempConfig).score = currentScore; +"use strict"; - if (!bestFormatIsValid) { - if ( - scoreToBeat == null || - currentScore < scoreToBeat || - validFormatFound - ) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - if (validFormatFound) { - bestFormatIsValid = true; - } - } - } else { - if (currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - } - extend(config, bestMoment || tempConfig); - } +Object.defineProperty(exports, "__esModule", ({ value: true })); - function configFromObject(config) { - if (config._d) { - return; - } +/*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ - var i = normalizeObjectUnits(config._i), - dayOrDate = i.day === undefined ? i.date : i.day; - config._a = map( - [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond], - function (obj) { - return obj && parseInt(obj, 10); - } - ); +function isObject(o) { + return Object.prototype.toString.call(o) === '[object Object]'; +} - configFromArray(config); - } +function isPlainObject(o) { + var ctor,prot; - function createFromConfig(config) { - var res = new Moment(checkOverflow(prepareConfig(config))); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } + if (isObject(o) === false) return false; - return res; - } + // If has modified constructor + ctor = o.constructor; + if (ctor === undefined) return true; - function prepareConfig(config) { - var input = config._i, - format = config._f; + // If has modified prototype + prot = ctor.prototype; + if (isObject(prot) === false) return false; - config._locale = config._locale || getLocale(config._l); + // If constructor does not have an Object-specific method + if (prot.hasOwnProperty('isPrototypeOf') === false) { + return false; + } - if (input === null || (format === undefined && input === '')) { - return createInvalid({ nullInput: true }); - } + // Most likely a plain Object + return true; +} - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } +exports.isPlainObject = isPlainObject; - if (isMoment(input)) { - return new Moment(checkOverflow(input)); - } else if (isDate(input)) { - config._d = input; - } else if (isArray(format)) { - configFromStringAndArray(config); - } else if (format) { - configFromStringAndFormat(config); - } else { - configFromInput(config); - } - if (!isValid(config)) { - config._d = null; - } +/***/ }), - return config; - } +/***/ 5902: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function configFromInput(config) { - var input = config._i; - if (isUndefined(input)) { - config._d = new Date(hooks.now()); - } else if (isDate(input)) { - config._d = new Date(input.valueOf()); - } else if (typeof input === 'string') { - configFromString(config); - } else if (isArray(input)) { - config._a = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - configFromArray(config); - } else if (isObject(input)) { - configFromObject(config); - } else if (isNumber(input)) { - // from milliseconds - config._d = new Date(input); - } else { - hooks.createFromInputFallback(config); - } - } +var hashClear = __nccwpck_require__(1789), + hashDelete = __nccwpck_require__(712), + hashGet = __nccwpck_require__(5395), + hashHas = __nccwpck_require__(5232), + hashSet = __nccwpck_require__(7320); - function createLocalOrUTC(input, format, locale, strict, isUTC) { - var c = {}; +/** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; - if (format === true || format === false) { - strict = format; - format = undefined; - } + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} - if (locale === true || locale === false) { - strict = locale; - locale = undefined; - } +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; - if ( - (isObject(input) && isObjectEmpty(input)) || - (isArray(input) && input.length === 0) - ) { - input = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c._isAMomentObject = true; - c._useUTC = c._isUTC = isUTC; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; +module.exports = Hash; - return createFromConfig(c); - } - function createLocal(input, format, locale, strict) { - return createLocalOrUTC(input, format, locale, strict, false); - } +/***/ }), - var prototypeMin = deprecate( - 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', - function () { - var other = createLocal.apply(null, arguments); - if (this.isValid() && other.isValid()) { - return other < this ? this : other; - } else { - return createInvalid(); - } - } - ), - prototypeMax = deprecate( - 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', - function () { - var other = createLocal.apply(null, arguments); - if (this.isValid() && other.isValid()) { - return other > this ? this : other; - } else { - return createInvalid(); - } - } - ); +/***/ 6608: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // Pick a moment m from moments so that m[fn](other) is true for all - // other. This relies on the function fn to be transitive. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return createLocal(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (!moments[i].isValid() || moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } +var listCacheClear = __nccwpck_require__(9792), + listCacheDelete = __nccwpck_require__(7716), + listCacheGet = __nccwpck_require__(5789), + listCacheHas = __nccwpck_require__(9386), + listCacheSet = __nccwpck_require__(7399); - // TODO: Use [].sort instead? - function min() { - var args = [].slice.call(arguments, 0); +/** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; - return pickBy('isBefore', args); - } + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} - function max() { - var args = [].slice.call(arguments, 0); +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; - return pickBy('isAfter', args); - } +module.exports = ListCache; - var now = function () { - return Date.now ? Date.now() : +new Date(); - }; - var ordering = [ - 'year', - 'quarter', - 'month', - 'week', - 'day', - 'hour', - 'minute', - 'second', - 'millisecond', - ]; - - function isDurationValid(m) { - var key, - unitHasDecimal = false, - i, - orderLen = ordering.length; - for (key in m) { - if ( - hasOwnProp(m, key) && - !( - indexOf.call(ordering, key) !== -1 && - (m[key] == null || !isNaN(m[key])) - ) - ) { - return false; - } - } +/***/ }), - for (i = 0; i < orderLen; ++i) { - if (m[ordering[i]]) { - if (unitHasDecimal) { - return false; // only allow non-integers for smallest unit - } - if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { - unitHasDecimal = true; - } - } - } +/***/ 881: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - return true; - } +var getNative = __nccwpck_require__(4479), + root = __nccwpck_require__(9882); - function isValid$1() { - return this._isValid; - } +/* Built-in method references that are verified to be native. */ +var Map = getNative(root, 'Map'); - function createInvalid$1() { - return createDuration(NaN); - } +module.exports = Map; - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || normalizedInput.isoWeek || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - this._isValid = isDurationValid(normalizedInput); +/***/ }), - // representation for dateAddRemove - this._milliseconds = - +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + weeks * 7; - // It is impossible to translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + quarters * 3 + years * 12; +/***/ 938: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - this._data = {}; +var mapCacheClear = __nccwpck_require__(1610), + mapCacheDelete = __nccwpck_require__(6657), + mapCacheGet = __nccwpck_require__(1372), + mapCacheHas = __nccwpck_require__(609), + mapCacheSet = __nccwpck_require__(5582); - this._locale = getLocale(); +/** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ +function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; - this._bubble(); - } + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} - function isDuration(obj) { - return obj instanceof Duration; - } +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; - function absRound(number) { - if (number < 0) { - return Math.round(-1 * number) * -1; - } else { - return Math.round(number); - } - } +module.exports = MapCache; - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ( - (dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i])) - ) { - diffs++; - } - } - return diffs + lengthDiff; - } - // FORMATTING +/***/ }), - function offset(token, separator) { - addFormatToken(token, 0, 0, function () { - var offset = this.utcOffset(), - sign = '+'; - if (offset < 0) { - offset = -offset; - sign = '-'; - } - return ( - sign + - zeroFill(~~(offset / 60), 2) + - separator + - zeroFill(~~offset % 60, 2) - ); - }); - } +/***/ 9213: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - offset('Z', ':'); - offset('ZZ', ''); +var root = __nccwpck_require__(9882); - // PARSING +/** Built-in value references. */ +var Symbol = root.Symbol; + +module.exports = Symbol; - addRegexToken('Z', matchShortOffset); - addRegexToken('ZZ', matchShortOffset); - addParseToken(['Z', 'ZZ'], function (input, array, config) { - config._useUTC = true; - config._tzm = offsetFromString(matchShortOffset, input); - }); - // HELPERS +/***/ }), - // timezone chunker - // '+10:00' > ['10', '00'] - // '-1530' > ['-15', '30'] - var chunkOffset = /([\+\-]|\d\d)/gi; +/***/ 4356: +/***/ ((module) => { - function offsetFromString(matcher, string) { - var matches = (string || '').match(matcher), - chunk, - parts, - minutes; +/** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ +function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); - if (matches === null) { - return null; - } + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; +} - chunk = matches[matches.length - 1] || []; - parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; - minutes = +(parts[1] * 60) + toInt(parts[2]); - - return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function cloneWithOffset(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = - (isMoment(input) || isDate(input) - ? input.valueOf() - : createLocal(input).valueOf()) - res.valueOf(); - // Use low-level api, because this fn is low-level api. - res._d.setTime(res._d.valueOf() + diff); - hooks.updateOffset(res, false); - return res; - } else { - return createLocal(input).local(); - } - } +module.exports = arrayMap; - function getDateOffset(m) { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return -Math.round(m._d.getTimezoneOffset()); - } - // HOOKS +/***/ }), - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - hooks.updateOffset = function () {}; +/***/ 6752: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // MOMENTS +var eq = __nccwpck_require__(1901); - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset - // +0200, so we adjust the time as needed, to be valid. - // - // Keeping the time actually adds/subtracts (one hour) - // from the actual represented time. That is why we call updateOffset - // a second time. In case it wants us to change the offset again - // _changeInProgress == true case, then we have to adjust, because - // there is no such time in the given timezone. - function getSetOffset(input, keepLocalTime, keepMinutes) { - var offset = this._offset || 0, - localAdjust; - if (!this.isValid()) { - return input != null ? this : NaN; - } - if (input != null) { - if (typeof input === 'string') { - input = offsetFromString(matchShortOffset, input); - if (input === null) { - return this; - } - } else if (Math.abs(input) < 16 && !keepMinutes) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = getDateOffset(this); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.add(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addSubtract( - this, - createDuration(input - offset, 'm'), - 1, - false - ); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - hooks.updateOffset(this, true); - this._changeInProgress = null; - } - } - return this; - } else { - return this._isUTC ? offset : getDateOffset(this); - } +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; } + } + return -1; +} - function getSetZone(input, keepLocalTime) { - if (input != null) { - if (typeof input !== 'string') { - input = -input; - } - - this.utcOffset(input, keepLocalTime); +module.exports = assocIndexOf; - return this; - } else { - return -this.utcOffset(); - } - } - function setOffsetToUTC(keepLocalTime) { - return this.utcOffset(0, keepLocalTime); - } +/***/ }), - function setOffsetToLocal(keepLocalTime) { - if (this._isUTC) { - this.utcOffset(0, keepLocalTime); - this._isUTC = false; +/***/ 5758: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (keepLocalTime) { - this.subtract(getDateOffset(this), 'm'); - } - } - return this; - } +var castPath = __nccwpck_require__(2688), + toKey = __nccwpck_require__(9071); - function setOffsetToParsedOffset() { - if (this._tzm != null) { - this.utcOffset(this._tzm, false, true); - } else if (typeof this._i === 'string') { - var tZone = offsetFromString(matchOffset, this._i); - if (tZone != null) { - this.utcOffset(tZone); - } else { - this.utcOffset(0, true); - } - } - return this; - } +/** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ +function baseGet(object, path) { + path = castPath(path, object); - function hasAlignedHourOffset(input) { - if (!this.isValid()) { - return false; - } - input = input ? createLocal(input).utcOffset() : 0; + var index = 0, + length = path.length; - return (this.utcOffset() - input) % 60 === 0; - } + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; +} - function isDaylightSavingTime() { - return ( - this.utcOffset() > this.clone().month(0).utcOffset() || - this.utcOffset() > this.clone().month(5).utcOffset() - ); - } +module.exports = baseGet; - function isDaylightSavingTimeShifted() { - if (!isUndefined(this._isDSTShifted)) { - return this._isDSTShifted; - } - var c = {}, - other; +/***/ }), - copyConfig(c, this); - c = prepareConfig(c); +/***/ 7497: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (c._a) { - other = c._isUTC ? createUTC(c._a) : createLocal(c._a); - this._isDSTShifted = - this.isValid() && compareArrays(c._a, other.toArray()) > 0; - } else { - this._isDSTShifted = false; - } +var Symbol = __nccwpck_require__(9213), + getRawTag = __nccwpck_require__(923), + objectToString = __nccwpck_require__(4200); - return this._isDSTShifted; - } +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; - function isLocal() { - return this.isValid() ? !this._isUTC : false; - } +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; - function isUtcOffset() { - return this.isValid() ? this._isUTC : false; - } +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); +} - function isUtc() { - return this.isValid() ? this._isUTC && this._offset === 0 : false; - } +module.exports = baseGetTag; - // ASP.NET json date format regex - var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - // and further modified to allow for strings containing both week and day - isoRegex = - /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; - function createDuration(input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - diffRes; +/***/ }), - if (isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months, - }; - } else if (isNumber(input) || !isNaN(+input)) { - duration = {}; - if (key) { - duration[key] = +input; - } else { - duration.milliseconds = +input; - } - } else if ((match = aspNetRegex.exec(input))) { - sign = match[1] === '-' ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match - }; - } else if ((match = isoRegex.exec(input))) { - sign = match[1] === '-' ? -1 : 1; - duration = { - y: parseIso(match[2], sign), - M: parseIso(match[3], sign), - w: parseIso(match[4], sign), - d: parseIso(match[5], sign), - h: parseIso(match[6], sign), - m: parseIso(match[7], sign), - s: parseIso(match[8], sign), - }; - } else if (duration == null) { - // checks for null or undefined - duration = {}; - } else if ( - typeof duration === 'object' && - ('from' in duration || 'to' in duration) - ) { - diffRes = momentsDifference( - createLocal(duration.from), - createLocal(duration.to) - ); +/***/ 411: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } +var isFunction = __nccwpck_require__(7799), + isMasked = __nccwpck_require__(9058), + isObject = __nccwpck_require__(3334), + toSource = __nccwpck_require__(6928); - ret = new Duration(duration); +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - if (isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; - if (isDuration(input) && hasOwnProp(input, '_isValid')) { - ret._isValid = input._isValid; - } +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto = Object.prototype; - return ret; - } +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; - createDuration.fn = Duration.prototype; - createDuration.invalid = createInvalid$1; +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - function parseIso(inp, sign) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - } +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); - function positiveMomentsDifference(base, other) { - var res = {}; +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} - res.months = - other.month() - base.month() + (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } +module.exports = baseIsNative; - res.milliseconds = +other - +base.clone().add(res.months, 'M'); - return res; - } +/***/ }), - function momentsDifference(base, other) { - var res; - if (!(base.isValid() && other.isValid())) { - return { milliseconds: 0, months: 0 }; - } +/***/ 6792: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - other = cloneWithOffset(other, base); - if (base.isBefore(other)) { - res = positiveMomentsDifference(base, other); - } else { - res = positiveMomentsDifference(other, base); - res.milliseconds = -res.milliseconds; - res.months = -res.months; - } +var Symbol = __nccwpck_require__(9213), + arrayMap = __nccwpck_require__(4356), + isArray = __nccwpck_require__(4869), + isSymbol = __nccwpck_require__(6403); - return res; - } +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; - // TODO: remove 'name' arg after deprecation is removed - function createAdder(direction, name) { - return function (val, period) { - var dur, tmp; - //invert the arguments, but complain about it - if (period !== null && !isNaN(+period)) { - deprecateSimple( - name, - 'moment().' + - name + - '(period, number) is deprecated. Please use moment().' + - name + - '(number, period). ' + - 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.' - ); - tmp = val; - val = period; - period = tmp; - } +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; - dur = createDuration(val, period); - addSubtract(this, dur, direction); - return this; - }; - } +/** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ +function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; +} - function addSubtract(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = absRound(duration._days), - months = absRound(duration._months); +module.exports = baseToString; - if (!mom.isValid()) { - // No op - return; - } - updateOffset = updateOffset == null ? true : updateOffset; +/***/ }), - if (months) { - setMonth(mom, get(mom, 'Month') + months * isAdding); - } - if (days) { - set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); - } - if (milliseconds) { - mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); - } - if (updateOffset) { - hooks.updateOffset(mom, days || months); - } - } +/***/ 2688: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - var add = createAdder(1, 'add'), - subtract = createAdder(-1, 'subtract'); +var isArray = __nccwpck_require__(4869), + isKey = __nccwpck_require__(9084), + stringToPath = __nccwpck_require__(1853), + toString = __nccwpck_require__(2931); - function isString(input) { - return typeof input === 'string' || input instanceof String; - } +/** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ +function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); +} - // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined - function isMomentInput(input) { - return ( - isMoment(input) || - isDate(input) || - isString(input) || - isNumber(input) || - isNumberOrStringArray(input) || - isMomentInputObject(input) || - input === null || - input === undefined - ); - } +module.exports = castPath; - function isMomentInputObject(input) { - var objectTest = isObject(input) && !isObjectEmpty(input), - propertyTest = false, - properties = [ - 'years', - 'year', - 'y', - 'months', - 'month', - 'M', - 'days', - 'day', - 'd', - 'dates', - 'date', - 'D', - 'hours', - 'hour', - 'h', - 'minutes', - 'minute', - 'm', - 'seconds', - 'second', - 's', - 'milliseconds', - 'millisecond', - 'ms', - ], - i, - property, - propertyLen = properties.length; - - for (i = 0; i < propertyLen; i += 1) { - property = properties[i]; - propertyTest = propertyTest || hasOwnProp(input, property); - } - return objectTest && propertyTest; - } +/***/ }), - function isNumberOrStringArray(input) { - var arrayTest = isArray(input), - dataTypeTest = false; - if (arrayTest) { - dataTypeTest = - input.filter(function (item) { - return !isNumber(item) && isString(input); - }).length === 0; - } - return arrayTest && dataTypeTest; - } - - function isCalendarSpec(input) { - var objectTest = isObject(input) && !isObjectEmpty(input), - propertyTest = false, - properties = [ - 'sameDay', - 'nextDay', - 'lastDay', - 'nextWeek', - 'lastWeek', - 'sameElse', - ], - i, - property; - - for (i = 0; i < properties.length; i += 1) { - property = properties[i]; - propertyTest = propertyTest || hasOwnProp(input, property); - } +/***/ 8380: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - return objectTest && propertyTest; - } - - function getCalendarFormat(myMoment, now) { - var diff = myMoment.diff(now, 'days', true); - return diff < -6 - ? 'sameElse' - : diff < -1 - ? 'lastWeek' - : diff < 0 - ? 'lastDay' - : diff < 1 - ? 'sameDay' - : diff < 2 - ? 'nextDay' - : diff < 7 - ? 'nextWeek' - : 'sameElse'; - } - - function calendar$1(time, formats) { - // Support for single parameter, formats only overload to the calendar function - if (arguments.length === 1) { - if (!arguments[0]) { - time = undefined; - formats = undefined; - } else if (isMomentInput(arguments[0])) { - time = arguments[0]; - formats = undefined; - } else if (isCalendarSpec(arguments[0])) { - formats = arguments[0]; - time = undefined; - } - } - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're local/utc/offset or not. - var now = time || createLocal(), - sod = cloneWithOffset(now, this).startOf('day'), - format = hooks.calendarFormat(this, sod) || 'sameElse', - output = - formats && - (isFunction(formats[format]) - ? formats[format].call(this, now) - : formats[format]); - - return this.format( - output || this.localeData().calendar(format, this, createLocal(now)) - ); - } +var root = __nccwpck_require__(9882); - function clone() { - return new Moment(this); - } +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; - function isAfter(input, units) { - var localInput = isMoment(input) ? input : createLocal(input); - if (!(this.isValid() && localInput.isValid())) { - return false; - } - units = normalizeUnits(units) || 'millisecond'; - if (units === 'millisecond') { - return this.valueOf() > localInput.valueOf(); - } else { - return localInput.valueOf() < this.clone().startOf(units).valueOf(); - } - } +module.exports = coreJsData; - function isBefore(input, units) { - var localInput = isMoment(input) ? input : createLocal(input); - if (!(this.isValid() && localInput.isValid())) { - return false; - } - units = normalizeUnits(units) || 'millisecond'; - if (units === 'millisecond') { - return this.valueOf() < localInput.valueOf(); - } else { - return this.clone().endOf(units).valueOf() < localInput.valueOf(); - } - } - function isBetween(from, to, units, inclusivity) { - var localFrom = isMoment(from) ? from : createLocal(from), - localTo = isMoment(to) ? to : createLocal(to); - if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) { - return false; - } - inclusivity = inclusivity || '()'; - return ( - (inclusivity[0] === '(' - ? this.isAfter(localFrom, units) - : !this.isBefore(localFrom, units)) && - (inclusivity[1] === ')' - ? this.isBefore(localTo, units) - : !this.isAfter(localTo, units)) - ); - } +/***/ }), - function isSame(input, units) { - var localInput = isMoment(input) ? input : createLocal(input), - inputMs; - if (!(this.isValid() && localInput.isValid())) { - return false; - } - units = normalizeUnits(units) || 'millisecond'; - if (units === 'millisecond') { - return this.valueOf() === localInput.valueOf(); - } else { - inputMs = localInput.valueOf(); - return ( - this.clone().startOf(units).valueOf() <= inputMs && - inputMs <= this.clone().endOf(units).valueOf() - ); - } - } +/***/ 2085: +/***/ ((module) => { - function isSameOrAfter(input, units) { - return this.isSame(input, units) || this.isAfter(input, units); - } +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - function isSameOrBefore(input, units) { - return this.isSame(input, units) || this.isBefore(input, units); - } +module.exports = freeGlobal; - function diff(input, units, asFloat) { - var that, zoneDelta, output; - if (!this.isValid()) { - return NaN; - } +/***/ }), - that = cloneWithOffset(input, this); +/***/ 9980: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (!that.isValid()) { - return NaN; - } +var isKeyable = __nccwpck_require__(3308); - zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} - units = normalizeUnits(units); +module.exports = getMapData; - switch (units) { - case 'year': - output = monthDiff(this, that) / 12; - break; - case 'month': - output = monthDiff(this, that); - break; - case 'quarter': - output = monthDiff(this, that) / 3; - break; - case 'second': - output = (this - that) / 1e3; - break; // 1000 - case 'minute': - output = (this - that) / 6e4; - break; // 1000 * 60 - case 'hour': - output = (this - that) / 36e5; - break; // 1000 * 60 * 60 - case 'day': - output = (this - that - zoneDelta) / 864e5; - break; // 1000 * 60 * 60 * 24, negate dst - case 'week': - output = (this - that - zoneDelta) / 6048e5; - break; // 1000 * 60 * 60 * 24 * 7, negate dst - default: - output = this - that; - } - return asFloat ? output : absFloor(output); - } +/***/ }), - function monthDiff(a, b) { - if (a.date() < b.date()) { - // end-of-month calculations work correct when the start month has more - // days than the end month. - return -monthDiff(b, a); - } - // difference in months - var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()), - // b is in (anchor - 1 month, anchor + 1 month) - anchor = a.clone().add(wholeMonthDiff, 'months'), - anchor2, - adjust; - - if (b - anchor < 0) { - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor - anchor2); - } else { - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor2 - anchor); - } +/***/ 4479: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - //check for negative zero, return zero if negative zero - return -(wholeMonthDiff + adjust) || 0; - } +var baseIsNative = __nccwpck_require__(411), + getValue = __nccwpck_require__(3542); - hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; - hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} - function toString() { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - } +module.exports = getNative; - function toISOString(keepOffset) { - if (!this.isValid()) { - return null; - } - var utc = keepOffset !== true, - m = utc ? this.clone().utc() : this; - if (m.year() < 0 || m.year() > 9999) { - return formatMoment( - m, - utc - ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' - : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ' - ); - } - if (isFunction(Date.prototype.toISOString)) { - // native implementation is ~50x faster, use it when we can - if (utc) { - return this.toDate().toISOString(); - } else { - return new Date(this.valueOf() + this.utcOffset() * 60 * 1000) - .toISOString() - .replace('Z', formatMoment(m, 'Z')); - } - } - return formatMoment( - m, - utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ' - ); - } - /** - * Return a human readable representation of a moment that can - * also be evaluated to get a new moment which is the same - * - * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects - */ - function inspect() { - if (!this.isValid()) { - return 'moment.invalid(/* ' + this._i + ' */)'; - } - var func = 'moment', - zone = '', - prefix, - year, - datetime, - suffix; - if (!this.isLocal()) { - func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; - zone = 'Z'; - } - prefix = '[' + func + '("]'; - year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY'; - datetime = '-MM-DD[T]HH:mm:ss.SSS'; - suffix = zone + '[")]'; +/***/ }), - return this.format(prefix + year + datetime + suffix); - } +/***/ 923: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function format(inputString) { - if (!inputString) { - inputString = this.isUtc() - ? hooks.defaultFormatUtc - : hooks.defaultFormat; - } - var output = formatMoment(this, inputString); - return this.localeData().postformat(output); - } - - function from(time, withoutSuffix) { - if ( - this.isValid() && - ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) - ) { - return createDuration({ to: this, from: time }) - .locale(this.locale()) - .humanize(!withoutSuffix); - } else { - return this.localeData().invalidDate(); - } - } +var Symbol = __nccwpck_require__(9213); - function fromNow(withoutSuffix) { - return this.from(createLocal(), withoutSuffix); - } +/** Used for built-in method references. */ +var objectProto = Object.prototype; - function to(time, withoutSuffix) { - if ( - this.isValid() && - ((isMoment(time) && time.isValid()) || createLocal(time).isValid()) - ) { - return createDuration({ from: this, to: time }) - .locale(this.locale()) - .humanize(!withoutSuffix); - } else { - return this.localeData().invalidDate(); - } - } +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - function toNow(withoutSuffix) { - return this.to(createLocal(), withoutSuffix); - } +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - function locale(key) { - var newLocaleData; +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = getLocale(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - } +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; - var lang = deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ); + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} - function localeData() { - return this._locale; + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; } + } + return result; +} - var MS_PER_SECOND = 1000, - MS_PER_MINUTE = 60 * MS_PER_SECOND, - MS_PER_HOUR = 60 * MS_PER_MINUTE, - MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; +module.exports = getRawTag; - // actual modulo - handles negative numbers (for dates before 1970): - function mod$1(dividend, divisor) { - return ((dividend % divisor) + divisor) % divisor; - } - function localStartOfDate(y, m, d) { - // the date constructor remaps years 0-99 to 1900-1999 - if (y < 100 && y >= 0) { - // preserve leap years using a full 400 year cycle, then reset - return new Date(y + 400, m, d) - MS_PER_400_YEARS; - } else { - return new Date(y, m, d).valueOf(); - } - } +/***/ }), - function utcStartOfDate(y, m, d) { - // Date.UTC remaps years 0-99 to 1900-1999 - if (y < 100 && y >= 0) { - // preserve leap years using a full 400 year cycle, then reset - return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS; - } else { - return Date.UTC(y, m, d); - } - } +/***/ 3542: +/***/ ((module) => { - function startOf(units) { - var time, startOfDate; - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond' || !this.isValid()) { - return this; - } +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} - startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; +module.exports = getValue; - switch (units) { - case 'year': - time = startOfDate(this.year(), 0, 1); - break; - case 'quarter': - time = startOfDate( - this.year(), - this.month() - (this.month() % 3), - 1 - ); - break; - case 'month': - time = startOfDate(this.year(), this.month(), 1); - break; - case 'week': - time = startOfDate( - this.year(), - this.month(), - this.date() - this.weekday() - ); - break; - case 'isoWeek': - time = startOfDate( - this.year(), - this.month(), - this.date() - (this.isoWeekday() - 1) - ); - break; - case 'day': - case 'date': - time = startOfDate(this.year(), this.month(), this.date()); - break; - case 'hour': - time = this._d.valueOf(); - time -= mod$1( - time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), - MS_PER_HOUR - ); - break; - case 'minute': - time = this._d.valueOf(); - time -= mod$1(time, MS_PER_MINUTE); - break; - case 'second': - time = this._d.valueOf(); - time -= mod$1(time, MS_PER_SECOND); - break; - } - this._d.setTime(time); - hooks.updateOffset(this, true); - return this; - } +/***/ }), - function endOf(units) { - var time, startOfDate; - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond' || !this.isValid()) { - return this; - } +/***/ 1789: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; +var nativeCreate = __nccwpck_require__(3041); - switch (units) { - case 'year': - time = startOfDate(this.year() + 1, 0, 1) - 1; - break; - case 'quarter': - time = - startOfDate( - this.year(), - this.month() - (this.month() % 3) + 3, - 1 - ) - 1; - break; - case 'month': - time = startOfDate(this.year(), this.month() + 1, 1) - 1; - break; - case 'week': - time = - startOfDate( - this.year(), - this.month(), - this.date() - this.weekday() + 7 - ) - 1; - break; - case 'isoWeek': - time = - startOfDate( - this.year(), - this.month(), - this.date() - (this.isoWeekday() - 1) + 7 - ) - 1; - break; - case 'day': - case 'date': - time = startOfDate(this.year(), this.month(), this.date() + 1) - 1; - break; - case 'hour': - time = this._d.valueOf(); - time += - MS_PER_HOUR - - mod$1( - time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), - MS_PER_HOUR - ) - - 1; - break; - case 'minute': - time = this._d.valueOf(); - time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1; - break; - case 'second': - time = this._d.valueOf(); - time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1; - break; - } +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; +} - this._d.setTime(time); - hooks.updateOffset(this, true); - return this; - } +module.exports = hashClear; - function valueOf() { - return this._d.valueOf() - (this._offset || 0) * 60000; - } - function unix() { - return Math.floor(this.valueOf() / 1000); - } +/***/ }), - function toDate() { - return new Date(this.valueOf()); - } +/***/ 712: +/***/ ((module) => { - function toArray() { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hour(), - m.minute(), - m.second(), - m.millisecond(), - ]; - } +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; +} - function toObject() { - var m = this; - return { - years: m.year(), - months: m.month(), - date: m.date(), - hours: m.hours(), - minutes: m.minutes(), - seconds: m.seconds(), - milliseconds: m.milliseconds(), - }; - } +module.exports = hashDelete; - function toJSON() { - // new Date(NaN).toJSON() === null - return this.isValid() ? this.toISOString() : null; - } - function isValid$2() { - return isValid(this); - } +/***/ }), - function parsingFlags() { - return extend({}, getParsingFlags(this)); - } +/***/ 5395: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function invalidAt() { - return getParsingFlags(this).overflow; - } +var nativeCreate = __nccwpck_require__(3041); - function creationData() { - return { - input: this._i, - format: this._f, - locale: this._locale, - isUTC: this._isUTC, - strict: this._strict, - }; - } +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; - addFormatToken('N', 0, 0, 'eraAbbr'); - addFormatToken('NN', 0, 0, 'eraAbbr'); - addFormatToken('NNN', 0, 0, 'eraAbbr'); - addFormatToken('NNNN', 0, 0, 'eraName'); - addFormatToken('NNNNN', 0, 0, 'eraNarrow'); - - addFormatToken('y', ['y', 1], 'yo', 'eraYear'); - addFormatToken('y', ['yy', 2], 0, 'eraYear'); - addFormatToken('y', ['yyy', 3], 0, 'eraYear'); - addFormatToken('y', ['yyyy', 4], 0, 'eraYear'); - - addRegexToken('N', matchEraAbbr); - addRegexToken('NN', matchEraAbbr); - addRegexToken('NNN', matchEraAbbr); - addRegexToken('NNNN', matchEraName); - addRegexToken('NNNNN', matchEraNarrow); - - addParseToken( - ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], - function (input, array, config, token) { - var era = config._locale.erasParse(input, token, config._strict); - if (era) { - getParsingFlags(config).era = era; - } else { - getParsingFlags(config).invalidEra = input; - } - } - ); +/** Used for built-in method references. */ +var objectProto = Object.prototype; - addRegexToken('y', matchUnsigned); - addRegexToken('yy', matchUnsigned); - addRegexToken('yyy', matchUnsigned); - addRegexToken('yyyy', matchUnsigned); - addRegexToken('yo', matchEraYearOrdinal); - - addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR); - addParseToken(['yo'], function (input, array, config, token) { - var match; - if (config._locale._eraYearOrdinalRegex) { - match = input.match(config._locale._eraYearOrdinalRegex); - } +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - if (config._locale.eraYearOrdinalParse) { - array[YEAR] = config._locale.eraYearOrdinalParse(input, match); - } else { - array[YEAR] = parseInt(input, 10); - } - }); +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; +} - function localeEras(m, format) { - var i, - l, - date, - eras = this._eras || getLocale('en')._eras; - for (i = 0, l = eras.length; i < l; ++i) { - switch (typeof eras[i].since) { - case 'string': - // truncate time - date = hooks(eras[i].since).startOf('day'); - eras[i].since = date.valueOf(); - break; - } +module.exports = hashGet; - switch (typeof eras[i].until) { - case 'undefined': - eras[i].until = +Infinity; - break; - case 'string': - // truncate time - date = hooks(eras[i].until).startOf('day').valueOf(); - eras[i].until = date.valueOf(); - break; - } - } - return eras; - } - - function localeErasParse(eraName, format, strict) { - var i, - l, - eras = this.eras(), - name, - abbr, - narrow; - eraName = eraName.toUpperCase(); - - for (i = 0, l = eras.length; i < l; ++i) { - name = eras[i].name.toUpperCase(); - abbr = eras[i].abbr.toUpperCase(); - narrow = eras[i].narrow.toUpperCase(); - - if (strict) { - switch (format) { - case 'N': - case 'NN': - case 'NNN': - if (abbr === eraName) { - return eras[i]; - } - break; - case 'NNNN': - if (name === eraName) { - return eras[i]; - } - break; +/***/ }), - case 'NNNNN': - if (narrow === eraName) { - return eras[i]; - } - break; - } - } else if ([name, abbr, narrow].indexOf(eraName) >= 0) { - return eras[i]; - } - } - } +/***/ 5232: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function localeErasConvertYear(era, year) { - var dir = era.since <= era.until ? +1 : -1; - if (year === undefined) { - return hooks(era.since).year(); - } else { - return hooks(era.since).year() + (year - era.offset) * dir; - } - } +var nativeCreate = __nccwpck_require__(3041); - function getEraName() { - var i, - l, - val, - eras = this.localeData().eras(); - for (i = 0, l = eras.length; i < l; ++i) { - // truncate time - val = this.clone().startOf('day').valueOf(); +/** Used for built-in method references. */ +var objectProto = Object.prototype; - if (eras[i].since <= val && val <= eras[i].until) { - return eras[i].name; - } - if (eras[i].until <= val && val <= eras[i].since) { - return eras[i].name; - } - } +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; - return ''; - } +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); +} - function getEraNarrow() { - var i, - l, - val, - eras = this.localeData().eras(); - for (i = 0, l = eras.length; i < l; ++i) { - // truncate time - val = this.clone().startOf('day').valueOf(); +module.exports = hashHas; - if (eras[i].since <= val && val <= eras[i].until) { - return eras[i].narrow; - } - if (eras[i].until <= val && val <= eras[i].since) { - return eras[i].narrow; - } - } - return ''; - } +/***/ }), - function getEraAbbr() { - var i, - l, - val, - eras = this.localeData().eras(); - for (i = 0, l = eras.length; i < l; ++i) { - // truncate time - val = this.clone().startOf('day').valueOf(); +/***/ 7320: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (eras[i].since <= val && val <= eras[i].until) { - return eras[i].abbr; - } - if (eras[i].until <= val && val <= eras[i].since) { - return eras[i].abbr; - } - } +var nativeCreate = __nccwpck_require__(3041); - return ''; - } +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; - function getEraYear() { - var i, - l, - dir, - val, - eras = this.localeData().eras(); - for (i = 0, l = eras.length; i < l; ++i) { - dir = eras[i].since <= eras[i].until ? +1 : -1; - - // truncate time - val = this.clone().startOf('day').valueOf(); - - if ( - (eras[i].since <= val && val <= eras[i].until) || - (eras[i].until <= val && val <= eras[i].since) - ) { - return ( - (this.year() - hooks(eras[i].since).year()) * dir + - eras[i].offset - ); - } - } +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; +} - return this.year(); - } +module.exports = hashSet; - function erasNameRegex(isStrict) { - if (!hasOwnProp(this, '_erasNameRegex')) { - computeErasParse.call(this); - } - return isStrict ? this._erasNameRegex : this._erasRegex; - } - function erasAbbrRegex(isStrict) { - if (!hasOwnProp(this, '_erasAbbrRegex')) { - computeErasParse.call(this); - } - return isStrict ? this._erasAbbrRegex : this._erasRegex; - } +/***/ }), - function erasNarrowRegex(isStrict) { - if (!hasOwnProp(this, '_erasNarrowRegex')) { - computeErasParse.call(this); - } - return isStrict ? this._erasNarrowRegex : this._erasRegex; - } +/***/ 9084: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function matchEraAbbr(isStrict, locale) { - return locale.erasAbbrRegex(isStrict); - } +var isArray = __nccwpck_require__(4869), + isSymbol = __nccwpck_require__(6403); - function matchEraName(isStrict, locale) { - return locale.erasNameRegex(isStrict); - } +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; - function matchEraNarrow(isStrict, locale) { - return locale.erasNarrowRegex(isStrict); - } +/** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ +function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); +} - function matchEraYearOrdinal(isStrict, locale) { - return locale._eraYearOrdinalRegex || matchUnsigned; - } +module.exports = isKey; - function computeErasParse() { - var abbrPieces = [], - namePieces = [], - narrowPieces = [], - mixedPieces = [], - i, - l, - eras = this.eras(); - for (i = 0, l = eras.length; i < l; ++i) { - namePieces.push(regexEscape(eras[i].name)); - abbrPieces.push(regexEscape(eras[i].abbr)); - narrowPieces.push(regexEscape(eras[i].narrow)); +/***/ }), - mixedPieces.push(regexEscape(eras[i].name)); - mixedPieces.push(regexEscape(eras[i].abbr)); - mixedPieces.push(regexEscape(eras[i].narrow)); - } +/***/ 3308: +/***/ ((module) => { - this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); - this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i'); - this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i'); - this._erasNarrowRegex = new RegExp( - '^(' + narrowPieces.join('|') + ')', - 'i' - ); - } +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} - // FORMATTING +module.exports = isKeyable; - addFormatToken(0, ['gg', 2], 0, function () { - return this.weekYear() % 100; - }); - addFormatToken(0, ['GG', 2], 0, function () { - return this.isoWeekYear() % 100; - }); +/***/ }), - function addWeekYearFormatToken(token, getter) { - addFormatToken(0, [token, token.length], 0, getter); - } +/***/ 9058: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - addWeekYearFormatToken('gggg', 'weekYear'); - addWeekYearFormatToken('ggggg', 'weekYear'); - addWeekYearFormatToken('GGGG', 'isoWeekYear'); - addWeekYearFormatToken('GGGGG', 'isoWeekYear'); +var coreJsData = __nccwpck_require__(8380); - // ALIASES +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); - addUnitAlias('weekYear', 'gg'); - addUnitAlias('isoWeekYear', 'GG'); +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} - // PRIORITY +module.exports = isMasked; - addUnitPriority('weekYear', 1); - addUnitPriority('isoWeekYear', 1); - // PARSING +/***/ }), - addRegexToken('G', matchSigned); - addRegexToken('g', matchSigned); - addRegexToken('GG', match1to2, match2); - addRegexToken('gg', match1to2, match2); - addRegexToken('GGGG', match1to4, match4); - addRegexToken('gggg', match1to4, match4); - addRegexToken('GGGGG', match1to6, match6); - addRegexToken('ggggg', match1to6, match6); +/***/ 9792: +/***/ ((module) => { - addWeekParseToken( - ['gggg', 'ggggg', 'GGGG', 'GGGGG'], - function (input, week, config, token) { - week[token.substr(0, 2)] = toInt(input); - } - ); +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} - addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { - week[token] = hooks.parseTwoDigitYear(input); - }); +module.exports = listCacheClear; - // MOMENTS - function getSetWeekYear(input) { - return getSetWeekYearHelper.call( - this, - input, - this.week(), - this.weekday(), - this.localeData()._week.dow, - this.localeData()._week.doy - ); - } +/***/ }), - function getSetISOWeekYear(input) { - return getSetWeekYearHelper.call( - this, - input, - this.isoWeek(), - this.isoWeekday(), - 1, - 4 - ); - } +/***/ 7716: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function getISOWeeksInYear() { - return weeksInYear(this.year(), 1, 4); - } +var assocIndexOf = __nccwpck_require__(6752); - function getISOWeeksInISOWeekYear() { - return weeksInYear(this.isoWeekYear(), 1, 4); - } +/** Used for built-in method references. */ +var arrayProto = Array.prototype; - function getWeeksInYear() { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - } +/** Built-in value references. */ +var splice = arrayProto.splice; - function getWeeksInWeekYear() { - var weekInfo = this.localeData()._week; - return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy); - } +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); - function getSetWeekYearHelper(input, week, weekday, dow, doy) { - var weeksTarget; - if (input == null) { - return weekOfYear(this, dow, doy).year; - } else { - weeksTarget = weeksInYear(input, dow, doy); - if (week > weeksTarget) { - week = weeksTarget; - } - return setWeekAll.call(this, input, week, weekday, dow, doy); - } - } + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; +} - function setWeekAll(weekYear, week, weekday, dow, doy) { - var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), - date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); +module.exports = listCacheDelete; - this.year(date.getUTCFullYear()); - this.month(date.getUTCMonth()); - this.date(date.getUTCDate()); - return this; - } - // FORMATTING +/***/ }), - addFormatToken('Q', 0, 'Qo', 'quarter'); +/***/ 5789: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // ALIASES +var assocIndexOf = __nccwpck_require__(6752); - addUnitAlias('quarter', 'Q'); +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); - // PRIORITY + return index < 0 ? undefined : data[index][1]; +} - addUnitPriority('quarter', 7); +module.exports = listCacheGet; - // PARSING - addRegexToken('Q', match1); - addParseToken('Q', function (input, array) { - array[MONTH] = (toInt(input) - 1) * 3; - }); +/***/ }), - // MOMENTS +/***/ 9386: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function getSetQuarter(input) { - return input == null - ? Math.ceil((this.month() + 1) / 3) - : this.month((input - 1) * 3 + (this.month() % 3)); - } +var assocIndexOf = __nccwpck_require__(6752); - // FORMATTING +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} - addFormatToken('D', ['DD', 2], 'Do', 'date'); +module.exports = listCacheHas; - // ALIASES - addUnitAlias('date', 'D'); +/***/ }), - // PRIORITY - addUnitPriority('date', 9); +/***/ 7399: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // PARSING +var assocIndexOf = __nccwpck_require__(6752); - addRegexToken('D', match1to2); - addRegexToken('DD', match1to2, match2); - addRegexToken('Do', function (isStrict, locale) { - // TODO: Remove "ordinalParse" fallback in next major release. - return isStrict - ? locale._dayOfMonthOrdinalParse || locale._ordinalParse - : locale._dayOfMonthOrdinalParseLenient; - }); +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); - addParseToken(['D', 'DD'], DATE); - addParseToken('Do', function (input, array) { - array[DATE] = toInt(input.match(match1to2)[0]); - }); + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} - // MOMENTS +module.exports = listCacheSet; - var getSetDayOfMonth = makeGetSet('Date', true); - // FORMATTING +/***/ }), - addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); +/***/ 1610: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // ALIASES +var Hash = __nccwpck_require__(5902), + ListCache = __nccwpck_require__(6608), + Map = __nccwpck_require__(881); - addUnitAlias('dayOfYear', 'DDD'); +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; +} - // PRIORITY - addUnitPriority('dayOfYear', 4); +module.exports = mapCacheClear; - // PARSING - addRegexToken('DDD', match1to3); - addRegexToken('DDDD', match3); - addParseToken(['DDD', 'DDDD'], function (input, array, config) { - config._dayOfYear = toInt(input); - }); +/***/ }), - // HELPERS +/***/ 6657: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // MOMENTS +var getMapData = __nccwpck_require__(9980); - function getSetDayOfYear(input) { - var dayOfYear = - Math.round( - (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5 - ) + 1; - return input == null ? dayOfYear : this.add(input - dayOfYear, 'd'); - } +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; +} - // FORMATTING +module.exports = mapCacheDelete; - addFormatToken('m', ['mm', 2], 0, 'minute'); - // ALIASES +/***/ }), - addUnitAlias('minute', 'm'); +/***/ 1372: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // PRIORITY +var getMapData = __nccwpck_require__(9980); - addUnitPriority('minute', 14); +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} - // PARSING +module.exports = mapCacheGet; - addRegexToken('m', match1to2); - addRegexToken('mm', match1to2, match2); - addParseToken(['m', 'mm'], MINUTE); - // MOMENTS +/***/ }), - var getSetMinute = makeGetSet('Minutes', false); +/***/ 609: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // FORMATTING +var getMapData = __nccwpck_require__(9980); - addFormatToken('s', ['ss', 2], 0, 'second'); +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} - // ALIASES +module.exports = mapCacheHas; - addUnitAlias('second', 's'); - // PRIORITY +/***/ }), - addUnitPriority('second', 15); +/***/ 5582: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // PARSING +var getMapData = __nccwpck_require__(9980); - addRegexToken('s', match1to2); - addRegexToken('ss', match1to2, match2); - addParseToken(['s', 'ss'], SECOND); +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; - // MOMENTS + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; +} - var getSetSecond = makeGetSet('Seconds', false); +module.exports = mapCacheSet; - // FORMATTING - addFormatToken('S', 0, 0, function () { - return ~~(this.millisecond() / 100); - }); +/***/ }), - addFormatToken(0, ['SS', 2], 0, function () { - return ~~(this.millisecond() / 10); - }); +/***/ 9422: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - addFormatToken(0, ['SSS', 3], 0, 'millisecond'); - addFormatToken(0, ['SSSS', 4], 0, function () { - return this.millisecond() * 10; - }); - addFormatToken(0, ['SSSSS', 5], 0, function () { - return this.millisecond() * 100; - }); - addFormatToken(0, ['SSSSSS', 6], 0, function () { - return this.millisecond() * 1000; - }); - addFormatToken(0, ['SSSSSSS', 7], 0, function () { - return this.millisecond() * 10000; - }); - addFormatToken(0, ['SSSSSSSS', 8], 0, function () { - return this.millisecond() * 100000; - }); - addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { - return this.millisecond() * 1000000; - }); +var memoize = __nccwpck_require__(9885); - // ALIASES +/** Used as the maximum memoize cache size. */ +var MAX_MEMOIZE_SIZE = 500; - addUnitAlias('millisecond', 'ms'); +/** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ +function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); - // PRIORITY + var cache = result.cache; + return result; +} - addUnitPriority('millisecond', 16); +module.exports = memoizeCapped; - // PARSING - addRegexToken('S', match1to3, match1); - addRegexToken('SS', match1to3, match2); - addRegexToken('SSS', match1to3, match3); +/***/ }), - var token, getSetMillisecond; - for (token = 'SSSS'; token.length <= 9; token += 'S') { - addRegexToken(token, matchUnsigned); - } +/***/ 3041: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function parseMs(input, array) { - array[MILLISECOND] = toInt(('0.' + input) * 1000); - } +var getNative = __nccwpck_require__(4479); - for (token = 'S'; token.length <= 9; token += 'S') { - addParseToken(token, parseMs); - } +/* Built-in method references that are verified to be native. */ +var nativeCreate = getNative(Object, 'create'); - getSetMillisecond = makeGetSet('Milliseconds', false); +module.exports = nativeCreate; - // FORMATTING - addFormatToken('z', 0, 0, 'zoneAbbr'); - addFormatToken('zz', 0, 0, 'zoneName'); +/***/ }), - // MOMENTS +/***/ 4200: +/***/ ((module) => { - function getZoneAbbr() { - return this._isUTC ? 'UTC' : ''; - } +/** Used for built-in method references. */ +var objectProto = Object.prototype; - function getZoneName() { - return this._isUTC ? 'Coordinated Universal Time' : ''; - } +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; - var proto = Moment.prototype; +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); +} - proto.add = add; - proto.calendar = calendar$1; - proto.clone = clone; - proto.diff = diff; - proto.endOf = endOf; - proto.format = format; - proto.from = from; - proto.fromNow = fromNow; - proto.to = to; - proto.toNow = toNow; - proto.get = stringGet; - proto.invalidAt = invalidAt; - proto.isAfter = isAfter; - proto.isBefore = isBefore; - proto.isBetween = isBetween; - proto.isSame = isSame; - proto.isSameOrAfter = isSameOrAfter; - proto.isSameOrBefore = isSameOrBefore; - proto.isValid = isValid$2; - proto.lang = lang; - proto.locale = locale; - proto.localeData = localeData; - proto.max = prototypeMax; - proto.min = prototypeMin; - proto.parsingFlags = parsingFlags; - proto.set = stringSet; - proto.startOf = startOf; - proto.subtract = subtract; - proto.toArray = toArray; - proto.toObject = toObject; - proto.toDate = toDate; - proto.toISOString = toISOString; - proto.inspect = inspect; - if (typeof Symbol !== 'undefined' && Symbol.for != null) { - proto[Symbol.for('nodejs.util.inspect.custom')] = function () { - return 'Moment<' + this.format() + '>'; - }; - } - proto.toJSON = toJSON; - proto.toString = toString; - proto.unix = unix; - proto.valueOf = valueOf; - proto.creationData = creationData; - proto.eraName = getEraName; - proto.eraNarrow = getEraNarrow; - proto.eraAbbr = getEraAbbr; - proto.eraYear = getEraYear; - proto.year = getSetYear; - proto.isLeapYear = getIsLeapYear; - proto.weekYear = getSetWeekYear; - proto.isoWeekYear = getSetISOWeekYear; - proto.quarter = proto.quarters = getSetQuarter; - proto.month = getSetMonth; - proto.daysInMonth = getDaysInMonth; - proto.week = proto.weeks = getSetWeek; - proto.isoWeek = proto.isoWeeks = getSetISOWeek; - proto.weeksInYear = getWeeksInYear; - proto.weeksInWeekYear = getWeeksInWeekYear; - proto.isoWeeksInYear = getISOWeeksInYear; - proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear; - proto.date = getSetDayOfMonth; - proto.day = proto.days = getSetDayOfWeek; - proto.weekday = getSetLocaleDayOfWeek; - proto.isoWeekday = getSetISODayOfWeek; - proto.dayOfYear = getSetDayOfYear; - proto.hour = proto.hours = getSetHour; - proto.minute = proto.minutes = getSetMinute; - proto.second = proto.seconds = getSetSecond; - proto.millisecond = proto.milliseconds = getSetMillisecond; - proto.utcOffset = getSetOffset; - proto.utc = setOffsetToUTC; - proto.local = setOffsetToLocal; - proto.parseZone = setOffsetToParsedOffset; - proto.hasAlignedHourOffset = hasAlignedHourOffset; - proto.isDST = isDaylightSavingTime; - proto.isLocal = isLocal; - proto.isUtcOffset = isUtcOffset; - proto.isUtc = isUtc; - proto.isUTC = isUtc; - proto.zoneAbbr = getZoneAbbr; - proto.zoneName = getZoneName; - proto.dates = deprecate( - 'dates accessor is deprecated. Use date instead.', - getSetDayOfMonth - ); - proto.months = deprecate( - 'months accessor is deprecated. Use month instead', - getSetMonth - ); - proto.years = deprecate( - 'years accessor is deprecated. Use year instead', - getSetYear - ); - proto.zone = deprecate( - 'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', - getSetZone - ); - proto.isDSTShifted = deprecate( - 'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', - isDaylightSavingTimeShifted - ); +module.exports = objectToString; - function createUnix(input) { - return createLocal(input * 1000); - } - function createInZone() { - return createLocal.apply(null, arguments).parseZone(); - } +/***/ }), - function preParsePostFormat(string) { - return string; - } +/***/ 9882: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - var proto$1 = Locale.prototype; +var freeGlobal = __nccwpck_require__(2085); - proto$1.calendar = calendar; - proto$1.longDateFormat = longDateFormat; - proto$1.invalidDate = invalidDate; - proto$1.ordinal = ordinal; - proto$1.preparse = preParsePostFormat; - proto$1.postformat = preParsePostFormat; - proto$1.relativeTime = relativeTime; - proto$1.pastFuture = pastFuture; - proto$1.set = set; - proto$1.eras = localeEras; - proto$1.erasParse = localeErasParse; - proto$1.erasConvertYear = localeErasConvertYear; - proto$1.erasAbbrRegex = erasAbbrRegex; - proto$1.erasNameRegex = erasNameRegex; - proto$1.erasNarrowRegex = erasNarrowRegex; +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - proto$1.months = localeMonths; - proto$1.monthsShort = localeMonthsShort; - proto$1.monthsParse = localeMonthsParse; - proto$1.monthsRegex = monthsRegex; - proto$1.monthsShortRegex = monthsShortRegex; - proto$1.week = localeWeek; - proto$1.firstDayOfYear = localeFirstDayOfYear; - proto$1.firstDayOfWeek = localeFirstDayOfWeek; +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); - proto$1.weekdays = localeWeekdays; - proto$1.weekdaysMin = localeWeekdaysMin; - proto$1.weekdaysShort = localeWeekdaysShort; - proto$1.weekdaysParse = localeWeekdaysParse; +module.exports = root; - proto$1.weekdaysRegex = weekdaysRegex; - proto$1.weekdaysShortRegex = weekdaysShortRegex; - proto$1.weekdaysMinRegex = weekdaysMinRegex; - proto$1.isPM = localeIsPM; - proto$1.meridiem = localeMeridiem; +/***/ }), - function get$1(format, index, field, setter) { - var locale = getLocale(), - utc = createUTC().set(setter, index); - return locale[field](utc, format); - } +/***/ 1853: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function listMonthsImpl(format, index, field) { - if (isNumber(format)) { - index = format; - format = undefined; - } +var memoizeCapped = __nccwpck_require__(9422); - format = format || ''; +/** Used to match property names within property paths. */ +var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - if (index != null) { - return get$1(format, index, field, 'month'); - } +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; - var i, - out = []; - for (i = 0; i < 12; i++) { - out[i] = get$1(format, i, field, 'month'); - } - return out; - } - - // () - // (5) - // (fmt, 5) - // (fmt) - // (true) - // (true, 5) - // (true, fmt, 5) - // (true, fmt) - function listWeekdaysImpl(localeSorted, format, index, field) { - if (typeof localeSorted === 'boolean') { - if (isNumber(format)) { - index = format; - format = undefined; - } +/** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ +var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +}); - format = format || ''; - } else { - format = localeSorted; - index = format; - localeSorted = false; +module.exports = stringToPath; - if (isNumber(format)) { - index = format; - format = undefined; - } - format = format || ''; - } +/***/ }), - var locale = getLocale(), - shift = localeSorted ? locale._week.dow : 0, - i, - out = []; +/***/ 9071: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - if (index != null) { - return get$1(format, (index + shift) % 7, field, 'day'); - } +var isSymbol = __nccwpck_require__(6403); - for (i = 0; i < 7; i++) { - out[i] = get$1(format, (i + shift) % 7, field, 'day'); - } - return out; - } +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; - function listMonths(format, index) { - return listMonthsImpl(format, index, 'months'); - } +/** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ +function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; +} - function listMonthsShort(format, index) { - return listMonthsImpl(format, index, 'monthsShort'); - } +module.exports = toKey; - function listWeekdays(localeSorted, format, index) { - return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); - } - function listWeekdaysShort(localeSorted, format, index) { - return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); - } +/***/ }), - function listWeekdaysMin(localeSorted, format, index) { - return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); - } +/***/ 6928: +/***/ ((module) => { - getSetGlobalLocale('en', { - eras: [ - { - since: '0001-01-01', - until: +Infinity, - offset: 1, - name: 'Anno Domini', - narrow: 'AD', - abbr: 'AD', - }, - { - since: '0000-12-31', - until: -Infinity, - offset: 1, - name: 'Before Christ', - narrow: 'BC', - abbr: 'BC', - }, - ], - dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal: function (number) { - var b = number % 10, - output = - toInt((number % 100) / 10) === 1 - ? 'th' - : b === 1 - ? 'st' - : b === 2 - ? 'nd' - : b === 3 - ? 'rd' - : 'th'; - return number + output; - }, - }); +/** Used for built-in method references. */ +var funcProto = Function.prototype; - // Side effect imports +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; - hooks.lang = deprecate( - 'moment.lang is deprecated. Use moment.locale instead.', - getSetGlobalLocale - ); - hooks.langData = deprecate( - 'moment.langData is deprecated. Use moment.localeData instead.', - getLocale - ); +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} - var mathAbs = Math.abs; +module.exports = toSource; - function abs() { - var data = this._data; - this._milliseconds = mathAbs(this._milliseconds); - this._days = mathAbs(this._days); - this._months = mathAbs(this._months); +/***/ }), - data.milliseconds = mathAbs(data.milliseconds); - data.seconds = mathAbs(data.seconds); - data.minutes = mathAbs(data.minutes); - data.hours = mathAbs(data.hours); - data.months = mathAbs(data.months); - data.years = mathAbs(data.years); +/***/ 1901: +/***/ ((module) => { - return this; - } +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} - function addSubtract$1(duration, input, value, direction) { - var other = createDuration(input, value); +module.exports = eq; - duration._milliseconds += direction * other._milliseconds; - duration._days += direction * other._days; - duration._months += direction * other._months; - return duration._bubble(); - } +/***/ }), - // supports only 2.0-style add(1, 's') or add(duration) - function add$1(input, value) { - return addSubtract$1(this, input, value, 1); - } +/***/ 6908: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - // supports only 2.0-style subtract(1, 's') or subtract(duration) - function subtract$1(input, value) { - return addSubtract$1(this, input, value, -1); - } +var baseGet = __nccwpck_require__(5758); - function absCeil(number) { - if (number < 0) { - return Math.floor(number); - } else { - return Math.ceil(number); - } - } +/** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ +function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; +} - function bubble() { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, - minutes, - hours, - years, - monthsFromDays; - - // if we have a mix of positive and negative values, bubble down first - // check: https://github.com/moment/moment/issues/2166 - if ( - !( - (milliseconds >= 0 && days >= 0 && months >= 0) || - (milliseconds <= 0 && days <= 0 && months <= 0) - ) - ) { - milliseconds += absCeil(monthsToDays(months) + days) * 864e5; - days = 0; - months = 0; - } +module.exports = get; - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - seconds = absFloor(milliseconds / 1000); - data.seconds = seconds % 60; +/***/ }), - minutes = absFloor(seconds / 60); - data.minutes = minutes % 60; +/***/ 4869: +/***/ ((module) => { - hours = absFloor(minutes / 60); - data.hours = hours % 24; +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; - days += absFloor(hours / 24); +module.exports = isArray; - // convert days to months - monthsFromDays = absFloor(daysToMonths(days)); - months += monthsFromDays; - days -= absCeil(monthsToDays(monthsFromDays)); - // 12 months -> 1 year - years = absFloor(months / 12); - months %= 12; +/***/ }), - data.days = days; - data.months = months; - data.years = years; +/***/ 7799: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - return this; - } +var baseGetTag = __nccwpck_require__(7497), + isObject = __nccwpck_require__(3334); - function daysToMonths(days) { - // 400 years have 146097 days (taking into account leap year rules) - // 400 years have 12 months === 4800 - return (days * 4800) / 146097; - } +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; - function monthsToDays(months) { - // the reverse of daysToMonths - return (months * 146097) / 4800; - } +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; +} - function as(units) { - if (!this.isValid()) { - return NaN; - } - var days, - months, - milliseconds = this._milliseconds; - - units = normalizeUnits(units); - - if (units === 'month' || units === 'quarter' || units === 'year') { - days = this._days + milliseconds / 864e5; - months = this._months + daysToMonths(days); - switch (units) { - case 'month': - return months; - case 'quarter': - return months / 3; - case 'year': - return months / 12; - } - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(monthsToDays(this._months)); - switch (units) { - case 'week': - return days / 7 + milliseconds / 6048e5; - case 'day': - return days + milliseconds / 864e5; - case 'hour': - return days * 24 + milliseconds / 36e5; - case 'minute': - return days * 1440 + milliseconds / 6e4; - case 'second': - return days * 86400 + milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': - return Math.floor(days * 864e5) + milliseconds; - default: - throw new Error('Unknown unit ' + units); - } - } - } +module.exports = isFunction; - // TODO: Use this.as('ms')? - function valueOf$1() { - if (!this.isValid()) { - return NaN; - } - return ( - this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6 - ); - } - function makeAs(alias) { - return function () { - return this.as(alias); - }; - } +/***/ }), - var asMilliseconds = makeAs('ms'), - asSeconds = makeAs('s'), - asMinutes = makeAs('m'), - asHours = makeAs('h'), - asDays = makeAs('d'), - asWeeks = makeAs('w'), - asMonths = makeAs('M'), - asQuarters = makeAs('Q'), - asYears = makeAs('y'); +/***/ 3334: +/***/ ((module) => { - function clone$1() { - return createDuration(this); - } +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} - function get$2(units) { - units = normalizeUnits(units); - return this.isValid() ? this[units + 's']() : NaN; - } +module.exports = isObject; - function makeGetter(name) { - return function () { - return this.isValid() ? this._data[name] : NaN; - }; - } - var milliseconds = makeGetter('milliseconds'), - seconds = makeGetter('seconds'), - minutes = makeGetter('minutes'), - hours = makeGetter('hours'), - days = makeGetter('days'), - months = makeGetter('months'), - years = makeGetter('years'); +/***/ }), - function weeks() { - return absFloor(this.days() / 7); - } +/***/ 5926: +/***/ ((module) => { - var round = Math.round, - thresholds = { - ss: 44, // a few seconds to seconds - s: 45, // seconds to minute - m: 45, // minutes to hour - h: 22, // hours to day - d: 26, // days to month/week - w: null, // weeks to month - M: 11, // months to year - }; +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) { - var duration = createDuration(posNegDuration).abs(), - seconds = round(duration.as('s')), - minutes = round(duration.as('m')), - hours = round(duration.as('h')), - days = round(duration.as('d')), - months = round(duration.as('M')), - weeks = round(duration.as('w')), - years = round(duration.as('y')), - a = - (seconds <= thresholds.ss && ['s', seconds]) || - (seconds < thresholds.s && ['ss', seconds]) || - (minutes <= 1 && ['m']) || - (minutes < thresholds.m && ['mm', minutes]) || - (hours <= 1 && ['h']) || - (hours < thresholds.h && ['hh', hours]) || - (days <= 1 && ['d']) || - (days < thresholds.d && ['dd', days]); - - if (thresholds.w != null) { - a = - a || - (weeks <= 1 && ['w']) || - (weeks < thresholds.w && ['ww', weeks]); - } - a = a || - (months <= 1 && ['M']) || - (months < thresholds.M && ['MM', months]) || - (years <= 1 && ['y']) || ['yy', years]; +module.exports = isObjectLike; - a[2] = withoutSuffix; - a[3] = +posNegDuration > 0; - a[4] = locale; - return substituteTimeAgo.apply(null, a); - } - // This function allows you to set the rounding function for relative time strings - function getSetRelativeTimeRounding(roundingFunction) { - if (roundingFunction === undefined) { - return round; - } - if (typeof roundingFunction === 'function') { - round = roundingFunction; - return true; - } - return false; - } +/***/ }), - // This function allows you to set a threshold for relative time strings - function getSetRelativeTimeThreshold(threshold, limit) { - if (thresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return thresholds[threshold]; - } - thresholds[threshold] = limit; - if (threshold === 's') { - thresholds.ss = limit - 1; - } - return true; - } +/***/ 6403: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function humanize(argWithSuffix, argThresholds) { - if (!this.isValid()) { - return this.localeData().invalidDate(); - } +var baseGetTag = __nccwpck_require__(7497), + isObjectLike = __nccwpck_require__(5926); - var withSuffix = false, - th = thresholds, - locale, - output; +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; - if (typeof argWithSuffix === 'object') { - argThresholds = argWithSuffix; - argWithSuffix = false; - } - if (typeof argWithSuffix === 'boolean') { - withSuffix = argWithSuffix; - } - if (typeof argThresholds === 'object') { - th = Object.assign({}, thresholds, argThresholds); - if (argThresholds.s != null && argThresholds.ss == null) { - th.ss = argThresholds.s - 1; - } - } +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); +} - locale = this.localeData(); - output = relativeTime$1(this, !withSuffix, th, locale); +module.exports = isSymbol; - if (withSuffix) { - output = locale.pastFuture(+this, output); - } - return locale.postformat(output); - } +/***/ }), - var abs$1 = Math.abs; +/***/ 9885: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - function sign(x) { - return (x > 0) - (x < 0) || +x; - } +var MapCache = __nccwpck_require__(938); - function toISOString$1() { - // for ISO strings we do not use the normal bubbling rules: - // * milliseconds bubble up until they become hours - // * days do not bubble at all - // * months bubble up until they become years - // This is because there is no context-free conversion between hours and days - // (think of clock changes) - // and also not between days and months (28-31 days per month) - if (!this.isValid()) { - return this.localeData().invalidDate(); - } +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; - var seconds = abs$1(this._milliseconds) / 1000, - days = abs$1(this._days), - months = abs$1(this._months), - minutes, - hours, - years, - s, - total = this.asSeconds(), - totalSign, - ymSign, - daysSign, - hmsSign; - - if (!total) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } +/** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ +function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; - // 3600 seconds -> 60 minutes -> 1 hour - minutes = absFloor(seconds / 60); - hours = absFloor(minutes / 60); - seconds %= 60; - minutes %= 60; - - // 12 months -> 1 year - years = absFloor(months / 12); - months %= 12; - - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : ''; - - totalSign = total < 0 ? '-' : ''; - ymSign = sign(this._months) !== sign(total) ? '-' : ''; - daysSign = sign(this._days) !== sign(total) ? '-' : ''; - hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : ''; - - return ( - totalSign + - 'P' + - (years ? ymSign + years + 'Y' : '') + - (months ? ymSign + months + 'M' : '') + - (days ? daysSign + days + 'D' : '') + - (hours || minutes || seconds ? 'T' : '') + - (hours ? hmsSign + hours + 'H' : '') + - (minutes ? hmsSign + minutes + 'M' : '') + - (seconds ? hmsSign + s + 'S' : '') - ); + if (cache.has(key)) { + return cache.get(key); } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; +} - var proto$2 = Duration.prototype; - - proto$2.isValid = isValid$1; - proto$2.abs = abs; - proto$2.add = add$1; - proto$2.subtract = subtract$1; - proto$2.as = as; - proto$2.asMilliseconds = asMilliseconds; - proto$2.asSeconds = asSeconds; - proto$2.asMinutes = asMinutes; - proto$2.asHours = asHours; - proto$2.asDays = asDays; - proto$2.asWeeks = asWeeks; - proto$2.asMonths = asMonths; - proto$2.asQuarters = asQuarters; - proto$2.asYears = asYears; - proto$2.valueOf = valueOf$1; - proto$2._bubble = bubble; - proto$2.clone = clone$1; - proto$2.get = get$2; - proto$2.milliseconds = milliseconds; - proto$2.seconds = seconds; - proto$2.minutes = minutes; - proto$2.hours = hours; - proto$2.days = days; - proto$2.weeks = weeks; - proto$2.months = months; - proto$2.years = years; - proto$2.humanize = humanize; - proto$2.toISOString = toISOString$1; - proto$2.toString = toISOString$1; - proto$2.toJSON = toISOString$1; - proto$2.locale = locale; - proto$2.localeData = localeData; - - proto$2.toIsoString = deprecate( - 'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', - toISOString$1 - ); - proto$2.lang = lang; +// Expose `MapCache`. +memoize.Cache = MapCache; - // FORMATTING +module.exports = memoize; - addFormatToken('X', 0, 0, 'unix'); - addFormatToken('x', 0, 0, 'valueOf'); - // PARSING +/***/ }), - addRegexToken('x', matchSigned); - addRegexToken('X', matchTimestamp); - addParseToken('X', function (input, array, config) { - config._d = new Date(parseFloat(input) * 1000); - }); - addParseToken('x', function (input, array, config) { - config._d = new Date(toInt(input)); - }); +/***/ 2931: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - //! moment.js - - hooks.version = '2.29.4'; - - setHookCallback(createLocal); - - hooks.fn = proto; - hooks.min = min; - hooks.max = max; - hooks.now = now; - hooks.utc = createUTC; - hooks.unix = createUnix; - hooks.months = listMonths; - hooks.isDate = isDate; - hooks.locale = getSetGlobalLocale; - hooks.invalid = createInvalid; - hooks.duration = createDuration; - hooks.isMoment = isMoment; - hooks.weekdays = listWeekdays; - hooks.parseZone = createInZone; - hooks.localeData = getLocale; - hooks.isDuration = isDuration; - hooks.monthsShort = listMonthsShort; - hooks.weekdaysMin = listWeekdaysMin; - hooks.defineLocale = defineLocale; - hooks.updateLocale = updateLocale; - hooks.locales = listLocales; - hooks.weekdaysShort = listWeekdaysShort; - hooks.normalizeUnits = normalizeUnits; - hooks.relativeTimeRounding = getSetRelativeTimeRounding; - hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; - hooks.calendarFormat = getCalendarFormat; - hooks.prototype = proto; - - // currently HTML5 input type only supports 24-hour formats - hooks.HTML5_FMT = { - DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // - DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // - DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // - DATE: 'YYYY-MM-DD', // - TIME: 'HH:mm', // - TIME_SECONDS: 'HH:mm:ss', // - TIME_MS: 'HH:mm:ss.SSS', // - WEEK: 'GGGG-[W]WW', // - MONTH: 'YYYY-MM', // - }; +var baseToString = __nccwpck_require__(6792); - return hooks; +/** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ +function toString(value) { + return value == null ? '' : baseToString(value); +} -}))); +module.exports = toString; /***/ }), @@ -23017,6 +20100,34 @@ module.exports = require("zlib"); /***/ }), +/***/ 3286: +/***/ ((module) => { + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + "default": obj + }; +} +module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports; + +/***/ }), + +/***/ 5605: +/***/ ((module) => { + +function _typeof(o) { + "@babel/helpers - typeof"; + + return (module.exports = _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { + return typeof o; + } : function (o) { + return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; + }, module.exports.__esModule = true, module.exports["default"] = module.exports), _typeof(o); +} +module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports; + +/***/ }), + /***/ 6717: /***/ ((__unused_webpack_module, exports) => { @@ -25286,8 +22397,8 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"] /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { -/******/ id: moduleId, -/******/ loaded: false, +/******/ // no module.id needed +/******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ @@ -25300,23 +22411,11 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"] /******/ if(threw) delete __webpack_module_cache__[moduleId]; /******/ } /******/ -/******/ // Flag the module as loaded -/******/ module.loaded = true; -/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ -/******/ /* webpack/runtime/node module decorator */ -/******/ (() => { -/******/ __nccwpck_require__.nmd = (module) => { -/******/ module.paths = []; -/******/ if (!module.children) module.children = []; -/******/ return module; -/******/ }; -/******/ })(); -/******/ /******/ /* webpack/runtime/compat */ /******/ /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; diff --git a/.github/actions/javascript/getDeployPullRequestList/action.yml b/.github/actions/javascript/getDeployPullRequestList/action.yml index 4cbf7041a7eb..1362f207ba4a 100644 --- a/.github/actions/javascript/getDeployPullRequestList/action.yml +++ b/.github/actions/javascript/getDeployPullRequestList/action.yml @@ -14,5 +14,5 @@ outputs: PR_LIST: description: Array of pull request numbers runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index e97e5dbcb43a..974824ac4628 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -111,6 +111,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; @@ -132,23 +133,42 @@ const {getPreviousVersion, SEMANTIC_VERSION_LEVELS} = __nccwpck_require__(8007); /** * @param {String} tag + * @param {String} [shallowExcludeTag] when fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) */ -function fetchTag(tag) { - const previousPatchVersion = getPreviousVersion(tag, SEMANTIC_VERSION_LEVELS.PATCH); - try { - let command = `git fetch origin tag ${tag} --no-tags`; +function fetchTag(tag, shallowExcludeTag = '') { + let shouldRetry = true; + let needsRepack = false; + while (shouldRetry) { + try { + let command = ''; + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + command = 'git repack -d'; + console.log(`Running command: ${command}`); + execSync(command); + } - // Exclude commits reachable from the previous patch version (i.e: previous checklist), - // so that we don't have to fetch the full history - // Note that this condition would only ever _not_ be true in the 1.0.0-0 edge case - if (previousPatchVersion !== tag) { - command += ` --shallow-exclude=${previousPatchVersion}`; - } + command = `git fetch origin tag ${tag} --no-tags`; - console.log(`Running command: ${command}`); - execSync(command); - } catch (e) { - console.error(e); + // Note that this condition is only ever NOT true in the 1.0.0-0 edge case + if (shallowExcludeTag && shallowExcludeTag !== tag) { + command += ` --shallow-exclude=${shallowExcludeTag}`; + } + + console.log(`Running command: ${command}`); + execSync(command); + shouldRetry = false; + } catch (e) { + console.error(e); + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } } } @@ -160,8 +180,10 @@ function fetchTag(tag) { * @returns {Promise>>} */ function getCommitHistoryAsJSON(fromTag, toTag) { - fetchTag(fromTag); - fetchTag(toTag); + // Fetch tags, exclude commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousVersion(fromTag, SEMANTIC_VERSION_LEVELS.PATCH); + fetchTag(fromTag, previousPatchVersion); + fetchTag(toTag, previousPatchVersion); console.log('Getting pull requests merged between the following tags:', fromTag, toTag); return new Promise((resolve, reject) => { @@ -238,16 +260,15 @@ function getValidMergedPRs(commits) { * @param {String} toTag * @returns {Promise>} – Pull request numbers */ -function getPullRequestsMergedBetween(fromTag, toTag) { +async function getPullRequestsMergedBetween(fromTag, toTag) { console.log(`Looking for commits made between ${fromTag} and ${toTag}...`); - return getCommitHistoryAsJSON(fromTag, toTag).then((commitList) => { - console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); + const commitList = await getCommitHistoryAsJSON(fromTag, toTag); + console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); - // Find which commit messages correspond to merged PR's - const pullRequestNumbers = getValidMergedPRs(commitList); - console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); - return _.map(pullRequestNumbers, (prNum) => Number.parseInt(prNum, 10)); - }); + // Find which commit messages correspond to merged PR's + const pullRequestNumbers = getValidMergedPRs(commitList).sort((a, b) => a - b); + console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); + return pullRequestNumbers; } module.exports = { diff --git a/.github/actions/javascript/getPreviousVersion/action.yml b/.github/actions/javascript/getPreviousVersion/action.yml index 6b2221af7c40..ec81bd99e4f8 100644 --- a/.github/actions/javascript/getPreviousVersion/action.yml +++ b/.github/actions/javascript/getPreviousVersion/action.yml @@ -8,5 +8,5 @@ outputs: PREVIOUS_VERSION: description: The previous semver version of the application, according to the SEMVER_LEVEL provided runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/getPullRequestDetails/action.yml b/.github/actions/javascript/getPullRequestDetails/action.yml index ed2c60f018a1..d931d101b5da 100644 --- a/.github/actions/javascript/getPullRequestDetails/action.yml +++ b/.github/actions/javascript/getPullRequestDetails/action.yml @@ -22,5 +22,5 @@ outputs: FORKED_REPO_URL: description: 'Output forked repo URL if PR includes changes from a fork' runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/getPullRequestDetails/index.js b/.github/actions/javascript/getPullRequestDetails/index.js index 82e03e3075d9..3c5bd277a60e 100644 --- a/.github/actions/javascript/getPullRequestDetails/index.js +++ b/.github/actions/javascript/getPullRequestDetails/index.js @@ -63,6 +63,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/getReleaseBody/action.yml b/.github/actions/javascript/getReleaseBody/action.yml index c221acbdaae2..e4a451ccda8d 100644 --- a/.github/actions/javascript/getReleaseBody/action.yml +++ b/.github/actions/javascript/getReleaseBody/action.yml @@ -8,5 +8,5 @@ outputs: RELEASE_BODY: description: String body of a production release. runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/getReleaseBody/index.js b/.github/actions/javascript/getReleaseBody/index.js index 8cf926d63030..9ae04c4ef02a 100644 --- a/.github/actions/javascript/getReleaseBody/index.js +++ b/.github/actions/javascript/getReleaseBody/index.js @@ -63,6 +63,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/isStagingDeployLocked/action.yml b/.github/actions/javascript/isStagingDeployLocked/action.yml index 9e5e50b26452..395a081a7620 100644 --- a/.github/actions/javascript/isStagingDeployLocked/action.yml +++ b/.github/actions/javascript/isStagingDeployLocked/action.yml @@ -10,5 +10,5 @@ outputs: NUMBER: description: StagingDeployCash issue number runs: - using: 'node16' + using: 'node20' main: 'index.js' diff --git a/.github/actions/javascript/isStagingDeployLocked/index.js b/.github/actions/javascript/isStagingDeployLocked/index.js index b355e5c126b8..fb4cdc1afd40 100644 --- a/.github/actions/javascript/isStagingDeployLocked/index.js +++ b/.github/actions/javascript/isStagingDeployLocked/index.js @@ -47,6 +47,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/action.yml b/.github/actions/javascript/markPullRequestsAsDeployed/action.yml index 7015293d2bb8..f0ca77bdbf00 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/action.yml +++ b/.github/actions/javascript/markPullRequestsAsDeployed/action.yml @@ -28,5 +28,5 @@ inputs: description: "Web job result ('success', 'failure', 'cancelled', or 'skipped')" required: true runs: - using: "node16" + using: "node20" main: "./index.js" diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/index.js b/.github/actions/javascript/markPullRequestsAsDeployed/index.js index 83a32d258509..73a51b622759 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/index.js +++ b/.github/actions/javascript/markPullRequestsAsDeployed/index.js @@ -212,6 +212,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/postTestBuildComment/action.yml b/.github/actions/javascript/postTestBuildComment/action.yml index 07829dfab8cd..00c826badf9f 100644 --- a/.github/actions/javascript/postTestBuildComment/action.yml +++ b/.github/actions/javascript/postTestBuildComment/action.yml @@ -32,5 +32,5 @@ inputs: description: "Link for the web build" required: false runs: - using: "node16" + using: "node20" main: "./index.js" diff --git a/.github/actions/javascript/postTestBuildComment/index.js b/.github/actions/javascript/postTestBuildComment/index.js index c2d486b325bb..2c0fa6726ede 100644 --- a/.github/actions/javascript/postTestBuildComment/index.js +++ b/.github/actions/javascript/postTestBuildComment/index.js @@ -91,6 +91,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/reopenIssueWithComment/action.yml b/.github/actions/javascript/reopenIssueWithComment/action.yml index 0a163e6651f0..3dfcba9b0c35 100644 --- a/.github/actions/javascript/reopenIssueWithComment/action.yml +++ b/.github/actions/javascript/reopenIssueWithComment/action.yml @@ -11,5 +11,5 @@ inputs: description: The comment string we want to leave on the issue after we reopen it. required: true runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/reopenIssueWithComment/index.js b/.github/actions/javascript/reopenIssueWithComment/index.js index c387679d3a05..39906af7bd05 100644 --- a/.github/actions/javascript/reopenIssueWithComment/index.js +++ b/.github/actions/javascript/reopenIssueWithComment/index.js @@ -17,6 +17,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/reviewerChecklist/action.yml b/.github/actions/javascript/reviewerChecklist/action.yml index 24fe815dcc6a..d8c1e6620b77 100644 --- a/.github/actions/javascript/reviewerChecklist/action.yml +++ b/.github/actions/javascript/reviewerChecklist/action.yml @@ -5,5 +5,5 @@ inputs: description: Auth token for New Expensify Github required: true runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/reviewerChecklist/index.js b/.github/actions/javascript/reviewerChecklist/index.js index 09fb168330ec..aebf5205feab 100644 --- a/.github/actions/javascript/reviewerChecklist/index.js +++ b/.github/actions/javascript/reviewerChecklist/index.js @@ -17,6 +17,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/actions/javascript/validateReassureOutput/action.yml b/.github/actions/javascript/validateReassureOutput/action.yml index 1b4488757e9c..4fd53e838fb5 100644 --- a/.github/actions/javascript/validateReassureOutput/action.yml +++ b/.github/actions/javascript/validateReassureOutput/action.yml @@ -11,5 +11,5 @@ inputs: description: Refers to the results obtained from regression tests `.reassure/output.json`. required: true runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/verifySignedCommits/action.yml b/.github/actions/javascript/verifySignedCommits/action.yml index 1a641cddb391..a724220eba32 100644 --- a/.github/actions/javascript/verifySignedCommits/action.yml +++ b/.github/actions/javascript/verifySignedCommits/action.yml @@ -9,5 +9,5 @@ inputs: required: false runs: - using: 'node16' + using: 'node20' main: './index.js' diff --git a/.github/actions/javascript/verifySignedCommits/index.js b/.github/actions/javascript/verifySignedCommits/index.js index 71a01456457b..7f08a5f95790 100644 --- a/.github/actions/javascript/verifySignedCommits/index.js +++ b/.github/actions/javascript/verifySignedCommits/index.js @@ -17,6 +17,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/libs/CONST.js b/.github/libs/CONST.js index 36eeb804aa00..b3ba9bed08c1 100644 --- a/.github/libs/CONST.js +++ b/.github/libs/CONST.js @@ -8,6 +8,7 @@ const CONST = { DEPLOY_BLOCKER: 'DeployBlockerCash', INTERNAL_QA: 'InternalQA', }, + DATE_FORMAT_STRING: 'yyyy-MM-dd', }; CONST.APP_REPO_URL = `https://github.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}`; diff --git a/.github/libs/GitUtils.js b/.github/libs/GitUtils.js index 7bc600470dd1..2076763fbb55 100644 --- a/.github/libs/GitUtils.js +++ b/.github/libs/GitUtils.js @@ -6,23 +6,42 @@ const {getPreviousVersion, SEMANTIC_VERSION_LEVELS} = require('../libs/versionUp /** * @param {String} tag + * @param {String} [shallowExcludeTag] when fetching the given tag, exclude all history reachable by the shallowExcludeTag (used to make fetch much faster) */ -function fetchTag(tag) { - const previousPatchVersion = getPreviousVersion(tag, SEMANTIC_VERSION_LEVELS.PATCH); - try { - let command = `git fetch origin tag ${tag} --no-tags`; - - // Exclude commits reachable from the previous patch version (i.e: previous checklist), - // so that we don't have to fetch the full history - // Note that this condition would only ever _not_ be true in the 1.0.0-0 edge case - if (previousPatchVersion !== tag) { - command += ` --shallow-exclude=${previousPatchVersion}`; - } +function fetchTag(tag, shallowExcludeTag = '') { + let shouldRetry = true; + let needsRepack = false; + while (shouldRetry) { + try { + let command = ''; + if (needsRepack) { + // We have seen some scenarios where this fixes the git fetch. + // Why? Who knows... https://github.com/Expensify/App/pull/31459 + command = 'git repack -d'; + console.log(`Running command: ${command}`); + execSync(command); + } + + command = `git fetch origin tag ${tag} --no-tags`; + + // Note that this condition is only ever NOT true in the 1.0.0-0 edge case + if (shallowExcludeTag && shallowExcludeTag !== tag) { + command += ` --shallow-exclude=${shallowExcludeTag}`; + } - console.log(`Running command: ${command}`); - execSync(command); - } catch (e) { - console.error(e); + console.log(`Running command: ${command}`); + execSync(command); + shouldRetry = false; + } catch (e) { + console.error(e); + if (!needsRepack) { + console.log('Attempting to repack and retry...'); + needsRepack = true; + } else { + console.error("Repack didn't help, giving up..."); + shouldRetry = false; + } + } } } @@ -34,8 +53,10 @@ function fetchTag(tag) { * @returns {Promise>>} */ function getCommitHistoryAsJSON(fromTag, toTag) { - fetchTag(fromTag); - fetchTag(toTag); + // Fetch tags, exclude commits reachable from the previous patch version (i.e: previous checklist), so that we don't have to fetch the full history + const previousPatchVersion = getPreviousVersion(fromTag, SEMANTIC_VERSION_LEVELS.PATCH); + fetchTag(fromTag, previousPatchVersion); + fetchTag(toTag, previousPatchVersion); console.log('Getting pull requests merged between the following tags:', fromTag, toTag); return new Promise((resolve, reject) => { @@ -112,16 +133,15 @@ function getValidMergedPRs(commits) { * @param {String} toTag * @returns {Promise>} – Pull request numbers */ -function getPullRequestsMergedBetween(fromTag, toTag) { +async function getPullRequestsMergedBetween(fromTag, toTag) { console.log(`Looking for commits made between ${fromTag} and ${toTag}...`); - return getCommitHistoryAsJSON(fromTag, toTag).then((commitList) => { - console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); + const commitList = await getCommitHistoryAsJSON(fromTag, toTag); + console.log(`Commits made between ${fromTag} and ${toTag}:`, commitList); - // Find which commit messages correspond to merged PR's - const pullRequestNumbers = getValidMergedPRs(commitList); - console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); - return _.map(pullRequestNumbers, (prNum) => Number.parseInt(prNum, 10)); - }); + // Find which commit messages correspond to merged PR's + const pullRequestNumbers = getValidMergedPRs(commitList).sort((a, b) => a - b); + console.log(`List of pull requests merged between ${fromTag} and ${toTag}`, pullRequestNumbers); + return pullRequestNumbers; } module.exports = { diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 68b98ab625be..d940d99d9cde 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -42,12 +42,12 @@ Due to the large, ever-growing history of this repo, do not do any full-fetches ```yaml # Bad -- uses: actions/checkout@v3 +- uses: actions/checkout@v4 with: fetch-depth: 0 # Good -- uses: actions/checkout@v3 +- uses: actions/checkout@v4 ``` ```sh @@ -63,7 +63,7 @@ git fetch origin tag 1.0.1-0 --no-tags --shallow-exclude=1.0.0-0 # This will fet ## Security Rules 🔐 1. Do **not** use `pull_request_target` trigger unless an external fork needs access to secrets, or a _write_ `GITHUB_TOKEN`. -1. Do **not ever** write a `pull_request_target` trigger with an explicit PR checkout, e.g. using `actions/checkout@v2`. This is [discussed further here](https://securitylab.github.com/research/github-actions-preventing-pwn-requests) +1. Do **not ever** write a `pull_request_target` trigger with an explicit PR checkout, e.g. using `actions/checkout@v4`. This is [discussed further here](https://securitylab.github.com/research/github-actions-preventing-pwn-requests) 1. **Do use** the `pull_request` trigger as it does not send internal secrets and only grants a _read_ `GITHUB_TOKEN`. 1. If an untrusted (i.e: not maintained by GitHub) external action needs access to any secret (`GITHUB_TOKEN` or internal secret), use the commit hash of the workflow to prevent a modification of underlying source code at that version. For example: 1. **Bad:** `hmarr/auto-approve-action@v2.0.0` Relies on the tag @@ -139,12 +139,11 @@ In order to bundle actions with their dependencies into a single Node.js executa - When calling your GitHub Action from one of our workflows, you must: - First call `@actions/checkout`. - - Use the absolute path of the action in GitHub, including the repo name, path, and branch ref, like so: + - Use the relative path of the action in GitHub from the root of this repo, like so: ```yaml - name: Generate Version - uses: Expensify/App/.github/actions/javascript/bumpVersion@main + uses: ./.github/actions/javascript/bumpVersion ``` - Do not try to use a relative path. -- Confusingly, paths in action metadata files (`action.yml`) _must_ use relative paths. + - You can't use any dynamic values or environment variables in a `uses` statement - In general, it is a best practice to minimize any side-effects of each action. Using atomic ("dumb") actions that have a clear and simple purpose will promote reuse and make it easier to understand the workflows that use them. diff --git a/.github/workflows/authorChecklist.yml b/.github/workflows/authorChecklist.yml index 740e7b3a5e69..907b1e7be6ca 100644 --- a/.github/workflows/authorChecklist.yml +++ b/.github/workflows/authorChecklist.yml @@ -13,7 +13,8 @@ jobs: runs-on: ubuntu-latest if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v4 - name: authorChecklist.js uses: ./.github/actions/javascript/authorChecklist diff --git a/.github/workflows/cherryPick.yml b/.github/workflows/cherryPick.yml index 43f3c64554bc..dd2c92e95568 100644 --- a/.github/workflows/cherryPick.yml +++ b/.github/workflows/cherryPick.yml @@ -27,7 +27,7 @@ jobs: createNewVersion: needs: validateActor if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} - uses: Expensify/App/.github/workflows/createNewVersion.yml@main + uses: ./.github/workflows/createNewVersion.yml secrets: inherit cherryPick: @@ -35,14 +35,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout staging branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: staging token: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Set up git for OSBotify id: setupGitForOSBotify - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + uses: ./.github/actions/composite/setupGitForOSBotifyApp with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} @@ -50,7 +50,7 @@ jobs: - name: Get previous app version id: getPreviousVersion - uses: Expensify/App/.github/actions/javascript/getPreviousVersion@main + uses: ./.github/actions/javascript/getPreviousVersion with: SEMVER_LEVEL: "PATCH" @@ -67,7 +67,7 @@ jobs: - name: Get merge commit for pull request to CP id: getCPMergeCommit - uses: Expensify/App/.github/actions/javascript/getPullRequestDetails@main + uses: ./.github/actions/javascript/getPullRequestDetails with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} USER: ${{ github.actor }} diff --git a/.github/workflows/createDeployChecklist.yml b/.github/workflows/createDeployChecklist.yml new file mode 100644 index 000000000000..9a1cac41ed69 --- /dev/null +++ b/.github/workflows/createDeployChecklist.yml @@ -0,0 +1,20 @@ +name: Create or update deploy checklist + +on: + workflow_call: + workflow_dispatch: + +jobs: + createChecklist: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Create or update deploy checklist + uses: ./.github/actions/javascript/createOrUpdateStagingDeploy + with: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/createNewVersion.yml b/.github/workflows/createNewVersion.yml index c9c97d5355fb..5f7f95e102e3 100644 --- a/.github/workflows/createNewVersion.yml +++ b/.github/workflows/createNewVersion.yml @@ -68,7 +68,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} - name: Check out - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main # The OS_BOTIFY_COMMIT_TOKEN is a personal access token tied to osbotify @@ -76,7 +76,7 @@ jobs: token: ${{ secrets.OS_BOTIFY_COMMIT_TOKEN }} - name: Setup git for OSBotify - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} @@ -85,7 +85,7 @@ jobs: - name: Generate version id: bumpVersion - uses: Expensify/App/.github/actions/javascript/bumpVersion@main + uses: ./.github/actions/javascript/bumpVersion with: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} SEMVER_LEVEL: ${{ inputs.SEMVER_LEVEL }} @@ -105,6 +105,6 @@ jobs: - name: Announce failed workflow in Slack if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 78040f237689..63148f9e4eb5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,12 +10,13 @@ jobs: if: github.ref == 'refs/heads/staging' steps: - name: Checkout staging branch - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: ref: staging token: ${{ secrets.OS_BOTIFY_TOKEN }} - - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + - name: Setup git for OSBotify + uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} @@ -32,13 +33,14 @@ jobs: runs-on: ubuntu-latest if: github.ref == 'refs/heads/production' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 name: Checkout with: ref: production token: ${{ secrets.OS_BOTIFY_TOKEN }} - - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + - name: Setup git for OSBotify + uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} @@ -50,7 +52,7 @@ jobs: - name: Get Release Pull Request List id: getReleasePRList - uses: Expensify/App/.github/actions/javascript/getDeployPullRequestList@main + uses: ./.github/actions/javascript/getDeployPullRequestList with: TAG: ${{ env.PRODUCTION_VERSION }} GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} @@ -58,7 +60,7 @@ jobs: - name: Generate Release Body id: getReleaseBody - uses: Expensify/App/.github/actions/javascript/getReleaseBody@main + uses: ./.github/actions/javascript/getReleaseBody with: PR_LIST: ${{ steps.getReleasePRList.outputs.PR_LIST }} diff --git a/.github/workflows/deployBlocker.yml b/.github/workflows/deployBlocker.yml index f42d19ca8241..cb5dc6d28b32 100644 --- a/.github/workflows/deployBlocker.yml +++ b/.github/workflows/deployBlocker.yml @@ -6,35 +6,28 @@ on: - labeled jobs: + updateChecklist: + if: github.event.label.name == 'DeployBlockerCash' + uses: ./.github/workflows/createDeployChecklist.yml + deployBlocker: + if: github.event.label.name == 'DeployBlockerCash' runs-on: ubuntu-latest - if: ${{ github.event.label.name == 'DeployBlockerCash' }} - steps: - name: Checkout - uses: actions/checkout@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} + uses: actions/checkout@v4 - - name: Get URL, title, & number of new deploy blocker (issue) - if: ${{ github.event_name == 'issues' }} + - name: Give the issue/PR the Hourly, Engineering labels + run: gh issue edit ${{ github.event.issue.number }} --add-label 'Engineering,Hourly' --remove-label 'Daily,Weekly,Monthly' env: - TITLE: ${{ github.event.issue.title }} - run: | - { echo "DEPLOY_BLOCKER_URL=${{ github.event.issue.html_url }}"; - echo "DEPLOY_BLOCKER_NUMBER=${{ github.event.issue.number }}"; - echo "DEPLOY_BLOCKER_TITLE=$(sed -e "s/'/'\\\\''/g; s/\`/\\\\\`/g; 1s/^/'/; \$s/\$/'/" <<< "$TITLE")";} >> "$GITHUB_ENV" - - - name: Update StagingDeployCash with new deploy blocker - uses: Expensify/App/.github/actions/javascript/createOrUpdateStagingDeploy@main - with: - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} - - name: Give the issue/PR the Hourly, Engineering labels - uses: andymckay/labeler@978f846c4ca6299fd136f465b42c5e87aca28cac - with: - add-labels: 'Hourly, Engineering' - remove-labels: 'Daily, Weekly, Monthly' + - name: Escape html characters in GH issue title + env: + GH_ISSUE_TITLE: ${{ github.event.issue.title }} + run: | + escaped_title=$(echo "$GH_ISSUE_TITLE" | sed -e 's/&/\&/g; s//\>/g; s/"/\"/g; s/'"'"'/\'/g; s/|/\|/g') + echo "GH_ISSUE_TITLE=$escaped_title" >> "$GITHUB_ENV" - name: 'Post the issue in the #expensify-open-source slack room' if: ${{ success() }} @@ -46,26 +39,29 @@ jobs: channel: '#expensify-open-source', attachments: [{ color: "#DB4545", - text: '💥 We have found a New Expensify Deploy Blocker, if you have any idea which PR could be causing this, please comment in the issue: <${{ env.DEPLOY_BLOCKER_URL }}|'+ `${{ env.DEPLOY_BLOCKER_TITLE }}`.replace(/(^'|'$)/gi, '').replace(/'\''/gi,'\'') + '>', + text: '💥 We have found a New Expensify Deploy Blocker, if you have any idea which PR could be causing this, please comment in the issue: <${{ github.event.issue.html_url }}|${{ env.GH_ISSUE_TITLE }}>' }] } env: GITHUB_TOKEN: ${{ github.token }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - name: Comment on deferred PR - uses: actions-ecosystem/action-create-comment@cd098164398331c50e7dfdd0dfa1b564a1873fac - with: - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} - number: ${{ env.DEPLOY_BLOCKER_NUMBER }} - body: | - :wave: Friendly reminder that deploy blockers are time-sensitive ⏱ issues! [Check out the open `StagingDeployCash` deploy checklist](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3AStagingDeployCash) to see the list of PRs included in this release, then work quickly to do one of the following: - 1. Identify the pull request that introduced this issue and revert it. - 2. Find someone who can quickly fix the issue. - 3. Fix the issue yourself. + - name: Comment on deploy blocker + run: | + gh issue comment ${{ github.event.issue.number }} --body "$(cat <<'EOF' + :wave: Friendly reminder that deploy blockers are time-sensitive ⏱ issues! [Check out the open \`StagingDeployCash\` deploy checklist](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3AStagingDeployCash) to see the list of PRs included in this release, then work quickly to do one of the following: + + 1. Identify the pull request that introduced this issue and revert it. + 2. Find someone who can quickly fix the issue. + 3. Fix the issue yourself. + + EOF + )" + env: + GITHUB_TOKEN: ${{ github.token }} - name: Announce failed workflow in Slack if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/deployExpensifyHelp.yml b/.github/workflows/deployExpensifyHelp.yml index 4a53e75354c6..82cd62c5e832 100644 --- a/.github/workflows/deployExpensifyHelp.yml +++ b/.github/workflows/deployExpensifyHelp.yml @@ -29,10 +29,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 - name: Setup NodeJS - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Create docs routes file run: ./.github/scripts/createDocsRoutes.sh diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 9d94bf900615..92b4e52c159c 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -22,7 +22,7 @@ jobs: outputs: VERSION: ${{ steps.getMostRecentRelease.outputs.VERSION }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Get most recent release version id: getMostRecentRelease @@ -49,7 +49,7 @@ jobs: - name: Checkout latest main commit (TODO temporary until new version is released) run: git switch --detach main - - uses: Expensify/App/.github/actions/composite/setupNode@main + - uses: ./.github/actions/composite/setupNode - uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011 with: @@ -64,7 +64,7 @@ jobs: - name: Build APK run: npm run android-build-e2e shell: bash - + - name: Upload APK uses: actions/upload-artifact@65d862660abb392b8c4a3d1195a2108db131dd05 with: @@ -78,11 +78,11 @@ jobs: outputs: DELTA_REF: ${{ steps.getDeltaRef.outputs.DELTA_REF }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Get pull request details id: getPullRequestDetails - uses: Expensify/App/.github/actions/javascript/getPullRequestDetails@main + uses: ./.github/actions/javascript/getPullRequestDetails with: GITHUB_TOKEN: ${{ github.token }} PULL_REQUEST_NUMBER: ${{ inputs.PR_NUMBER }} @@ -136,13 +136,13 @@ jobs: with: ruby-version: "2.7" bundler-cache: true - + - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef - + - name: Build APK run: npm run android-build-e2edelta shell: bash - + - name: Upload APK uses: actions/upload-artifact@65d862660abb392b8c4a3d1195a2108db131dd05 with: @@ -154,10 +154,10 @@ jobs: needs: [buildBaseline, buildDelta] name: Run E2E tests in AWS device farm steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Make zip directory for everything to send to AWS Device Farm run: mkdir zip @@ -190,7 +190,7 @@ jobs: run: zip -qr App.zip ./zip - name: Configure AWS Credentials - uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main + uses: ./.github/actions/composite/configureAwsCredentials with: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -211,7 +211,9 @@ jobs: test_spec_file: tests/e2e/TestSpec.yml test_spec_type: APPIUM_NODE_TEST_SPEC remote_src: false - file_artifacts: Customer Artifacts.zip + file_artifacts: | + Customer Artifacts.zip + Test spec output.txt log_artifacts: debug.log cleanup: true timeout: 5400 @@ -220,6 +222,7 @@ jobs: if: failure() run: | echo ${{ steps.schedule-awsdf-main.outputs.data }} + cat "./mainResults/Host_Machine_Files/\$WORKING_DIRECTORY/Test spec output.txt" unzip "Customer Artifacts.zip" -d mainResults cat ./mainResults/Host_Machine_Files/\$WORKING_DIRECTORY/debug.log diff --git a/.github/workflows/finishReleaseCycle.yml b/.github/workflows/finishReleaseCycle.yml index f8b68786aaab..2285eec56065 100644 --- a/.github/workflows/finishReleaseCycle.yml +++ b/.github/workflows/finishReleaseCycle.yml @@ -13,12 +13,13 @@ jobs: isValid: ${{ fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) && !fromJSON(steps.checkDeployBlockers.outputs.HAS_DEPLOY_BLOCKERS) }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main token: ${{ secrets.OS_BOTIFY_TOKEN }} - - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + - name: Setup git for OSBotify + uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} @@ -38,7 +39,7 @@ jobs: - name: Reopen and comment on issue (not a team member) if: ${{ !fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) }} - uses: Expensify/App/.github/actions/javascript/reopenIssueWithComment@main + uses: ./.github/actions/javascript/reopenIssueWithComment with: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} @@ -49,14 +50,14 @@ jobs: - name: Check for any deploy blockers if: ${{ fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) }} id: checkDeployBlockers - uses: Expensify/App/.github/actions/javascript/checkDeployBlockers@main + uses: ./.github/actions/javascript/checkDeployBlockers with: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} - name: Reopen and comment on issue (has blockers) if: ${{ fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) && fromJSON(steps.checkDeployBlockers.outputs.HAS_DEPLOY_BLOCKERS || 'false') }} - uses: Expensify/App/.github/actions/javascript/reopenIssueWithComment@main + uses: ./.github/actions/javascript/reopenIssueWithComment with: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} @@ -66,7 +67,7 @@ jobs: - name: Announce failed workflow in Slack if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} @@ -77,14 +78,14 @@ jobs: if: ${{ fromJSON(needs.validate.outputs.isValid) }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: staging token: ${{ secrets.OS_BOTIFY_TOKEN }} - - name: Setup Git for OSBotify + - name: Setup git for OSBotify id: setupGitForOSBotify - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + uses: ./.github/actions/composite/setupGitForOSBotifyApp with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} @@ -100,7 +101,7 @@ jobs: - name: Announce failed workflow in Slack if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} @@ -108,7 +109,7 @@ jobs: createNewPatchVersion: needs: validate if: ${{ fromJSON(needs.validate.outputs.isValid) }} - uses: Expensify/App/.github/workflows/createNewVersion.yml@main + uses: ./.github/workflows/createNewVersion.yml secrets: inherit with: SEMVER_LEVEL: PATCH @@ -119,13 +120,13 @@ jobs: needs: [updateProduction, createNewPatchVersion] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main token: ${{ secrets.OS_BOTIFY_TOKEN }} - - name: Setup Git for OSBotify - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + - name: Setup git for OSBotify + uses: ./.github/actions/composite/setupGitForOSBotifyApp with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} @@ -141,6 +142,6 @@ jobs: - name: Announce failed workflow in Slack if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3072b3354a84..33c850823413 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Lint JavaScript and Typescript with ESLint run: npm run lint diff --git a/.github/workflows/lockDeploys.yml b/.github/workflows/lockDeploys.yml index 6ca025bb2a25..d73f982a47cb 100644 --- a/.github/workflows/lockDeploys.yml +++ b/.github/workflows/lockDeploys.yml @@ -10,13 +10,13 @@ jobs: runs-on: macos-12 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main token: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Wait for staging deploys to finish - uses: Expensify/App/.github/actions/javascript/awaitStagingDeploys@main + uses: ./.github/actions/javascript/awaitStagingDeploys with: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} @@ -30,6 +30,6 @@ jobs: - name: Announce failed workflow if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index d494ea0d008b..8ccc0a7f6056 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -36,24 +36,10 @@ jobs: # Note: we're updating the checklist before running the deploys and assuming that it will succeed on at least one platform deployChecklist: name: Create or update deploy checklist - runs-on: ubuntu-latest + uses: ./.github/workflows/createDeployChecklist.yml if: ${{ github.event_name != 'release' }} needs: validateActor - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main - - - name: Set version - id: getVersion - run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_OUTPUT" - - - name: Create or update staging deploy - uses: Expensify/App/.github/actions/javascript/createOrUpdateStagingDeploy@main - with: - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - NPM_VERSION: ${{ steps.getVersion.outputs.VERSION }} + secrets: inherit android: name: Build and deploy Android @@ -62,14 +48,20 @@ jobs: runs-on: ubuntu-latest-xl steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'oracle' + java-version: '17' + - name: Setup Ruby uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011 with: @@ -146,10 +138,10 @@ jobs: runs-on: macos-12-xl steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Decrypt Developer ID Certificate run: cd desktop && gpg --quiet --batch --yes --decrypt --passphrase="$DEVELOPER_ID_SECRET_PASSPHRASE" --output developer_id.p12 developer_id.p12.gpg @@ -185,13 +177,13 @@ jobs: runs-on: macos-13-xlarge steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Setup Ruby uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011 @@ -297,16 +289,16 @@ jobs: runs-on: ubuntu-latest-xl steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Setup Cloudflare CLI run: pip3 install cloudflare - name: Configure AWS Credentials - uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main + uses: ./.github/actions/composite/configureAwsCredentials with: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -355,8 +347,11 @@ jobs: if: ${{ failure() }} needs: [android, desktop, iOS, web] steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Post Slack message on failure - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} @@ -367,7 +362,7 @@ jobs: needs: [android, desktop, iOS, web] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set version run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" @@ -428,24 +423,24 @@ jobs: needs: [android, desktop, iOS, web] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Set version run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - name: Get Release Pull Request List id: getReleasePRList - uses: Expensify/App/.github/actions/javascript/getDeployPullRequestList@main + uses: ./.github/actions/javascript/getDeployPullRequestList with: TAG: ${{ env.VERSION }} GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - name: Comment on issues - uses: Expensify/App/.github/actions/javascript/markPullRequestsAsDeployed@main + uses: ./.github/actions/javascript/markPullRequestsAsDeployed with: PR_LIST: ${{ steps.getReleasePRList.outputs.PR_LIST }} IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} diff --git a/.github/workflows/preDeploy.yml b/.github/workflows/preDeploy.yml index bae843e74709..8f9512062e9d 100644 --- a/.github/workflows/preDeploy.yml +++ b/.github/workflows/preDeploy.yml @@ -7,13 +7,13 @@ on: jobs: typecheck: - uses: Expensify/App/.github/workflows/typecheck.yml@main + uses: ./.github/workflows/typecheck.yml lint: - uses: Expensify/App/.github/workflows/lint.yml@main + uses: ./.github/workflows/lint.yml test: - uses: Expensify/App/.github/workflows/test.yml@main + uses: ./.github/workflows/test.yml confirmPassingBuild: runs-on: ubuntu-latest @@ -21,9 +21,11 @@ jobs: if: ${{ always() }} steps: + - uses: actions/checkout@v4 + - name: Announce failed workflow in Slack if: ${{ needs.typecheck.result == 'failure' || needs.lint.result == 'failure' || needs.test.result == 'failure' }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} @@ -39,6 +41,8 @@ jobs: SHOULD_DEPLOY: ${{ fromJSON(steps.shouldDeploy.outputs.SHOULD_DEPLOY) }} steps: + - uses: actions/checkout@v4 + - name: Get merged pull request id: getMergedPullRequest uses: actions-ecosystem/action-get-merged-pull-request@59afe90821bb0b555082ce8ff1e36b03f91553d9 @@ -47,7 +51,7 @@ jobs: - name: Check if StagingDeployCash is locked id: isStagingDeployLocked - uses: Expensify/App/.github/actions/javascript/isStagingDeployLocked@main + uses: ./.github/actions/javascript/isStagingDeployLocked with: GITHUB_TOKEN: ${{ github.token }} @@ -71,7 +75,7 @@ jobs: createNewVersion: needs: chooseDeployActions if: ${{ fromJSON(needs.chooseDeployActions.outputs.SHOULD_DEPLOY) }} - uses: Expensify/App/.github/workflows/createNewVersion.yml@main + uses: ./.github/workflows/createNewVersion.yml secrets: inherit updateStaging: @@ -86,13 +90,13 @@ jobs: GITHUB_TOKEN: ${{ github.token }} - name: Checkout main - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main token: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Setup Git for OSBotify - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab + uses: ./.github/actions/composite/setupGitForOSBotifyApp with: GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} @@ -108,14 +112,14 @@ jobs: - name: Announce failed workflow in Slack if: ${{ failure() }} - uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main + uses: ./.github/actions/composite/announceFailedWorkflowInSlack with: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} e2ePerformanceTests: needs: [chooseDeployActions] if: ${{ needs.chooseDeployActions.outputs.SHOULD_DEPLOY }} - uses: Expensify/App/.github/workflows/e2ePerformanceTests.yml@main + uses: ./.github/workflows/e2ePerformanceTests.yml secrets: inherit with: PR_NUMBER: ${{ needs.chooseDeployActions.outputs.MERGED_PR }} diff --git a/.github/workflows/reassurePerformanceTests.yml b/.github/workflows/reassurePerformanceTests.yml index b259ff9052b6..a58745b742ad 100644 --- a/.github/workflows/reassurePerformanceTests.yml +++ b/.github/workflows/reassurePerformanceTests.yml @@ -12,10 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup NodeJS - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Run performance testing script shell: bash @@ -38,7 +38,7 @@ jobs: - name: Validate output.json id: validateReassureOutput - uses: Expensify/App/.github/actions/javascript/validateReassureOutput@main + uses: ./.github/actions/javascript/validateReassureOutput with: DURATION_DEVIATION_PERCENTAGE: 20 COUNT_DEVIATION: 0 diff --git a/.github/workflows/reviewerChecklist.yml b/.github/workflows/reviewerChecklist.yml index e86e08375269..19aeab8a1be7 100644 --- a/.github/workflows/reviewerChecklist.yml +++ b/.github/workflows/reviewerChecklist.yml @@ -9,7 +9,9 @@ jobs: runs-on: ubuntu-latest if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' steps: + - uses: actions/checkout@v4 + - name: reviewerChecklist.js - uses: Expensify/App/.github/actions/javascript/reviewerChecklist@main + uses: ./.github/actions/javascript/reviewerChecklist with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/shellCheck.yml b/.github/workflows/shellCheck.yml index 609541e9a660..366caa8a0d19 100644 --- a/.github/workflows/shellCheck.yml +++ b/.github/workflows/shellCheck.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Lint shell scripts with ShellCheck run: npm run shellcheck diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa47a2f61d4a..6540a0fdd583 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,10 +20,10 @@ jobs: name: test (job ${{ fromJSON(matrix.chunk) }}) steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Get number of CPU cores id: cpu-cores @@ -44,9 +44,9 @@ jobs: runs-on: ubuntu-latest name: Storybook tests steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: Expensify/App/.github/actions/composite/setupNode@main + - uses: ./.github/actions/composite/setupNode - name: Storybook run run: npm run storybook -- --smoke-test --ci @@ -57,10 +57,10 @@ jobs: name: Shell tests steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Test CI git logic run: tests/unit/CIGitLogicTest.sh diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index b79b687e638e..94a51a2d11bd 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -50,7 +50,7 @@ jobs: steps: - name: Checkout if: ${{ github.event_name == 'workflow_dispatch' }} - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 - name: Check if pull request number is correct if: ${{ github.event_name == 'workflow_dispatch' }} @@ -70,9 +70,8 @@ jobs: env: PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} steps: - # This action checks-out the repository, so the workflow can access it. - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha || needs.getBranchRef.outputs.REF }} @@ -83,7 +82,13 @@ jobs: echo "PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER" >> .env.adhoc - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'oracle' + java-version: '17' - name: Setup Ruby uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011 @@ -102,7 +107,7 @@ jobs: LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - name: Configure AWS Credentials - uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main + uses: ./.github/actions/composite/configureAwsCredentials with: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -135,9 +140,8 @@ jobs: PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} runs-on: macos-13-xlarge steps: - # This action checks-out the repository, so the workflow can access it. - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha || needs.getBranchRef.outputs.REF }} @@ -151,7 +155,7 @@ jobs: echo "PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER" >> .env.adhoc - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Setup XCode run: sudo xcode-select -switch /Applications/Xcode_14.2.app @@ -193,7 +197,7 @@ jobs: LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - name: Configure AWS Credentials - uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main + uses: ./.github/actions/composite/configureAwsCredentials with: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -221,7 +225,7 @@ jobs: runs-on: macos-12-xl steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha || needs.getBranchRef.outputs.REF }} @@ -232,7 +236,7 @@ jobs: echo "PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER" >> .env.adhoc - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Decrypt Developer ID Certificate run: cd desktop && gpg --quiet --batch --yes --decrypt --passphrase="$DEVELOPER_ID_SECRET_PASSPHRASE" --output developer_id.p12 developer_id.p12.gpg @@ -240,7 +244,7 @@ jobs: DEVELOPER_ID_SECRET_PASSPHRASE: ${{ secrets.DEVELOPER_ID_SECRET_PASSPHRASE }} - name: Configure AWS Credentials - uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main + uses: ./.github/actions/composite/configureAwsCredentials with: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -264,7 +268,7 @@ jobs: runs-on: ubuntu-latest-xl steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha || needs.getBranchRef.outputs.REF }} @@ -275,10 +279,10 @@ jobs: echo "PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER" >> .env.adhoc - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode - name: Configure AWS Credentials - uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main + uses: ./.github/actions/composite/configureAwsCredentials with: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -302,7 +306,7 @@ jobs: PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }} with: ref: ${{ github.event.pull_request.head.sha || needs.getBranchRef.outputs.REF }} @@ -345,7 +349,7 @@ jobs: - name: Publish links to apps for download if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }} - uses: Expensify/App/.github/actions/javascript/postTestBuildComment@main + uses: ./.github/actions/javascript/postTestBuildComment with: PR_NUMBER: ${{ env.PULL_REQUEST_NUMBER }} GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} diff --git a/.github/workflows/testGithubActionsWorkflows.yml b/.github/workflows/testGithubActionsWorkflows.yml new file mode 100644 index 000000000000..58de3ba2d9f3 --- /dev/null +++ b/.github/workflows/testGithubActionsWorkflows.yml @@ -0,0 +1,35 @@ +name: Test GitHub Actions workflows + +on: + workflow_dispatch: + workflow_call: + pull_request: + types: [opened, reopened, edited, synchronize] + branches-ignore: [staging, production] + paths: ['.github/**'] + +jobs: + testGHWorkflows: + if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' || github.event_name == 'workflow_call' }} + runs-on: ubuntu-latest + env: + CI: true + name: test GitHub Workflows + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Node + uses: Expensify/App/.github/actions/composite/setupNode@main + + - name: Setup Homebrew + uses: Homebrew/actions/setup-homebrew@master + + - name: Install Act + run: brew install act + + - name: Set ACT_BINARY + run: echo "ACT_BINARY=$(which act)" >> "$GITHUB_ENV" + + - name: Run tests + run: npm run workflow-test diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 3e54975433f6..0951b194430b 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -5,18 +5,35 @@ on: pull_request: types: [opened, synchronize] branches-ignore: [staging, production] - paths: ['**.ts', '**.tsx', 'package.json', 'package-lock.json', 'tsconfig.json'] + paths: ['**.js', '**.ts', '**.tsx', 'package.json', 'package-lock.json', 'tsconfig.json'] jobs: typecheck: if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: Expensify/App/.github/actions/composite/setupNode@main + - uses: ./.github/actions/composite/setupNode - name: Type check with TypeScript run: npm run typecheck env: CI: true + + - name: Check for new JavaScript files + run: | + git fetch origin main --no-tags --depth=1 + + # Explanation: + # - comm is used to get the intersection between two bash arrays + # - git diff is used to see the files that were added on this branch + # - gh pr view is used to list files touched by this PR. Git diff may give false positives if the branch isn't up-to-date with main + # - wc counts the words in the result of the intersection + count_new_js=$(comm -1 -2 <(git diff --name-only --diff-filter=A origin/main HEAD -- 'src/libs/*.js' 'src/hooks/*.js' 'src/styles/*.js' 'src/languages/*.js') <(gh pr view ${{ github.event.pull_request.number }} --json files | jq -r '.files | map(.path) | .[]') | wc -l) + if [ "$count_new_js" -gt "0" ]; then + echo "ERROR: Found new JavaScript files in the /src/libs, /src/hooks, /src/styles, or /src/languages directories; use TypeScript instead." + exit 1 + fi + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/updateHelpDotRedirects.yml b/.github/workflows/updateHelpDotRedirects.yml index 531b8a3812fd..af24d5f17db4 100644 --- a/.github/workflows/updateHelpDotRedirects.yml +++ b/.github/workflows/updateHelpDotRedirects.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 - name: Create help dot redirect env: diff --git a/.github/workflows/validateDocsRoutes.yml b/.github/workflows/validateDocsRoutes.yml index 14c08e087565..ceeca1ad39f1 100644 --- a/.github/workflows/validateDocsRoutes.yml +++ b/.github/workflows/validateDocsRoutes.yml @@ -11,9 +11,9 @@ jobs: if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: Expensify/App/.github/actions/composite/setupNode@main + - uses: ./.github/actions/composite/setupNode # Verify that no new hubs were created without adding their metadata to _routes.yml - name: Validate Docs Routes File diff --git a/.github/workflows/validateGithubActions.yml b/.github/workflows/validateGithubActions.yml index 5cfc4670620f..700f0b68100e 100644 --- a/.github/workflows/validateGithubActions.yml +++ b/.github/workflows/validateGithubActions.yml @@ -12,10 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode # Rebuild all the actions on this branch and check for a diff. Fail if there is one, # because that would be a sign that the PR author did not rebuild the Github Actions diff --git a/.github/workflows/verifyPodfile.yml b/.github/workflows/verifyPodfile.yml index d98780e3e829..04cd8d62461b 100644 --- a/.github/workflows/verifyPodfile.yml +++ b/.github/workflows/verifyPodfile.yml @@ -15,8 +15,10 @@ jobs: runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Setup Node - uses: Expensify/App/.github/actions/composite/setupNode@main + uses: ./.github/actions/composite/setupNode + - name: Verify podfile run: ./.github/scripts/verifyPodfile.sh diff --git a/.github/workflows/verifySignedCommits.yml b/.github/workflows/verifySignedCommits.yml index ee1b0c4c78da..9134dcd63a7a 100644 --- a/.github/workflows/verifySignedCommits.yml +++ b/.github/workflows/verifySignedCommits.yml @@ -9,7 +9,9 @@ jobs: verifySignedCommits: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 + - name: Verify signed commits - uses: Expensify/App/.github/actions/javascript/verifySignedCommits@main + uses: ./.github/actions/javascript/verifySignedCommits with: GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml index 43e0e1650381..1ea81129fc15 100644 --- a/.github/workflows/welcome.yml +++ b/.github/workflows/welcome.yml @@ -10,7 +10,7 @@ jobs: if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get merged pull request id: getMergedPullRequest diff --git a/.gitignore b/.gitignore index 335efdc5586a..3ed0ef54523a 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,7 @@ tsconfig.tsbuildinfo # Workflow test logs /workflow_tests/logs/ +/workflow_tests/repo/ # Yalc .yalc diff --git a/.imgbotconfig b/.imgbotconfig index ff5c3345cc4d..45cdf03ec36e 100644 --- a/.imgbotconfig +++ b/.imgbotconfig @@ -1,6 +1,7 @@ { "ignoredFiles": [ - "assets/images/empty-state_background-fade.png" // Caused an issue with colour gradients, https://github.com/Expensify/App/issues/30499 + "assets/images/themeDependent/empty-state_background-fade-dark.png", // Caused an issue with colour gradients, https://github.com/Expensify/App/issues/30499 + "assets/images/themeDependent/empty-state_background-fade-light.png" ], "aggressiveCompression": "false" } diff --git a/.nvmrc b/.nvmrc index d9289897d305..43bff1f8cf98 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.15.1 +20.9.0 \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 80888b18a317..2df776736b69 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,4 +16,4 @@ package-lock.json *.scss *.md # We need to modify the import here specifically, hence we disable prettier to get rid of the sorted imports -src/libs/E2E/reactNativeLaunchingTest.js +src/libs/E2E/reactNativeLaunchingTest.ts diff --git a/.storybook/public/index.css b/.storybook/public/index.css index 8ace4b240684..2d2411c083c1 100644 --- a/.storybook/public/index.css +++ b/.storybook/public/index.css @@ -24,5 +24,5 @@ a.sidebar-item[data-selected="true"], a.sidebar-item[data-selected="true"]:focus } .sidebar-container { - background: #07271f; + background: #072419; } diff --git a/.storybook/theme.js b/.storybook/theme.js index 96631764726f..67898fb00943 100644 --- a/.storybook/theme.js +++ b/.storybook/theme.js @@ -7,17 +7,17 @@ export default create({ fontBase: 'ExpensifyNeue-Regular', fontCode: 'monospace', base: 'dark', - appBg: colors.darkHighlightBackground, - colorPrimary: colors.darkDefaultButton, + appBg: colors.productDark200, + colorPrimary: colors.productDark400, colorSecondary: colors.green, - appContentBg: colors.darkAppBackground, - textColor: colors.darkPrimaryText, - barTextColor: colors.darkPrimaryText, + appContentBg: colors.productDark100, + textColor: colors.productDark900, + barTextColor: colors.productDark900, barSelectedColor: colors.green, - barBg: colors.darkAppBackground, - appBorderColor: colors.darkBorders, - inputBg: colors.darkHighlightBackground, - inputBorder: colors.darkBorders, + barBg: colors.productDark100, + appBorderColor: colors.productDark400, + inputBg: colors.productDark200, + inputBorder: colors.productDark400, appBorderRadius: 8, inputBorderRadius: 8, }); diff --git a/Gemfile.lock b/Gemfile.lock index 079b5a5b742b..93dab195ebdd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,21 +18,21 @@ GEM rubyzip (~> 2.0) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.824.0) - aws-sdk-core (3.181.1) + aws-eventstream (1.3.0) + aws-partitions (1.857.0) + aws-sdk-core (3.188.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.71.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-kms (1.73.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.134.0) - aws-sdk-core (~> 3, >= 3.181.0) + aws-sdk-s3 (1.140.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.0) + aws-sigv4 (1.7.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -81,14 +81,13 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20231109) dotenv (2.8.1) emoji_regex (3.2.3) escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.103.0) + excon (0.104.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -118,7 +117,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.7) - fastlane (2.215.1) + fastlane (2.217.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -166,9 +165,9 @@ GEM fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.49.0) + google-apis-androidpublisher_v3 (0.53.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.1) + google-apis-core (0.11.2) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -181,23 +180,23 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) + google-apis-storage_v1 (0.29.0) + google-apis-core (>= 0.11.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.44.0) + google-cloud-storage (1.45.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.29.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.8.0) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) multi_json (~> 1.11) @@ -229,7 +228,7 @@ GEM os (1.1.4) plist (3.7.0) public_suffix (4.0.7) - rake (13.0.6) + rake (13.1.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) @@ -262,13 +261,10 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (2.4.2) + unicode-display_width (2.5.0) webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.22.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) diff --git a/__mocks__/@ua/react-native-airship.js b/__mocks__/@ua/react-native-airship.js index 1672c064f9be..29be662e96a1 100644 --- a/__mocks__/@ua/react-native-airship.js +++ b/__mocks__/@ua/react-native-airship.js @@ -31,7 +31,7 @@ const Airship = { }, contact: { identify: jest.fn(), - getNamedUserId: jest.fn(), + getNamedUserId: () => Promise.resolve(undefined), reset: jest.fn(), }, }; diff --git a/__mocks__/fs.js b/__mocks__/fs.js new file mode 100644 index 000000000000..cca0aa9520ec --- /dev/null +++ b/__mocks__/fs.js @@ -0,0 +1,3 @@ +const {fs} = require('memfs'); + +module.exports = fs; diff --git a/__mocks__/fs/promises.js b/__mocks__/fs/promises.js new file mode 100644 index 000000000000..1a58f0f013ac --- /dev/null +++ b/__mocks__/fs/promises.js @@ -0,0 +1,3 @@ +const {fs} = require('memfs'); + +module.exports = fs.promises; diff --git a/android/app/build.gradle b/android/app/build.gradle index cd4108fd29d5..afa05a280390 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001039804 - versionName "1.3.98-4" + versionCode 1001041106 + versionName "1.4.11-6" } flavorDimensions "default" diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index aa0e8136957f..a040598e982d 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -11,7 +11,6 @@ @drawable/rn_edit_text_material @style/AppTheme.Popup @style/TextViewSpinnerDropDownItem - @style/DatePickerDialogTheme @style/AlertDialogTheme @@ -28,18 +27,6 @@ @font/expneuebold - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/home-background--mobile.svg b/assets/images/home-background--mobile.svg index 7c4d4d8289b7..d2fa08475c9d 100644 --- a/assets/images/home-background--mobile.svg +++ b/assets/images/home-background--mobile.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/home-fade-gradient--mobile.svg b/assets/images/home-fade-gradient--mobile.svg index 0b24b678a2e6..ad150f3c870c 100644 --- a/assets/images/home-fade-gradient--mobile.svg +++ b/assets/images/home-fade-gradient--mobile.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/home-fade-gradient.svg b/assets/images/home-fade-gradient.svg index bfe04d545364..c446d7b46a42 100644 --- a/assets/images/home-fade-gradient.svg +++ b/assets/images/home-fade-gradient.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/product-illustrations/payment-hands.svg b/assets/images/product-illustrations/payment-hands.svg new file mode 100644 index 000000000000..bf76b528ee76 --- /dev/null +++ b/assets/images/product-illustrations/payment-hands.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/themeDependent/empty-state_background-fade-dark.png b/assets/images/themeDependent/empty-state_background-fade-dark.png new file mode 100644 index 000000000000..59951ef707fb Binary files /dev/null and b/assets/images/themeDependent/empty-state_background-fade-dark.png differ diff --git a/assets/images/themeDependent/empty-state_background-fade-light.png b/assets/images/themeDependent/empty-state_background-fade-light.png new file mode 100644 index 000000000000..200996057b47 Binary files /dev/null and b/assets/images/themeDependent/empty-state_background-fade-light.png differ diff --git a/assets/images/themeDependent/example-check-image-dark-en.png b/assets/images/themeDependent/example-check-image-dark-en.png new file mode 100644 index 000000000000..6b8e84a0faa2 Binary files /dev/null and b/assets/images/themeDependent/example-check-image-dark-en.png differ diff --git a/assets/images/themeDependent/example-check-image-dark-es.png b/assets/images/themeDependent/example-check-image-dark-es.png new file mode 100644 index 000000000000..446678e401b6 Binary files /dev/null and b/assets/images/themeDependent/example-check-image-dark-es.png differ diff --git a/assets/images/themeDependent/example-check-image-light-en.png b/assets/images/themeDependent/example-check-image-light-en.png new file mode 100644 index 000000000000..d7b5f035c625 Binary files /dev/null and b/assets/images/themeDependent/example-check-image-light-en.png differ diff --git a/assets/images/themeDependent/example-check-image-light-es.png b/assets/images/themeDependent/example-check-image-light-es.png new file mode 100644 index 000000000000..2183b522a35b Binary files /dev/null and b/assets/images/themeDependent/example-check-image-light-es.png differ diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 22d035368c42..008b4f45911f 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -66,7 +66,8 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({ template: 'web/index.html', filename: 'index.html', splashLogo: fs.readFileSync(path.resolve(__dirname, `../../assets/images/new-expensify${mapEnvToLogoSuffix(envFile)}.svg`), 'utf-8'), - usePolyfillIO: platform === 'web', + isWeb: platform === 'web', + isProduction: envFile === '.env.production', isStaging: envFile === '.env.staging', }), new FontPreloadPlugin({ @@ -210,7 +211,21 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({ // This is also why we have to use .website.js for our own web-specific files... // Because desktop also relies on "web-specific" module implementations // This also skips packing web only dependencies to desktop and vice versa - extensions: ['.web.js', platform === 'web' ? '.website.js' : '.desktop.js', '.js', '.jsx', '.web.ts', platform === 'web' ? '.website.ts' : '.desktop.ts', '.ts', '.web.tsx', '.tsx'], + extensions: [ + '.web.js', + ...(platform === 'desktop' ? ['.desktop.js'] : []), + '.website.js', + '.js', + '.jsx', + '.web.ts', + ...(platform === 'desktop' ? ['.desktop.ts'] : []), + '.website.ts', + ...(platform === 'desktop' ? ['.desktop.tsx'] : []), + '.website.tsx', + '.ts', + '.web.tsx', + '.tsx', + ], fallback: { 'process/browser': require.resolve('process/browser'), }, diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index d7a94c2a4337..543b133fe62b 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -1,6 +1,6 @@ # Overview -The navigation in the App consists of a top-level Stack Navigator (called `RootStack`) with each of its `Screen` components handling different high-level flow. All those flows can be seen in `AuthScreens.js` file. +The navigation in the App consists of a top-level Stack Navigator (called `RootStack`) with each of its `Screen` components handling different high-level flow. All those flows can be seen in `AuthScreens.tsx` file. ## Terminology @@ -20,11 +20,11 @@ Navigation Actions - User actions correspond to resulting navigation actions tha ## Adding RHP flows -Most of the time, if you want to add some of the flows concerning one of your reports, e.g. `Money Request` from a user, you will most probably use `RightModalNavigator.js` and `ModalStackNavigators.js` file: +Most of the time, if you want to add some of the flows concerning one of your reports, e.g. `Money Request` from a user, you will most probably use `RightModalNavigator.tsx` and `ModalStackNavigators.tsx` file: -- Since each of those flows is kind of a modal stack, if you want to add a page to the existing flow, you should just add a page to the correct stack in `ModalStackNavigators.js`. +- Since each of those flows is kind of a modal stack, if you want to add a page to the existing flow, you should just add a page to the correct stack in `ModalStackNavigators.tsx`. -- If you want to create new flow, add a `Screen` in `RightModalNavigator.js` and make new modal in `ModalStackNavigators.js` with chosen pages. +- If you want to create new flow, add a `Screen` in `RightModalNavigator.tsx` and make new modal in `ModalStackNavigators.tsx` with chosen pages. When creating RHP flows, you have to remember a couple things: @@ -40,13 +40,36 @@ When creating RHP flows, you have to remember a couple things: An example of adding `Settings_Workspaces` page: -1. Add path to `ROUTES.js`: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/ROUTES.js#L36 +1. Add the page name to `SCREENS.ts` which will be reused throughout the app (linkingConfig, navigators, etc.): + +```ts +const SCREENS = { + SETTINGS: { + WORKSPACES: 'Settings_Workspaces', + }, +} as const; +``` + +2. Add path to `ROUTES.ts`: https://github.com/Expensify/App/blob/main/src/ROUTES.ts + +```ts +export const ROUTES = { + // static route + SETTINGS_WORKSPACES: 'settings/workspaces', + // dynamic route + SETTINGS_WORKSPACES: { + route: 'settings/:accountID', + getRoute: (accountID: number) => `settings/${accountID}` as const, + }, +}; + +``` -2. Add `Settings_Workspaces` page to proper RHP flow in `linkingConfig.js`: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/libs/Navigation/linkingConfig.js#L40-L42 +3. Add `Settings_Workspaces` page to proper RHP flow in `linkingConfig.ts`: https://github.com/Expensify/App/blob/fbc11ca729ffa4676fb3bc8cd110ac3890debff6/src/libs/Navigation/linkingConfig.ts#L47-L50 -3. Add your page to proper navigator (it should be aligned with where you've put it in the previous step) https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/libs/Navigation/AppNavigator/ModalStackNavigators.js#L334-L338 +4. Add your page to proper navigator (it should be aligned with where you've put it in the previous step) https://github.com/Expensify/App/blob/fbc11ca729ffa4676fb3bc8cd110ac3890debff6/src/libs/Navigation/AppNavigator/ModalStackNavigators.js#L141 -4. Make sure `HeaderWithBackButton` leads to the previous page in navigation flow of your page: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/pages/workspace/WorkspacesListPage.js#L186 +5. Make sure `HeaderWithBackButton` leads to the previous page in navigation flow of your page: https://github.com/Expensify/App/blob/3531af22dcadaa94ed11eccf370517dca0b8c305/src/pages/workspace/WorkspacesListPage.js#L186 ## Performance solutions @@ -183,4 +206,4 @@ The action for the first step created with `getMinimalAction` looks like this: ``` ### Deeplinking -There is no minimal action for deeplinking directly to the `Profile` screen. But because the `Settings_root` is not on the stack, pressing UP will reset the params for navigators to the correct ones. \ No newline at end of file +There is no minimal action for deeplinking directly to the `Profile` screen. But because the `Settings_root` is not on the stack, pressing UP will reset the params for navigators to the correct ones. diff --git a/contributingGuides/REVIEWER_CHECKLIST.md b/contributingGuides/REVIEWER_CHECKLIST.md index 16c8f88927b1..b7cbd87dc4b9 100644 --- a/contributingGuides/REVIEWER_CHECKLIST.md +++ b/contributingGuides/REVIEWER_CHECKLIST.md @@ -46,7 +46,7 @@ - [ ] The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory - [ ] If a new CSS style is added I verified that: - [ ] A similar style doesn't already exist - - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/StyleUtils.js) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG`) + - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/utils/index.ts) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(theme.componentBG`) - [ ] If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic. - [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) - [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. diff --git a/docs/_data/_routes.yml b/docs/_data/_routes.yml index 84735e95e0e9..e320b690c226 100644 --- a/docs/_data/_routes.yml +++ b/docs/_data/_routes.yml @@ -88,18 +88,18 @@ platforms: image: /assets/images/settings-new-dot.svg hubs: - - href: getting-started - title: Getting Started - icon: /assets/images/accounting.svg - description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. - + - href: chat + title: Chat + icon: /assets/images/chat-bubble.svg + description: Enhance your financial experience using Expensify's chat feature, offering quick and secure communication for personalized support and payment transfers. + - href: account-settings title: Account Settings icon: /assets/images/gears.svg description: Discover how to personalize your profile, add secondary logins, and grant delegated access to employees with our comprehensive guide on Account Settings. - - href: bank-accounts-and-credit-cards - title: Bank Accounts & Credit Cards + - href: bank-accounts + title: Bank Accounts icon: /assets/images/bank-card.svg description: Find out how to connect Expensify to your financial institutions, track credit card transactions, and best practices for reconciling company cards. @@ -108,45 +108,15 @@ platforms: icon: /assets/images/money-wings.svg description: Here is where you can review Expensify's billing and subscription options, plan types, and payment methods. - - href: expense-and-report-features - title: Expense & Report Features - icon: /assets/images/money-receipt.svg - description: From enabling automatic expense auditing to tracking attendees, here is where you can review tips and tutorials to streamline expense management. - - href: expensify-card title: Expensify Card icon: /assets/images/hand-card.svg description: Explore how the Expensify Card combines convenience and security to enhance everyday business transactions. Discover how to apply for, oversee, and maximize your card perks here. - - - href: expensify-partner-program - title: Expensify Partner Program - icon: /assets/images/handshake.svg - description: Discover how to get the most out of Expensify as an ExpensifyApproved! accountant partner. Learn how to set up your clients, receive CPE credits, and take advantage of your partner discount. - href: get-paid-back title: Get Paid Back icon: /assets/images/money-into-wallet.svg description: Whether you submit an expense report or an invoice, find out here how to ensure a smooth and timely payback process every time. - - - href: insights-and-custom-reporting - title: Insights & Custom Reporting - icon: /assets/images/monitor.svg - description: From exporting reports to creating custom templates, here is where you can learn more about Expensify's versatile export options. - - - href: integrations - title: Integrations - icon: /assets/images/workflow.svg - description: Enhance Expensify’s capabilities by integrating it with your accounting or HR software. Here is where you can learn more about creating a synchronized financial management ecosystem. - - - href: manage-employees-and-report-approvals - title: Manage Employees & Report Approvals - icon: /assets/images/envelope-receipt.svg - description: Master the art of overseeing employees and reports by utilizing Expensify’s automation features and approval workflows. - - - href: send-payments - title: Send Payments - icon: /assets/images/money-wings.svg - description: Uncover step-by-step guidance on sending direct reimbursements to employees, paying an invoice to a vendor, and utilizing third-party payment options. - href: workspace-and-domain-settings title: Workspace & Domain Settings diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html index d18ca2199e33..798fb2cf7e96 100644 --- a/docs/_includes/footer.html +++ b/docs/_includes/footer.html @@ -111,6 +111,8 @@

Get Started

+ + diff --git a/docs/_sass/_colors.scss b/docs/_sass/_colors.scss index b34a7d13b7f0..f0c89d31c580 100644 --- a/docs/_sass/_colors.scss +++ b/docs/_sass/_colors.scss @@ -1,14 +1,36 @@ -$color-green400: #03D47C; -$color-green-icons: #8B9C8F; -$color-green-borders: #1A3D32; -$color-button-background: #1A3D32; -$color-button-hovered: #2C6755; -$color-green-highlightBG: #07271F; -$color-green-highlightBG-hover: #06231c; -$color-green-appBG: #061B09; -$color-green-hover: #00a862; -$color-light-gray-green: #AFBBB0; -$color-blue300: #5AB0FF; +// Product Color Spectrum +$color-product-dark-100: #061B09; +$color-product-dark-200: #072419; +$color-product-dark-300: #0A2E25; +$color-product-dark-400: #1A3D32; +$color-product-dark-500: #224F41; +$color-product-dark-600: #2A604F; +$color-product-dark-700: #8B9C8F; +$color-product-dark-800: #AFBBB0; +$color-product-dark-900: #E7ECE9; + +// Colors for Links and Success $color-blue200: #B0D9FF; -$color-white: #E7ECE9; -$color-gray-label: #afbbb0; +$color-blue300: #5AB0FF; +$color-green400: #03D47C; +$color-green500: #00a862; + +// Overlay BG color +$color-overlay-background: rgba(26, 61, 50, 0.72); + +// UI Colors +$color-text: $color-product-dark-900; +$color-text-supporting: $color-product-dark-800; +$color-icons: $color-product-dark-700; +$color-borders: $color-product-dark-400; +$color-highlightBG: $color-product-dark-200; +$color-row-hover: $color-product-dark-300; +$color-appBG: $color-product-dark-100; +$color-success: $color-green400; +$color-accent : $color-green400; +$color-link: $color-blue300; +$color-link-hovered: $color-blue200; +$color-button-background: $color-product-dark-400; +$color-button-background-hover: $color-product-dark-500; +$color-button-success-background: $color-green400; +$color-button-success-background-hover: $color-green500; diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 46434787d6df..eaaa1c63badb 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -3,19 +3,6 @@ @import 'fonts'; @import 'search-bar'; -$color-appBG: $color-green-appBG; -$color-highlightBG: $color-green-highlightBG; -$color-accent : $color-green400; -$color-borders: $color-green-borders; -$color-icons: $color-green-icons; -$color-text: $color-white; -$color-link: $color-blue300; -$color-link-hovered: $color-blue200; -$color-success: $color-green400; -$color-text-supporting: $color-light-gray-green; -$color-green-hover: $color-green-hover; -$color-gray-label: $color-gray-label; - * { margin: 0; padding: 0; @@ -78,6 +65,7 @@ body { height: 100%; min-height: 100%; background: $color-appBG; + color: $color-text-supporting; } hr { @@ -148,7 +136,7 @@ textarea { font-weight: 400; font-family: "ExpensifyNeue", "Helvetica Neue", "Helvetica", Arial, sans-serif; font-size: 16px; - color: $color-text; + color: $color-text-supporting; } button { @@ -159,7 +147,7 @@ button { font-weight: bold; &.success { - background-color: $color-success; + background-color: $color-button-success-background; color: $color-text; width: 100%; border-radius: 100px; @@ -167,7 +155,7 @@ button { padding-right: 20px; &:hover { - background-color: desaturate($color-success, 15%); + background-color: $color-button-success-background-hover; cursor: pointer; } @@ -262,6 +250,7 @@ button { .lhn-header { padding: 24px; + @include breakpoint($breakpoint-tablet) { padding: 44px; } @@ -269,6 +258,7 @@ button { #header-button { display: block; padding-right: 24px; + @include breakpoint($breakpoint-tablet) { display: none; } @@ -282,7 +272,7 @@ button { margin-right: auto; @include breakpoint($breakpoint-desktop) { - width: 210px; + width: 180px; align-content: normal; display: flex; margin-left: 0; @@ -372,7 +362,7 @@ button { // Box shadow is used here because border-radius and border-collapse don't work together. It leads to double borders. // https://stackoverflow.com/questions/628301/the-border-radius-property-and-border-collapsecollapse-dont-mix-how-can-i-use border-style: hidden; - box-shadow: 0 0 0 1px $color-green-borders; + box-shadow: 0 0 0 1px $color-borders; } th:first-child { @@ -394,12 +384,12 @@ button { th, td { padding: 6px 13px; - border: 1px solid $color-green-borders; + border: 1px solid $color-borders; } thead tr th { font-weight: bold; - background-color: $color-green-highlightBG; + background-color: $color-highlightBG; } .img-wrap { @@ -457,11 +447,11 @@ button { .link { display: inline; - color: $color-link; + color: $color-text-supporting; cursor: pointer; &:hover { - color: $color-link-hovered; + color: $color-link; } } @@ -530,7 +520,7 @@ button { background-color: $color-highlightBG; &:hover { - background-color: darken($color-highlightBG, 1%); + background-color: $color-row-hover; } .row { @@ -629,13 +619,14 @@ button { } p.description { + color: $color-text-supporting; padding: 20px 0 20px 0; } p.url { padding: 0; font-size: 0.8em; - color: $color-gray-label; + color: $color-text-supporting; } } @@ -657,6 +648,7 @@ button { p.description { padding: 0; + color: $color-text-supporting; &.with-min-height { min-height: 68px; @@ -738,7 +730,7 @@ button { .get-help { flex-wrap: wrap; - margin-top: auto; + margin-top: 40px; } .floating-concierge-button { @@ -772,9 +764,12 @@ button { h3 { color: $color-success; + font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; font-size: 17px; - font-weight: 700; + font-weight: 500; + padding: 0; margin-bottom: 16px; + margin-top: 0; } ul { @@ -786,13 +781,13 @@ button { margin: 0 0 8px; a { - color: $color-text; + color: $color-text-supporting; display: block; padding: 4px 0; word-break: break-word; &:hover { - color: $color-success; + color: $color-link; } } } @@ -802,11 +797,11 @@ button { padding-bottom: 20px; a { - color: $color-text; + color: $color-text-supporting; display: inline-block; &:hover { - color: $color-success; + color: $color-link; } } } diff --git a/docs/_sass/_search-bar.scss b/docs/_sass/_search-bar.scss index e9c56835af50..f414d25fc266 100644 --- a/docs/_sass/_search-bar.scss +++ b/docs/_sass/_search-bar.scss @@ -2,20 +2,6 @@ @import 'colors'; @import 'fonts'; -$color-appBG: $color-green-appBG; -$color-highlightBG: $color-green-highlightBG; -$color-highlightBG-hover: $color-green-highlightBG-hover; -$color-accent : $color-green400; -$color-borders: $color-green-borders; -$color-icons: $color-green-icons; -$color-text: $color-white; -$color-link: $color-blue300; -$color-link-hovered: $color-blue200; -$color-success: $color-green400; -$color-text-supporting: $color-light-gray-green; -$color-green-hover: $color-green-hover; -$color-gray-label: $color-gray-label; - .search-icon { margin: auto 0px; } @@ -81,7 +67,7 @@ $color-gray-label: $color-gray-label; left: 0; right: 0; bottom: 0; - background-color: rgba(0, 0, 0, 0.4); + background-color: $color-overlay-background; z-index: 1; } @@ -158,7 +144,7 @@ label.search-label { transform: translateY(-50%); left: 20px; pointer-events: none; - color: $color-gray-label; + color: $color-text-supporting; transform-origin: left top; user-select: none; transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1), color 150ms cubic-bezier(0.4, 0, 0.2, 1), top 500ms; @@ -194,14 +180,14 @@ label.search-label { margin-left: 15px; margin-right: 20px; border-radius: 25px; - background-color: $color-green400; + background-color: $color-button-success-background; cursor: pointer; width: 40px; height: 40px; } .gsc-search-button.gsc-search-button-v2:hover { - background-color: $color-green-hover; + background-color: $color-button-success-background-hover; } .gsc-search-button.gsc-search-button-v2 svg { @@ -210,9 +196,7 @@ label.search-label { width: auto; } -/* Change the path of the Google Search Button icon into Expensify icon */ .gsc-search-button.gsc-search-button-v2 svg path { - d: path('M8 1c3.9 0 7 3.1 7 7 0 1.4-.4 2.7-1.1 3.8l5.2 5.2c.6.6.6 1.5 0 2.1-.6.6-1.5.6-2.1 0l-5.2-5.2C10.7 14.6 9.4 15 8 15c-3.9 0-7-3.1-7-7s3.1-7 7-7zm0 3c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4 1.8-4 4-4z'); fill-rule: evenodd; clip-rule: evenodd; } @@ -229,7 +213,7 @@ label.search-label { /* Change Font result Paragraph color */ .gsc-results .gs-webResult:not(.gs-no-results-result):not(.gs-error-result) .gs-snippet, .gs-fileFormatType { - color: $color-text; + color: $color-text-supporting; } @@ -280,7 +264,7 @@ label.search-label { color: $color-text; &:hover { - background-color: $color-button-hovered; + background-color: $color-button-background-hover; text-decoration: none; } } diff --git a/docs/articles/expensify-classic/account-settings/Account-Details.md b/docs/articles/expensify-classic/account-settings/Account-Details.md index 8f80a35f3525..bc4b94bf8a51 100644 --- a/docs/articles/expensify-classic/account-settings/Account-Details.md +++ b/docs/articles/expensify-classic/account-settings/Account-Details.md @@ -59,3 +59,11 @@ Is your Secondary Login (personal email) invalidated in your company account? If 3. You will be presented with a confirmation message saying Expensify sent you an email with a validation link 4. Head to your personal email account and follow the prompts 5. You'll receive a link in the email to click that will unlink the two accounts + +# FAQ +## The profile picture on my account updated automatically. Why did this happen? +Our focus is always on making your experience user-friendly and saving you valuable time. One of the ways we achieve this is by utilizing a public API to retrieve public data linked to your email address. + +This tool searches for public accounts or profiles associated with your email address, such as on LinkedIn. When it identifies one, it pulls in the uploaded profile picture and name to Expensify. + +While this automated process is generally accurate, there may be instances where it's not entirely correct. If this happens, we apologize for any inconvenience caused. The good news is that rectifying such situations is a straightforward process. You can quickly update your information manually by following the directions provided above, ensuring your data is accurate and up to date in no time. diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md index 5e18490fc357..c25c22de9704 100644 --- a/docs/articles/expensify-classic/account-settings/Close-Account.md +++ b/docs/articles/expensify-classic/account-settings/Close-Account.md @@ -1,5 +1,123 @@ --- -title: Close Account +title: Close Account description: Close Account ---- -## Resource Coming Soon! +--- +# Overview + +Here is a walk through of how to close an Expensify account through the website or mobile app. + +# How to close your account +On the Web: + +1. Go to **Settings** in the left hand menu. Click **Account**. +2. Click “Close Account” +3. Follow the prompts to verify your email or phone number. +4. Your account will be closed, and all data will be deleted.* + +![Close Account via Website]({{site.url}}/assets/images/ExpensifyHelp_CloseAccount_Desktop.png){:width="100%"} + +On the Mobile App: + +Open the app and tap the three horizontal lines in the upper left corner. +Select Settings from the menu. +Look for the "Close Account" option in the "Others" section. (If you don’t see this option, you have a Domain Controlled account and will need to ask your Domain Admin to delete your account.) +Complete the verification process using your email or phone number. +Your account will be closed, and all data will be deleted.* + +![Close Account on Mobile Application]({{site.url}}/assets/images/ExpensifyHelp_CloseAccount_Mobile.png){:width="100%"} + +These instructions may vary depending on the specific device you are using, so be sure to follow the steps as they appear on your screen. + +*Note: Transactions shared with other accounts will still be visible to those accounts. (Example: A report submitted to your company and reimbursed will not be deleted from your company’s account.) Additionally, we are required to retain certain records of transactions in compliance with laws in various jurisdictions. + +# How to reopen your account + +If your Expensify account is closed and not associated with a verified domain, you can reopen it with the following steps: + +1. Visit [expensify.com](https://www.expensify.com/). +2. Attempt to sign in using your email address or phone number associated with the closed account. +3. After entering your user name, you will see a prompt to reopen your account. +4. Click on **Reopen Account**. +5. A magic link will be sent to your email address. +6. Access your email and click on the magic link. This link will take you to Expensify and reopen your account. +7. Follow the prompts to create a new password associated with your account. +8. Your account is now reopened. Any previously approved expense data will still be visible in the account. + +Note: Reports submitted and closed on an Individual workspace will not be retained since they have not been approved or shared with anyone else in Expensify. + +That's it! Your account is successfully reopened, and you can access your historical data that was shared with other accounts. Remember to recreate any workspaces and adjust settings if needed. + +# How to Reopen a Domain-controlled account +Once an account has been **Closed** by a Domain Admin, it can be reopened by any Domain Admin on that domain. + +The Domain Admin will simply need to invite the previously closed account in the same manner that new accounts are invited to the Domain. The user will receive a magic link to their email account which they can use to Reopen the account. + +# How to retain a free account to keep historical expenses +If you no longer need a group workspace or have a more advanced workspace than necessary in Expensify, and you want to downgrade while retaining your historical data, here's what you should do: + +1. If you're part of a group workspace, request the Workspace Admin to remove you, or if you own the workspace, delete it to downgrade to a free version. +2. Once you've removed or been removed from a workspace, start using your free Expensify account. Your submitted expenses will still be saved, allowing you to access the historical data. +3. Domain Admins in the company will still retain access to approved and reimbursed expenses. +4. To keep your data, avoid closing your account. Account closures are irreversible and will result in the deletion of all your unapproved data. + +# Deep Dive + +## I’m unable to close my account + +If you're encountering an error message while trying to close your Expensify account, it's important to pinpoint the specific error. Encountering an error when trying to close your account is typically only experienced if the account has been an admin on a company’s Expensify workspace. (Especially if the account was involved in responsibilities like reimbursing employees or exporting expense reports.) + +In order to avoid users accidentally creating issues for their company, Expensify prevents account closure if you still have any individual responsibilities related to a Workspace within the platform. To successfully close your account, you need to ensure that your workspace no longer relies on your account to operate. + +Here are the reasons why you might encounter an error when trying to close your Expensify account, along with the actions required to address each of these issues: + +- **Account Under a Validated Domain**: If your account is associated with a validated domain, only a Domain Admin can close it. You can find this option in your Domain Admin's settings under Settings > Domains > Domain Members. Afterward, if you have a secondary personal login, you can delete it by following the instructions mentioned above. +- **Sole Domain Admin for Your Company**: If you are the only Domain Admin for your company's domain, you must appoint another Domain Admin before you can close your account. This is to avoid accidentally prohibiting your entire company from using Expensify. You can do this by going to Settings > Domains > [Domain Name] > Domain Admins and making the necessary changes, or you can reset the entire domain. +- **Workspace Billing Owner with an Annual Subscription**: If you are the Workspace Billing Owner with an Annual Subscription, you need to downgrade from the Annual subscription before closing the account. Alternatively, you can have another user take over billing for your workspaces. +- **Ownership of a Company Workspace or Outstanding Balance**: If you own a company workspace or there is an outstanding balance owed to Expensify, you must take one of the following actions before closing your account: + + - Make the payment for the outstanding balance. + - Have another user take over billing for the workspace. + - Request a refund for your initial bill. + - Delete the workspace. + +- **Preferred Exporter for Your Workspace Integration**: If you are the "Preferred Exporter" for a workspace Integration, you must update the Preferred Exporter before closing your account. You can do this by navigating to **Settings** > **Workspaces** > **Group** > [Workspace name] > **Connections** > **Configure** and selecting any Workspace Admin from the dropdown menu as the Preferred Exporter. +- **Verified Business Account with Outstanding Balance or Locked Status**: If you have a Verified Business Account with an outstanding balance or if the account is locked, you should wait for all payments to settle or unlock the account. To settle the amount owed, go to **Settings** > **Account** > **Payments** > **Bank Accounts** and take the necessary steps. + +## Validate the account to close it + +Sometimes, you may find yourself with an Expensify account that you don't need. This could be due to various reasons like a company inviting you for reimbursement, a vendor inviting you to pay, or a mistaken sign-up. + +In such cases, you have two options: + +**Option 1**: Retain the Account for Future Use +You can keep the Expensify account just in case you need it later. + +**Option 2**: Close the Account + +Start by verifying your email or phone number + +Before closing the account, you need to verify that you have access to the email or phone number associated with it. This ensures that only you can close the account. + +Here's how to do it: + +1. Go to [www.expensify.com](http://www.expensify.com/). +2. Enter your email address or phone number (whichever is associated with the unwanted account). +3. Click the **Resend Link** button. +4. Check your Home Page for the most recent email with the subject line "Please validate your Expensify login." Click the link provided in the email to validate your email address. + - If it's an account linked to a phone number, tap the link sent to your phone. +5. After clicking the validation link, you'll be directed to an Expensify Home Page. +6. Navigate to **Settings** > **Account** > **Account Details** > **Close Account**. +7. Click the **Close My Account** button. + - Re-enter the email address or phone number of the account when prompted. + - Check the box that says, "I understand all of my unsubmitted expense data will be deleted." + - Click the **Close My Account** button. + +By following these steps, you can easily verify your email or phone number and close an unwanted Expensify account. + +# FAQ + +## What should I do if I'm not directed to my account when clicking the validate option from my phone or email? +It's possible your browser has blocked this, either because of some existing cache or extension. In this case, you should follow the Reset Password flow to reset the password and manually gain access with the new password, along with your email address. + +## Why don't I see the Close Account option? +It's possible your account is on a managed company domain. In this case, only the admins from that company can close it. diff --git a/docs/articles/expensify-classic/account-settings/Merge-Accounts.md b/docs/articles/expensify-classic/account-settings/Merge-Accounts.md index 7fc355b30bd9..abb218c74118 100644 --- a/docs/articles/expensify-classic/account-settings/Merge-Accounts.md +++ b/docs/articles/expensify-classic/account-settings/Merge-Accounts.md @@ -5,29 +5,32 @@ description: How to merge two Expensify accounts and why this is useful. # Overview -Merging accounts allows you to combine two accounts. When you combine two accounts, all receipts, expenses, expense reports, invoices, bills, imported cards, secondary logins, co-pilots, and group policy settings will be combined into one account. +Merging accounts allows you to combine two accounts. When you combine two accounts, all receipts, expenses, expense reports, invoices, bills, imported cards, secondary logins, co-pilots, and group workspace settings will be combined into one account. This can be useful if you start off with an account of your own but your organization creates a separate account for you. You can then track both personal and business expenses via one account. # How to merge accounts Merging two accounts together is fairly straightforward. Let’s go over how to do that below: 1. Navigate to [expensify.com](https://www.expensify.com) 2. Log into the account you want to set as the Primary account -3. Navigate to Settings > Account > Account Details -4. Scroll down to the Merge Accounts section and fill in the fields. Once you click Merge, a magic code link will be sent to you via email and you'll be prompted to enter the magic code -5. Copy the magic code, switch back to the expensify.com page, and paste the code into the required field +3. Navigate to **Settings > Account > Account Details** +4. Scroll down to Merge Accounts and fill in the fields 6. Click Merge Accounts +7. Once you click Merge, a magic code is sent to you via email +8. Paste the code into the required field If you have any questions about this process, feel free to reach out to Concierge for some assistance! # FAQ ## Can you merge accounts from the mobile app? No, accounts can only be merged from the full website at expensify.com. ## Can I administratively merge two accounts together? -No, only the account holder (user) can perform account merging. +No, only the account holder (member) can perform account merging. ## Is merging accounts reversible? No, merging accounts is not reversible. It is a permanent action that cannot be undone. +## I have open expenses in the account I'm merging from. Will those expenses merge into the new account? +All expenses must be reported and submitted for them to merge into the new account. Any open expenses will not merge. ## Are there any restrictions on account merging? Yes! Please see below: -* If your email address belongs to a verified domain (verified in Expensify), you must start the process from the email account under the verified domain. You cannot merge a verified company email account into a personal account. -* If you have two accounts with two different verified domains, you cannot merge them together. -## What happens to my “personal” Individual policy when merging accounts? -The old “personal” Individual policy will be deleted. If you plan to submit reports under a different policy in the future, ensure that any reports on the Individual policy in the old account are marked as Open before merging the accounts. You can typically do this by selecting “Undo Submit” on any submitted reports. +- If your email address belongs to a verified domain (verified in Expensify), you must start the process from the email account under the verified domain. You cannot merge a verified company email account into a personal account. +- If you have two accounts with two different verified domains, you cannot merge them together. +## What happens to my “personal” Individual workspace when merging accounts? +The old “personal” Individual workspace is deleted. If you plan to submit reports under a different workspace in the future, ensure that any reports on the Individual workspace in the old account are marked as Open before merging the accounts. You can typically do this by selecting “Undo Submit” on any submitted reports. diff --git a/docs/articles/expensify-classic/account-settings/Notification-Troubleshooting.md b/docs/articles/expensify-classic/account-settings/Notification-Troubleshooting.md new file mode 100644 index 000000000000..22df0dc7f6ca --- /dev/null +++ b/docs/articles/expensify-classic/account-settings/Notification-Troubleshooting.md @@ -0,0 +1,75 @@ +--- +title: Notification Troubleshooting +description: This article is about how to troubleshoot notifications from Expensify. +--- + +# Overview +Sometimes, members may have trouble receiving important email notifications from Expensify, such as Expensify Magic Code emails, account validation emails, secondary login validations, integration emails, or report action notifications (rejections, approvals, etc.). + +# Here's how to troubleshoot missing Expensify notifications: + +1. **No error message, but the email is never received** +The email might be delayed; give it 30-60 minutes to arrive in your inbox. +Check **Email Preferences** on the web via **Settings > Your Account > Preferences**In the **Contact Preferences** section. Ensure that the relevant boxes are checked for the email type you're missing. Check your email spam and trash folders, as Expensify messages might end up there inadvertently. +Check to make sure you haven't unintentionally blocked Expensify emails and whitelist [expensify.com](https://community.expensify.com/home/leaving?allowTrusted=1&target=http%3A%2F%2Fexpensify.com%2F), mg.expensify.com, and [amazonSES.com](https://community.expensify.com/home/leaving?allowTrusted=1&target=http%3A%2F%2Famazonses.com%2F) with your email provider. + +2. **A "We're having trouble emailing you" banner at the top of your screen** +Verify that your email address in your account settings is correct and is a real deliverable email address. +Re-send Verification Email: Look for an option to re-send a verification email, usually provided when this banner appears. + +![ExpensifyHelp_EmailError]({{site.url}}/assets/images/ExpensifyHelp_EmailError.png){:width="100%"} + +# Deep Dive + +**For Private Domains**: + +If your organization uses a private domain, consult your IT department or IT person to ensure that the following domains are whitelisted to receive our emails: expensify.com, mg.expensify.com, and amazonSES.com. These domains are the sources of various notification emails, so make sure they aren't being blocked. + +**For Public Domains (e.g., Gmail, Yahoo, Hotmail)**: + +To whitelist our emails on public email services: + +1. Check your Spam Folder: Search for messages from expensify.com in your Spam folder, open them, and click "Not Spam" at the top of the message. +2. Create a Filter: Set up a filter that identifies the entire expensify.com domain and directs all incoming messages to your inbox, preventing them from going to Spam. +3. Add Specific Contacts: While optional, adding specific email addresses from Expensify as contacts can further prevent emails from going to Spam. + +Please note that even if you receive emails from our Concierge support communication, ensure that both expensify.com and mg.expensify.com are whitelisted as they use different servers. + +**Email Server Blocking**: +Your email server may be blocking our emails due to spam filters or other services. Check with your IT department to investigate and resolve any server-level email blocking issues. + +**Mimecast**: +If your company uses Mimecast, a service that can affect email deliverability, check with your IT department. If Mimecast is in use, reach out to us at concierge@expensify.com through a new email, as this should ensure delivery to your inbox. Mimecast should eventually recognize the Expensify domain, preventing future filtering. + +**For Outlook Users**: +For Outlook users specifically: + +1. Click the gear icon in Outlook and select "View all Outlook settings." +2. Choose "Mail" from the settings menu. +3. Under the "Junk email" submenu, click "Add" under "Safe senders and domains." +4. Enter the email address you want to whitelist. +5. Click "Save." + +When you click the "Settings" link in the banner in Expensify, you'll be directed to your account settings page, where you may encounter a few different scenarios: + +- "Temporarily Suspended Emails": If the message mentions "temporarily suspended emails to," follow the steps provided in the yellow box. This situation typically occurs when we can't find a valid inbox to send our emails to. Possible reasons include: + - A misspelled email address during account creation. + - Use of a distribution list email (acting as an "alias" email) without a linked inbox. + - An auto-responder that has been responding to our emails for an extended period. +- To resolve this issue, confirm that the email address is indeed associated with an active inbox. Then, click the link that says "here," and your email should be unblocked shortly. +- SMTP Error (Gray Box): In some cases, you might encounter a gray box with an SMTP error message. This error can vary, but it typically looks something like this: + +![ExpensifyHelp_SMTPError]({{site.url}}/assets/images/ExpensifyHelp_SMTPError.png){:width="100%"} + +**These look a bit cryptic, yes, but hang in there!** + +The error messages you see are the raw message text received from your email provider's server to Amazon. These messages can vary in text, but the best course of action is to follow the link provided (by copying and pasting) in the text for the next steps. + +**Scenario 1**: If the message in the gray box includes "mimecast.com": It means that our emails are being blocked by the server. In this case, you should contact your IT person or team to address the issue. + +**Scenario 2**: If the message in the gray box mentions "blacklist at org/.com/.net," or resembles the screenshot provided, it indicates that your IT team has configured your email to use a third-party email reputation or blacklisting service. Here's what you need to know: +- All our emails are SPF and DKIM-signed, meaning they are cryptographically signed as coming from us and are not spam. +- The problem arises because we send mail from a cloud-based service. This means that the sender's IP serves multiple vendors, including Expensify. If one of those vendors is marked as spam, it can block all messages from that IP, even if they're from different vendors (including us). +- The better approach is for the server to flag spam via DKIM and SPF (rather than solely relying on the sender's IP address), as our messages are correctly signed and encrypted to prevent spoofing. + +To resolve these issues, consider discussing them with your IT team, as they can help implement the necessary changes to ensure you receive our emails without interruption. diff --git a/docs/articles/expensify-classic/account-settings/Preferences.md b/docs/articles/expensify-classic/account-settings/Preferences.md index 532da4d8a986..8131cd0e80c5 100644 --- a/docs/articles/expensify-classic/account-settings/Preferences.md +++ b/docs/articles/expensify-classic/account-settings/Preferences.md @@ -1,5 +1,28 @@ --- -title: Preferences -description: Preferences +title: Account Preferences +description: Expensify Account Preferences --- -## Resource Coming Soon! + +# Overview +Customize your Expensify experience by updating your account details and preferences. Here you can update your profile picture, adjust contact preferences, and perform other actions to personalize your account. + +# How to manage contact preferences +To edit your notification preferences or unsubscribe from Expensify updates: +- On the web, navigate to **Settings > Account > Preferences** +Scroll down to find the ‘Contact Preferences’ section. To stop receiving a specific type of email, uncheck the corresponding box. + +# How to set your time zone +Wherever you are, we'll time-stamp your report actions according to your local time. This helps you keep track of when submissions or approvals occurred. Setting your time zone in Expensify is simple and ensures accurate time-stamping for your report actions, especially in the comments section of the expense report you're reviewing. + +To set your time zone: +Navigate to **Settings > Account > Preferences > Scroll down to Time Zone** + +![ExpensifyHelp_Timezone]({{site.url}}/assets/images/ExpensifyHelp_Timezone.png){:width="100%"} + + **Note:** To set your time zone automatically based on your location, tick the box that says **Set my time zone automatically**. + +If you prefer to set your time zone manually, leave the box unticked and select your time zone from the searchable list of locations. + +When you add a comment to a report, all the report actions will be time-stamped in your local time. Adjusting your time zone to the appropriate location makes tracking and understanding submission and approval times much easier. + +![ExpensifyHelp_Time]({{site.url}}/assets/images/ExpensifyHelp_Time.png){:width="100%"} diff --git a/docs/articles/expensify-classic/account-settings/Profile-Settings.md b/docs/articles/expensify-classic/account-settings/Profile-Settings.md deleted file mode 100644 index 3b2a0b830926..000000000000 --- a/docs/articles/expensify-classic/account-settings/Profile-Settings.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Profile Settings -description: Profile Settings ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Cards.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Cards.md deleted file mode 100644 index 71edcdeba00d..000000000000 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Cards.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Personal Cards -description: Connect your credit card directly to Expensify to easily track your personal finances. ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md new file mode 100644 index 000000000000..fa5879d85ea8 --- /dev/null +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md @@ -0,0 +1,91 @@ +--- +title: Company-Card-Settings.md +description: Once you connect your cards, customize the configuration using company card settings. +--- +# Overview +Once you’ve imported your company cards via commercial card feed, direct bank feed, or CSV import, the next step is to configure the cards’ settings. + +As a Domain Admin, you can access the company card settings by navigating to Settings > Domains> Domain Name > Company Card > Settings. + +If you cannot access Domains, you will need to request Domain Admin access my the Domain Admin. + +# How to configure company card settings +You can manage company cards and set and adjust the settings from the Domains page by navigating to Settings > Domains > [Domain name] > Settings + +## Reimbursable preference + +You can control how your employees' company card expenses are flagged for reimbursement: + +Force Yes: All expenses will be marked as reimbursable, and employees cannot change this setting. +Force No: All expenses will be marked as non-reimbursable, and employees cannot change this setting. +Do Not Force: Expenses will default to either reimbursable or non-reimbursable (your choice), but employees can adjust if necessary. + +## Liability type + +Choose the liability type that suits your needs: + +Corporate Liability: Users cannot delete company card expenses. +Personal Liability: Users are allowed to delete company card expenses. + +If you update the settings on an existing company card feed, the changes will apply to expenses imported after the date the setting is saved. The update will not affect previously imported expenses. + +## Preferred policy + +Setting a preferred policy for a company card feed will ensure that the imported transactions are added to a report on the policy you set. This setting is useful when members are on multiple policies and need to ensure their company card expenses are reported to a particular policy. + +# How to use Scheduled Submit with company cards +All expenses must be placed on a report if they need to be approved; with Scheduled Submit, you no longer need to worry about the arduous task of employees creating their expenses, adding them to a report, and submitting them manually. All they need to do is SmartScan their receipts and Concierge will take care of the rest, on a variety of schedules that you can set according to your preferences! + +Concierge won't automatically submit expenses on reports that have Expense Violations. Instead, these expenses will be moved to a new report, creating an additional report for the current reporting period. + +An employee can add comments in the Expense Comment field or at the bottom of the report to clarify any details. + +## Enable Scheduled Submit +Scheduled Submit is enabled in the Group Policy by navigating to Settings > Policies > Group > Policy Name > Reports > Scheduled Submit +Use the toggle to enable Scheduled Submit +Choose your desired frequency + +If Scheduled Submit is disabled on the group policy level (or set to a manual frequency), and you have noticed expense reports are still automatically submitted to the group policy, it's likely Scheduled Submit is enabled on the user’s Individual Policy settings. + +# How to connect company cards to an accounting integration + +If you're using a connected accounting system such as NetSuite, Xero, Intacct, Quickbooks Desktop, or QuickBooks Online, you can also connect the card to export to a specific credit card GL account. First, connect the card itself, and once completed, follow the steps below: +Go to Settings > Domains > Domain name > Company Cards +Click Edit Exports on the right-hand side of the card table and select the GL account you want to export expenses to +You're all done. After the account is set, exported expenses will be mapped to the specific account selected when exported by a Domain Admin. + +# How to export company card expenses to a connected accounting integration + +## Pooled GL account + +To export credit card expenses to a pooled GL account: +Go to Settings > Policies > Group > Policy Name > Connections > Accounting Integrations > Configure +Select Credit Card / Charge Card / Bank Transaction as your Non-reimbursable export option. +Please review the Export Settings page for exporting Expense Reports to NetSuite +Select the Vendor/liability account you want to export all non-reimbursable expenses to. + +## Individual GL account + +Go to Settings > Domain > Domain name > Company Cards +Click the Export Settings cog to the right-hand side of the card and select the GL account you want to export expenses to. +You're all done! After the account is set, exported expenses will be mapped to the specific account selected. + +# Deep Dive +## Identifying company card transactions +When you link your credit cards to Expensify, the transactions will appear in each user's account on the Expenses page as soon as they're posted. You can identify transactions from centrally managed cards by seeing the locked card icon next to them. That icon indicates that they’re company card expenses: +[add image here] + +## Importing historical transactions + +After a card is connected via direct connection or via Approved! banks, Expensify will import 30-90 days' worth of historical transactions to your account (the timeframe is based on your bank's discretion). Any historical expenses beyond that date range can be imported using the CSV spreadsheet import method. + +## Using eReceipts +Expensify eReceipts serve as digital substitutes for paper receipts in your purchase transactions, eliminating the necessity to retain physical receipts or utilize SmartScanning receipts. In the case of Expensify Card transactions, eReceipts are automatically generated for all amounts. For other card programs, eReceipts are specifically generated for purchases amounting to $75 or less, provided the transactions are in USD. +To ensure seamless automatic importation, it's essential to maintain your transactions in US Dollars. Additionally, eReceipts can be directly imported from your bank account. Please be aware that CSV/OFX imported files of bank transactions do not support eReceipts. +It's important to note that eReceipts are not generated for lodging expenses. Moreover, due to incomplete or inaccurate category information from certain banks, there may be instances of invalid eReceipts being generated for hotel purchases. If you choose to re-categorize expenses, a similar situation may arise. It's crucial to remember that our Expensify eReceipt Guarantee excludes coverage for hotel and motel expenses. + +# FAQ +## What plan/subscription is required in order to manage corporate cards? +Group Policy (Collect or Control plan only) +## When do my company card transactions import to Expensify? +Credit card transactions are imported to Expensify once they’re posted to the bank account. This usually takes 1-3 business days between the point of purchase and when the transactions populate in your account. diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md deleted file mode 100644 index 112c3b9617c9..000000000000 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Connect Company Cards -description: Connect Company Cards ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md index 8b6ea7de2642..372edd8f14ec 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md @@ -64,7 +64,13 @@ If you're using a connected accounting system such as NetSuite, Xero, Sage Intac ![Expensify domain cards settings](https://help.expensify.com/assets/images/ExpensifyHelp_UnassignCard-1.png){:width="100%"} -You can access the remaining company card settings by navigating to **Settings > Domains > _Domain Name_ > Company Cards > Settings.** More information on card settings can be found by searching **“How to configure company card settings”**. +You can access the remaining company card settings by navigating to **Settings > Domains > _Domain Name_ > Company Cards > Settings.** + +## Connecting multiple card programs to the same domain + +If you need to connect a separate card program from the same bank (that's accessed via a different set of login credentials), when you try to import it by clicking **Import Card/Bank**, the connection to your previous card is disconnected. + +To fix this, you would need to contact your bank and request to combine all of your cards under a single set of login credentials. That way, you can connect all of your cards from that bank to Expensify using a single set of login credentials. # FAQ ## How can I connect and manage my company’s cards centrally if I’m not a domain admin? diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md b/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md index e08aaa3d6094..4f660588d432 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md @@ -1,5 +1,44 @@ --- title: Free Trial -description: Free Trial +description: Learn more about your free trial with Expensify. --- -## Resource Coming Soon! + +# Overview +New customers can take advantage of a seven-day Free Trial on a group Workspace. This trial period allows you to fully explore Expensify's features and capabilities before deciding on a subscription. +During the trial, your organization will have complete access to all the features and functionality offered by the Collect or Control workspace plan. This post provides a step-by-step guide on how to begin, oversee, and successfully conclude your organization's Expensify Free Trial. + +# How to start a Free Trial +1. Sign up for a new Expensify account at expensify.com. +2. After you've signed up for a new Expensify account, you will see a task on your Home page asking if you are using Expensify for your business or as an individual. + a. **Note**: If you select “Individual”, Expensify is free for individuals for up to 25 SmartScans per month. Selecting Individual will **not** start a Free Trial. More details on individual subscriptions can be found [here](https://help.expensify.com/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription). +3. Select the Business option. +4. Select which Expensify features you'd like to set up for your organization. +5. Congratulations, your seven-day Free Trial has started! + +Once you've made these selections, we'll automatically enroll you in a Free Trial and create a Group Workspace, which will trigger new tasks on your Home page to walk you through how to configure Expensify for your organization. If you have any questions about a specific task or need assistance setting up your company, you can speak with your designated Setup Specialist by clicking “Support” on the left-hand navigation menu and selecting their name. This will allow you to message your Setup Specialist, and request a call if you need. + +# How to unlock additional Free Trial weeks +When you begin a Free Trial, you'll have an initial seven-day period before you need to provide your billing information to continue using Expensify. Luckily, Expensify offers the option to extend your Free Trial by an additional five weeks! + +To access these extra free weeks, all you need to do is complete the tasks on your Home page marked with the "Free Week!" banner. Each task completed in this category will automatically add seven more days to your trial. You can easily keep track of the remaining days of your Free Trial by checking the top right-hand corner of your Expensify Home page. + +# How to make the most of your Free Trial +- Complete all of the "Free Week!" tasks right away. These tasks are crucial for establishing your organization's Workspace, and finishing them will give you a clear idea of how much time you have left in your Free Trial. + +- Every Free Trial has dedicated access to a Setup Specialist who can help you set up your account to your preferences. We highly recommend booking a call with your dedicated Setup Specialist as soon as you start your Free Trial. If you ever need assistance with a setup task, your tasks also include demo videos. + +- Invite a few employees to join Expensify as early as possible during the Free Trial. Bringing employees on board and having them submit expenses will allow you to fully experience how all of the features and functionalities of Expensify work together to save time. We provide excellent resources to help employees get started with Expensify. + +- Establish a connection between Expensify and your accounting system from the outset. By doing this early, you can start testing Expensify comprehensively from end to end. + +# FAQ +## What happens when my Free Trial ends? +If you’ve already added a billing card to Expensify, you will automatically start your organization’s Expensify subscription after your Free Trial ends. At the beginning of the following month, we'll bill the card you have on file for your subscription, adjusting the charge to exclude the Free Trial period. +If your Free Trial concludes without a billing card on file, you will see a notification on your Home page saying, 'Your Free Trial has expired.' +If you still have outstanding 'Free Week!' tasks, completing them will extend your Free Trial by additional days. +If you continue without adding a billing card, you will be granted a five-day grace period after the following billing cycle before all Group Workspace functionality is disabled. To continue using Expensify's Group Workspace features, you will need to input your billing card information and initiate a subscription. + +## How can I downgrade my account after my Free Trial ends? +If you’d like to downgrade to an individual account after your Free Trial has ended, you will need to delete any Group Workspace that you have created. This action will remove the Workspaces, subscription, and any amount owed. You can do this in one of two ways from the Expensify web app: +- Select the “Downgrade” option on the billing card task on your Home page. +- Go to **Settings > Workspaces > [Workspace name]**, then click the gear button next to the Workspace and select Delete. diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md b/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md deleted file mode 100644 index 41a1fb96f56f..000000000000 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Payment Card -description: Payment Card ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md index 42a8a914e5bc..5431355dd790 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md +++ b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md @@ -66,7 +66,7 @@ A Workspace admin can see Processing, Approved, and Reimbursed expenses as long If employees submit expense reports on a workspace where you are not an admin, you will not have visibility into those expenses. Additionally, if an expense is left unreported, a workspace admin will not be able to see that expense until it’s been added to a report. A Workspace admin can edit the tags and categories on an expense, but if they want to edit the amount, date, or merchant name, the expense will need to be in a Processing state or rejected back to the submitter for changes. -We have more about company card expense reconciliation in this support article. +We have more about company card expense reconciliation in this [support article](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation). ## Can I edit multiple expenses at once? Yes! Select the expenses you want to edit and click **Edit Multiple**. diff --git a/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md b/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md index 5f5ecca13b2f..bc8a8d8bf184 100644 --- a/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md +++ b/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md @@ -69,9 +69,13 @@ Once Auto-Reconciliation is enabled, there are a few things that happen. Let’s ### Example - We have card transactions for the day totaling $100, so we create the following journal entry upon sync: +![QBO Journal Entry](https://help.expensify.com/assets/images/Auto-Reconciliation QBO 1.png){:width="100%"} - The current balance of the Expensify Clearing Account is now $100: +![QBO Clearing Account](https://help.expensify.com/assets/images/Auto-reconciliation QBO 2.png){:width="100%"} - After transactions are posted in Expensify and the report is approved and exported, a second journal entry is generated: +![QBO Second Journal Entry](https://help.expensify.com/assets/images/Auto-reconciliation QBO 3.png){:width="100%"} - We reconcile the matching amounts automatically, clearing the balance of the Expensify Clearing Account: +![QBO Clearing Account 2](https://help.expensify.com/assets/images/Auto-reconciliation QBO 4.png){:width="100%"} - Now, you'll have a debit on your credit card account (increasing the total spent) and a credit on the bank account (reducing the available amount). The Clearing Account balance is $0. - Each expense will also create a credit card expense, similar to how we do it today, exported upon final approval. This action debits the expense account (category) and includes any other line item data. - This process occurs daily during the QuickBooks Online Auto-Sync to ensure your card remains reconciled. @@ -89,6 +93,7 @@ Once Auto-Reconciliation is enabled, there are a few things that happen. Let’s ### How This Works 1. During the first overnight Auto Sync after enabling Continuous Reconciliation, Expensify will create a Liability Account (Bank Account) on your Xero Dashboard. If you've opted for Daily Settlement, an additional Clearing Account will be created in your General Ledger. Two Contacts —Expensify and Expensify Card— will also be generated: +![Xero Contacts](https://help.expensify.com/assets/images/Auto-reconciliation Xero 1.png){:width="100%"} 2. The bank account for Expensify Card transactions is tied to the Liability Account Expensify created. Note that this doesn't apply to other cards or non-reimbursable expenses, which follow your workspace settings. ### Daily Settlement Reconciliation @@ -129,7 +134,9 @@ Once Auto-Reconciliation is enabled, there are a few things that happen. Let’s ### Example - Let's say you have card transactions totaling $100 for the day. - We create a journal entry: +![NetSuite Journal Entry](https://help.expensify.com/assets/images/Auto-reconciliation NS 1.png){:width="100%"} - After transactions are posted in Expensify, we create the second Journal Entry(ies): +![NetSuite Second Journal Entry](https://help.expensify.com/assets/images/Auto-reconciliation NS 2.png){:width="100%"} - We then reconcile the matching amounts automatically, clearing the balance of the Expensify Clearing Account. - Now, you'll have a debit on your Credit Card account (increasing the total spent) and a credit on the bank account (reducing the amount available). The clearing account has a $0 balance. - Each expense will also create a Journal Entry, just as we do today, exported upon final approval. This entry will debit the expense account (category) and contain any other line item data. diff --git a/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md b/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md new file mode 100644 index 000000000000..bc0cb28f42b1 --- /dev/null +++ b/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md @@ -0,0 +1,84 @@ +--- +title: Cardholder Settings and Features +description: Expensify Card Settings for Employees +--- + +# How to use your Expensify Card +Once you receive your card, you can start using it right away. + +First, you'll want to take note of the Smart Limit tied to your card – this is listed in your card settings via **Settings > Account > Credit Card Import**. This limit represents the total amount of unapproved expenses you can have on the card. + +It's crucial to continuously submit your expenses promptly, as that'll ensure they can be approved and restore your full limit. You can always chat with your admin if you need your limit adjusted. + +You can swipe your Expensify Card like you would with any other card. As you make purchases, you'll get instant alerts on your phone letting you know if you need to SmartScan receipts. Any SmartScanned receipts should merge with the card expense automatically. + +If your organization doesn't require itemized receipts, you can rely on eReceipts instead. As long as the expense isn't lodging-related, Expensify will automatically generate an IRS-compliant eReceipt for every transaction. + +You can report and submit Expensify Card expenses just like any other expenses. As they're approved, your Smart Limit will be refreshed accordingly, allowing you to keep making purchases. + +## Enable Notifications +Download the Expensify mobile app and enable push notifications to stay current on your spending activity. Your card is connected to your Expensify account, so each transaction on your card will trigger a push notification. We'll also send you a push notification if we detect potentially fraudulent activity and allow you to confirm your purchase. + +Follow the steps below to enable real-time alerts on your mobile device. + +**If you have an iPhone**: +1. Open the Expensify app and tap the three-bar icon in the upper-left corner +2. Tap **Settings** and enable **Receive realtime alerts** +3. Accept the confirmation dialogue to go to your iPhone's notification settings for Expensify. Turn on Allow Notifications, and choose the notification types you’d like! + +**If you have an Android**: +1. Go to Settings and open 'Apps and Notifications'. +2. Find and open Expensify and enable notifications. +3. Customize your alerts. Depending on your phone model, you may have extra options to customize the types of notifications you receive. + +## Your virtual card +Once you're assigned a limit, you'll be able to use your virtual card immediately. You can view your virtual card details via **Settings > Account > Credit Card Import > Show Details**. Keep in mind that your virtual card and physical card share a limit. + +The virtual Expensify Card includes a card number, expiration date, and security code (CVC). You can use the virtual card for online purchases, in-app transactions, and in-person payments once it's linked to a mobile wallet (Apple Pay or Google Pay). + +## How to access your virtual card details +Here's how to access your virtual card details via the Expensify mobile app: +1. Tap the three-bar icon in the upper-left corner +2. Tap **Settings > Connected Cards** +3. Under **Virtual Card**, tap **Show Details** + +From there, you can view your virtual card's number, CVV, expiration date, and billing address. + +Here's how to access your virtual card details via the Expensify web app: +1. Head to **Settings > Account > Credit Card Import** +2. Under **Virtual Card**, click **Show Details** + +From there, you can view your virtual card's card number, CVV, expiration date, and billing address. + +## How to add your virtual card to a digital wallet (Apple Pay or Google Pay) + +To use the Expensify Card for contactless payment, add it to your digital wallet from the mobile app: +1. Tap the three-bar icon in the upper-left corner +2. Tap **Settings > Connected Cards** +3. Depending on your device, tap **Add to Apple Wallet** or **Add to Gpay** +4. Complete the remaining steps + +## Expensify Card declines +As long as you've enabled 'Receive real-time alerts', you'll get a notification explaining the reason for each decline. You can enable alerts in the mobile app by clicking on the three-bar icon in the upper-left corner > **Settings** > toggle **Receive real-time alerts**. + +Here are some reasons an Expensify Card transaction might be declined: + +- You have an insufficient card limit + - If a transaction exceeds your Expensify Card's available limit, the transaction will be declined. You can see the remaining limit in the mobile app under **Settings > Connected Cards** or in the web app under **Settings > Account > Credit Card Import**. + - Submitting expenses and getting them approved will free up your limit for more spending. + +- Your card isn't active yet or it was disabled by your Domain Admin +- Your card information was entered incorrectly with the merchant. Entering incorrect card information, such as the CVC, ZIP, or expiration date, will also lead to declines. +There was suspicious activity +- If Expensify detects unusual or suspicious activity, we may block transactions as a security measure + - This could happen due to irregular spending patterns, attempted purchases from risky vendors, or multiple rapid transactions. + - Check your Expensify Home page to approve unusual merchants and try again. + - If the spending looks suspicious, we may complete a manual due diligence check, and our team will do this as quickly as possible - your cards will all be locked while this happens. +- The merchant is located in a restricted country + +# FAQ +## Can I use Smart Limits with a free Expensify account? +If you're on the Free plan, you won't have the option to use Smart Limits. Your card limit will simply reset at the end of each calendar month. + +## I still haven't received my Expensify Card. What should I do? +For more information on why your card hasn't arrived, you can check out this resource on [Requesting a Card](https://help.expensify.com/articles/expensify-classic/expensify-card/Request-the-Card#what-if-i-havent-received-my-card-after-multiple-weeks). diff --git a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md index 4c216faffc18..8bcc11fbf167 100644 --- a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md +++ b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md @@ -5,7 +5,30 @@ description: Get the most out of your Expensify Card with exclusive perks! # Overview -The Expensify Card is packed with perks, both native to our Card program and through exclusive discounts with partnering solutions. Below, we’ll cover all of our exclusive offers in more detail and how to claim discounts with our partners. +The Expensify Card is packed with perks, both native to our Card program and through exclusive discounts with partnering solutions. The Expensify Card’s primary perks include: +- Swipe to Win, where every swipe has a chance to win fun personalized gifts for you and your closest friends and family members +- Unbeatable cash back incentive with each swipe +Below, we’ll cover all of our exclusive offers in more detail and how to claim discounts with our partners. + +# Expensify Card Perks + +## Swipe to Win +Swipe to Win is a new [Expensify Card](https://use.expensify.com/company-credit-card) perk that gives cardholders the chance to send a gift to a friend, family member, or essential worker on the frontlines! + +Winners can choose to _Send a Smile_ or _Send a Laugh_. To start, we’re offering one gift per option: + +- **Send A Smile:** Champagne by Expensify +- **Send a Laugh:** Jenga Set + +**How to Participate** +It’s easy! Once you have an Expensify Card, you just need to start using it. With each swipe, you're automatically entered to win and have a 1 in 250 chance of getting a prize! + +**How will I know if I’ve won?** +Winners will be notified immediately via the Expensify app, and receive additional instructions on how to choose and send their desired gift. + +If you don't have Expensify notifications turned on yet, here are some helpful guides: +- [Apple Notification Preferences](https://support.apple.com/en-us/HT201925) +- [Android Notification Preferences](https://community.expensify.com/home/leaving?allowTrusted=1&target=https%3A%2F%2Fsupport.google.com%2Fandroid%2Fanswer%2F9079661%3Fhl%3Den) # Partner Specific Perks @@ -188,4 +211,3 @@ Stripe Atlas helps removes obstacles typically associated with starting a busine **Receive $100 off Stripe Atlas and get access to a startup toolkit and special offers on additional Strip Atlas services.** **How to redeem:** Sign up with your Expensify Card. - diff --git a/docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md b/docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.md b/docs/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.md new file mode 100644 index 000000000000..e14fadbec915 --- /dev/null +++ b/docs/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.md @@ -0,0 +1,38 @@ +--- +title: ExpensifyApproved! Partner Program +description: How to Join the ExpensifyApproved! Partner Program +--- + +# Overview + +As trusted accountants and financial advisors, you strive to offer your clients the best tools available. Expensify is recognized as a leading, all-in-one expense and corporate card management platform suitable for clients of every size. By becoming an ExpensifyApproved! Partner, you unlock exclusive benefits for both you and your clientele. +## Key Benefits +Dedicated Partner Manager: Enjoy personalized assistance with an assigned Partner Manager post-course completion. +Client Onboarding Support: A dedicated Client Onboarding Manager will aid in smooth transitions. +Free Expensify Account: Complimentary access to our platform for your convenience. +Revenue share (US-only): All partners receive 0.5% revenue share on client Expensify Card transactions. Keep this as a bonus or offer it to your clients as cash back. +Exclusive CPA Card (US-only): Automated expense reconciliation from swipe to journal entry with the CPA Card. +Special Pricing Offers (US-only): Avail partner-specific discounts for your clients and a revenue share from client Expensify Card transactions. +Professional Growth (US-only): Earn 3 CPE credits after completing the ExpensifyApproved! University. +Cobranded Marketing - Collaborate with your Partner Manager to craft custom marketing materials, case studies, and more. + +# How to join the ExpensifyApproved! Partner Program + +1. Enroll in ExpensifyApproved! University (EA!U) +Visit university.expensify.com and enroll in the “Getting Started with Expensify” course. +This course imparts the essentials of Expensify, ensuring you follow the best practices for client setups. + +2. Complete the course +Grasp the core features and functionalities of Expensify. +Ensure you're equipped to serve your clients using Expensify to its fullest. +Once completed, you’ll be prompted to schedule a call with your Partner Manager. **This call is required to earn your certification.** + +3. Once you successfully complete the course, you'll unlock: +- A dedicated Partner Manager - assigned to you after you have completed the course! +- A dedicated Client Setup Specialist +- Membership to the ExpensifyApproved! Partner Program. +- A complimentary free Expensify account +- Access to the exclusive CPA Card (US-only). +- Partner-specific discounts to extend to your clients. +- A 0.5% revenue share on client Expensify Card expenses (US-only) +- 3 CPE credits (US-only). diff --git a/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md new file mode 100644 index 000000000000..750a1fc10e77 --- /dev/null +++ b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md @@ -0,0 +1,87 @@ +--- +title: Partner Billing Guide +description: Understand how Expensify bills partners and their clients +--- + +# Overview + +The ExpensifyApproved! Partner Program offers exclusive billing rates and features tailored for accountants to ensure seamless client management. If you are an accountant or consultant who recommends spend management solutions to your clients, becoming an ExpensifyApproved! Accountant may be a great certification for you. This guide will walk you through the unique billing perks available to ExpensifyApproved! partners, emphasizing the importance of understanding and managing client billing effectively. To learn what perks partners receive, check out the ExpensifyApproved! program details here. + +# Get exclusive partner pricing + +All ExpensifyApproved! Partners are automatically eligible for a special rate of $9/seat monthly, without an annual commitment when they adopt the Expensify Card. This provides flexibility as active users can vary. Here are the specifics on pricing for our Approved! Partners’ clients: +- **Bundled pricing:** US Clients using the Expensify Card get up to a 50% discount, bringing their monthly bill to $9/seat. Reach out to your Partner Manager to discuss exclusive international pricing discount. +- **Unbundled pricing (or pay-per-use pricing):** Clients not using the Expensify Card are billed at $18/seat monthly. +- **No annual commitment:** Partners pay only for what they use, with no annual subscriptions required. +- **Expensify Card revenue share:** All partners receive a 0.5% revenue share on Expensify Card transactions made by clients. This revenue share can be passed back to the client for an additional discount to offset their Expensify bill. + +# Understanding the billing process + +Expensify bills the owner of the expense workspace for the activity on that workspace. If accountants retain ownership of client workspaces, they receive the bill and can then re-bill their clients based on individual agreements. + +Each month, Expensify will send a consolidated bill detailing: +- **Pay-per-use seats:** This is the number of active clients and their users for the month. +- **Expensify Card discount**: This amount reflects how much spend is put on your card, which then determines the discount for that month. +- **Total monthly price:** This amount is the overall price of Expensify when using the Expensify Card discount to offset the cost of the pay-per-use seats. +- **Workspace list:** This is an overview of all client workspaces with their respective active seats. + +## Consolidated Domain Billing + +If your firm wishes to consolidate all Expensify billing to a single account, the Consolidated Domain Billing feature is your go-to tool. It centralizes payment for all group workspaces owned by any domain member of your firm. + +### Activating Consolidated Domain Billing: + 1. Claim and verify your firm’s domain. + 2. Navigate to **Settings > Domains > [Domain Name] > Domain Admins** and set a **"Primary Domain Admin"** by using the drop down toggle to select an email address. + 3. Enable **Consolidated Domain Billing** in the same section. + +The Consolidated Domain Billing tool ensures that billing takes place under a single Expensify account associated with your firm. This eliminates the need to add multiple payment cards across various accounts to cover payments for multiple clients. + +## Maintaining a Console of all clients: + +If your firm wants to have a console view of all client workspaces and domains, you will want to create a single, centralized login to manage all client workspaces and domains, such as accounting@myfirm.com. + + 1. Create a dedicated email address that will act as the universal workspace owner, for example, accounting@myfirm.com. + 2. Register this email with Expensify or your chosen platform and ensure it is verified and secured. + 3. Within each client workspace settings, add your centralized email (e.g. accounting@myfirm.com) as a workspace admin. + 4. Do the same with each client domain. + +## Applying Client IDs to a bill + +Using client IDs for Optimized Billing in Expensify: A unique identifier feature for ExpensifyApproved! accountants. Streamline client Workspace recognition and make your billing process more efficient. + +# How to assign a client ID to a workspace + 1. Log in to your account: Ensure you’re using an Approved! accountant account. + 2. Navigate to the desired Workspace: Go to **Settings > Workspaces > [Workspace Name] > Overview**. + 3. Input the identifier: Here, you can input an alphanumeric unique identifier for each client workspace. +**Note:** If a client has multiple workspaces, ensure each workspace has a consistent client ID. + +# How to access and download billing receipts +- Accessing Billing: **Settings: Go to Settings > Your Account > Payments > Billing History.** +- Download the Receipt: Click on **"Download Receipt CSV".** + +# Deep Dive +- Using client IDs for all Workspaces: It's beneficial to use client IDs for all Workspaces to ensure each one is easily recognizable. +- Benefits of itemized billing receipts: Employing client IDs offers itemized billing by client, with each itemization detailing unique active users. + +# FAQ + +**Do I automatically get the special billing rate as an ExpensifyApproved! Partner?** +- Yes, when you join the ExpensifyApproved! program, you will automatically get the special billing rate. To join the ExpensifyApproved! Program, you need to enroll in ExpensifyApproved! University. + +**How can I check my billing details?** +- To check your billing details, be on the lookout for your detailed billing statement sent out at the end of each month. + +**Can I pass the bill to my clients?** +- Yes, you can pass the bill on to your clients. If you retain ownership of client workspaces in Expensify, you can re-bill your clients. If you’d like the client to own the billing of the Expensify, they can take over billing. + +**What if I don't want to use the Expensify Card?** +- If you prefer not to use the Expensify Card, your clients will be billed at $18/seat monthly. + +**Why use client IDs?** +- Client IDs provide a streamlined method to identify and manage workspaces, especially beneficial when a client has multiple workspaces. + +**Do I need a client ID for each Workspace?** +- Yes, if you want to ensure seamless identification and billing processes. + +**Where can I see the Billing Receipts?** +- All billing owners receive an emailed PDF of their monthly billing receipt, but a CSV version can also be downloaded from the platform. diff --git a/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md b/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md index 2db69d0a8791..8243833dcc23 100644 --- a/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md +++ b/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md @@ -1,5 +1,5 @@ --- -title: Your Expensify Partner Manager +title: Expensify Partner Support description: Understanding support for our partners --- @@ -10,6 +10,7 @@ Our well-rounded support methodology is designed to provide comprehensive assist ## 1. ExpensifyApproved! University **Purpose:** Equip your team with a comprehensive understanding of Expensify. + **Benefits:** - Foundation-level knowledge about the platform. - 3 CPE credits upon successful completion (US-only). @@ -17,16 +18,39 @@ Our well-rounded support methodology is designed to provide comprehensive assist - Visit university.Expensify.com to access our comprehensive training program. ## 2. Partner Manager -**Role:** A designated liaison for your firm. +**Role:** +A Partner Manager is a dedicated point of contact for your firm Partner Managers support our accounting partners by providing recommendations for client’s accounts, assisting with firm-wide training, and ensuring partners receive the full benefits of our partnership program. They will actively monitor open technical issues and be proactive with recommendations to increase efficiency. + + **Key Responsibilities:** - Handle any escalations promptly. - Organize firm-wide training sessions. - Assist with strategic planning and the introduction of new features. - Once you've completed the ExpensifyApproved! University, log in to your Expensify account. Click on the "Support" option to connect with your dedicated Partner Manager. +**How do I know if I have a Partner Manager?** + +For your firm to be assigned a Partner Manager, you must complete the ExpensifyApproved! University training course. Every external accountant or bookkeeper who completes the training is automatically enrolled in our program and receives all the benefits, including access to the Partner Manager. So everyone at your firm must complete the training to receive the maximum benefit. + +You can check to see if you’ve completed the course and enrolled in the ExpensifyApproved! Accountants program simply by logging into your Expensify account. In the bottom left-hand corner of the website, you will see the ExpensifyApproved! logo. + +**How do I contact my Partner Manager?** +1. Signing in to new.expensify.com and searching for your Partner Manager +2. Replying to or clicking the chat link on any email you get from your Partner Manager + +**How do I know if my Partner Manager is online?** + +You will be able to see if they are online via their status in new.expensify.com, which will either say “online” or have their working hours. + +**Can I get on a call with my Partner Manager?** + +Of course! You can ask your Partner Manager to schedule a call whenever you think one might be helpful. Partner Managers can discuss client onboarding strategies, firm-wide training, and client setups. + +We recommend continuing to work with Concierge for general support questions, as this team is always online and available to help immediately. ## 3. Client Setup Specialist **Purpose:** Ensure smooth onboarding for every client you refer. + **Duties:** - Comprehensive assistance with setting up Expensify. - Help with configuring accounting integrations. @@ -35,6 +59,7 @@ Our well-rounded support methodology is designed to provide comprehensive assist ## 4. Client Account Manager **Role:** Dedicated support for ongoing client needs. + **Responsibilities:** - Address day-to-day product inquiries. - Assist clients in navigating and optimizing their use of Expensify. @@ -42,6 +67,7 @@ Our well-rounded support methodology is designed to provide comprehensive assist ## 5. Concierge chat support **Availability:** Real-time support for any urgent inquiries. + **Features:** - Immediate assistance with an average response time of under two minutes. - Available to both accountants and clients for all product-related questions. diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md b/docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md similarity index 89% rename from docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md rename to docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md index 214188e35137..1b537839af77 100644 --- a/docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md +++ b/docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md @@ -1,17 +1,17 @@ --- -title: Creating Per Diem Expenses +title: Per-Diem-Expenses description: How to create Per Diem expenses on mobile and web. --- # Overview What are Per Diems? Per diems, short for "per diem allowance" or "daily allowance," are fixed daily payments provided by your employer to cover expenses incurred during business or work-related travel. These allowances simplify expense tracking and reimbursement for meals, lodging, and incidental expenses during a trip. Per Diems can be masterfully tracked in Expensify! -## How To create per diem expenses +## How to create per diem expenses To add per diem expenses, you need three pieces of information: 1. Where did you go? - Specify your travel destination. 2. How long were you away? - Define the period you're claiming for. -3. Which rate did you use? - Select the appropriate per diem rate. +3. Which rate did you use? - Select the appropriate per diem rate (this is set by your employer). ### Step 1: On either the web or mobile app, click New Expense and choose Per Diem @@ -31,15 +31,15 @@ Finally, submit your Per Diem expense for approval, and you'll be on your way to # FAQ -## Can I Edit My Per Diems? +## Can I edit my per diem expenses? Per Diems cannot be amended. To make changes, delete the expense and recreate it as needed. -## What If My Admin Requires Daily Per Diems? +## What if my admin requires daily per diems? No problem! Create a separate Per Diem expense for each day of your trip. -## I Have Questions About the Amount I'm Due +## I have questions about the amount I'm due Reach out to your internal Admin team, as they've configured the rates in your policy to meet specific requirements. -## Can I Add Start and End Times to a Per Diem? +## Can I add start and end times to per diems? Unfortunately, you cannot add start and end times to Per Diems in Expensify. By following these steps, you can efficiently create and manage your Per Diem expenses in Expensify, making the process of tracking and getting reimbursed hassle-free. diff --git a/docs/articles/expensify-classic/get-paid-back/Per-Diem.md b/docs/articles/expensify-classic/get-paid-back/Per-Diem.md deleted file mode 100644 index 780e5969c441..000000000000 --- a/docs/articles/expensify-classic/get-paid-back/Per-Diem.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Per Diem -description: Per Diem ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Referral-Program.md b/docs/articles/expensify-classic/get-paid-back/Referral-Program.md similarity index 100% rename from docs/articles/expensify-classic/getting-started/Referral-Program.md rename to docs/articles/expensify-classic/get-paid-back/Referral-Program.md diff --git a/docs/articles/expensify-classic/get-paid-back/Trips.md b/docs/articles/expensify-classic/get-paid-back/Trips.md index 7efba1875a90..a65a8bfb8eec 100644 --- a/docs/articles/expensify-classic/get-paid-back/Trips.md +++ b/docs/articles/expensify-classic/get-paid-back/Trips.md @@ -1,5 +1,37 @@ --- title: Trips -description: Trips +description: Automate getting paid back for your travel through Expensify's Trips feature. --- -## Resource Coming Soon! +# Overview + +Discover how Expensify streamlines your travel expense management when it comes to trips. With the automatic classification of trip receipts and real-time notifications for travel changes, you can effortlessly stay organized and informed on all your trips. + +When a travel receipt/itinerary is uploaded into Expensify and SmartScanned, the Trips section of the mobile app will automatically populate your trip information.. If your flight has any cancellations, unexpected changes, or delays, we will make sure you know about it. We will notify you of the change as soon as it happens via the mobile app. + +For the receipt to be processed as a Trip, it must include the total amount of the expense, date, and merchant name. + +If your company is using a travel integration from the list shown below, you can automate this process entirely: +- [TravelPerk](https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/TravelPerk) +- [Egencia](https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Egencia) +- [Navan](https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Trip-Actions) + +# How to add a Trip to your account + +Trip receipts are typically sent via email, and will include multiple pages. With that in mind, we recommend emailing receipts directly to Expensify for ease. + +To email a flight or hotel receipt, you’ll forward the receipt from your Expensify-associated email address to receipts@expensify.com. + +# How to access your Trip information + +To view details about your past or upcoming trips, follow these steps within the Expensify mobile app: +1. Open the Expensify mobile app +2. Navigate to the "Menu" option (top left ≡ icon) +3. Select **Trips** + +# FAQ + +## How do I capture Trip receipts sent to my personal email address? +If you received your receipt in an email that is not associated with your Expensify account, you can add this email as a [secondary login](https://help.expensify.com/articles/expensify-classic/account-settings/Account-Details#how-to-add-a-secondary-login) to directly forward the receipt into your account. + +## How do I upload Trip receipts that were not sent to me by email? +If your trip receipt was not sent to you by email, you can manually upload the receipt to your account. Check out this resource for more information on [manually uploading receipts](https://help.expensify.com/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts#manually-upload). diff --git a/docs/articles/expensify-classic/getting-started/Employees.md b/docs/articles/expensify-classic/getting-started/Employees.md index 6d3c2dc705e1..76660edf94eb 100644 --- a/docs/articles/expensify-classic/getting-started/Employees.md +++ b/docs/articles/expensify-classic/getting-started/Employees.md @@ -2,4 +2,137 @@ title: Employees description: Employees --- -## Resource Coming Soon! +# Overview + +This post will cover getting started with Expensify for new users (submitters and employees). + +# Download the Mobile App + +You can download Expensify for [iOS](https://apps.apple.com/us/app/new-expensify/id1530278510) and [Android](https://play.google.com/store/apps/details?id=com.expensify.chat&hl=en_US&gl=US) devices using the respective links here. + +# How to review homepage tasks + +Every time you log into Expensify, you'll land on your Home page. Here, you'll find tasks you need to take care of, like: +- Reviewing and fixing mistakes before sending your report +- Starting the review process for upcoming expense reports +- Getting helpful tips on how to use Expensify + +# Create your first expense + +You can create expenses in two ways: manually or automatically with SmartScan. + +### Manual Expense Creation: +- On the mobile app, tap the blue "+" icon. +- On the desktop app, click "New Expense." + +### Automatic Expense Creation with SmartScan: +- On the mobile app, tap the "camera" icon. +- Take a clear picture of your receipt. +- Click "Save" for the expense. + SmartScan will pull the details from the receipt and fill them in for you. + +You can also forward receipts from your email address to [receipts@expensify.com](mailto:receipts@expensify.com). SmartScan will handle the receipts the same way. + +Feel free to add coding details, categories, tags, comments, or attendees while SmartScan processes your receipt. SmartScan will handle the merchant, date, amount, and currency for you. + +For more details on how to create and edit expenses, take a look [here](https://help.expensify.com/articles/expensify-classic/get-paid-back/expenses/Create-Expenses). + +# Submit your first report + +Expensify can automatically handle your reports through Scheduled Submit. There are two ways to activate this: + +### Activating Scheduled Submit for personal use: +- Go to Settings > Workspaces > Individual > [Workspace Name] > Reports. +- Toggle the setting to "Enabled". +- Choose how often you want reports to be submitted. + +### Activating Scheduled Submit globally for members of your Group Workspace: +- Go to Settings > Workspaces > Group > [Workspace Name] > Reports. +- Toggle the setting to "Enabled". +- Choose how often you want reports to be submitted. + +_Note: If you are a member of a Group Workspace, the company's settings might already have Scheduled Submit enabled. In this case, your personal Scheduled Submit settings will be ignored in favor of the Group Workspace’s submission schedule._ + +If you need to send a report manually: +- Click the Submit button in the top left of the report. +- On the mobile app, tap the report and click, Submit Report. + +For more details on creating and submitting reports, take a look [here](https://help.expensify.com/articles/expensify-classic/get-paid-back/reports/Create-A-Report#how-to-create-a-report). + +# What happens to my reports when they’re submitted? + +When you create a report, Expensify will automatically set your report to submit under the company Workspace your account is set to submit under. That means, when your report is submitted, it will follow the rules and approval chain of the Workspace. + +Every new user account has access to a “personal” Workspace, which is essentially a set of rules that you set for your own, non-company reports. + +With that in mind, it’s important to make sure your account is set to your company’s Workspace by default, to ensure that all newly created reports will be submitted under your company’s Workspace by default. + +If you find your reports are being submitted under your personal Workspace, you can correct this by changing your default Workspace which can be found in the account menu by clicking your Account Switcher icon. Additionally, if you have a Draft report that is set to submit under your personal Workspace, you can correct that by navigating to the report, clicking the Details button in the top right corner, and selecting your company Workspace from the dropdown. + +# How to use the Expenses page + +The Expenses page is your hub for managing your expenses. Here you'll see three types of expenses, each with an icon representing an expense type: + +- Cash Expense (represented by an icon of a bank note) +- Personal Credit Card (represented by an icon of a credit card) +- Corporate Company Card (represented by an icon of a credit card with a lock) + +In Expensify, any expense that has been manually created (i.e., not imported from a bank automatically) is considered a Cash Expense. These are typically out-of-pocket expenses and default to "reimbursable" unless indicated otherwise by your Workspace Admin. + +A Personal Credit Card expense is an expense that has been imported automatically from your personal bank. Personal Credit Cards can be imported through your Personal Settings, and the expenses are considered reimbursable by default unless you set it otherwise. + +A Corporate Company Card expense is an expense that has been imported automatically from your company card feed set on your company's domain. This card is assigned to you by your Domain Admin, and the expenses are typically non-reimbursable. + +### Navigating the Expenses page + +The Expenses page allows you to search your expenses using a wide variety of filters, including date ranges, merchant names, categories and tags, and the state of the report that the expense is contained within. You can also change the view of the Expenses page to fit your personal preferences. + +# How to use the Reports page + +The Reports page is a hub for managing your expense reports. There are four available states for reports: + +- Draft Reports: These are reports you've created but haven't submitted for approval. +- Processing Reports: These are reports currently under review by your admin. +- Approved Reports: These are reports that have been reviewed and approved by your admin. +- Reimbursed Reports: These are reports that have been reimbursed either through Expensify or by your admin outside of Expensify. + +### Navigating the Reports page + +The Reports page allows you to search your reports using a wide variety of filters, including date range, Report name or email address of the submitter, Report type, and Report state. + +# How to add a deposit account + +Adding a deposit account allows you to be reimbursed through Expensify by your company. There are a few nuanced differences between how to add deposit accounts depending on the currency you will be reimbursed in. Take a look at the different options [here](https://help.expensify.com/expensify-classic/hubs/bank-accounts-and-credit-cards/deposit-accounts). + +# Add a Secondary Login to your account + +Expensify accounts are personal by design. They belong to you, the user, forever. Yes, you might change careers, but your account will always be yours, just add your new company email address. + +To ensure you get to keep your Expensify account as you shuffle through your professional life, we recommend adding your personal email address as your Secondary Login. This will ensure that, even if you were to leave your current position for something new and exciting, your account will not be closed when you are removed from the company. Instead, your company email address would be stripped from the account, but you would maintain ownership of the Expensify account. + +[Here’s](https://help.expensify.com/articles/expensify-classic/account-settings/Account-Details#how-to-add-a-secondary-login) how you can do that! + +# How to secure your account + +You can add an extra layer of security to your account by turning on Two Factor Authentication (2FA). Follow these steps on either your computer or mobile phone: + +### On Computer (Desktop): +- Open the desktop app. +- Go to Settings > Accounts > Account Details > Two Factor Authentication. +- Toggle the switch to "Enabled." +- Save or download your Recovery Codes. If you can't use your authenticator app, these codes are essential for access. + +### On Mobile phone: +- Open the Expensify app and go to Settings. +- Turn on the switch next to Two Factor Authentication. +- Save or download your Recovery Codes. +- On the next screen, copy the Secret Key and paste it into your preferred authenticator app. +- Once connected, enter the code from your app into Expensify before the time runs out. + +*Note: It's best to keep the time/date set to "Network" for Android and iOS to avoid issues with authentication codes that depend on time zones.* + +### Using Recovery Codes + +Only use a recovery code as a last resort to sign into your Expensify account. If you do use a recovery code: +- Reset 2FA in your account settings on the web or mobile app after gaining access. +- Toggle off and on 2FA to set it up again and get new recovery codes. diff --git a/docs/articles/expensify-classic/getting-started/Mobile-App.md b/docs/articles/expensify-classic/getting-started/Mobile-App.md deleted file mode 100644 index 7fa57abbdf61..000000000000 --- a/docs/articles/expensify-classic/getting-started/Mobile-App.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Using the App -description: Using the App ---- -## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md b/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md new file mode 100644 index 000000000000..f4a6acdd8571 --- /dev/null +++ b/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md @@ -0,0 +1,117 @@ +--- +title: Your Expensify Account Manager +description: Everything you need to know about Having an Expensify account manager +redirect_from: articles/other/Your-Expensify-Account-Manager/ +--- + + + +# Introduction to Expensify Support + +Expensify offers comprehensive support for customers of all sizes. From small business owners to multinational corporations, Expensify's support teams are available to assist! + +Expensify has four different support teams. Let's go over how each of them operates below. + +**Concierge Support:** +- Concierge is available 24/7 and is the first line of support +- Users can access Concierge through the Expensify app or via email at concierge@expensify.com +- Provides quick responses, usually within minutes +- Don't be your team's tech support - refer your users to Concierge for all their Expensify product questions + +**Setup Specialists:** +- Dedicated onboarding experts to assist users in getting started with Expensify +- Assist in connecting cards and bank accounts, configuring integrations, and more + +**Account Managers:** +- A dedicated point of contact for companies with more than ten users +- Serve as product specialists +- Available to answer questions and promote best practices +- Provide ongoing support and guidance + +**ExpensifyApproved! Accounting Partner Managers:** +- Offer an additional support layer for accounting partners +- Partner Managers are dedicated Expensify team members +- Provide firmwide training, assist with strategic goal planning, and collaborative marketing + +This comprehensive support structure ensures that Expensify users receive the assistance they need, whether new to the platform or looking to optimize their experience. + +# How to get support in Expensify + +## Concierge + +Reach out to Concierge when you have general questions about Expensify. Concierge can also be used to manage expenses, submit reports, and automate approvals. You can contact Concierge while logged into your Expensify account by clicking **Support** on the left-hand menu and then selecting **Concierge**. + +Try questions such as: +- What is SmartScan? +- How do I add a mileage expense from the mobile app? +- Where can I add a Secondary Login? + +## Setup Specialist + +Expensify provides onboarding guidance for anyone through a Setup Specialist! You can contact your Setup Specialist while logged into your Expensify account by clicking **Support** on the left-hand menu and then selecting **Account Setup Specialist**. + +### What to expect from your Setup Specialist: + +- Personalized Support: Your Setup Specialist is here to assist you with tailored support. They can answer your questions and arrange screen share calls to help you set up your Expensify account or familiarize you with the product. + +- Product Demos: Are you curious about how the Expensify Card works or how it integrates with your accounting software? Just let your Setup Specialist know, and they'll guide you and your team through any feature you'd like to explore. + +- Setup Assistant: You don't have to do it alone when setting up your Expensify account. When you're ready to begin, chat with your Setup Specialist in the #admins room. They'll ensure everything is configured correctly right from the start. + + +## Account Manager + +If you have more than ten active users, or you're an ExpensifyApproved! Accountant's client, you're eligible for a designated Account Manager. + +Once you've completed onboarding to Expensify with your Setup Specialist, your Account Manager will take over as the main point of contact. Your account manager is there to support you and other Workspace admins in reviewing your account, advising on best practices, and making changes to your Workspace on your behalf whenever you need a hand. + +They will actively monitor open technical issues and be proactive with recommendations to increase efficiency and minimize time spent on expense management. + +### How to contact your Account Manager + +If you are a Workspace admin or domain admin, you will hear from your Account Manager as soon as one is assigned to your company. + +Unlike Concierge, an Account Manager's support will not be real-time, 24 hours a day. Your Account Manager will be as responsive as possible when online, but anything sent when they're offline will not be responded to until they're working again. + +You can contact your Account Manager while logged into your Expensify account by clicking **Support** on the left-hand menu and then selecting **Account Manager**. + +## Partner Manager + +A Partner Manager is a dedicated point of contact to support our ExpensifyApproved! Accountants with questions about their Expensify account. Partner Managers support our accounting partners by providing recommendations for client's accounts, assisting with firm-wide training, and ensuring partners receive the full benefits of our partnership program. They will actively monitor open technical issues and be proactive with recommendations to increase efficiency and minimize time spent on expense management. + +For your firm to be assigned a Partner Manager, you must complete the [ExpensifyApproved! University](https://use.expensify.com/accountants-program) training course. Every external accountant or bookkeeper who completes the training is automatically enrolled in our program and receives benefits, including access to a Partner Manager. Everyone at your firm must complete the training to receive the maximum benefit. + +### How to contact your Partner Manager + +Your Partner Manager should reach out to you once you've completed ExpensifyApproved! University. Otherwise, you can contact your Partner Manager anytime by clicking **Support** on the left-hand menu and then selecting **Partner Manager**. + +## Tips on Contacting Expensify Support + +- **Use the Right Email**: Contact us from the email address linked to your Expensify account. This helps us locate your information accurately. +- **Be Clear and Specific**: When asking questions or reporting issues, provide specific examples like affected users' email addresses or report IDs. This makes it easier for us to assist you effectively. +- **Practice Kindness**: Remember that we're here to help. Please be polite, considerate, and patient as we work together to resolve any concerns you have. + +# FAQ +## Who gets an Account Manager? +Members who have 10 or more active users, or clients of ExpensifyApproved! Accounts are automatically assigned a dedicated Account Manager. + +To be assigned an Account Manager immediately, log into your Expensify account and go to **Settings > Workspaces > Group**, then click **Subscription** and increase your subscription size to 10 or more. + +## What if I'm unable to reach my Account Manager? +If you're unable to reach your account manager, then you can always reach out to Concierge for assistance. Your account manager will always reply once they're online again. + +## Can I schedule a call with my Account Manager? +Of course! You can ask your Account Manager for a call whenever you think one might be helpful. + +**What makes a successful call with an Account Manager**: +- Scheduling the call using their calendar link (this should be shared with you once you're assigned an Account Manager) +- Listing out exactly what you'd like to go over with the Account Manager, and then sharing that list with them before the call +- Having anyone else in your organization who regularly manages your Expensify setup join the call + +## When should I chat with Concierge instead of my Account Manager? +If you have a general question about the status of a report or updating an account setting, Concierge is more than capable of getting you the answers you need. + +We recommend working with Concierge on general support questions, as this team is always online and available to help immediately. + +## Who gets assigned a Setup Specialist? +This feature is specifically for new members! Whenever you start a free trial, a product Setup Specialist will be assigned to guide you through configuring your Expensify account. diff --git a/docs/articles/expensify-classic/getting-started/support/Your-Expensify-Account-Manager.md b/docs/articles/expensify-classic/getting-started/support/Your-Expensify-Account-Manager.md deleted file mode 100644 index a6fa0220c0dc..000000000000 --- a/docs/articles/expensify-classic/getting-started/support/Your-Expensify-Account-Manager.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Your Expensify Account Manager -description: Everything you need to know about Having an Expensify account manager -redirect_from: articles/other/Your-Expensify-Account-Manager/ ---- - - - -# What is an account manager? -An account manager is a dedicated point of contact to support policy admins with questions about their Expensify account. They are available to help you and other policy admins review your account, advise on best practices, and make changes to your policy on your behalf whenever you need a hand. They will actively monitor open technical issues and be proactive with recommendations to increase efficiency and minimize time spent on expense management. - -Unlike Concierge, an account manager’s support will not be real-time, 24 hours a day. A benefit of Concierge is that you get real-time support every day. Your account manager will be super responsive when online, but anything sent when they’re offline will not be responded to until they’re online again. - -For real-time responses and simple troubleshooting issues, you can always message our general support by writing to Concierge via the in-product chat or by emailing concierge@expensify.com. - -# How do I know if I have an account manager? -If you are a policy admin or domain admin, you will also hear from your account manager as soon as one gets assigned to your company. If you'd like a reminder who your account manager is, just click the Support link on the left side of Expensify - you'll see your account manager's name and photo, with an option to contact them for help. - -## How do I contact my account manager? -We make it easy to contact your account manager: - -1. Log in to your Expensify account, click "Support" along the left side of the page, and click the “Account Manager” option -2. Reply to (or click the chat link on) any email you get from your account manager -3. Sign in to new.expensify.com and go to the #admins room for any of your policies. Your account manager is in your #admin rooms ready to help you, so you can ask for help here and your account manager will respond in the chat. - -# FAQs -## Who gets an account manager? -Every customer with 10 or more paid subscribers is automatically assigned a dedicated account manager. If you have fewer than 10 active users each month, you can still get an account manager by increasing your subscription to 10 or more users, To get assigned an account manager immediately, log into your Expensify account and go to Settings > Policies > Group, then click Subscription and increase your subscription size to 10 or more. - -## How do I know if my account manager is online? -You will be able to see if they are online via their status, which will either say something like “online” or have their working hours. - -## What if I’m unable to reach my account manager? -If for some reason, you’re unable to reach your account manager, perhaps because they’re offline, then you can always reach out to Concierge for assistance. Your account manager will always get back to you when they’re online again. - -## Can I get on a call with my account manager? -Of course! You can ask your account manager to schedule a call whenever you think one might be helpful. We usually find that the most effective calls are those that deal with general setup questions. For technical troubleshooting, we typically recommend chat as that allows your account manager time to look into the issue, test things on their end, and, if needed, consult the wider Expensify technical team. It also allows you to easily refer back to instructions and links. \ No newline at end of file diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md index d8c7c145a670..958e423273ce 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md @@ -76,6 +76,7 @@ Expensify's integration with QuickBooks brings in your Chart of Accounts as Cate 3. Expensify offers Auto-Categorization to automatically assign expenses to the appropriate expense categories. 4. If needed, you can edit the names of the imported Categories to simplify expense coding for your employees. Keep in mind that if you make changes to these accounts in QuickBooks Desktop, the category names in Expensify will update to match them during the next sync. 5. _**Important:**_ Each expense must have a category selected to export to QuickBooks Desktop. The selected category must be one imported from QuickBooks Desktop; you cannot manually create categories within Expensify policy settings. + ## Classes Classes can be imported from QuickBooks as either tags (line-item level) or report fields (header level). diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md index 3ee1c8656b4b..4075aaf18016 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md @@ -1,5 +1,322 @@ --- -title: Coming Soon -description: Coming Soon +title: QuickBooks Online +description: Everything you need to know about using Expensify's direct integration with QuickBooks Online. --- -## Resource Coming Soon! +# Overview + +The Expensify integration with QuickBooks Online brings in your expense accounts and other data and even exports reports directly to QuickBooks for easy reconciliation. Plus, with advanced features in QuickBooks Online, you can fine-tune coding settings in Expensify for automated data export to optimize your accounting workflow. + +## Before connecting + +It's crucial to understand the requirements based on your specific QuickBooks subscription: + +- While all the features are available in Expensify, their accessibility may vary depending on your QuickBooks Online subscription. +- An error will occur if you try to export to QuickBooks with a feature enabled that isn't part of your subscription. +- Please be aware that Expensify does not support the Self-Employed subscription in QuickBooks Online. + +![QuickBooks Online - Subscription types]({{site.url}}/assets/images/QBO1.png){:width="100%"} + +# How to connect to QuickBooks Online + +## Step 1: Setup employees in QuickBooks Online + +Employees must be set up as either Vendors or Employees in QuickBooks Online. Make sure to include the submitter's email in their record. + +If you use vendor records, you can export as Vendor Bills, Checks, or Journal Entries. If you use employee records, you can export as Checks or Journal Entries (if exporting against a liability account). + +Additional Options for Streamlined Setup: + +- Automatic Vendor Creation: Enable “Automatically Create Entities” in your connection settings to automatically generate Vendor or Employee records upon export for submitters that don't already exist in QBO. +- Employee Setup Considerations: If setting up submitters as Employees, ensure you activate QuickBooks Online Payroll. This will grant access to the Employee Profile tab to input employee email addresses. + +## Step 2: Connect Expensify and QuickBooks Online + +- Navigate to Settings > Workspaces > Group > [Workspace Name] > Connections > QuickBooks Online. Click Connect to QuickBooks. +- Enter your QuickBooks Online Administrator’s login information and choose the QuickBooks Online Company File you want to connect to Expensify (you can connect one Company File per Workspace). Then click Authorize. +- Enter your QuickBooks Online Administrator’s login information and choose the QuickBooks Online Company File you want to connect to Expensify (you can connect one Company File per Workspace): + +## Exporting historical Reports to QuickBooks Online: + +After connecting QuickBooks Online to Expensify, you may receive a prompt to export all historical reports from Expensify. To export multiple reports at once, follow these steps: + +- Go to the Reports page on the web. +- Tick the checkbox next to the reports you want to export. +- Click 'Export To' and select 'QuickBooks Online' from the drop-down list. + +If you don't want to export specific reports, click “Mark as manually entered” on the report. + +# How to configure export settings for QuickBooks Online + +Our QuickBooks Online integration offers a range of features. This section will focus on Export Settings and how to set them up. + +## Preferred Exporter + +Any Workspace admin can export to your accounting integration, but the Preferred Exporter can be chosen to automate specific steps. You can set this role from Settings > Workspaces > Group > [Workspace Name] > Connections > Configure > Export > Preferred Exporter. + +The Preferred Exporter: + +- Is the user whose Concierge performs all automated exports on behalf of. +- Is the only user who will see reports awaiting export in their **Home.** +- Must be a **Domain Admin** if you have set individual GL accounts for Company Card export. +- Must be a **Domain Admin** if this is the Preferred Workspace for any Expensify Card domain using Automatic Reconciliation. + +## Date + +When exporting reports to QuickBooks Online, you can choose the report's **submitted date**, the report's **exported date**, or the **date of the last expense on the report.** + +Most export options (Check, Journal Entry, and Vendor Bill) will create a single itemized entry with one date. +Please note that if you choose a Credit Card or Debit Card for non-reimbursable expenses, we'll use the transaction date on each expense during export. + +# Reimbursable expenses + +Reimbursable expenses export to QuickBooks Online as: + +- Vendor Bills +- Checks +- Journal Entries + +## Vendor bill (recommended) + +This is a single itemized vendor bill for each Expensify report. If the accounting period is closed, we will post the vendor bill on the first day of the next open period. If you export as Vendor Bills, you can also choose to Sync reimbursed reports (set on the Advanced tab). **An A/P account is required to export to a vendor bill.** + +The submitter will be listed as the vendor in the vendor bill. + +![Vendor Bill]({{site.url}}/assets/images/QBO2-Bill.png){:width="100%"} + +## Check + +This is a single itemized check for each Expensify report. You can mark a check to be printed later in QuickBooks Online. + +![Check to print]({{site.url}}/assets/images/QBO3-Checktoprint.png){:width="100%"} + +## Journal entry + +This is a single itemized journal entry for each Expensify report. + +![Journal Entry]({{site.url}}/assets/images/QBO4-JournalEntry.png){:width="100%"} + +# Non-reimbursable expenses + +Non-reimbursable expenses export to QuickBooks Online as: + +- Credit Card expenses +- Debit Card Expenses +- Vendor Bills + +## Credit/debit card + +Using Credit/Debit Card Transactions: + +- Each expense will be exported as a bank transaction with its transaction date. +- If you split an expense in Expensify, we'll consolidate it into a single credit card transaction in QuickBooks with multiple line items posted to the corresponding General Ledger accounts. + +Pro-Tip: To ensure the payee field in QuickBooks Online reflects the merchant name for Credit Card expenses, ensure there's a matching Vendor in QuickBooks Online. Expensify checks for an exact match during export. If none are found, the payee will be mapped to a vendor we create and labeled as Credit Card Misc. or Debit Card Misc. + +![Expense]({{site.url}}/assets/images/QBO5-Expense.png){:width="100%"} + +If you centrally manage your company cards through Domains, you can export expenses from each card to a specific account in QuickBooks. + +## Vendor Bill + +- A single detailed vendor bill is generated for each Expensify report. If the accounting period is closed, the vendor bill will be posted on the first day of the next open period. If you choose to export non-reimbursable expenses as Vendor Bills, you can assign a default vendor to the bill. +- The export will use your default vendor if you have Default Vendor enabled. If the Default Vendor is disabled, the report's submitter will be set as the Vendor in QuickBooks. + +## Billable Expenses + +- In Expensify, you can designate expenses as billable. These will be exported to QuickBooks Online with the billable flag. This feature applies only to expenses exported as Vendor Bills or Checks. To maximize this functionality, ensure that any billable expense is associated with a Customer/Job. + +## Export Invoices + +If you are creating Invoices in Expensify and exporting these to QuickBooks Online, this is the account the invoice will appear against. + +# Configure coding for QuickBooks Online + +The coding tab is where your information is configured for Expensify; this will allow employees to code expenses and reports accurately. + +- Categories +- Classes and/or Customers/Projects +- Locations +- Items +- Tax + +## Categories + +QuickBooks Online expense accounts will be automatically imported into Expensify as Categories. + +## Account Import + +Equity type accounts will also be imported as categories. + +Important notes: + +- Other Current Liabilities can only be exported as Journal Entries if the submitter is set up as an Employee in QuickBooks. +- Exchange Gain or Loss detail type does not import. + +Recommended steps to take after importing the expense accounts from QuickBooks to Expensify: + +- Go to Settings > Workspaces > Groups > [Workspace Name] > Categories to see the accounts imported from QuickBooks Online. +- Use the enable/disable button to choose which Categories to make available to your employees, and set Category specific rules via the blue settings cog. +- If necessary, edit the names of imported Categories to make expense coding easier for your employees. (Please Note: If you make any changes to these accounts in QuickBooks Online, the category names on Expensify's side will revert to match the name of the account in QuickBooks Online the next time you sync). +- If you use Items in QuickBooks Online, you can import them into Expensify as Categories. + +Please note that each expense has to have a category selected to export to QuickBooks Online. The chosen category has to be imported from QuickBooks Online and cannot be manually created within the Workspace settings. + +## Classes and Customers/Projects + +If you use Classes or Customers/Projects in QuickBooks Online, you can import those into Expensify as Tags or Report Fields: + +- Tags let you apply a Class and/or Customer/Project to each expense. +- Report Fields enables you to apply a Class and/or Customer/Project to all expenses on a report. + +Note: Although Projects can be imported into Expensify and coded to expenses, due to the limitations of the QuickBooks API, expenses cannot be created within the Projects module in QuickBooks. + +## Locations + +Locations can be imported into Expensify as a Report Field or, if you export reimbursable expenses as Journal Entries and non-reimbursable expenses as Credit/Debit Card, you can import Locations as Tags. + +## Items + +If you use Items in QuickBooks Online, you can import Items defined with Purchasing Information (with or without Sales Information) into Expensify as Categories. + +## Tax + +- Using our tax tracking feature, you can assign a tax rate and amount to each expense. +- To activate tax tracking, go to connection configuration and enable it. This will automatically import purchasing taxes from QuickBooks Online into Expensify. +- After the connection is set, navigate to Settings > Workspaces > Groups > [Workspace Name] > Tax. Here, you can view the taxes imported from QuickBooks Online. +- Use the enable/disable button to choose which taxes are accessible to your employees. +- Set a default tax for the Company Workspace, which will automatically apply to all new expenses. +- Please note that, at present, tax cannot be exported to Journal Entries in QuickBooks Online. +- Expensify performs a daily sync to ensure your information is up-to-date. This minimizes errors from outdated QuickBooks Online data and saves you time on syncing. + +# How to configure advanced settings for QuickBooks Online + +The advanced settings are where functionality for automating and customizing the QuickBooks Online integration can be enabled. +Navigate to this section of your Workspace by following Settings > Workspaces > Group > [Workspace Name] > Connections > Configure button > Advanced tab. + +## Auto Sync +With QuickBooks Online auto-sync, once a non-reimbursable report is final approved in Expensify, it's automatically queued for export to QuickBooks Online. For expenses eligible for reimbursement with a linked business bank account, they'll sync when marked as reimbursed. + +## Newly Imported Categories + +This setting determines the default status of newly imported categories from QuickBooks Online to Expensify, either enabled or disabled. + +## Invite Employees + +Enabling this automatically invites all Employees from QuickBooks Online to the connected Expensify Company Workspace. If not, you can manually invite or import them using a CSV file. + +## Automatically Create Entities + +When exporting reimbursable expenses as Vendor Bills or Journal Entries, Expensify will automatically create a vendor in QuickBooks if one doesn't exist. It will also generate a customer when exporting Invoices. + +## Sync Reimbursed Reports + +Enabling this marks the Vendor Bill as paid in QuickBooks Online when you reimburse a report via ACH direct deposit in Expensify. If reimbursing outside Expensify, marking the Vendor Bill as paid will automatically in QuickBooks Online update the report as reimbursed in Expensify. Note: After enabling this feature, select your QuickBooks Account in the drop-down, indicating the bank account for reimbursements. + +## Collection Account + +If you are exporting Invoices from Expensify to Quickbooks Online, this is the account the Invoice will appear against once marked as Paid. + +# Deep Dive + +## Preventing Duplicate Transactions in QuickBooks + +When importing a banking feed directly into QuickBooks Online while also importing transactions from Expensify, it's possible to encounter duplicate entries in QuickBooks. To prevent this, follow these steps: + +Step 1: Complete the Approval Process in Expensify + +- Before exporting any expenses to QuickBooks Online, ensure they are added to a report and the report receives approval. Depending on your Workspace setup, reports may require approval from one or more individuals. The approval process concludes when the last user who views the report selects "Final Approve." + +Step 2: Exporting Reports to QuickBooks Online + +- To ensure expenses exported from Expensify match seamlessly in the QuickBooks Banking platform, make sure these expenses are marked as non-reimbursable within Expensify and that “Credit Card” is selected as the non-reimbursable export option for your expenses. + +Step 3: Importing Your Credit Card Transactions into QuickBooks Online + +- After completing Steps 1 and 2, you can import your credit card transactions into QuickBooks Online. These imported banking transactions will align with the ones brought in from Expensify. QuickBooks Online will guide you through the process of matching these transactions, similar to the example below: + +![Transactions]({{site.url}}/assets/images/QBO7-Transactions.png){:width="100%"} + +## Tax in QuickBooks Online + +If your country applies taxes on sales (like GST, HST, or VAT), you can utilize Expensify's Tax Tracking along with your QuickBooks Online tax rates. Please note: Tax Tracking is not available for Workspaces linked to the US version of QuickBooks Online. If you need assistance applying taxes after reports are exported, contact QuickBooks. + +To get started: + +- Go to Settings > Workspaces > Group > [Workspace Name] > Connections, and click Configure. +- Navigate to the Coding tab. +- Turn on **Tax**. +- Click Save. This imports the Tax Name and rate from QuickBooks Online. +- Visit Settings > Workspaces > Group > [Workspace Name] > Tax to view the imported taxes. +- Use the enable/disable button in the Tax tab to choose which taxes your employees can use. + +Remember, you can also set a default tax rate for the entire Workspace. This will be automatically applied to all new expenses. The user can still choose a different tax rate for each expense. + +Tax information can't be sent to Journal Entries in QuickBooks Online. Also, when dealing with multiple tax rates, where one receipt has different tax rates (like in the EU, UK, and Canada), users should split the expense into the respective parts and set the appropriate tax rate for each part. + +## Multi-currency + +When working with QuickBooks Online Multi-Currency, there are some things to remember when exporting Vendor Bills and Check! Make sure the vendor's currency and the Accounts Payable (A/P) bank account match. + +In QuickBooks Online, the currency conversion rates are not applied when exporting. All transactions will be exported with a 1:1 conversion rate, so for example, if a vendor's currency is CAD (Canadian Dollar) and the home currency is USD (US Dollar), the export will show these currencies without applying conversion rates. + +![Check]({{site.url}}/assets/images/QBO6-Check.png){:width="100%"} + +To correct this, you must manually update the conversion rate after the report has been exported to QuickBooks Online. + +Specifically for Vendor Bills: + +If multi-currency is enabled and the Vendor's currency is different from the Workspace currency, OR if QuickBooks Online home currency is foreign from the Workspace currency, then: + +- We create the Vendor Bill in the Vendor's currency (this is a QuickBooks Online requirement - we don't have a choice) +- We set the exchange rate between the home currency and the Vendor's currency +- We convert line item amounts to the vendor's currency + +Let's consider this example: + +- QuickBooks Online home currency is USD +- Vendor's currency is VND +- Workspace (report) currency is JPY + +Upon export, we: + +1. Specified the bill is in VND +2. Set the exchange rate between VND and USD (home currency), computed at the time of export. +3. Converted line items from JPY (currency in Expensify) to VND +4. QuickBooks Online automatically computed the USD amount (home currency) based on the exchange rate we specified +5. Journal Entries, Credit Card, and Debit Card: + +Multi-currency exports will fail as the account currency must match both the vendor and home currencies. + +## Report Fields + +Report fields are a handy way to collect specific information for a report tailored to your organization's needs. They can specify a project, business trip, client, location, and more! + +When integrating Expensify with Your Accounting Software, you can create your report fields in your accounting software so the next time you sync your Workspace, these fields will be imported into Expensify. + +To select how a specific field imports to Expensify, head to Settings > Workspaces > Group > +[Workspace Name] > Connections > Accounting Integrations > QuickBooks Online > Configure > Coding. + +Here are the QuickBooks Online fields that can be mapped as a report field within Expensify: + +- Classes +- Customers/Projects +- Locations + +# FAQ + +## What happens if the report can't be exported to QuickBooks Online automatically? + +If a report encounters an issue during automatic export to QuickBooks Online, you'll receive an email with details about the problem, including any specific error messages. These messages will also be recorded in the report's history section. + +The report will be placed in your Home for your attention. You can address the issues there. If you need further assistance, refer to our QuickBooks Online Export Errors page or export the report manually. + +## How can I ensure that I final approve reports before they're exported to QuickBooks Online? + +To ensure reports are reviewed before export, set up your Workspaces with the appropriate workflow in Expensify. Additionally, consider changing your Workspace settings to enforce expense Workspace workflows strictly. This guarantees that your Workspace's workflow is consistently followed. + +## What happens to existing approved and reimbursed reports if I enable Auto Sync? + +- If Auto Sync was disabled when your Workspace was linked to QuickBooks Online, enabling it won't impact existing reports that haven't been exported. +- If a report has been exported and reimbursed via ACH, it will be automatically marked as paid in QuickBooks Online during the next sync. +- If a report has been exported and marked as paid in QuickBooks Online, it will be automatically marked as reimbursed in Expensify during the next sync. +- Reports that have yet to be exported to QuickBooks Online won't be automatically exported. diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md b/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md similarity index 100% rename from docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md rename to docs/articles/expensify-classic/integrations/travel-integrations/Navan.md diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md b/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md index 3ee1c8656b4b..16da0c0caa5b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md @@ -1,5 +1,24 @@ --- -title: Coming Soon -description: Coming Soon +title: Uber integration +description: Connecting your Uber account to Expensify --- -## Resource Coming Soon! +## Overview + +Link Expensify directly to your Uber account so your Uber for Business receipts populate automatically in Expensify. + +# How to connect Uber to Expensify + +You can do this right in the Uber app: + +1. Head to Account > Business hub > Get started +2. Tap Create an individual account > Get started +3. Enter your business email and tap Next +4. Select the payment card you'd like to use for your business profile +5. Choose how frequently you’d like to receive travel summaries +6. Select Expensify as your expense provider +Expensify and Uber are now connected! + +Now, every time you use Uber for Business – be it for rides or meals – the receipt will be imported and scanned into Expensify automatically. + +![Uber integration set up steps: Connecting your account](https://help.expensify.com/assets/images/Uber1.png){:width="100%"} +![Uber integration set up steps: Selecting Expensify](https://help.expensify.com/assets/images/Uber2.png){:width="100%"} diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md index 3ee1c8656b4b..32ce41d3cbf3 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md @@ -1,5 +1,189 @@ --- -title: Coming Soon -description: Coming Soon +title: How To Manage Employees and Reports > Approving Reports +description: This page will help you understand the lifecycle of a report and how to approve reports that are submitted to you. --- -## Resource Coming Soon! +# About +This article provides a comprehensive guide on report management within our platform. From viewing, editing, and submitting your employees' Open reports to handling rejections and unapproving, as well as harnessing the power of our "Guided Review" feature. Additionally, we'll delve into best practices for Concierge, offering insights on how to streamline and automate your report approval processes for maximum efficiency. +Let's dive in! + + +# How-to manage reports +This section covers the most essential information a user needs to operate a feature i.e. what to click on. We’ll go over any action the user might take when configuring or using the feature, starting from configuration and moving to usage. + + +What options does a user have when configuring this feature? + + +What options does a user have then interacting with this feature? + + +What elements of this feature are pay-walled vs. free? + + +As a Workspace admin, you have the ability to view, edit, and submit your employees' Open reports. + + +We recommend beginning this process from the web version of Expensify because it offers more functionality compared to the mobile app. Here's how to get started: +Click on the "Reports" tab. +Select the "All Submitters" and "Open" filters. +This will display all employee reports on your Workspaces that have not yet been submitted. +​ +## Viewing Employee Reports +Viewing employee reports can vary depending on whether you're using the web or mobile versions of Expensify. We generally recommend using the web version for this purpose, as it offers the following advantages: + + +You will only receive reports directly submitted to you when using the mobile app. + + +The option to filter reports via the Reports page is exclusively available in the web version, making it more convenient when reviewing multiple reports during a session. +​ +## Viewing employee reports on the mobile app +When using the mobile app to view reports, please note the following: + + +Tapping on the Reports list will only display your own reports; you won't see reports from other Workspace members. + + +To view another Workspace member's report in the Expensify app, it must be submitted directly to you, and you must access it through a link from an email or via Home. + + +When you access a report in this manner, you will have the option to approve/reject it or go through the review process if there are expenses that require your attention. + + +Once you've approved or rejected the report, it won't be accessible in the app anymore. To view it again, please visit the website and follow the steps mentioned above. +​ +## Editing employee reports +If a report has been submitted directly to you, follow these steps to edit the expense details. Please note that you cannot change the expense amount; to make changes affecting the report total, you must reject it and return it to the employee. + + +Here's what to do: +- Click on any expense within the report to edit the expense details. +- Remember that you cannot modify the expense amount directly. To make changes affecting the report total, reject the report, and it will be sent back to the employee for revisions. +- If you're a Workspace admin and need to edit a report that wasn't submitted directly to you, use the "Take Control" button at the top of the report. Keep in mind that taking control of a report will disrupt the approval workflow. +​ +Additionally, here are some other editing options for Admins: +- Undelete deleted company card expenses via the Reconciliation Dashboard (requires Domain Admin privileges). +- Add unreported company card expenses to an existing Open (unsubmitted) report or create a new report via the Reconciliation Dashboard (requires Domain Admin privileges). +- Add or modify expense coding, including Category, Tag(s), and Attendees. +- Attach a receipt to an expense that doesn't have one. +- Move card expenses between two Open (unsubmitted) reports. +- Merge duplicate expenses (only applicable if they are not card transactions). +- Change the Workspace associated with a report.​ + + +## Submitting Employee Reports +As a Workspace Admin, you have the option to submit any of your employee's Open reports. If an employee is unable to do it themselves, a Workspace admin can submit an expense report on their behalf to initiate the approval process. Follow these steps: +Click the "Submit" button located at the top of the report. + + +## Report History and Comments +Please keep in mind that any changes made by the admin are tracked under "Report History and Comments." If you change the reimbursable status of an expense (e.g., from Reimbursable to Non-Reimbursable), an email notification will be sent to the employee to notify them of this change. + + +## Rejecting or Unapproving a Report +If you need to reject a report that has been submitted to you or Unapprove a report that has already been approved. + + +To reject the report, click Reject rather than beginning the Review process. If there are multiple approvers involved, you can choose how far back to reject the report. + + +Rejecting a report will return the report back to the submitter in an Open status or, in the case of a multi-level approval workflow, back to the previous approver in a Processing status (awaiting their approval). You may need to do this if the submitter is not ready to submit the report, or perhaps the report as a whole needs to be rejected based on the configuration of your organization's expense Workspace. + + +## Unapprove a Report +You can click the red Unapprove button at the top of the report to undo approving a report. Keep in mind that you'll only see the Unapprove button if you're a report approver on an admin that has taken control of the report.​ + + +## Marking a Report as Reimbursed Outside of Expensify +If you are reimbursing reports via paper check, through payroll or any other method that takes place outside of Expensify, you'll want to keep track of which reports have been taken care of by marking reports as reimbursed. + + +1. Log into your Expensify account using your preferred web browser, (ie: Chrome or Safari) +2. Head to your Reports page and locate the report +3. Click the report name to open it +4. Click on Reimburse +5. Choose "I'll do it manually - just mark it as reimbursed". This will change the report status to Reimbursed +6. The submitter can then go into the report and confirm that they received the reimbursement by clicking the button at the top of the report. +7. This will change the report status to Reimbursed: CONFIRMED + + +# How to Use Guided Review to Approve Reports +Guided Review helps alert you to what might be out-of-Workspace for an Expense Report. You'll be guided through all report violations and warnings and given the option to Reject or Edit items that need review prior to approving a report. + + +Guided Review helps approvers quickly identify reports that need more attention so they can pass over reports that can be quickly approved. Both Submitters and Approvers have actionable notifications for the following: violations, warnings, and notices. These notifications are important since they will be included in “review mode” for the approver to make clear approve or reject decisions. + + +Via the Website:​ +1. Simply click Review at the top left of the report and the system will begin to walk you through the entire report. +2. Choose to Reject, View, or skip over an item needing review. If you wish to stop the process at any time, click the X in the progress bar in the top right corner. +Reject: This will remove the expense from the report and send it back to the submitter. An email will be sent to the submitter explaining this expense has been rejected. +View: This will allow you to open the expense so you can view and fix any incorrect data. +Next: This will allow you to skip over the current item and move forward to review the rest of the report. +Finish: Click this to finish reviewing the report! +3. Click the Finish button if you are done reviewing, or reject/edit the last item to finish the review process. +4. Approve the report! Approve and Forward the report if there is another person who needs to review the report in your approval workflow, or you can Final Approve if you are the final approver. Note: When in Guided Review, you'll automatically Approve the report adhering to your Company's Approval Workflow once you Approve the final expense on the report. You'll then be immediately taken to the next report requiring your attention - making Approving multiple expenses a quick and painless process! + + + + +Via the Mobile App:​ +1. From Home, under Reports that need your attention, click Begin Review, and the system will bring you to the first expense on the oldest report in Home. +2. Edit the expense: Make any necessary edits to the expense by tapping the corresponding field. Be sure to address any Violations and Notes on the expense! Notes are indicated at the top of the expense with a yellow exclamation point, while violations appear on the expense with a red exclamation point: +3. Choose Reject or Accept at the top of the expense. + + +Reject: This will remove the expense from the report and send it back to the submitter. An email will be sent to the submitter explaining this expense has been rejected, and a comment will be added to the report it was rejected from. If this is the only expense on the report, the entire report will be rejected (and the expense will remain on the report). + + +If Scheduled Submit is being used, rejected expenses will auto-report to the next Open report on the Workspace (as if it were a new expense). If an open report doesn't exist, Concierge will create a new one. +​ + + +If Scheduled Submit is not being used, any rejected expenses will be Unreported in the submitter's account and need to be manually applied to a new report. +​ +Accept: This will move to the next expense on the report, leaving behind any outstanding violations or notes. If this is the last expense on the report, you'll be all done! +Once you've made it through all of the expenses on the report, you'll be all set! + + +# Deep Dive +## Concierge Report Management + + +Concierge report approval removes the need for you to manually click "Approve" on endless reports! Instead, you can set up your group Workspace to capture all the requirements you have for your team's expenses. As long as all the rules have been followed and Concierge's additional audit is passed (more below), we will automatically approve such reports on behalf of the approver after submission. +​ +Before you start: +Ensure are a Workspace admin on a group Workspace +Set your workflow to Submit-and-Approve or Advanced Approval workflow​ + + +## Then follow these steps: +Set up your group Workspace so that all of your expense requirements are defined. Setting automatic categories for employees and category rules (e.g., maximum amounts, receipt requirements, etc.) are great examples! + + +Navigate to Settings > Workspaces > Group > [Workspace Name] > Members.​ + + +Scroll down to Approval Mode and select either Submit-and-Approve or Advanced Approval. + + +Under Expense Approvals, select a Manual Approval Threshold greater than $0.​ + + +With this setup, manual approval will only be required: +- For reports that fail audit (i.e. there is at least one Workspace violation on the report) +- For reports that contain at least one expense over the Manual Approval Threshold +- For any percentage of reports that you'd like to spot-check (this is set at 5% or 1 in 20 by default). +- If the report meets all of the requirements you specify in your Workspace settings and all expenses are under the Manual Approval Threshold, then Concierge will automatically move your report through each step of your designated approval workflow (unless it's routed for a spot-check).​ + + + + +## Concierge Receipt Audit +Concierge Receipt Audit is a real-time audit and compliance of receipts submitted by employees and Workspace users. Concierge checks every receipt for accuracy and compliance, flagging any expenses that seem fishy before expense reports are even submitted for approval. All risky expenses are highlighted for manual review, leaving you with more control over and visibility into employee expenses. + + +1. Concierge will SmartScan every receipt to verify the data input by the user matches the currency, date, and amount on the physical receipt. +2. After the report is submitted for approval, Concierge highlights any differences between the SmartScanned values and the employee's chosen input. +3. Each receipt that has been verified will show the "Verified" logo. + diff --git a/docs/articles/expensify-classic/send-payments/Pay-Bills.md b/docs/articles/expensify-classic/send-payments/Pay-Bills.md index 41c0146126ba..8a5c7c5c7f88 100644 --- a/docs/articles/expensify-classic/send-payments/Pay-Bills.md +++ b/docs/articles/expensify-classic/send-payments/Pay-Bills.md @@ -1,5 +1,110 @@ --- title: Pay Bills -description: Pay Bills +description: How to receive and pay company bills in Expensify --- -## Resource Coming Soon! + + +# Overview +Simplify your back office by receiving bills from vendors and suppliers in Expensify. Anyone with or without an Expensify account can send you a bill, and Expensify will file it as a Bill and help you issue the payment. + +# How to Receive Vendor or Supplier Bills in Expensify + +There are three ways to get a vendor or supplier bill into Expensify: + +**Option 1:** Have vendors send bills to Expensify directly: Ask your vendors to email all bills to your Expensify billing intake email. + +**Option 2:** Forward bills to Expensify: If your bills are emailed to you, you can forward those bills to your Expensify billing intake email yourself. + +**Option 3:** Manually upload bills to Expensify: If you receive physical bills, you can manually create a Bill in Expensify on the web from the Reports page: +1. Click **New Report** and choose **Bill** +2. Add the expense details and vendor's email address to the pop-up window +3. Upload a pdf/image of the bill +4. Click **Submit** + +# How to Pay Bills + +There are multiple ways to pay Bills in Expensify. Let’s go over each method below: + +## ACH bank-to-bank transfer + +To use this payment method, you must have a business bank account connected to your Expensify account. + +To pay with an ACH bank-to-bank transfer: + +1. Sign in to your Expensify account on the web at www.expensify.com. +2. Go to the Inbox or Reports page and locate the Bill that needs to be paid. +3. Click the **Pay** button to be redirected to the Bill. +4. Choose the ACH option from the drop-down list. +5. Follow the prompts to connect your business bank account to Expensify. + +**Fees:** None + +## Pay using a credit or debit card + +This option is available to all US and International customers receiving an bill from a US vendor with a US business bank account. + +To pay with a credit or debit card: +1. Sign-in to your Expensify account on the web app at www.expensify.com. +2, Click on the Bill you’d like to pay to see the details. +3, Click the **Pay** button. +4. You’ll be prompted to enter your credit card or debit card details. + +**Fees:** Includes 2.9% credit card payment fee + +## Venmo + +If both you and the vendor have Venmo setup in their Expensify account, you can opt to pay the bill through Venmo. + +**Fees:** Venmo charges a 3% sender’s fee + +## Pay Outside of Expensify + +If you are not able to pay using one of the above methods, then you can mark the Bill as paid manually in Expensify to update its status and indicate that you have made payment outside Expensify. + +To mark a Bill as paid outside of Expensify: + +1. Sign-in to your Expensify account on the web app at www.expensify.com. +2. Click on the Bill you’d like to pay to see the details. +3. Click on the **Reimburse** button. +4. Choose **I’ll do it manually** + +**Fees:** None + +# FAQ + +## What is my company's billing intake email? +Your billing intake email is [yourdomain.com]@expensify.cash. Example, if your domain is `company.io` your billing email is `company.io@expensify.cash`. + +## When a vendor or supplier bill is sent to Expensify, who receives it? + +Bills are received by the Primary Contact for the domain. This is the email address listed at **Settings > Domains > Domain Admins**. + +## Who can view a Bill in Expensify? + +Only the primary contact of the domain can view a Bill. + +## Who can pay a Bill? + +Only the primary domain contact (owner of the bill) will be able to pay the Mill. + +## How can you share access to Bills? + +To give others the ability to view a Bill, the primary contact can manually “share” the Bill under the Details section of the report via the Sharing Options button. +To give someone else the ability to pay Bills, the primary domain contact will need to grant those individuals Copilot access to the primary domain contact's account. + +## Is Bill Pay supported internationally? + +Payments are currently only supported for users paying in United States Dollars (USD). + +## What’s the difference between a Bill and an Invoice in Expensify? + +A Bill is a payable which represents an amount owed to a payee (usually a vendor or supplier), and is usually created from a vendor invoice. An Invoice is a receivable, and indicates an amount owed to you by someone else. + +# Deep Dive: How company bills and vendor invoices are processed in Expensify + +Here is how a vendor or supplier bill goes from received to paid in Expensify: + +1. When a vendor or supplier bill is received in Expensify via, the document is SmartScanned automatically and a Bill is created. The Bill is owned by the primary domain contact, who will see the Bill on the Reports page on their default group policy. +2. When the Bill is ready for processing, it is submitted and follows the primary domain contact’s approval workflow. Each time the Bill is approved, it is visible in the next approver's Inbox. +3. The final approver pays the Bill from their Expensify account on the web via one of the methods. +4. The Bill is coded with the relevant imported GL codes from a connected accounting software. After it has finished going through the approval workflow the Bill can be exported back to the accounting package connected to the policy. diff --git a/docs/articles/new-expensify/account-settings/Coming-Soon.md b/docs/articles/new-expensify/account-settings/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/account-settings/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/account-settings/Profile.md b/docs/articles/new-expensify/account-settings/Profile.md new file mode 100644 index 000000000000..908cf39c7ac6 --- /dev/null +++ b/docs/articles/new-expensify/account-settings/Profile.md @@ -0,0 +1,92 @@ +--- +title: Profile +description: How to manage your Expensify Profile +--- +# Overview +Your Profile in Expensify allows you to: +- Set your public profile photo +- Set a display name +- Manage your contact methods +- Communicate your current status +- Set your pronouns +- Configure your timezone +- Store your personal details (for travel and payment purposes) + +# How to set your public profile photo + +To set or update your profile photo: +1. Go to **Settings > Profile** +2. Tap on the default or your existing profile photo, +3. You can either either upload (to set a new profile photo), remove or view your profile photo + +Your profile photo is visible to all Expensify users. + +# How to set a display name + +To set or update your display name: +1. Go to **Settings > Profile** +2. Tap on **Display name** +3. Set a first name and a last name, then **Save** + +Your display name is public to all Expensify users. + +# How to add or remove contact methods (email address and phone number) + +Your contact methods allow people to contact you (using your email address or phone number), and allow you to forward receipts to receipts@expensify.com from multiple email addresses. + +To manage your contact methods: +1. Go to **Settings > Profile** +2. Tap on **Contact method** +3. Tap **New contact method** to add a new email or phone number + +Your default contact method (email address or phone number) will be visible to "known" users, with whom you have interacted or are part of your team. + +To change the email address or phone number that's displayed on your Expensify account, add a new contact method, then tap on that email address and tap **Set as default**. + +# How to communicate your current status + +You can use your status emoji to communicate your mood, focus or current activity. You can optionally add a status message too! + +To set your status emoji and status message: +1. Go to **Settings > Profile** +2. Tap on **Status** then **Status** +3. Choose a status emoji, and optionally set a status message +4. Tap on **Save** + +Your status emoji will be visible next to your name in Expensify, and your status emoji and status message will appear in your profile (which is public to all Expensify users). On a computer, your status message will also be visible by hovering your mouse over your name. + +You can also remove your current status: +1. Go to **Settings > Profile** +2. Tap on **Status** +3. Tap on **Clear status** + +# How to set your pronouns + +To set your pronouns: +1. Go to **Settings > Profile** +2. Tap on **Pronouns** +3. Search for your preferred pronouns, then tap on your choice + +Your pronouns will be visible to "known" users, with whom you have interacted or are part of your team. + +# How to configure your timezone + +Your timezone is automatically set using an estimation based on your IP address. + +To set your timezone manually: +1. Go to **Settings > Profile** +2. Tap on **Timezone** +3. Disable **Automatically determine your location** +4. Tap on **Timezone** +5. Search for your preferred timezone, then tap on your choice + +Your timezone will be visible to "known" users, with whom you have interacted or are part of your team. + +# How to store your personal details (for travel and payment purposes) + +Your personal details can be used in Expensify for travel and payment purposes. These will not be shared with any other Expensify user. + +To set your timezone manually: +1. Go to **Settings > Profile** +2. Tap on **Personal details** +3. Tap on **Legal name**, **Date of birth**, and **Address** to set your personal details diff --git a/docs/articles/new-expensify/getting-started/Security.md b/docs/articles/new-expensify/account-settings/Security.md similarity index 100% rename from docs/articles/new-expensify/getting-started/Security.md rename to docs/articles/new-expensify/account-settings/Security.md diff --git a/docs/articles/new-expensify/bank-accounts-and-credit-cards/Coming-Soon.md b/docs/articles/new-expensify/bank-accounts-and-credit-cards/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/bank-accounts-and-credit-cards/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md b/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md new file mode 100644 index 000000000000..de66315f2d79 --- /dev/null +++ b/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md @@ -0,0 +1,142 @@ +--- +title: Connect a Business Bank Account - US +description: How to connect a business bank account to Expensify (US) +--- +# Overview +Adding a verified business bank account unlocks a myriad of features and automation in Expensify. +Once you connect your business bank account, you can: +- Reimburse expenses via direct bank transfer +- Pay bills +- Collect invoice payments +- Issue the Expensify Card + +# How to add a verified business bank account +To connect a business bank account to Expensify, follow the below steps: +1. Go to **Settings > Workspaces > _Workspace Name_ > Bank account > Connect bank account** +2. Click **Connect online with Plaid** +3. Click **Continue** +4. When you reach the **Plaid** screen, you'll be shown a list of compatible banks that offer direct online login access +5. Login to the business bank account: +- If the bank is not listed, click the X to go back to the connection type +- Here you’ll see the option to **Connect Manually** +- Enter your account and routing numbers +6. Enter your bank login credentials: +- If your bank requires additional security measures, you will be directed to obtain and enter a security code +- If you have more than one account available to choose from, you will be directed to choose the desired account + +Next, to verify the bank account, you’ll enter some details about the business as well as some personal information. + +## Enter company information +This is where you’ll add the legal business name as well as several other company details. + +- **Company address**: The company address must be located in the US and a physical location (If you input a maildrop address, PO box, or UPS Store, the address will be flagged for review, and adding the bank account to Expensify will be delayed) +- **Tax Identification Number**: This is the identification number that was assigned to the business by the IRS +- **Company website**: A company website is required to use most of Expensify’s payment features. When adding the website of the business, format it as, https://www.domain.com +- **Industry Classification Code**: You can locate a list of Industry Classification Codes [here]([url](https://www.census.gov/naics/?input=software&year=2022)) + +## Enter personal information +Whoever is connecting the bank account to Expensify, must enter their details under the Requestor Information section: +- The address must be a physical address +- The address must be located in the US +- The SSN must be US-issued + +This does not need to be a signor on the bank account. If someone other than the Expensify account holder enters their personal information in this section, the details will be flagged for review, and adding the bank account to Expensify will be delayed. + +## Upload ID +After entering your personal details, you’ll be prompted to click a link or scan a QR code so that you can do the following: +1. Upload a photo of the front and back of your ID (this cannot be a photo of an existing image) +2. Use your device to take a selfie and record a short video of yourself + +**Your ID must be:** +- Issued in the US +- Current (ie: the expiration date must be in the future) + +## Additional Information +Check the appropriate box under **Additional Information**, accept the agreement terms, and verify that all of the information is true and accurate: +- A Beneficial Owner refers to an **individual** who owns 25% or more of the business. +- If you or another **individual** owns 25% or more of the business, please check the appropriate box +- If someone else owns 25% or more of the business, you will be prompted to provide their personal information + +If no individual owns more than 25% of the company you do not need to list any beneficial owners. In that case, be sure to leave both boxes unchecked under the Beneficial Owner Additional Information section. + +# How to validate the bank account + +The account you set up can be found under **Settings > Workspaces > _Workspace Name_ > Bank account** in either the **Verifying** or **Pending** state. + +If it is **Verifying**, then this means we sent you a message and need more information from you. Please review the automated message sent by Concierge. This should include a message with specific details about what's required to move forward. + +If it is **Pending**, then in 1-2 business days Expensify will administer 3 test transactions to your bank account. If after two business days you do not see these test transactions, reach out to Concierge for assistance. + +After these transactions (2 withdrawals and 1 deposit) have been processed to your account, head to the **Bank accounts** section of your workspace settings. Here you'll see a prompt to input the transaction amounts. + +Once you've finished these steps, your business bank account is ready to use in Expensify! + +# How to delete a verified bank account +If you need to delete a bank account from Expensify, run through the following steps: +1. Go to **Settings > Workspaces > _Workspace Name_ > Bank account** +2. Click the red **Delete** button under the corresponding bank account + +# Deep Dive + +## Verified bank account requirements + +To add a business bank account to issue reimbursements via ACH (US), to pay invoices (US), or to issue Expensify Cards: +- You must enter a physical address for yourself, any Beneficial Owner (if one exists), and the business associated with the bank account. We **cannot** accept a PO Box or MailDrop location. +- If you are adding the bank account to Expensify, you must add it from **your** Expensify account settings. +- If you are adding a bank account to Expensify, we are required by law to verify your identity. Part of this process requires you to verify a US-issued photo ID. For using features related to US ACH, your ID must be issued by the United States. You and any Beneficial Owner (if one exists), must also have a US address +- You must have a valid website for your business to utilize the Expensify Card, or to pay invoices with Expensify. + +## Locked bank account +When you reimburse a report, you authorize Expensify to withdraw the funds from your account. If your bank rejects Expensify’s withdrawal request, your verified bank account is locked until the issue is resolved. + +Withdrawal requests can be rejected due to insufficient funds, or if the bank account has not been enabled for direct debit. +If you need to enable direct debits from your verified bank account, your bank will require the following details: +- The ACH CompanyIDs (1270239450, 4270239450 and 2270239450) +- The ACH Originator Name (Expensify) + +To request to unlock the bank account, go to **Settings > Workspaces > _Workspace Name_ > Bank account** and click **Fix.** This sends a request to our support team to review why the bank account was locked, who will send you a message to confirm that. + +Unlocking a bank account can take 4-5 business days to process, to allow for ACH processing time and clawback periods. + +## Error adding an ID to Onfido + +Expensify is required by both our sponsor bank and federal law to verify the identity of the individual who is initiating the movement of money. We use Onfido to confirm that the person adding a payment method is genuine and not impersonating someone else. + +If you get a generic error message that indicates, "Something's gone wrong", please go through the following steps: + +1. Ensure you are using either Safari (on iPhone) or Chrome (on Android) as your web browser. +2. Check your browser's permissions to make sure that the camera and microphone settings are set to "Allow" +3. Clear your web cache for Safari (on iPhone) or Chrome (on Android). +4. If using a corporate Wi-Fi network, confirm that your corporate firewall isn't blocking the website. +5. Make sure no other apps are overlapping your screen, such as the Facebook Messenger bubble, while recording the video. +6. On iPhone, if using iOS version 15 or later, disable the Hide IP address feature in Safari. +7. If possible, try these steps on another device +8. If you have another phone available, try to follow these steps on that device +If the issue persists, please contact your Account Manager or Concierge for further troubleshooting assistance. + +# FAQ +## What is a Beneficial Owner? + +A Beneficial Owner refers to an **individual** who owns 25% or more of the business. If no individual owns 25% or more of the business, the company does not have a Beneficial Owner. + +## What do I do if the Beneficial Owner section only asks for personal details, but my organization is owned by another company? + +Please only indicate you have a Beneficial Owner, if it is an individual that owns 25% or more of the business. + +## Why can’t I input my address or upload my ID? + +Are you entering a US address? When adding a verified business bank account in Expensify, the individual adding the account, and any beneficial owner (if one exists) are required to have a US address, US photo ID, and a US SSN. If you do not meet these requirements, you’ll need to have another admin add the bank account, and then share access with you once verified. + +## Why am I asked for documents when adding my bank account? + +When a bank account is added to Expensify, we complete a series of checks to verify the information provided to us. We conduct these checks to comply with both our sponsor bank's requirements and federal government regulations, specifically the Bank Secrecy Act / Anti-Money Laundering (BSA / AML) laws. Expensify also has anti-fraud measures in place. +If automatic verification fails, we may request manual verification, which could involve documents such as address verification for your business, a letter from your bank confirming bank account ownership, etc. + +If you have any questions regarding the documentation request you received, please contact Concierge and they will be happy to assist. + +## I don’t see all three microtransactions I need to validate my bank account. What should I do? + +It's a good idea to wait till the end of that second business day. If you still don’t see them, please reach out to your bank and ask them to whitelist our ACH IDs **1270239450**, **4270239450**, and **2270239450**. Expensify’s ACH Originator Name is "Expensify". + +Make sure to reach out to your Account Manager or Concierge once that's all set, and our team will be able to re-trigger those three test transactions! + diff --git a/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md b/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md index e157ede1969d..3b79072aa393 100644 --- a/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md +++ b/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md @@ -30,16 +30,38 @@ Once you’ve completed your company setup, you should have completed the follow - Invited members to the workspace - Assigned Expensify Cards -# Inviting Members to the Free Plan: +# Inviting Members to the Free Plan - Navigate to the Settings Menu and click **_Members_** to invite your team. You can invite employees one at a time, or you can invite multiple users by listing out their email addresses separated by a comma - To use the Expensify Card, you must invite them to your workspace via your company email address (i.e., admin@companyemail.com and NOT admin@gmail.com). # Managing the Free Plan -To access your workspace settings, click your profile icon and then on your workspace name. +## Workspace Settings -This settings menu allows you to manage your workspace members, issue additional Expensify Cards, and utilize this plan’s various bill pay and payment options. +To access your workspace settings, click your profile icon and then on your workspace name. This settings menu allows you to manage your workspace members, issue additional Expensify Cards, and utilize this plan’s various bill pay and payment options. + +## Paying an Expense Report +- Once a user creates an expense it will automatically be shared with you in a Processing report. +- Pay expenses directly through Expensify by choosing ‘Reimburse > via Direct Deposit (ACH)` in a report on www.expensify.com or by choosing ‘Pay with Expensify’ in a payment request on new.expensify.com. +- Notify your user that you’ll pay them manually outside of Expensify by choosing ‘Reimburse > I’ll do it manually’ in a report on www.expensify.com or choosing ‘Pay Elsewhere’ in a payment request on new.expensify.com. +- Reports with only non-reimbursable expenses on them have the option to ‘Mark as Closed’ in the report on www.expensify.com or ‘Mark as Done’ in the payment request on new.expensify.com. + +## Changing Submitted Expenses + +Request an edit an expense or remove an expense before you pay, you can let your user know by making a comment in the Report History section of their Processing report or chatting with them on new.expensify.com. + +# Managing Expenses + +## Creating an Expense +- You can create an expense either by swiping the Expensify card or just smartscan a receipt! +- Once you create an expense it will be automatically added to a report and shared with your admin. +- You can edit or delete any expense that hasn’t been paid or closed by your admin. + +## Getting paid for Expenses +- Automatic submission is already set up, so your admin can pay you back immediately once you create an expense. +- Your admin will get a notification when you send them a new expense, but you can also remind them to pay you by making a comment in the Report History section of your Processing report or chatting with them on new.expensify.com. # FAQs + ## Do I need a business bank account to use the Free Plan? You will need a US business checking account if you want to enable the Expensify Card and set up direct ACH reimbursement. @@ -50,9 +72,27 @@ If you're not in the US, you can still use the Free Plan, but the Expensify Card The Expensify Workplace only allows for one admin (the workspace creator). -## Scheduled Submit is set to weekly on the Free Plan. Can I change this? +## I am on a paid plan, can I switch to a Free Plan? + +You can set up a Free Plan, but you must honor any active subscription you have also. If you're on a paid plan, it is likely you want more functionality than what the Free Plan offers such as a direct connection with an accounting integration and approval workflows. + +## Can I get cashback on Expensify Card purchases if I have a free plan? + +You can get 1% credited back to your settlement account once you spend over $25,000 per month across all cards and 2% when you spend over $250,000! -No, expense reports on the Free Plan submit weekly, and there is no way to customize approval settings. +## Can I switch the workspace currency on the Free Plan? It looks set to USD + +Yes, you can change the currency of the Free Plan by going to Avatar > [Workspace Name] > General settings > Default currency. + +We do require a US business bank account for reimbursements and Expensify Card settlements though, so if you have a business bank account linked to your account, then the currency of the Free Plan will be USD. + +## Is a free plan available to people outside the USA? + +Yes! You can use the free plan anywhere in the world to track expenses, send invoices etc. Just remember, anything that requires a verified business bank account (such as ACH reimbursement and the Expensify Card) is only available to those with a US checking account! + +## Can I integrate the free plan with my accounting package? + +No. In order to use our accounting sync, you will need to update to a paid plan ## With the Free Plan, can I add my own categories? @@ -60,4 +100,48 @@ Categories are standardized on the Free Plan and can’t be edited. Custom categ ## With the Free Plan, can I export reports using a custom format? -The Free Plan offers standard report export formats. You'll need to upgrade to a paid plan to create a custom export format. \ No newline at end of file +The Free Plan offers standard report export formats. You'll need to upgrade to a paid plan to create a custom export format. + +## Can I change the mileage rate or unit used for distance tracking? + +Yes. The workspace admin can access the rate and unit settings by going to Avatar > [Workspace name] > Reimburse expenses > Track distance. + +## Can I add non-Expensify cardholders to my Workspace? + +Yes. You can invite any user to your Workspace. Just click invite and enter their email and they will be invited to download the app and join! + +## Expenses are automatically shared with the admin on a Processing report on the Free Plan, can I change this? + +No. Expense reports submitted on the Free Plan are set to submit automatically and do not allow for approvals. Different Scheduled Submit settings are available on our paid plans. + +## How do I give a user I invited to my Workspace an Expensify Card? + +You can give a user an Expensify Card by going to the Company Cards Page on expensify.com and setting a card limit >$0. Please note that in order to give a user a card, they must be using a private company email address (i.e. name@companyname.com NOT name@gmail.com) + +## Can I use a different bank account to the one I have added for some of the features in the workspace? + +No. The bank account you have added will be used to issue corporate cards, reimburse expenses, collect invoices, and pay bills! + +## Can I upgrade my Free Workspace to a Paid Workspace or do I need to create a new one? + +There is no way to upgrade a workspace, so you would need to create a new Workspace. Paid workspaces have more functionalities than what the Free Plan offers, such as a direct connection with an accounting integration and approval workflows. + +## Can I create more than one Processing report at a time? + +No. To keep things simple, we only allow one Processing report per user at a time. If you need to have more than one report at a time, our paid plans support unlimited reports. + +## A user has added an expense I need to change before I pay it, how do I let them know? + +Users can edit and delete expenses on Processing reports. If you need something changed, let them know by commenting in the Report History section of the report on expensify.com or by chatting with them in new.expensify.com. + +## Can I ‘Reopen’ a report once it’s Reimbursed or Closed? + +No. Once an admin reimburses or closes a report, it cannot be ‘reopened’, but you can always comment on a report to add context. + +## I accidentally reimbursed a report too soon. Can I cancel the reimbursement? + +Depending on how quickly you report it to us, we may be able to help cancel a reimbursement. Chat Concierge to see if we can help cancel a reimbursement. + +## As an admin, can I edit users’ expenses and delete them from reports? + +No. Only users can edit and delete expenses on the Free plan. Admin control of submitted expenses on a workspace is a feature of our paid plans. If you need something changed, let the user know by commenting in the Report History section of the report on www.expensify.com or by chatting with them in new.expensify.com. diff --git a/docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Admins.md b/docs/articles/new-expensify/chat/Expensify-Chat-For-Admins.md similarity index 97% rename from docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Admins.md rename to docs/articles/new-expensify/chat/Expensify-Chat-For-Admins.md index 17c7a60b8e5a..5128484adc9d 100644 --- a/docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Admins.md +++ b/docs/articles/new-expensify/chat/Expensify-Chat-For-Admins.md @@ -1,7 +1,6 @@ --- title: Expensify Chat for Admins description: Best Practices for Admins settings up Expensify Chat -redirect_from: articles/other/Expensify-Chat-For-Admins/ --- # Overview diff --git a/docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Conference-Attendees.md b/docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Attendees.md similarity index 100% rename from docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Conference-Attendees.md rename to docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Attendees.md diff --git a/docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Conference-Speakers.md b/docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Speakers.md similarity index 100% rename from docs/articles/new-expensify/getting-started/chat/Expensify-Chat-For-Conference-Speakers.md rename to docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Speakers.md diff --git a/docs/articles/new-expensify/getting-started/chat/Expensify-Chat-Playbook-For-Conferences.md b/docs/articles/new-expensify/chat/Expensify-Chat-Playbook-For-Conferences.md similarity index 100% rename from docs/articles/new-expensify/getting-started/chat/Expensify-Chat-Playbook-For-Conferences.md rename to docs/articles/new-expensify/chat/Expensify-Chat-Playbook-For-Conferences.md diff --git a/docs/articles/new-expensify/getting-started/chat/Get-to-know-Expensify-Chat.md b/docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md similarity index 85% rename from docs/articles/new-expensify/getting-started/chat/Get-to-know-Expensify-Chat.md rename to docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md index da78061027fa..25ccdefad261 100644 --- a/docs/articles/new-expensify/getting-started/chat/Get-to-know-Expensify-Chat.md +++ b/docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md @@ -1,5 +1,5 @@ --- -title: Get to know Expensify Chat +title: Introducing Expensify Chat description: Everything you need to know about Expensify Chat! redirect_from: articles/other/Everything-About-Chat/ --- @@ -24,30 +24,30 @@ After downloading the app, log into your new.expensify.com account (you’ll use ## How to send messages -Click **+** then **Send message** in New Expensify -Choose **Chat** -Search for any name, email or phone number -Select the individual to begin chatting +1. Click **+** then **Send message** in New Expensify +2. Choose **Chat** +3. Search for any name, email or phone number +4. Select the individual to begin chatting ## How to create a group -Click **+**, then **Send message** in New Expensify -Search for any name, email or phone number -Click **Add to group** -Group participants are listed with a green check -Repeat steps 1-3 to add more participants to the group -Click **Create chat** to start chatting +1. Click **+**, then **Send message** in New Expensify +2. Search for any name, email or phone number +3. Click **Add to group** +4. Group participants are listed with a green check +5. Repeat steps 1-3 to add more participants to the group +6. Click **Create chat** to start chatting ## How to create a room -Click **+**, then **Send message** in New Expensify -Click **Room** -Enter a room name that doesn’t already exist on the intended Workspace -Choose the Workspace you want to associate the room with. -Choose the room’s visibility setting: -Private: Only people explicitly invited can find the room* -Restricted: Workspace members can find the room* -Public: Anyone can find the room +1. Click **+**, then **Send message** in New Expensify +2. Click **Room** +3. Enter a room name that doesn’t already exist on the intended Workspace +4. Choose the Workspace you want to associate the room with. +5. Choose the room’s visibility setting: +6. Private: Only people explicitly invited can find the room* +7. Restricted: Workspace members can find the room* +8. Public: Anyone can find the room *Anyone, including non-Workspace Members, can be invited to a Private or Restricted room. @@ -56,26 +56,29 @@ Public: Anyone can find the room You can invite people to a Group or Room by @mentioning them or from the Members pane. ## Mentions: -Type **@** and start typing the person’s name or email address -Choose one or more contacts -Input message, if desired, then send + +1. Type **@** and start typing the person’s name or email address +2. Choose one or more contacts +3. Input message, if desired, then send ## Members pane invites: -Click the **Room** or **Group** header -Select **Members** -Click **Invite** -Find and select any contact/s you’d like to invite -Click **Next** -Write a custom invitation if you like -Click **Invite** + +1. Click the **Room** or **Group** header +2. Select **Members** +3. Click **Invite** +4. Find and select any contact/s you’d like to invite +5. Click **Next** +6. Write a custom invitation if you like +7. Click **Invite** ## Members pane removals: -Click the **Room** or **Group** header -Select **Members** -Find and select any contact/s you’d like to remove -Click **Remove** -Click **Remove members** + +1. Click the **Room** or **Group** header +2. Select **Members** +3. Find and select any contact/s you’d like to remove +4. Click **Remove** +5. Click **Remove members** ## How to format text diff --git a/docs/articles/new-expensify/expense-and-report-features/Coming-Soon.md b/docs/articles/new-expensify/expense-and-report-features/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/expense-and-report-features/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/expensify-partner-program/Coming-Soon.md b/docs/articles/new-expensify/expensify-partner-program/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/expensify-partner-program/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/get-paid-back/Distance-Requests.md b/docs/articles/new-expensify/get-paid-back/Distance-Requests.md new file mode 100644 index 000000000000..91b88409be8b --- /dev/null +++ b/docs/articles/new-expensify/get-paid-back/Distance-Requests.md @@ -0,0 +1,27 @@ +--- +title: Distance Requests +description: How to create a distance request and request reimbursement for mileage +--- + + +# Overview + +Expensify allows you to request reimbursement for mileage by creating a distance request from a map. You can send a distance request in Expensify's mobile, desktop, or web app. + + +# How to create and send a distance request + +1. Click the green + button and select Request Money. +2. Select Distance along the top row of the Request Money window. +3. Enter the Start and Finish addresses then click Next. If there are multiple stops, you can add them before clicking Next. +4. Choose who to send the request to by selecting your organization's workspace from the list of recent workspaces. +5. On the confirmation page, confirm the amount, date, distance, and optionally add a description or category. Click the Request button. +6. A workspace admin will receive your request and can reimburse you through Expensify or elsewhere! + + + +# FAQs + +## Is there an easy way to reuse recent locations? + +Yes! We save your recently used locations and list them out on the page where you select the Start and Finish. diff --git a/docs/articles/new-expensify/getting-started/Referral-Program.md b/docs/articles/new-expensify/get-paid-back/Referral-Program.md similarity index 100% rename from docs/articles/new-expensify/getting-started/Referral-Program.md rename to docs/articles/new-expensify/get-paid-back/Referral-Program.md diff --git a/docs/articles/new-expensify/get-paid-back/Request-Money.md b/docs/articles/new-expensify/get-paid-back/Request-Money.md index a2b765915af0..43a72a075de7 100644 --- a/docs/articles/new-expensify/get-paid-back/Request-Money.md +++ b/docs/articles/new-expensify/get-paid-back/Request-Money.md @@ -1,6 +1,36 @@ --- -title: Request Money -description: Request Money +title: Request Money and Split Bills with Friends +description: Everything you need to know about Requesting Money and Splitting Bills with Friends! redirect_from: articles/request-money/Request-and-Split-Bills/ --- -## Resource Coming Soon! + + + +# How do these Payment Features work? +Our suite of money movement features enables you to request money owed by an individual or split a bill with a group. + +**Request Money** lets your friends pay you back directly in Expensify. When you send a payment request to a friend, Expensify will display the amount owed and the option to pay the corresponding request in a chat between you. + +**Split Bill** allows you to split payments between friends and ensures the person who settled the tab gets paid back. + +These two features ensure you can live in the moment and settle up afterward. + +# How to Request Money +- Select the Green **+** button and choose **Request Money** +- Enter the amount **$** they owe and click **Next** +- Search for the user or enter their email! +- Enter a reason for the request (optional) +- Click **Request!** +- If you change your mind, all you have to do is click **Cancel** +- The user will be able to **Settle up outside of Expensify** or pay you via **Venmo** or **PayPal.me** + +# How to Split a Bill +- Select the Green **+** button and choose **Split Bill** +- Enter the total amount for the bill and click **Next** +- Search for users or enter their emails and **Select** +- Enter a reason for the split +- The split is then shared equally between the attendees + +# FAQs +## Can I request money from more than one person at a time? +If you need to request money for more than one person at a time, you’ll want to use the Split Bill feature. The Request Money option is for one-to-one payments between two people. diff --git a/docs/articles/new-expensify/getting-started/Expensify-Lounge.md b/docs/articles/new-expensify/getting-started/Expensify-Lounge.md deleted file mode 100644 index bdccbe927769..000000000000 --- a/docs/articles/new-expensify/getting-started/Expensify-Lounge.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Welcome to the Expensify Lounge! -description: How to get the most out of the Expensify Lounge. -redirect_from: articles/other/Expensify-Lounge/ ---- - - -# What is the Expensify Lounge? -The Expensify Lounge is a place where people go to Get Shit Done. It's a beautiful environment with great coffee and a group of people to collaborate with. Check out this guide on how to best utilize the Expensify Lounge! - -# The Two Rules -### Rule #1 - Get Shit Done - -The Lounge is a space for people to get work done. It is optimized to be the perfect environment for you to focus on your work, collaborate with others, and advance your most wild and creative ideas. To make this a reality, we ask our members to keep the following in mind: - -- **#focus** - Use the space for how it was designed and do not distract from others' focus. The space is beautiful, social, and collaborative, but it was created to help our members work effectively. -- **#urgency** - Working remotely is great, but there's nothing like real-time collaboration with your colleagues. Use the lounge to meet with co-workers IRL to continue the progress on whatever it is you're working on. -- **#results** - Don't mistake time for effort or effort for output. Upon arrival, visualize what you want to accomplish, and don't leave until it's done. - -## Rule #2 - Don’t Ruin it for Everyone Else - -We want this place to be incredible, innovative, and always elvoving. To achieve that, we have some general guidelines: - -- **#writeitdown** - If you can help others learn from you, do so. Write a blog post, a document, or a post in Expensify Chat to share with others. This includes making the Expensify Lounge a better space. Feel free to write down any improvements so we can make it better. -- **#showup** - If you are in the lounge, be fully present. Meet others, and collaborate in social rooms. The point is to build a community of people who are focused on getting shit done; you’ll get out what you put in. -- **#oneteam** - Providing an inclusive community is our priority, and we do not tolerate any form of discrimination. Aim to go out of your way to include people who want to be included. -- **#nocreeps** - Do not make people feel uncomfortable with your words or actions. If you are made to feel uncomfortable or notice this happening to someone else, you can use the escalation process outlined in the FAQ section. - -# How to Use the Expensify Lounge -Keeping those two rules in mind, below is a guide on how our members can get the most out of the lounge. - -### Rule #1 - Getting Shit Done -- **Order drinks from Concierge** - [Write Concierge here](https://new.expensify.com/concierge) to ask lounge questions or order beverages. Concierge will bring your order directly to you! -- **Using an office** - Offices are first come, first serve. If an office is open, feel free to use it! Please keep office use to under an hour. We currently do not allow reserving offices. -- **Lounge hours** - The lounge will be open from 8am-6pm PT, Monday through Friday and closed on some major holidays. You can review our Google Maps profile to check our holiday hours. -- **Make the lounge better** - Make any suggestions to improve the lounge experience in [#announce - Expensify Lounge](https://new.expensify.com/r/8292963527436014). - -## Rule #2 - Not Ruining it for Everyone Else -- **Offices are for calls** - Please do not occupy an office unless you have a call or collaborative meeting happening, and don't stay in an office for longer than an hour. -- **Respect other people** - Please do not be too loud or distracting while others are trying to work. While collaborating in Expensify Chat, be respectful of others’ viewpoints and keep a positive environment. -- **Stay home if you’re sick** - If you feel sick, please do not visit the lounge, or consider wearing a mask in public areas. -- **If you see something, say something** - If you are made to feel uncomfortable or witness others being made uncomfortable, let Concierge know. If this is happening in Expensify Chat, use our moderation tools (outlined below in the FAQ) to apply the applicable level of moderation. - -We’re so happy you are here to live rich, have fun, and save the world with us. Now, go enjoy the Expensify Lounge, and let's Get Shit Done! - -# FAQs - -#### What is Concierge? - -Concierge is our automated system that answers member questions in real-time. Questions regarding the local lounge will be routed directly to the lounge's Concierge. You can send Concierge a message if you have a drink request or general questions. They’ll take care of everything for you! - -#### Who is invited to the Expensify Lounge? - -Everyone is invited to the Expensify Lounge! Whether you're an existing customer, or you're someone looking for a great space to Get Shit Done, we'd love to have you. - -#### How do I escalate something that's making me or someone else uncomfortable? - -If you see something in Expensify Chat that should be escalated, you can use the escalation feature to mark a chat as: -- **Spam or Inconsiderate**: This will send a whisper to the sender of the message warning them of the violation, and the message will have a flag applied to it which will be visible to all users. Concierge will not review these flags. -- **Intimidating or Bullying**: The message will be immediately hidden, and the content will be reviewed by our team. After reviewing the message, and it's confirmed intimidation or bullying, the message will be permanently hidden and we'll communicate the violation to the sender of the message. -- **Harassment or Assault**: The message will be immediately hidden and reviewed by our team. The user will be sent a message to warning them of the violation, and Concierge can block the user if that's deemed necessary. - -If you witness something in-person, please write to Concierge referencing which lounge you are in, and they will escalate the issue appropriately. - -#### Where are other Expensify Lounge locations? - -Right now, we only have the San Francisco Lounge, but be on the lookout for more coming soon! diff --git a/docs/articles/new-expensify/insights-and-custom-reporting/Coming-Soon.md b/docs/articles/new-expensify/insights-and-custom-reporting/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/insights-and-custom-reporting/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md deleted file mode 100644 index 7a0717eeb5d1..000000000000 --- a/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md +++ /dev/null @@ -1,320 +0,0 @@ ---- -title: The QuickBooks Online Integration -description: Expensify's integration with QuickBooks Online streamlines your expense management. - ---- -# Overview - -The Expensify integration with QuickBooks Online brings in your expense accounts and other data and even exports reports directly to QuickBooks for easy reconciliation. Plus, with advanced features in QuickBooks Online, you can fine-tune coding settings in Expensify for automated data export to optimize your accounting workflow. - -## Before connecting - -It's crucial to understand the requirements based on your specific QuickBooks subscription: - -- While all the features are available in Expensify, their accessibility may vary depending on your QuickBooks Online subscription. -- An error will occur if you try to export to QuickBooks with a feature enabled that isn't part of your subscription. -- Please be aware that Expensify does not support the Self-Employed subscription in QuickBooks Online. - -# How to connect to QuickBooks Online - -## Step 1: Setup employees in QuickBooks Online - -Employees must be set up as either Vendors or Employees in QuickBooks Online. Make sure to include the submitter's email in their record. - -If you use vendor records, you can export as Vendor Bills, Checks, or Journal Entries. If you use employee records, you can export as Checks or Journal Entries (if exporting against a liability account). - -Additional Options for Streamlined Setup: - -- Automatic Vendor Creation: Enable “Automatically Create Entities” in your connection settings to automatically generate Vendor or Employee records upon export for submitters that don't already exist in QBO. -- Employee Setup Considerations: If setting up submitters as Employees, ensure you activate QuickBooks Online Payroll. This will grant access to the Employee Profile tab to input employee email addresses. - -## Step 2: Connect Expensify and QuickBooks Online - -- Navigate to Settings > Workspaces > Group > [Workspace Name] > Connections > QuickBooks Online. Click Connect to QuickBooks. -- Enter your QuickBooks Online Administrator’s login information and choose the QuickBooks Online Company File you want to connect to Expensify (you can connect one Company File per Workspace). Then Click Authorize. -- Enter your QuickBooks Online Administrator’s login information and choose the QuickBooks Online Company File you want to connect to Expensify (you can connect one Company File per Workspace): - -Exporting Historical Reports to QuickBooks Online: - -After connecting QuickBooks Online to Expensify, you may receive a prompt to export all historical reports from Expensify. To export multiple reports at once, follow these steps: - -a. Go to the Reports page on the web. - -b. Tick the checkbox next to the reports you want to export. - -c. Click 'Export To' and select 'QuickBooks Online' from the drop-down list. - -If you don't want to export specific reports, click “Mark as manually entered” on the report. - -# How to configure export settings for QuickBooks Online - -Our QuickBooks Online integration offers a range of features. This section will focus on Export Settings and how to set them up. - -## Preferred Exporter - -Any Workspace admin can export to your accounting integration, but the Preferred Exporter can be chosen to automate specific steps. You can set this role from Settings > Workspaces > Group > [Workspace Name] > Connections > Configure > Export > Preferred Exporter. - -The Preferred Exporter: - -- Is the user whose Concierge performs all automated exports on behalf of. -- Is the only user who will see reports awaiting export in their **Home.** -- Must be a **Domain Admin** if you have set individual GL accounts for Company Card export. -- Must be a **Domain Admin** if this is the Preferred Workspace for any Expensify Card domain using Automatic Reconciliation. - -## Date - -When exporting reports to QuickBooks Online, you can choose the report's **submitted date**, the report's **exported date**, or the **date of the last expense on the report.** - -Most export options (Check, Journal Entry, and Vendor Bill) will create a single itemized entry with one date. -Please note that if you choose a Credit Card or Debit Card for non-reimbursable expenses, we'll use the transaction date on each expense during export. - -# Reimbursable expenses - -Reimbursable expenses export to QuickBooks Online as: - -- Vendor Bills -- Checks -- Journal Entries - -## Vendor bill (recommended) - -This is a single itemized vendor bill for each Expensify report. If the accounting period is closed, we will post the vendor bill on the first day of the next open period. If you export as Vendor Bills, you can also choose to Sync reimbursed reports (set on the Advanced tab). **An A/P account is required to export to a vendor bill. Here is a screenshot of how your expenses map in QuickBooks.** - -The submitter will be listed as the vendor in the vendor bill. - -## Check - -This is a single itemized check for each Expensify report. You can mark a check to be printed later in QuickBooks Online. - -## Journal entry - -This is a single itemized journal entry for each Expensify report. - -# Non-reimbursable expenses - -Non-reimbursable expenses export to QuickBooks Online as: - -- Credit Card expenses -- Debit Card Expenses -- Vendor Bills - -## Credit/debit card - -Using Credit/Debit Card Transactions: - -- Each expense will be exported as a bank transaction with its transaction date. -- If you split an expense in Expensify, we'll consolidate it into a single credit card transaction in QuickBooks with multiple line items posted to the corresponding General Ledger accounts. - -Pro-Tip: To ensure the payee field in QuickBooks Online reflects the merchant name for Credit Card expenses, ensure there's a matching Vendor in QuickBooks Online. Expensify checks for an exact match during export. If none are found, the payee will be mapped to a vendor we create and labeled as Credit Card Misc. or Debit Card Misc. - -If you centrally manage your company cards through Domains, you can export expenses from each card to a specific account in QuickBooks. - -## Vendor Bill - -- A single detailed vendor bill is generated for each Expensify report. If the accounting period is closed, the vendor bill will be posted on the first day of the next open period. If you choose to export non-reimbursable expenses as Vendor Bills, you can assign a default vendor to the bill. -- The export will use your default vendor if you have Default Vendor enabled. If the Default Vendor is disabled, the report's submitter will be set as the Vendor in QuickBooks. - -Billable Expenses: - -- In Expensify, you can designate expenses as billable. These will be exported to QuickBooks Online with the billable flag. - This feature applies only to expenses exported as Vendor Bills or Checks. To maximize this functionality, ensure that any billable expense is associated with a Customer/Job. - -## Export Invoices - -If you are creating Invoices in Expensify and exporting these to QuickBooks Online, this is the account the invoice will appear against. - -# Configure coding for QuickBooks Online - -The coding tab is where your information is configured for Expensify; this will allow employees to code expenses and reports accurately. - -- Categories -- Classes and/or Customers/Projects -- Locations -- Items -- Tax - -## Categories - -QuickBooks Online expense accounts will be automatically imported into Expensify as Categories. - -## Account Import - -Equity type accounts will also be imported as categories. - -Important notes: - -- Other Current Liabilities can only be exported as Journal Entries if the submitter is set up as an Employee in QuickBooks. -- Exchange Gain or Loss detail type does not import. - -Recommended steps to take after importing the expense accounts from QuickBooks to Expensify: - -- Go to Settings > Workspaces > Groups > [Workspace Name] > Categories to see the accounts imported from QuickBooks Online. -- Use the enable/disable button to choose which Categories to make available to your employees, and set Category specific rules via the blue settings cog. -- If necessary, edit the names of imported Categories to make expense coding easier for your employees. (Please Note: If you make any changes to these accounts in QuickBooks Online, the category names on Expensify's side will revert to match the name of the account in QuickBooks Online the next time you sync). -- If you use Items in QuickBooks Online, you can import them into Expensify as Categories. - -Please note that each expense has to have a category selected to export to QuickBooks Online. The chosen category has to be imported from QuickBooks Online and cannot be manually created within the Workspace settings. - -## Classes and Customers/Projects - -If you use Classes or Customers/Projects in QuickBooks Online, you can import those into Expensify as Tags or Report Fields: - -- Tags let you apply a Class and/or Customer/Project to each expense -- Report Fields enables you to apply a Class and/or Customer/Project to all expenses on a report. - -Note: Although Projects can be imported into Expensify and coded to expenses, due to the limitations of the QuickBooks API, expenses cannot be created within the Projects module in QuickBooks. - -## Locations - -Locations can be imported into Expensify as a Report Field or, if you export reimbursable expenses as Journal Entries and non-reimbursable expenses as Credit/Debit Card, you can import Locations as Tags. - -## Items - -If you use Items in QuickBooks Online, you can import Items defined with Purchasing Information (with or without Sales Information) into Expensify as Categories. -## Tax - -- Using our tax tracking feature, you can assign a tax rate and amount to each expense. --To activate tax tracking, go to connection configuration and enable it. This will automatically import purchasing taxes from QuickBooks Online into Expensify. -- After the connection is set, navigate to Settings > Worspaces > Groups > Workspace Name] > Tax. Here, you can view the taxes imported from QuickBooks Online. -- Use the enable/disable button to choose which taxes are accessible to your employees. -- Set a default tax for the Company Workspace, which will automatically apply to all new expenses. -- Please note that, at present, tax cannot be exported to Journal Entries in QuickBooks Online. -- Expensify performs a daily sync to ensure your information is up-to-date. This minimizes errors from outdated QuickBooks Online data and saves you time on syncing. - -# How to configure advanced settings for QuickBooks Online - -The advanced settings are where functionality for automating and customizing the QuickBooks Online integration can be enabled. -Navigate to this section of your Workspace by following Settings > Workspaces > Group > [Workspace Name] > Connections > Configure button > Advanced tab. -## Auto Sync -With QuickBooks Online auto-sync, once a non-reimbursable report is final approved in Expensify, it's automatically queued for export to QuickBooks Online. For expenses eligible for reimbursement with a linked business bank account, they'll sync when marked as reimbursed. - -## Newly Imported Categories - -This setting determines the default status of newly imported categories from QuickBooks Online to Expensify, either enabled or disabled. - -## Invite Employees - -Enabling this automatically invites all Employees from QuickBooks Online to the connected Expensify Company Workspace. If not, you can manually invite or import them using a CSV file. - -## Automatically Create Entities - -When exporting reimbursable expenses as Vendor Bills or Journal Entries, Expensify will automatically create a vendor in QuickBooks if one doesn't exist. It will also generate a customer when exporting Invoices. - -## Sync Reimbursed Reports - -Enabling this marks the Vendor Bill as paid in QuickBooks Online when you reimburse a report via ACH direct deposit in Expensify. If reimbursing outside Expensify, marking the Vendor Bill as paid will automatically in QuickBooks Online update the report as reimbursed in Expensify. Note: After enabling this feature, select your QuickBooks Account in the drop-down, indicating the bank account for reimbursements. - -## Collection Account - -If you are exporting Invoices from Expensify to Quickbooks Online, this is the account the Invoice will appear against once marked as Paid. - -# Deep Dive - -## Preventing Duplicate Transactions in QuickBooks - -When importing a banking feed directly into QuickBooks Online while also importing transactions from Expensify, it's possible to encounter duplicate entries in QuickBooks. To prevent this, follow these steps: - -Step 1: Complete the Approval Process in Expensify - -- Before exporting any expenses to QuickBooks Online, ensure they are added to a report and the report receives approval. Depending on your Workspace setup, reports may require approval from one or more individuals. The approval process concludes when the last user who views the report selects "Final Approve." - -Step 2: Exporting Reports to QuickBooks Online - -- To ensure expenses exported from Expensify match seamlessly in the QuickBooks Banking platform, make sure these expenses are marked as non-reimbursable within Expensify and that “Credit Card” is selected as the non-reimbursable export option for your expenses. - -Step 3: Importing Your Credit Card Transactions into QuickBooks Online - -- After completing Steps 1 and 2, you can import your credit card transactions into QuickBooks Online. These imported banking transactions will align with the ones brought in from Expensify. QuickBooks Online will guide you through the process of matching these transactions, similar to the example below: - -## Tax in QuickBooks Online - -If your country applies taxes on sales (like GST, HST, or VAT), you can utilize Expensify's Tax Tracking along with your QuickBooks Online tax rates. Please note: Tax Tracking is not available for Workspaces linked to the US version of QuickBooks Online. If you need assistance applying taxes after reports are exported, contact QuickBooks. - -To get started: - -- Go to Settings > Workpaces > Group > [Workspace Name] > Connections, and click Configure. -- Navigate to the Coding tab. -- Turn on 'T.''. -- Click Save. This imports the Tax Name and rate from QuickBooks Online. -- Visit Settings > Workspaces > Group > [Workspace Name] > Tax to view the imported taxes. -- Use the enable/disable button in the Tax tab to choose which taxes your employees can use. - -Remember, you can also set a default tax rate for the entire Workspace. This will be automatically applied to all new expenses. The user can still choose a different tax rate for each expense. - -Tax information can't be sent to Journal Entries in QuickBooks Online. Also, when dealing with multiple tax rates, where one receipt has different tax rates (like in the EU, UK, and Canada), users should split the expense into the respective parts and set the appropriate tax rate for each part. - -## Multi-currency - -When working with QuickBooks Online Multi-Currency, there are some things to remember when exporting Vendor Bills and Check! Make sure the vendor's currency and the Accounts Payable (A/P) bank account match. - -In QuickBooks Online, the currency conversion rates are not applied when exporting. All transactions will be exported with a 1:1 conversion rate, so for example, if a vendor's currency is CAD (Canadian Dollar) and the home currency is USD (US Dollar), the export will show these currencies without applying conversion rates. - -To correct this, you must manually update the conversion rate after the report has been exported to QuickBooks Online. - -Specifically for Vendor Bills: - -If multi-currency is enabled and the Vendor's currency is different from the Workspace currency, OR if QuickBooks Online home currency is foreign from the Workspace currency, then: - -- We create the Vendor Bill in the Vendor's currency (this is a QuickBooks Online requirement - we don't have a choice) -- We set the exchange rate between the home currency and the Vendor's currency -- We convert line item amounts to the vendor's currency - -Let's consider this example: - -- QuickBooks Online home currency is USD -- Vendor's currency is VND -- Workspace (report) currency is JPY - -Upon export, we: - -1. Specified the bill is in VND -2. Set the exchange rate between VND and USD (home currency), computed at the time of export. -3. Converted line items from JPY (currency in Expensify) to VND -4. QuickBooks Online automatically computed the USD amount (home currency) based on the exchange rate we specified -5. Journal Entries, Credit Card, and Debit Card: - -Multi-currency exports will fail as the account currency must match both the vendor and home currencies. - -## Report Fields - -Report fields are a handy way to collect specific information for a report tailored to your organization's needs. They can specify a project, business trip, client, location, and more! - -When integrating Expensify with Your Accounting Software, you can create your report fields in your accounting software so the next time you sync your Workspace, these fields will be imported into Expensify. - -To select how a specific field imports to Expensify, head to Settings > Workspaces > Group > -[Workspace Name] > Connections > Accounting Integrations > QuickBooks Online > Configure > Coding. - -Here are the QuickBooks Online fields that can be mapped as a report field within Expensify: - -- Classes -- Customers/Projects -- Locations - -# FAQ - -## What happens if the report can't be exported to QuickBooks Online automatically? - -If a report encounters an issue during automatic export to QuickBooks Online, you'll receive an email with details about the problem, including any specific error messages. These messages will also be recorded in the report's history section. - -The report will be placed in your Home for your attention. You can address the issues there. If you need further assistance, refer to our QuickBooks Online Export Errors page or export the report manually. - -## How can I ensure that I final approve reports before they're exported to QuickBooks Online? - -To ensure reports are reviewed before export, set up your Workspaces with the appropriate workflow in Expensify. Additionally, consider changing your Workspace settings to enforce expense Workspace workflows strictly. This guarantees that your Workspace's workflow is consistently followed. - -## What happens to existing approved and reimbursed reports if I enable Auto Sync? - -- If Auto Sync was disabled when your Workspace was linked to QuickBooks Online, enabling it won't impact existing reports that haven't been exported. -- If a report has been exported and reimbursed via ACH, it will be automatically marked as paid in QuickBooks Online during the next sync. -- If a report has been exported and marked as paid in QuickBooks Online, it will be automatically marked as reimbursed in Expensify during the next sync. -- Reports that have yet to be exported to QuickBooks Online won't be automatically exported. - - - - - - - - - - - diff --git a/docs/articles/new-expensify/manage-employees-and-report-approvals/Coming-Soon.md b/docs/articles/new-expensify/manage-employees-and-report-approvals/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/manage-employees-and-report-approvals/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/send-payments/Coming-Soon.md b/docs/articles/new-expensify/send-payments/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/send-payments/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md b/docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- diff --git a/docs/assets/images/Cancel Reimbursement.png b/docs/assets/images/Cancel Reimbursement.png new file mode 100644 index 000000000000..a1322202ded3 Binary files /dev/null and b/docs/assets/images/Cancel Reimbursement.png differ diff --git a/docs/assets/images/CompanyCards_Assign.png b/docs/assets/images/CompanyCards_Assign.png new file mode 100644 index 000000000000..53effeb56b88 Binary files /dev/null and b/docs/assets/images/CompanyCards_Assign.png differ diff --git a/docs/assets/images/CompanyCards_EmailAssign.png b/docs/assets/images/CompanyCards_EmailAssign.png new file mode 100644 index 000000000000..a3d9683518a7 Binary files /dev/null and b/docs/assets/images/CompanyCards_EmailAssign.png differ diff --git a/docs/assets/images/CompanyCards_Unassign.png b/docs/assets/images/CompanyCards_Unassign.png new file mode 100644 index 000000000000..14a2fdc205a7 Binary files /dev/null and b/docs/assets/images/CompanyCards_Unassign.png differ diff --git a/docs/assets/images/ExpensifyHelp_CloseAccount_Desktop.png b/docs/assets/images/ExpensifyHelp_CloseAccount_Desktop.png new file mode 100644 index 000000000000..8a102375d1c8 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_CloseAccount_Desktop.png differ diff --git a/docs/assets/images/ExpensifyHelp_EmailError.png b/docs/assets/images/ExpensifyHelp_EmailError.png new file mode 100644 index 000000000000..203f0cfe2b76 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_EmailError.png differ diff --git a/docs/assets/images/ExpensifyHelp_SMTPError.png b/docs/assets/images/ExpensifyHelp_SMTPError.png new file mode 100644 index 000000000000..b95ea70a9dfa Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_SMTPError.png differ diff --git a/docs/assets/images/ExpensifyHelp_Time.png b/docs/assets/images/ExpensifyHelp_Time.png new file mode 100644 index 000000000000..f4d91b1e8aeb Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_Time.png differ diff --git a/docs/assets/images/ExpensifyHelp_Timezone.png b/docs/assets/images/ExpensifyHelp_Timezone.png new file mode 100644 index 000000000000..d2afc9e693e7 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_Timezone.png differ diff --git a/docs/assets/images/QBO1.png b/docs/assets/images/QBO1.png new file mode 100644 index 000000000000..4037db44d3bb Binary files /dev/null and b/docs/assets/images/QBO1.png differ diff --git a/docs/assets/images/QBO2-Bill.png b/docs/assets/images/QBO2-Bill.png new file mode 100644 index 000000000000..f75716a85079 Binary files /dev/null and b/docs/assets/images/QBO2-Bill.png differ diff --git a/docs/assets/images/QBO3-Checktoprint.png b/docs/assets/images/QBO3-Checktoprint.png new file mode 100644 index 000000000000..732141a74353 Binary files /dev/null and b/docs/assets/images/QBO3-Checktoprint.png differ diff --git a/docs/assets/images/QBO4-JournalEntry.png b/docs/assets/images/QBO4-JournalEntry.png new file mode 100644 index 000000000000..342d20e49608 Binary files /dev/null and b/docs/assets/images/QBO4-JournalEntry.png differ diff --git a/docs/assets/images/QBO5-Expense.png b/docs/assets/images/QBO5-Expense.png new file mode 100644 index 000000000000..5d71f3955557 Binary files /dev/null and b/docs/assets/images/QBO5-Expense.png differ diff --git a/docs/assets/images/QBO6-Check.png b/docs/assets/images/QBO6-Check.png new file mode 100644 index 000000000000..087720a76875 Binary files /dev/null and b/docs/assets/images/QBO6-Check.png differ diff --git a/docs/assets/images/QBO7-Transactions.png b/docs/assets/images/QBO7-Transactions.png new file mode 100644 index 000000000000..c7752c42870b Binary files /dev/null and b/docs/assets/images/QBO7-Transactions.png differ diff --git a/docs/assets/images/Reimbursing Default.png b/docs/assets/images/Reimbursing Default.png new file mode 100644 index 000000000000..23ffd557ca14 Binary files /dev/null and b/docs/assets/images/Reimbursing Default.png differ diff --git a/docs/assets/images/Reimbursing Manual Warning.png b/docs/assets/images/Reimbursing Manual Warning.png new file mode 100644 index 000000000000..2579e21fe2e3 Binary files /dev/null and b/docs/assets/images/Reimbursing Manual Warning.png differ diff --git a/docs/assets/images/Reimbursing Manual.png b/docs/assets/images/Reimbursing Manual.png new file mode 100644 index 000000000000..3b9eb27bfa0b Binary files /dev/null and b/docs/assets/images/Reimbursing Manual.png differ diff --git a/docs/assets/images/Reimbursing Reports Dropdown.png b/docs/assets/images/Reimbursing Reports Dropdown.png new file mode 100644 index 000000000000..2e9c6329ae19 Binary files /dev/null and b/docs/assets/images/Reimbursing Reports Dropdown.png differ diff --git a/docs/assets/images/Uber1.png b/docs/assets/images/Uber1.png new file mode 100644 index 000000000000..d5a7d651c6b9 Binary files /dev/null and b/docs/assets/images/Uber1.png differ diff --git a/docs/assets/images/Uber2.png b/docs/assets/images/Uber2.png new file mode 100644 index 000000000000..27ac9925a900 Binary files /dev/null and b/docs/assets/images/Uber2.png differ diff --git a/docs/assets/images/chat-bubble.svg b/docs/assets/images/chat-bubble.svg new file mode 100644 index 000000000000..fbab26d72b44 --- /dev/null +++ b/docs/assets/images/chat-bubble.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/assets/images/playbook-impoort-employees.png b/docs/assets/images/playbook-impoort-employees.png index 1cb8a11b95fc..e45e7d461145 100644 Binary files a/docs/assets/images/playbook-impoort-employees.png and b/docs/assets/images/playbook-impoort-employees.png differ diff --git a/docs/assets/images/settings-old-dot.svg b/docs/assets/images/settings-old-dot.svg index ca5bc04bd0ff..85561a886459 100644 --- a/docs/assets/images/settings-old-dot.svg +++ b/docs/assets/images/settings-old-dot.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index aebd0f5d4864..dde3af22e900 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -101,6 +101,7 @@ function closeSidebarOnClickOutside(event) { function openSidebar() { document.getElementById('sidebar-layer').style.display = 'block'; + document.getElementById('gsc-i-id1').focus(); // Make body unscrollable const yAxis = document.documentElement.style.getPropertyValue('y-axis'); @@ -108,6 +109,8 @@ function openSidebar() { body.style.position = 'fixed'; body.style.top = `-${yAxis}`; + document.getElementById('gsc-i-id1').focus(); + // Close the sidebar when clicking sidebar layer (outside the sidebar search) const sidebarLayer = document.getElementById('sidebar-layer'); if (sidebarLayer) { @@ -120,25 +123,12 @@ function changeSVGViewBoxGoogle() { // Get all inline Google SVG elements on the page const svgsGoogle = document.querySelectorAll('svg'); - // Create a media query for screens wider than tablet - const mediaQuery = window.matchMedia('(min-width: 800px)'); - - // Check if the viewport is smaller than tablet - if (!mediaQuery.matches) { - Array.from(svgsGoogle).forEach((svg) => { - // Set the viewBox attribute to '0 0 13 13' to make the svg fit in the mobile view - svg.setAttribute('viewBox', '0 0 13 13'); - svg.setAttribute('height', '13'); - svg.setAttribute('width', '13'); - }); - } else { - Array.from(svgsGoogle).forEach((svg) => { - // Set the viewBox attribute to '0 0 20 20' to make the svg fit in the tablet-desktop view - svg.setAttribute('viewBox', '0 0 20 20'); - svg.setAttribute('height', '16'); - svg.setAttribute('width', '16'); - }); - } + Array.from(svgsGoogle).forEach((svg) => { + // Set the viewBox attribute to '0 0 13 13' to make the svg fit in the mobile view + svg.setAttribute('viewBox', '0 0 20 20'); + svg.setAttribute('height', '16'); + svg.setAttribute('width', '16'); + }); } // Function to insert element after another @@ -147,11 +137,23 @@ function insertElementAfter(referenceNode, newNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } +// Update the ICON for search input. +/* Change the path of the Google Search Button icon into Expensify icon */ +function updateGoogleSearchIcon() { + const node = document.querySelector('.gsc-search-button.gsc-search-button-v2 svg path'); + node.setAttribute( + 'd', + 'M8 1c3.9 0 7 3.1 7 7 0 1.4-.4 2.7-1.1 3.8l5.2 5.2c.6.6.6 1.5 0 2.1-.6.6-1.5.6-2.1 0l-5.2-5.2C10.7 14.6 9.4 15 8 15c-3.9 0-7-3.1-7-7s3.1-7 7-7zm0 3c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4 1.8-4 4-4z', + ); +} + // Need to wait up until page is load, so the svg viewBox can be changed // And the search label can be inserted window.addEventListener('load', () => { changeSVGViewBoxGoogle(); + updateGoogleSearchIcon(); + // Add required into the search input const searchInput = document.getElementById('gsc-i-id1'); searchInput.setAttribute('required', ''); diff --git a/docs/new-expensify/hubs/bank-accounts-and-credit-cards/index.html b/docs/new-expensify/hubs/bank-accounts/index.html similarity index 100% rename from docs/new-expensify/hubs/bank-accounts-and-credit-cards/index.html rename to docs/new-expensify/hubs/bank-accounts/index.html diff --git a/docs/new-expensify/hubs/chat/index.html b/docs/new-expensify/hubs/chat/index.html new file mode 100644 index 000000000000..9fa1f1547c0f --- /dev/null +++ b/docs/new-expensify/hubs/chat/index.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Chat +--- + +{% include hub.html %} diff --git a/docs/new-expensify/hubs/expense-and-report-features/index.html b/docs/new-expensify/hubs/expense-and-report-features/index.html deleted file mode 100644 index 0057ae0fa46c..000000000000 --- a/docs/new-expensify/hubs/expense-and-report-features/index.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default -title: Expense and Report Features ---- - -{% include hub.html %} \ No newline at end of file diff --git a/docs/new-expensify/hubs/getting-started/chat.html b/docs/new-expensify/hubs/getting-started/chat.html deleted file mode 100644 index 86641ee60b7d..000000000000 --- a/docs/new-expensify/hubs/getting-started/chat.html +++ /dev/null @@ -1,5 +0,0 @@ ---- -layout: default ---- - -{% include section.html %} diff --git a/docs/new-expensify/hubs/getting-started/index.html b/docs/new-expensify/hubs/getting-started/index.html deleted file mode 100644 index 14ca13d0c2e8..000000000000 --- a/docs/new-expensify/hubs/getting-started/index.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default -title: Getting Started ---- - -{% include hub.html %} \ No newline at end of file diff --git a/docs/new-expensify/hubs/insights-and-custom-reporting/index.html b/docs/new-expensify/hubs/insights-and-custom-reporting/index.html deleted file mode 100644 index 16c96cb51d01..000000000000 --- a/docs/new-expensify/hubs/insights-and-custom-reporting/index.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default -title: Exports ---- - -{% include hub.html %} \ No newline at end of file diff --git a/docs/new-expensify/hubs/integrations/accounting-integrations.html b/docs/new-expensify/hubs/integrations/accounting-integrations.html deleted file mode 100644 index 86641ee60b7d..000000000000 --- a/docs/new-expensify/hubs/integrations/accounting-integrations.html +++ /dev/null @@ -1,5 +0,0 @@ ---- -layout: default ---- - -{% include section.html %} diff --git a/docs/new-expensify/hubs/integrations/index.html b/docs/new-expensify/hubs/integrations/index.html deleted file mode 100644 index d1f173534c8a..000000000000 --- a/docs/new-expensify/hubs/integrations/index.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default -title: Integrations ---- - -{% include hub.html %} \ No newline at end of file diff --git a/docs/new-expensify/hubs/manage-employees-and-report-approvals/index.html b/docs/new-expensify/hubs/manage-employees-and-report-approvals/index.html deleted file mode 100644 index 31e992f32d5d..000000000000 --- a/docs/new-expensify/hubs/manage-employees-and-report-approvals/index.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default -title: Manage Employees & Report Approvals ---- - -{% include hub.html %} \ No newline at end of file diff --git a/docs/redirects.csv b/docs/redirects.csv index 3bcfb594bedb..9d9470919e41 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -17,4 +17,11 @@ https://community.expensify.com/discussion/5802/deep-dive-understanding-math-and https://community.expensify.com/discussion/5796/deep-dive-user-level-formula,https://help.expensify.com/articles/expensify-classic/insights-and-custom-reporting/Custom-Templates https://community.expensify.com/discussion/4750/how-to-create-a-custom-export,https://help.expensify.com/articles/expensify-classic/insights-and-custom-reporting/Custom-Templates https://community.expensify.com/discussion/4642/how-to-export-reports-to-a-custom-template,https://help.expensify.com/articles/expensify-classic/insights-and-custom-reporting/Custom-Templates - +https://community.expensify.com/discussion/5648/deep-dive-policy-users-and-roles,https://help.expensify.com/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles +https://community.expensify.com/discussion/5740/deep-dive-what-expense-information-is-available-based-on-role,https://help.expensify.com/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles +https://community.expensify.com/discussion/4472/how-to-set-or-edit-a-user-role,https://help.expensify.com/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles +https://community.expensify.com/discussion/5655/deep-dive-what-is-a-vacation-delegate,https://help.expensify.com/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate +https://community.expensify.com/discussion/5194/how-to-assign-a-vacation-delegate-for-an-employee-through-domains,https://help.expensify.com/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate +https://community.expensify.com/discussion/5190/how-to-individually-assign-a-vacation-delegate-from-account-settings,https://help.expensify.com/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate +https://community.expensify.com/discussion/5274/how-to-set-up-an-adp-indirect-integration-with-expensify,https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/ADP +https://community.expensify.com/discussion/5776/how-to-create-mileage-expenses-in-expensify,https://help.expensify.com/articles/expensify-classic/get-paid-back/Distance-Tracking#gsc.tab=0 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 98366cd3b967..2b5c15146eb3 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -15,10 +15,10 @@ opt_out_usage platform :android do desc "Generate a new local APK for e2e testing" - + lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.ts" ENV["E2E_TESTING"]="true" gradle( @@ -31,7 +31,7 @@ platform :android do lane :build_e2edelta do ENV["ENVFILE"]="tests/e2e/.env.e2edelta" - ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.ts" ENV["E2E_TESTING"]="true" gradle( diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index fc3fe4024b71..de36428b1b37 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.98 + 1.4.11 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.98.4 + 1.4.11.6 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 1e0f484b0247..e805f0e55da1 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.98 + 1.4.11 CFBundleSignature ???? CFBundleVersion - 1.3.98.4 + 1.4.11.6 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d94e36b0b3c9..390511397b0e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -256,7 +256,7 @@ PODS: - Onfido (~> 28.3.0) - React - OpenSSL-Universal (1.1.1100) - - Plaid (4.1.0) + - Plaid (4.7.0) - PromisesObjC (2.2.0) - RCT-Folly (2021.07.22.00): - boost @@ -569,7 +569,7 @@ PODS: - react-native-config/App (= 1.4.6) - react-native-config/App (1.4.6): - React-Core - - react-native-document-picker (8.1.1): + - react-native-document-picker (8.2.1): - React-Core - react-native-flipper (0.159.0): - React-Core @@ -585,12 +585,12 @@ PODS: - React-Core - react-native-pager-view (6.2.0): - React-Core - - react-native-pdf (6.7.1): + - react-native-pdf (6.7.3): - React-Core - react-native-performance (5.1.0): - React-Core - - react-native-plaid-link-sdk (10.0.0): - - Plaid (~> 4.1.0) + - react-native-plaid-link-sdk (10.8.0): + - Plaid (~> 4.7.0) - React-Core - react-native-quick-sqlite (8.0.0-beta.2): - React @@ -726,8 +726,6 @@ PODS: - React-Core - RNCPicker (2.4.4): - React-Core - - RNDateTimePicker (3.5.2): - - React-Core - RNDeviceInfo (10.3.0): - React-Core - RNDevMenu (4.1.1): @@ -919,7 +917,6 @@ DEPENDENCIES: - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)" - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" - - "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)" - RNDeviceInfo (from `../node_modules/react-native-device-info`) - RNDevMenu (from `../node_modules/react-native-dev-menu`) - RNFastImage (from `../node_modules/react-native-fast-image`) @@ -1121,8 +1118,6 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-clipboard/clipboard" RNCPicker: :path: "../node_modules/@react-native-picker/picker" - RNDateTimePicker: - :path: "../node_modules/@react-native-community/datetimepicker" RNDeviceInfo: :path: "../node_modules/react-native-device-info" RNDevMenu: @@ -1212,7 +1207,7 @@ SPEC CHECKSUMS: Onfido: c7d010d9793790d44a07799d9be25aa8e3814ee7 onfido-react-native-sdk: b346a620af5669f9fecb6dc3052314a35a94ad9f OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 + Plaid: 431ef9be5314a1345efb451bc5e6b067bfb3b4c6 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9 @@ -1233,7 +1228,7 @@ SPEC CHECKSUMS: react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6 react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151 react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e - react-native-document-picker: f68191637788994baed5f57d12994aa32cf8bf88 + react-native-document-picker: 69ca2094d8780cfc1e7e613894d15290fdc54bba react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 @@ -1241,9 +1236,9 @@ SPEC CHECKSUMS: react-native-key-command: 5af6ee30ff4932f78da6a2109017549042932aa5 react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2 react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df - react-native-pdf: 7c0e91ada997bac8bac3bb5bea5b6b81f5a3caae + react-native-pdf: b4ca3d37a9a86d9165287741c8b2ef4d8940c00e react-native-performance: cef2b618d47b277fb5c3280b81a3aad1e72f2886 - react-native-plaid-link-sdk: 9eb0f71dad94b3bdde649c7a384cba93024af46c + react-native-plaid-link-sdk: df1618a85a615d62ff34e34b76abb7a56497fbc1 react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4 react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a @@ -1270,7 +1265,6 @@ SPEC CHECKSUMS: RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60 RNCClipboard: d77213bfa269013bf4b857b7a9ca37ee062d8ef1 RNCPicker: 0b65be85fe7954fbb2062ef079e3d1cde252d888 - RNDateTimePicker: 7658208086d86d09e1627b5c34ba0cf237c60140 RNDeviceInfo: 4701f0bf2a06b34654745053db0ce4cb0c53ada7 RNDevMenu: 72807568fe4188bd4c40ce32675d82434b43c45d RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8 diff --git a/ios/expensify_chat_adhoc.mobileprovision.gpg b/ios/expensify_chat_adhoc.mobileprovision.gpg index 1dae451f168c..f4691df10d67 100644 Binary files a/ios/expensify_chat_adhoc.mobileprovision.gpg and b/ios/expensify_chat_adhoc.mobileprovision.gpg differ diff --git a/jest.config.js b/jest.config.js index efd72d20694f..611a0248b491 100644 --- a/jest.config.js +++ b/jest.config.js @@ -24,7 +24,7 @@ module.exports = { }, testEnvironment: 'jsdom', setupFiles: ['/jest/setup.js', './node_modules/@react-native-google-signin/google-signin/jest/build/setup.js'], - setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect', '/jest/setupAfterEnv.js'], + setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect', '/jest/setupAfterEnv.js', '/tests/perf-test/setupAfterEnv.js'], cacheDirectory: '/.jest-cache', moduleNameMapper: { '\\.(lottie)$': '/__mocks__/fileMock.js', diff --git a/metro.config.js b/metro.config.js index 8917e60fc758..2dac15111977 100644 --- a/metro.config.js +++ b/metro.config.js @@ -30,7 +30,7 @@ const config = { const resolution = context.resolveRequest(context, moduleName, platform); if (isE2ETesting && moduleName.includes('/API')) { const originalPath = resolution.filePath; - const mockPath = originalPath.replace('src/libs/API.ts', 'src/libs/E2E/API.mock.js').replace('/src/libs/API.js/', 'src/libs/E2E/API.mock.js'); + const mockPath = originalPath.replace('src/libs/API.ts', 'src/libs/E2E/API.mock.ts').replace('/src/libs/API.ts/', 'src/libs/E2E/API.mock.ts'); // eslint-disable-next-line no-console console.log('⚠️⚠️⚠️⚠️ Replacing resolution path', originalPath, ' => ', mockPath); diff --git a/package-lock.json b/package-lock.json index 1d40f1d49a42..66b3fdc72cb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.98-4", + "version": "1.4.11-6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.98-4", + "version": "1.4.11-6", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -26,7 +26,6 @@ "@react-native-async-storage/async-storage": "^1.17.10", "@react-native-camera-roll/camera-roll": "5.4.0", "@react-native-clipboard/clipboard": "^1.12.1", - "@react-native-community/datetimepicker": "^3.5.2", "@react-native-community/geolocation": "^3.0.6", "@react-native-community/netinfo": "^9.3.10", "@react-native-firebase/analytics": "^12.3.0", @@ -51,7 +50,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#886f90cbd5e83218fdfd7784d8356c308ef05791", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#ee14b3255da33d2b6924c357f43393251b6dc6d2", "fbjs": "^3.0.2", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", @@ -59,8 +58,6 @@ "lodash": "4.17.21", "lottie-react-native": "^6.4.0", "mapbox-gl": "^2.15.0", - "moment": "^2.29.4", - "moment-timezone": "^0.5.31", "onfido-sdk-ui": "13.1.0", "patch-package": "^8.0.0", "process": "^0.11.10", @@ -76,11 +73,11 @@ "react-native": "0.72.4", "react-native-android-location-enabler": "^1.2.2", "react-native-blob-util": "^0.17.3", - "react-native-collapsible": "^1.6.0", + "react-native-collapsible": "^1.6.1", "react-native-config": "^1.4.5", "react-native-dev-menu": "^4.1.1", "react-native-device-info": "^10.3.0", - "react-native-document-picker": "^8.0.0", + "react-native-document-picker": "^8.2.1", "react-native-draggable-flatlist": "^4.0.1", "react-native-fast-image": "^8.6.3", "react-native-fs": "^2.20.0", @@ -94,13 +91,13 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.115", + "react-native-onyx": "1.0.118", "react-native-pager-view": "^6.2.0", - "react-native-pdf": "^6.7.1", + "react-native-pdf": "^6.7.3", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.9.3", - "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", - "react-native-plaid-link-sdk": "^10.0.0", + "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#0d15d4618f58e99c1261921111e68ee85bb3c2a8", + "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", "react-native-reanimated": "3.5.4", @@ -167,7 +164,6 @@ "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.195", "@types/mapbox-gl": "^2.7.13", - "@types/mock-fs": "^4.13.1", "@types/pusher-js": "^5.1.0", "@types/react": "^18.2.12", "@types/react-beautiful-dnd": "^13.1.4", @@ -215,8 +211,8 @@ "jest-cli": "29.4.1", "jest-environment-jsdom": "^29.4.1", "jest-transformer-svg": "^2.0.1", + "memfs": "^4.6.0", "metro-react-native-babel-preset": "0.76.8", - "mock-fs": "^4.13.0", "onchange": "^7.1.0", "portfinder": "^1.0.28", "prettier": "^2.8.8", @@ -243,8 +239,8 @@ "yaml": "^2.2.1" }, "engines": { - "node": "16.15.1", - "npm": "8.11.0" + "node": "20.9.0", + "npm": "10.1.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -8295,15 +8291,6 @@ "node": ">= 4.0.0" } }, - "node_modules/@react-native-community/datetimepicker": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-3.5.2.tgz", - "integrity": "sha512-TWRuAtr/DnrEcRewqvXMLea2oB+YF+SbtuYLHguALLxNJQLl/RFB7aTNZeF+OoH75zKFqtXECXV1/uxQUpA+sg==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.4" - } - }, "node_modules/@react-native-community/eslint-config": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-3.0.0.tgz", @@ -12825,6 +12812,18 @@ "semver": "bin/semver.js" } }, + "node_modules/@storybook/builder-webpack5/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/@storybook/builder-webpack5/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -16803,6 +16802,18 @@ "semver": "bin/semver.js" } }, + "node_modules/@storybook/manager-webpack5/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/@storybook/manager-webpack5/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -19415,15 +19426,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/mock-fs": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.1.tgz", - "integrity": "sha512-m6nFAJ3lBSnqbvDZioawRvpLXSaPyn52Srf7OfzjubYbYX8MTUdIgDxQl0wEapm4m/pNYSd9TXocpQ0TvZFlYA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/ms": { "version": "0.7.31", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", @@ -25874,10 +25876,9 @@ } }, "node_modules/crypto-js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", - "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", - "license": "MIT" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "node_modules/css-box-model": { "version": "1.2.1", @@ -29893,8 +29894,8 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#886f90cbd5e83218fdfd7784d8356c308ef05791", - "integrity": "sha512-f+HGB8GZ9NTHT1oI6fhiGfIM3Cd411Qg45Nl0Yd3Te2CU34FhwMNLEkcDa6/zAlYkCeoJUk5XUVmTimjEgS0ig==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#ee14b3255da33d2b6924c357f43393251b6dc6d2", + "integrity": "sha512-u5Is3a/jD9KJ/LtSofeevauDlxZX5++w+VENP2cNhT1lm1GSwRM5FlTT7bIVSyrHr0cppAgl7cLiW2aPDr2hKA==", "license": "MIT", "dependencies": { "classnames": "2.3.1", @@ -30234,9 +30235,10 @@ "license": "MIT" }, "node_modules/fast-diff": { - "version": "1.2.0", - "dev": true, - "license": "Apache-2.0" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true }, "node_modules/fast-equals": { "version": "4.0.3", @@ -30978,6 +30980,18 @@ "dev": true, "license": "MIT" }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", @@ -31123,9 +31137,10 @@ } }, "node_modules/fs-monkey": { - "version": "1.0.3", - "dev": true, - "license": "Unlicense" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true }, "node_modules/fs-write-stream-atomic": { "version": "1.0.10", @@ -32761,6 +32776,15 @@ "which": "bin/which" } }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, "node_modules/hyphenate-style-name": { "version": "1.0.4", "license": "BSD-3-Clause" @@ -37361,6 +37385,13 @@ "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", "license": "MIT" }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "peer": true + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -38589,14 +38620,70 @@ } }, "node_modules/memfs": { - "version": "3.4.7", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.6.0.tgz", + "integrity": "sha512-I6mhA1//KEZfKRQT9LujyW6lRbX7RkC24xKododIDO3AGShcaFAMKElv1yFGWX8fD4UaSiwasr3NeQ5TdtHY1A==", "dev": true, - "license": "Unlicense", "dependencies": { - "fs-monkey": "^1.0.3" + "json-joy": "^9.2.0", + "thingies": "^1.11.1" }, "engines": { "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/memfs/node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/memfs/node_modules/json-joy": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/json-joy/-/json-joy-9.9.1.tgz", + "integrity": "sha512-/d7th2nbQRBQ/nqTkBe6KjjvDciSwn9UICmndwk3Ed/Bk9AqkTRm4PnLVfXG4DKbT0rEY0nKnwE7NqZlqKE6kg==", + "dev": true, + "dependencies": { + "arg": "^5.0.2", + "hyperdyperid": "^1.2.0" + }, + "bin": { + "jj": "bin/jj.js", + "json-pack": "bin/json-pack.js", + "json-pack-test": "bin/json-pack-test.js", + "json-patch": "bin/json-patch.js", + "json-patch-test": "bin/json-patch-test.js", + "json-pointer": "bin/json-pointer.js", + "json-pointer-test": "bin/json-pointer-test.js", + "json-unpack": "bin/json-unpack.js" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "quill-delta": "^5", + "rxjs": "7", + "tslib": "2" + } + }, + "node_modules/memfs/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" } }, "node_modules/memoize-one": { @@ -40889,34 +40976,6 @@ "node": ">=10" } }, - "node_modules/mock-fs": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", - "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", - "dev": true, - "license": "MIT" - }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/moment-timezone": { - "version": "0.5.43", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", - "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", - "license": "MIT", - "dependencies": { - "moment": "^2.29.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -43674,6 +43733,21 @@ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" }, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "dev": true, + "peer": true, + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/raf-schd": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", @@ -44103,8 +44177,9 @@ } }, "node_modules/react-native-collapsible": { - "version": "1.6.0", - "license": "MIT", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.6.1.tgz", + "integrity": "sha512-orF4BeiXd2hZW7fu9YcqIJXzN6TJcFcddY807D3MAOVktLuW9oQ+RIkrTJ5DR3v9ZOFfREkOjEmS79qeUTvkBQ==", "peerDependencies": { "react": "*", "react-native": "*" @@ -44139,8 +44214,9 @@ } }, "node_modules/react-native-document-picker": { - "version": "8.1.1", - "license": "MIT", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-8.2.1.tgz", + "integrity": "sha512-luH2hKdq4cUwE651OscyGderLMsCusOsBzw4MBca91CgprlAGVMm1/pDwJDV5t9LIewVK8DIgXGXzgrsusKVhA==", "dependencies": { "invariant": "^2.2.4" }, @@ -44345,17 +44421,17 @@ } }, "node_modules/react-native-onyx": { - "version": "1.0.115", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.115.tgz", - "integrity": "sha512-uPrJcw3Ta/EFL3Mh3iUggZ7EeEwLTSSSc5iUkKAA+a9Y8kBo8+6MWup9VCM/4wgysZbf3VHUGJCWQ8H3vWKgUg==", + "version": "1.0.118", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.118.tgz", + "integrity": "sha512-w54jO+Bpu1ElHsrxZXIIpcBqNkrUvuVCQmwWdfOW5LvO4UwsPSwmMxzExbUZ4ip+7CROmm10IgXFaAoyfeYSVQ==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", "underscore": "^1.13.6" }, "engines": { - "node": ">=16.15.1 <=18.17.1", - "npm": ">=8.11.0 <=9.6.7" + "node": ">=16.15.1 <=20.9.0", + "npm": ">=8.11.0 <=10.1.0" }, "peerDependencies": { "idb-keyval": "^6.2.1", @@ -44390,11 +44466,11 @@ } }, "node_modules/react-native-pdf": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.1.tgz", - "integrity": "sha512-zszQygtNBYoUfEtP/fV7zhzGeohDlUksh2p3OzshLrxdY9mw7Tm5VXAxYq4d8HsomRJUbFlJ7rHaTU9AQL800g==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.3.tgz", + "integrity": "sha512-bK1fVkj18kBA5YlRFNJ3/vJ1bEX3FDHyAPY6ArtIdVs+vv0HzcK5WH9LSd2bxUsEMIyY9CSjP4j8BcxNXTiQkQ==", "dependencies": { - "crypto-js": "^3.2.0", + "crypto-js": "4.2.0", "deprecated-react-native-prop-types": "^2.3.0" }, "peerDependencies": { @@ -44438,9 +44514,9 @@ } }, "node_modules/react-native-picker-select": { - "version": "8.0.4", - "resolved": "git+ssh://git@github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", - "integrity": "sha512-3U/mtHN/pKC5yXtJnqj5rre8+4YPSqoXCn/3qKjb5u8BMIiuc5H3KJ0ZbKlZEg/8Uh4j0cvrtcNasdPgMqRgCQ==", + "version": "8.1.0", + "resolved": "git+ssh://git@github.com/Expensify/react-native-picker-select.git#0d15d4618f58e99c1261921111e68ee85bb3c2a8", + "integrity": "sha512-ly0ZCt3K4RX7t9lfSb2OSGAw0cv8UqdMoxNfh5j+KujYYq+N8VsI9O/lmqquNeX/AMp5hM3fjetEWue4nZw/hA==", "license": "MIT", "dependencies": { "lodash.isequal": "^4.5.0" @@ -44450,8 +44526,12 @@ } }, "node_modules/react-native-plaid-link-sdk": { - "version": "10.0.0", - "license": "MIT", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/react-native-plaid-link-sdk/-/react-native-plaid-link-sdk-10.8.0.tgz", + "integrity": "sha512-rhyI19SZdwKCsHtkJ0ZOCD/r0vNLS1vqUAS3HPPa97IIN6nS2ln9krLA7lFfMKtWxY5Z5d73SqTmqhd1qqdNuA==", + "dependencies": { + "react-native-plaid-link-sdk": "^10.4.0" + }, "peerDependencies": { "react": "*", "react-native": ">=0.66.0" @@ -49318,6 +49398,18 @@ "dev": true, "license": "MIT" }, + "node_modules/thingies": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.12.0.tgz", + "integrity": "sha512-AiGqfYC1jLmJagbzQGuoZRM48JPsr9yB734a7K6wzr34NMhjUPrWSQrkF7ZBybf3yCerCL2Gcr02kMv4NmaZfA==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, "node_modules/throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -51712,6 +51804,18 @@ "node": ">= 10" } }, + "node_modules/webpack-dev-server/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/webpack-dev-server/node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -58598,14 +58702,6 @@ "joi": "^17.2.1" } }, - "@react-native-community/datetimepicker": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-3.5.2.tgz", - "integrity": "sha512-TWRuAtr/DnrEcRewqvXMLea2oB+YF+SbtuYLHguALLxNJQLl/RFB7aTNZeF+OoH75zKFqtXECXV1/uxQUpA+sg==", - "requires": { - "invariant": "^2.2.4" - } - }, "@react-native-community/eslint-config": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-3.0.0.tgz", @@ -61835,6 +61931,15 @@ } } }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -64760,6 +64865,15 @@ } } }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -66623,15 +66737,6 @@ "version": "3.0.5", "dev": true }, - "@types/mock-fs": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.1.tgz", - "integrity": "sha512-m6nFAJ3lBSnqbvDZioawRvpLXSaPyn52Srf7OfzjubYbYX8MTUdIgDxQl0wEapm4m/pNYSd9TXocpQ0TvZFlYA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/ms": { "version": "0.7.31", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", @@ -71397,9 +71502,9 @@ } }, "crypto-js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", - "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "css-box-model": { "version": "1.2.1", @@ -74298,9 +74403,9 @@ } }, "expensify-common": { - "version": "git+ssh://git@github.com/Expensify/expensify-common.git#886f90cbd5e83218fdfd7784d8356c308ef05791", - "integrity": "sha512-f+HGB8GZ9NTHT1oI6fhiGfIM3Cd411Qg45Nl0Yd3Te2CU34FhwMNLEkcDa6/zAlYkCeoJUk5XUVmTimjEgS0ig==", - "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#886f90cbd5e83218fdfd7784d8356c308ef05791", + "version": "git+ssh://git@github.com/Expensify/expensify-common.git#ee14b3255da33d2b6924c357f43393251b6dc6d2", + "integrity": "sha512-u5Is3a/jD9KJ/LtSofeevauDlxZX5++w+VENP2cNhT1lm1GSwRM5FlTT7bIVSyrHr0cppAgl7cLiW2aPDr2hKA==", + "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#ee14b3255da33d2b6924c357f43393251b6dc6d2", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", @@ -74550,7 +74655,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-diff": { - "version": "1.2.0", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, "fast-equals": { @@ -75081,6 +75188,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, "schema-utils": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", @@ -75180,7 +75296,9 @@ } }, "fs-monkey": { - "version": "1.0.3", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", "dev": true }, "fs-write-stream-atomic": { @@ -76351,6 +76469,12 @@ } } }, + "hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true + }, "hyphenate-style-name": { "version": "1.0.4" }, @@ -79541,6 +79665,13 @@ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "peer": true + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -80450,10 +80581,41 @@ } }, "memfs": { - "version": "3.4.7", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.6.0.tgz", + "integrity": "sha512-I6mhA1//KEZfKRQT9LujyW6lRbX7RkC24xKododIDO3AGShcaFAMKElv1yFGWX8fD4UaSiwasr3NeQ5TdtHY1A==", "dev": true, "requires": { - "fs-monkey": "^1.0.3" + "json-joy": "^9.2.0", + "thingies": "^1.11.1" + }, + "dependencies": { + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "json-joy": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/json-joy/-/json-joy-9.9.1.tgz", + "integrity": "sha512-/d7th2nbQRBQ/nqTkBe6KjjvDciSwn9UICmndwk3Ed/Bk9AqkTRm4PnLVfXG4DKbT0rEY0nKnwE7NqZlqKE6kg==", + "dev": true, + "requires": { + "arg": "^5.0.2", + "hyperdyperid": "^1.2.0" + } + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + } } }, "memoize-one": { @@ -82108,25 +82270,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, - "mock-fs": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", - "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", - "dev": true - }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" - }, - "moment-timezone": { - "version": "0.5.43", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", - "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", - "requires": { - "moment": "^2.29.4" - } - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -84088,6 +84231,18 @@ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" }, + "quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "dev": true, + "peer": true, + "requires": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + } + }, "raf-schd": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", @@ -84511,7 +84666,9 @@ "dev": true }, "react-native-collapsible": { - "version": "1.6.0", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.6.1.tgz", + "integrity": "sha512-orF4BeiXd2hZW7fu9YcqIJXzN6TJcFcddY807D3MAOVktLuW9oQ+RIkrTJ5DR3v9ZOFfREkOjEmS79qeUTvkBQ==", "requires": {} }, "react-native-config": { @@ -84529,7 +84686,9 @@ "requires": {} }, "react-native-document-picker": { - "version": "8.1.1", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-8.2.1.tgz", + "integrity": "sha512-luH2hKdq4cUwE651OscyGderLMsCusOsBzw4MBca91CgprlAGVMm1/pDwJDV5t9LIewVK8DIgXGXzgrsusKVhA==", "requires": { "invariant": "^2.2.4" } @@ -84651,9 +84810,9 @@ } }, "react-native-onyx": { - "version": "1.0.115", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.115.tgz", - "integrity": "sha512-uPrJcw3Ta/EFL3Mh3iUggZ7EeEwLTSSSc5iUkKAA+a9Y8kBo8+6MWup9VCM/4wgysZbf3VHUGJCWQ8H3vWKgUg==", + "version": "1.0.118", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.118.tgz", + "integrity": "sha512-w54jO+Bpu1ElHsrxZXIIpcBqNkrUvuVCQmwWdfOW5LvO4UwsPSwmMxzExbUZ4ip+7CROmm10IgXFaAoyfeYSVQ==", "requires": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -84667,11 +84826,11 @@ "requires": {} }, "react-native-pdf": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.1.tgz", - "integrity": "sha512-zszQygtNBYoUfEtP/fV7zhzGeohDlUksh2p3OzshLrxdY9mw7Tm5VXAxYq4d8HsomRJUbFlJ7rHaTU9AQL800g==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.3.tgz", + "integrity": "sha512-bK1fVkj18kBA5YlRFNJ3/vJ1bEX3FDHyAPY6ArtIdVs+vv0HzcK5WH9LSd2bxUsEMIyY9CSjP4j8BcxNXTiQkQ==", "requires": { - "crypto-js": "^3.2.0", + "crypto-js": "4.2.0", "deprecated-react-native-prop-types": "^2.3.0" } }, @@ -84695,16 +84854,20 @@ "requires": {} }, "react-native-picker-select": { - "version": "git+ssh://git@github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", - "integrity": "sha512-3U/mtHN/pKC5yXtJnqj5rre8+4YPSqoXCn/3qKjb5u8BMIiuc5H3KJ0ZbKlZEg/8Uh4j0cvrtcNasdPgMqRgCQ==", - "from": "react-native-picker-select@git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", + "version": "git+ssh://git@github.com/Expensify/react-native-picker-select.git#0d15d4618f58e99c1261921111e68ee85bb3c2a8", + "integrity": "sha512-ly0ZCt3K4RX7t9lfSb2OSGAw0cv8UqdMoxNfh5j+KujYYq+N8VsI9O/lmqquNeX/AMp5hM3fjetEWue4nZw/hA==", + "from": "react-native-picker-select@git+https://github.com/Expensify/react-native-picker-select.git#0d15d4618f58e99c1261921111e68ee85bb3c2a8", "requires": { "lodash.isequal": "^4.5.0" } }, "react-native-plaid-link-sdk": { - "version": "10.0.0", - "requires": {} + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/react-native-plaid-link-sdk/-/react-native-plaid-link-sdk-10.8.0.tgz", + "integrity": "sha512-rhyI19SZdwKCsHtkJ0ZOCD/r0vNLS1vqUAS3HPPa97IIN6nS2ln9krLA7lFfMKtWxY5Z5d73SqTmqhd1qqdNuA==", + "requires": { + "react-native-plaid-link-sdk": "^10.4.0" + } }, "react-native-qrcode-svg": { "version": "6.2.0", @@ -88155,6 +88318,13 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "thingies": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.12.0.tgz", + "integrity": "sha512-AiGqfYC1jLmJagbzQGuoZRM48JPsr9yB734a7K6wzr34NMhjUPrWSQrkF7ZBybf3yCerCL2Gcr02kMv4NmaZfA==", + "dev": true, + "requires": {} + }, "throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -89952,6 +90122,15 @@ "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", "dev": true }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, "schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", diff --git a/package.json b/package.json index 75d50d4d1905..addbb623f592 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.98-4", + "version": "1.4.11-6", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", @@ -51,6 +51,7 @@ "symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map", "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", "test:e2e": "node tests/e2e/testRunner.js --development --skipCheckout --skipInstallDeps --buildMode none", + "test:e2e:dev": "node tests/e2e/testRunner.js --development --skipCheckout --config ./config.dev.js --buildMode skip --skipInstallDeps", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh", "workflow-test:generate": "node workflow_tests/utils/preGenerateTest.js", @@ -73,7 +74,6 @@ "@react-native-async-storage/async-storage": "^1.17.10", "@react-native-camera-roll/camera-roll": "5.4.0", "@react-native-clipboard/clipboard": "^1.12.1", - "@react-native-community/datetimepicker": "^3.5.2", "@react-native-community/geolocation": "^3.0.6", "@react-native-community/netinfo": "^9.3.10", "@react-native-firebase/analytics": "^12.3.0", @@ -98,7 +98,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#886f90cbd5e83218fdfd7784d8356c308ef05791", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#ee14b3255da33d2b6924c357f43393251b6dc6d2", "fbjs": "^3.0.2", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", @@ -106,8 +106,6 @@ "lodash": "4.17.21", "lottie-react-native": "^6.4.0", "mapbox-gl": "^2.15.0", - "moment": "^2.29.4", - "moment-timezone": "^0.5.31", "onfido-sdk-ui": "13.1.0", "patch-package": "^8.0.0", "process": "^0.11.10", @@ -123,11 +121,11 @@ "react-native": "0.72.4", "react-native-android-location-enabler": "^1.2.2", "react-native-blob-util": "^0.17.3", - "react-native-collapsible": "^1.6.0", + "react-native-collapsible": "^1.6.1", "react-native-config": "^1.4.5", "react-native-dev-menu": "^4.1.1", "react-native-device-info": "^10.3.0", - "react-native-document-picker": "^8.0.0", + "react-native-document-picker": "^8.2.1", "react-native-draggable-flatlist": "^4.0.1", "react-native-fast-image": "^8.6.3", "react-native-fs": "^2.20.0", @@ -141,13 +139,13 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.115", + "react-native-onyx": "1.0.118", "react-native-pager-view": "^6.2.0", - "react-native-pdf": "^6.7.1", + "react-native-pdf": "^6.7.3", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.9.3", - "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", - "react-native-plaid-link-sdk": "^10.0.0", + "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#0d15d4618f58e99c1261921111e68ee85bb3c2a8", + "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", "react-native-reanimated": "3.5.4", @@ -214,7 +212,6 @@ "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.195", "@types/mapbox-gl": "^2.7.13", - "@types/mock-fs": "^4.13.1", "@types/pusher-js": "^5.1.0", "@types/react": "^18.2.12", "@types/react-beautiful-dnd": "^13.1.4", @@ -262,8 +259,8 @@ "jest-cli": "29.4.1", "jest-environment-jsdom": "^29.4.1", "jest-transformer-svg": "^2.0.1", + "memfs": "^4.6.0", "metro-react-native-babel-preset": "0.76.8", - "mock-fs": "^4.13.0", "onchange": "^7.1.0", "portfinder": "^1.0.28", "prettier": "^2.8.8", @@ -304,7 +301,7 @@ ] }, "engines": { - "node": "16.15.1", - "npm": "8.11.0" + "node": "20.9.0", + "npm": "10.1.0" } } diff --git a/patches/react-native-web+0.19.9+004+fix-pointer-events.patch b/patches/react-native-web+0.19.9+004+fix-pointer-events.patch new file mode 100644 index 000000000000..a457fbcfe36c --- /dev/null +++ b/patches/react-native-web+0.19.9+004+fix-pointer-events.patch @@ -0,0 +1,22 @@ +diff --git a/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js b/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js +index bdcecc2..63f1364 100644 +--- a/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js ++++ b/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js +@@ -353,7 +353,7 @@ function createAtomicRules(identifier, property, value) { + var _block2 = createDeclarationBlock({ + pointerEvents: 'none' + }); +- rules.push(selector + ">*" + _block2); ++ rules.push(selector + " *" + _block2); + } + } else if (value === 'none' || value === 'box-none') { + finalValue = 'none!important'; +@@ -361,7 +361,7 @@ function createAtomicRules(identifier, property, value) { + var _block3 = createDeclarationBlock({ + pointerEvents: 'auto' + }); +- rules.push(selector + ">*" + _block3); ++ rules.push(selector + " *" + _block3); + } + } + var _block4 = createDeclarationBlock({ diff --git a/patches/react-pdf+6.2.2.patch b/patches/react-pdf+6.2.2.patch new file mode 100644 index 000000000000..752155761250 --- /dev/null +++ b/patches/react-pdf+6.2.2.patch @@ -0,0 +1,28 @@ +diff --git a/node_modules/react-pdf/dist/esm/Document.js b/node_modules/react-pdf/dist/esm/Document.js +index 91db4d4..82cafec 100644 +--- a/node_modules/react-pdf/dist/esm/Document.js ++++ b/node_modules/react-pdf/dist/esm/Document.js +@@ -78,7 +78,10 @@ var Document = /*#__PURE__*/function (_PureComponent) { + cancelRunningTask(_this.runningTask); + + // If another loading is in progress, let's destroy it +- if (_this.loadingTask) _this.loadingTask.destroy(); ++ if (_this.loadingTask) { ++ _this.loadingTask._worker.destroy(); ++ _this.loadingTask.destroy(); ++ }; + var cancellable = makeCancellable(_this.findDocumentSource()); + _this.runningTask = cancellable; + cancellable.promise.then(function (source) { +@@ -251,7 +254,10 @@ var Document = /*#__PURE__*/function (_PureComponent) { + cancelRunningTask(this.runningTask); + + // If loading is in progress, let's destroy it +- if (this.loadingTask) this.loadingTask.destroy(); ++ if (this.loadingTask) { ++ this.loadingTask._worker.destroy(); ++ this.loadingTask.destroy(); ++ }; + } + }, { + key: "childContext", diff --git a/scripts/build-desktop.sh b/scripts/build-desktop.sh index c67c37a527a2..025559dc4671 100755 --- a/scripts/build-desktop.sh +++ b/scripts/build-desktop.sh @@ -14,16 +14,15 @@ else fi SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") -LOCAL_PACKAGES=$(npm bin) source "$SCRIPTS_DIR/shellUtils.sh"; title "Bundling Desktop js Bundle Using Webpack" info " • ELECTRON_ENV: $ELECTRON_ENV" info " • ENV file: $ENV_FILE" info "" -"$LOCAL_PACKAGES/webpack" --config config/webpack/webpack.desktop.js --env envFile=$ENV_FILE +npx webpack --config config/webpack/webpack.desktop.js --env envFile=$ENV_FILE title "Building Desktop App Archive Using Electron" info "" shift 1 -"$LOCAL_PACKAGES/electron-builder" --config config/electronBuilder.config.js "$@" +npx electron-builder --config config/electronBuilder.config.js --publish always "$@" diff --git a/scripts/start-android.sh b/scripts/start-android.sh old mode 100644 new mode 100755 diff --git a/src/App.js b/src/App.js index 698dfe4437b2..e273dcce1e47 100644 --- a/src/App.js +++ b/src/App.js @@ -6,8 +6,10 @@ import Onyx from 'react-native-onyx'; import {PickerStateProvider} from 'react-native-picker-select'; import {SafeAreaProvider} from 'react-native-safe-area-context'; import '../wdyr'; +import ColorSchemeWrapper from './components/ColorSchemeWrapper'; import ComposeProviders from './components/ComposeProviders'; import CustomStatusBar from './components/CustomStatusBar'; +import CustomStatusBarContextProvider from './components/CustomStatusBar/CustomStatusBarContextProvider'; import ErrorBoundary from './components/ErrorBoundary'; import HTMLEngineProvider from './components/HTMLEngineProvider'; import {LocaleContextProvider} from './components/LocaleContextProvider'; @@ -24,6 +26,7 @@ import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; import * as Session from './libs/actions/Session'; import * as Environment from './libs/Environment/Environment'; import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext'; +import ThemeIllustrationsProvider from './styles/illustrations/ThemeIllustrationsProvider'; import ThemeProvider from './styles/themes/ThemeProvider'; import ThemeStylesProvider from './styles/ThemeStylesProvider'; @@ -50,6 +53,9 @@ function App() { - + + + diff --git a/src/CONST.ts b/src/CONST.ts index eda1dd34cc50..4a2c21dfa1fe 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -55,6 +55,9 @@ const CONST = { ALLOWED_RECEIPT_EXTENSIONS: ['jpg', 'jpeg', 'gif', 'png', 'pdf', 'htm', 'html', 'text', 'rtf', 'doc', 'tif', 'tiff', 'msword', 'zip', 'xml', 'message'], }, + // This is limit set on servers, do not update without wider internal discussion + API_TRANSACTION_CATEGORY_MAX_LENGTH: 255, + AUTO_AUTH_STATE: { NOT_STARTED: 'not-started', SIGNING_IN: 'signing-in', @@ -218,9 +221,8 @@ const CONST = { REGEX: { US_ACCOUNT_NUMBER: /^[0-9]{4,17}$/, - // If the account number length is from 4 to 13 digits, we show the last 4 digits and hide the rest with X - // If the length is longer than 13 digits, we show the first 6 and last 4 digits, hiding the rest with X - MASKED_US_ACCOUNT_NUMBER: /^[X]{0,9}[0-9]{4}$|^[0-9]{6}[X]{4,7}[0-9]{4}$/, + // The back-end is always returning account number with 4 last digits and mask the rest with X + MASKED_US_ACCOUNT_NUMBER: /^[X]{0,13}[0-9]{4}$/, SWIFT_BIC: /^[A-Za-z0-9]{8,11}$/, }, VERIFICATION_MAX_ATTEMPTS: 7, @@ -249,19 +251,9 @@ const CONST = { BETAS: { ALL: 'all', CHRONOS_IN_CASH: 'chronosInCash', - PAY_WITH_EXPENSIFY: 'payWithExpensify', - FREE_PLAN: 'freePlan', DEFAULT_ROOMS: 'defaultRooms', - BETA_EXPENSIFY_WALLET: 'expensifyWallet', BETA_COMMENT_LINKING: 'commentLinking', - INTERNATIONALIZATION: 'internationalization', POLICY_ROOMS: 'policyRooms', - PASSWORDLESS: 'passwordless', - TASKS: 'tasks', - THREADS: 'threads', - CUSTOM_STATUS: 'customStatus', - NEW_DOT_TAGS: 'newDotTags', - NEW_DOT_SAML: 'newDotSAML', VIOLATIONS: 'violations', }, BUTTON_STATES: { @@ -469,7 +461,6 @@ const CONST = { ONFIDO_FACIAL_SCAN_POLICY_URL: 'https://onfido.com/facial-scan-policy-and-release/', ONFIDO_PRIVACY_POLICY_URL: 'https://onfido.com/privacy/', ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/', - // Use Environment.getEnvironmentURL to get the complete URL with port number DEV_NEW_EXPENSIFY_URL: 'https://dev.new.expensify.com:', @@ -495,6 +486,7 @@ const CONST = { MAX_REPORT_PREVIEW_RECEIPTS: 3, }, REPORT: { + MAX_COUNT_BEFORE_FOCUS_UPDATE: 30, MAXIMUM_PARTICIPANTS: 8, SPLIT_REPORTID: '-2', ACTIONS: { @@ -507,7 +499,9 @@ const CONST = { CREATED: 'CREATED', IOU: 'IOU', MODIFIEDEXPENSE: 'MODIFIEDEXPENSE', + MOVED: 'MOVED', REIMBURSEMENTQUEUED: 'REIMBURSEMENTQUEUED', + REIMBURSEMENTDEQUEUED: 'REIMBURSEMENTDEQUEUED', RENAMED: 'RENAMED', REPORTPREVIEW: 'REPORTPREVIEW', SUBMITTED: 'SUBMITTED', @@ -517,6 +511,7 @@ const CONST = { TASKREOPENED: 'TASKREOPENED', POLICYCHANGELOG: { ADD_APPROVER_RULE: 'POLICYCHANGELOG_ADD_APPROVER_RULE', + ADD_BUDGET: 'POLICYCHANGELOG_ADD_BUDGET', ADD_CATEGORY: 'POLICYCHANGELOG_ADD_CATEGORY', ADD_CUSTOM_UNIT: 'POLICYCHANGELOG_ADD_CUSTOM_UNIT', ADD_CUSTOM_UNIT_RATE: 'POLICYCHANGELOG_ADD_CUSTOM_UNIT_RATE', @@ -526,6 +521,7 @@ const CONST = { ADD_TAG: 'POLICYCHANGELOG_ADD_TAG', DELETE_ALL_TAGS: 'POLICYCHANGELOG_DELETE_ALL_TAGS', DELETE_APPROVER_RULE: 'POLICYCHANGELOG_DELETE_APPROVER_RULE', + DELETE_BUDGET: 'POLICYCHANGELOG_DELETE_BUDGET', DELETE_CATEGORY: 'POLICYCHANGELOG_DELETE_CATEGORY', DELETE_CUSTOM_UNIT: 'POLICYCHANGELOG_DELETE_CUSTOM_UNIT', DELETE_CUSTOM_UNIT_RATE: 'POLICYCHANGELOG_DELETE_CUSTOM_UNIT_RATE', @@ -547,6 +543,7 @@ const CONST = { UPDATE_AUTOHARVESTING: 'POLICYCHANGELOG_UPDATE_AUTOHARVESTING', UPDATE_AUTOREIMBURSEMENT: 'POLICYCHANGELOG_UPDATE_AUTOREIMBURSEMENT', UPDATE_AUTOREPORTING_FREQUENCY: 'POLICYCHANGELOG_UPDATE_AUTOREPORTING_FREQUENCY', + UPDATE_BUDGET: 'POLICYCHANGELOG_UPDATE_BUDGET', UPDATE_CATEGORY: 'POLICYCHANGELOG_UPDATE_CATEGORY', UPDATE_CURRENCY: 'POLICYCHANGELOG_UPDATE_CURRENCY', UPDATE_CUSTOM_UNIT: 'POLICYCHANGELOG_UPDATE_CUSTOM_UNIT', @@ -567,6 +564,8 @@ const CONST = { UPDATE_REIMBURSEMENT_CHOICE: 'POLICYCHANGELOG_UPDATE_REIMBURSEMENT_CHOICE', UPDATE_REPORT_FIELD: 'POLICYCHANGELOG_UPDATE_REPORT_FIELD', UPDATE_TAG: 'POLICYCHANGELOG_UPDATE_TAG', + UPDATE_TAG_ENABLED: 'POLICYCHANGELOG_UPDATE_TAG_ENABLED', + UPDATE_TAG_LIST: 'POLICYCHANGELOG_UPDATE_TAG_LIST', UPDATE_TAG_LIST_NAME: 'POLICYCHANGELOG_UPDATE_TAG_LIST_NAME', UPDATE_TAG_NAME: 'POLICYCHANGELOG_UPDATE_TAG_NAME', UPDATE_TIME_ENABLED: 'POLICYCHANGELOG_UPDATE_TIME_ENABLED', @@ -610,6 +609,7 @@ const CONST = { ADMINS: '#admins', }, STATE: { + OPEN: 'OPEN', SUBMITTED: 'SUBMITTED', PROCESSING: 'PROCESSING', }, @@ -708,6 +708,14 @@ const CONST = { DARK: 'dark', SYSTEM: 'system', }, + COLOR_SCHEME: { + LIGHT: 'light', + DARK: 'dark', + }, + STATUS_BAR_STYLE: { + LIGHT_CONTENT: 'light-content', + DARK_CONTENT: 'dark-content', + }, TRANSACTION: { DEFAULT_MERCHANT: 'Request', UNKNOWN_MERCHANT: 'Unknown Merchant', @@ -892,6 +900,7 @@ const CONST = { ATTACHMENT_SOURCE_ATTRIBUTE: 'data-expensify-source', ATTACHMENT_PREVIEW_ATTRIBUTE: 'src', ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE: 'data-name', + ATTACHMENT_LOCAL_URL_PREFIX: ['blob:', 'file:'], ATTACHMENT_PICKER_TYPE: { FILE: 'file', @@ -962,6 +971,7 @@ const CONST = { GUIDES_DOMAIN: 'team.expensify.com', HELP: 'help@expensify.com', INTEGRATION_TESTING_CREDS: 'integrationtestingcreds@expensify.com', + NOTIFICATIONS: 'notifications@expensify.com', PAYROLL: 'payroll@expensify.com', QA: 'qa@expensify.com', QA_TRAVIS: 'qa+travisreceipts@expensify.com', @@ -981,6 +991,7 @@ const CONST = { FIRST_RESPONDER: Number(Config?.EXPENSIFY_ACCOUNT_ID_FIRST_RESPONDER ?? 9375152), HELP: Number(Config?.EXPENSIFY_ACCOUNT_ID_HELP ?? -1), INTEGRATION_TESTING_CREDS: Number(Config?.EXPENSIFY_ACCOUNT_ID_INTEGRATION_TESTING_CREDS ?? -1), + NOTIFICATIONS: Number(Config?.EXPENSIFY_ACCOUNT_ID_NOTIFICATIONS ?? 11665625), PAYROLL: Number(Config?.EXPENSIFY_ACCOUNT_ID_PAYROLL ?? 9679724), QA: Number(Config?.EXPENSIFY_ACCOUNT_ID_QA ?? 3126513), QA_TRAVIS: Number(Config?.EXPENSIFY_ACCOUNT_ID_QA_TRAVIS ?? 8595733), @@ -1120,7 +1131,8 @@ const CONST = { PAYMENT_METHODS: { DEBIT_CARD: 'debitCard', - BANK_ACCOUNT: 'bankAccount', + PERSONAL_BANK_ACCOUNT: 'bankAccount', + BUSINESS_BANK_ACCOUNT: 'businessBankAccount', }, PAYMENT_METHOD_ID_KEYS: { @@ -1129,6 +1141,8 @@ const CONST = { }, IOU: { + // This is the transactionID used when going through the create money request flow so that it mimics a real transaction (like the edit flow) + OPTIMISTIC_TRANSACTION_ID: '1', // Note: These payment types are used when building IOU reportAction message values in the server and should // not be changed. PAYMENT_TYPE: { @@ -1141,6 +1155,11 @@ const CONST = { SPLIT: 'split', REQUEST: 'request', }, + REQUEST_TYPE: { + DISTANCE: 'distance', + MANUAL: 'manual', + SCAN: 'scan', + }, REPORT_ACTION_TYPE: { PAY: 'pay', CREATE: 'create', @@ -1163,6 +1182,10 @@ const CONST = { DOCX: 'docx', SVG: 'svg', }, + RECEIPT_ERROR: 'receiptError', + CANCEL_REASON: { + PAYMENT_EXPIRED: 'CANCEL_REASON_PAYMENT_EXPIRED', + }, }, GROWL: { @@ -1209,7 +1232,11 @@ const CONST = { TYPE: { FREE: 'free', PERSONAL: 'personal', + + // Often referred to as "control" workspaces CORPORATE: 'corporate', + + // Often referred to as "collect" workspaces TEAM: 'team', }, ROLE: { @@ -1362,7 +1389,6 @@ const CONST = { TIME_STARTS_01: /^01:\d{2} [AP]M$/, TIME_FORMAT: /^\d{2}:\d{2} [AP]M$/, DATE_TIME_FORMAT: /^\d{2}-\d{2} \d{2}:\d{2} [AP]M$/, - ATTACHMENT_ROUTE: /\/r\/(\d*)\/attachment/, ILLEGAL_FILENAME_CHARACTERS: /\/|<|>|\*|"|:|\?|\\|\|/g, ENCODE_PERCENT_CHARACTER: /%(25)+/g, @@ -1399,6 +1425,7 @@ const CONST = { this.EMAIL.FIRST_RESPONDER, this.EMAIL.HELP, this.EMAIL.INTEGRATION_TESTING_CREDS, + this.EMAIL.NOTIFICATIONS, this.EMAIL.PAYROLL, this.EMAIL.QA, this.EMAIL.QA_TRAVIS, @@ -2741,6 +2768,9 @@ const CONST = { NEW_CHAT: 'chat', NEW_ROOM: 'room', RECEIPT_TAB_ID: 'ReceiptTab', + IOU_REQUEST_TYPE: 'iouRequestType', + }, + TAB_REQUEST: { MANUAL: 'manual', SCAN: 'scan', DISTANCE: 'distance', @@ -2794,7 +2824,7 @@ const CONST = { HORIZONTAL_SPACER: { DEFAULT_BORDER_BOTTOM_WIDTH: 1, DEFAULT_MARGIN_VERTICAL: 8, - HIDDEN_MARGIN_VERTICAL: 0, + HIDDEN_MARGIN_VERTICAL: 4, HIDDEN_BORDER_BOTTOM_WIDTH: 0, }, @@ -2810,6 +2840,77 @@ const CONST = { * The count of characters we'll allow the user to type after reaching SEARCH_MAX_LENGTH in an input. */ ADDITIONAL_ALLOWED_CHARACTERS: 20, + + REFERRAL_PROGRAM: { + CONTENT_TYPES: { + MONEY_REQUEST: 'request', + START_CHAT: 'startChat', + SEND_MONEY: 'sendMoney', + REFER_FRIEND: 'referralFriend', + SHARE_CODE: 'shareCode', + }, + REVENUE: 250, + LEARN_MORE_LINK: 'https://help.expensify.com/articles/new-expensify/billing-and-plan-types/Referral-Program', + LINK: 'https://join.my.expensify.com', + }, + + /** + * native IDs for close buttons in Overlay component + */ + OVERLAY: { + TOP_BUTTON_NATIVE_ID: 'overLayTopButton', + BOTTOM_BUTTON_NATIVE_ID: 'overLayBottomButton', + }, + + BACK_BUTTON_NATIVE_ID: 'backButton', + + /** + * The maximum count of items per page for OptionsSelector. + * When paginate, it multiplies by page number. + */ + MAX_OPTIONS_SELECTOR_PAGE_LENGTH: 500, + + /** + * Performance test setup - run the same test multiple times to get a more accurate result + */ + PERFORMANCE_TESTS: { + RUNS: 20, + }, + + /** + * Bank account names + */ + BANK_NAMES: { + EXPENSIFY: 'expensify', + AMERICAN_EXPRESS: 'americanexpress', + BANK_OF_AMERICA: 'bank of america', + BB_T: 'bbt', + CAPITAL_ONE: 'capital one', + CHASE: 'chase', + CHARLES_SCHWAB: 'charles schwab', + CITIBANK: 'citibank', + CITIZENS_BANK: 'citizens bank', + DISCOVER: 'discover', + FIDELITY: 'fidelity', + GENERIC_BANK: 'generic bank', + HUNTINGTON_BANK: 'huntington bank', + HUNTINGTON_NATIONAL: 'huntington national', + NAVY_FEDERAL_CREDIT_UNION: 'navy federal credit union', + PNC: 'pnc', + REGIONS_BANK: 'regions bank', + SUNTRUST: 'suntrust', + TD_BANK: 'td bank', + US_BANK: 'us bank', + USAA: 'usaa', + }, + + /** + * Constants for maxToRenderPerBatch parameter that is used for FlatList or SectionList. This controls the amount of items rendered per batch, which is the next chunk of items rendered on every scroll. + */ + MAX_TO_RENDER_PER_BATCH: { + DEFAULT: 5, + CAROUSEL: 3, + }, } as const; export default CONST; diff --git a/src/Expensify.js b/src/Expensify.js index 1b692f86a197..aece93c0ff4d 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -7,6 +7,7 @@ import _ from 'underscore'; import ConfirmModal from './components/ConfirmModal'; import DeeplinkWrapper from './components/DeeplinkWrapper'; import EmojiPicker from './components/EmojiPicker/EmojiPicker'; +import FocusModeNotification from './components/FocusModeNotification'; import GrowlNotification from './components/GrowlNotification'; import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper'; import SplashScreenHider from './components/SplashScreenHider'; @@ -76,6 +77,9 @@ const propTypes = { /** Whether the app is waiting for the server's response to determine if a room is public */ isCheckingPublicRoom: PropTypes.bool, + /** Whether we should display the notification alerting the user that focus mode has been auto-enabled */ + focusModeNotification: PropTypes.bool, + ...withLocalizePropTypes, }; @@ -88,6 +92,7 @@ const defaultProps = { isSidebarLoaded: false, screenShareRequest: null, isCheckingPublicRoom: true, + focusModeNotification: false, }; const SplashScreenHiddenContext = React.createContext({}); @@ -221,6 +226,7 @@ function Expensify(props) { isVisible /> ) : null} + {props.focusModeNotification ? : null} )} @@ -261,6 +267,10 @@ export default compose( screenShareRequest: { key: ONYXKEYS.SCREEN_SHARE_REQUEST, }, + focusModeNotification: { + key: ONYXKEYS.FOCUS_MODE_NOTIFICATION, + initWithStoredValues: false, + }, }), )(Expensify); diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index fa72a99b5fa2..9cd55b41455b 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -84,6 +84,9 @@ const ONYXKEYS = { /** Contains all the users settings for the Settings page and sub pages */ USER: 'user', + /** Contains latitude and longitude of user's last known location */ + USER_LOCATION: 'userLocation', + /** Contains metadata (partner, login, validation date) for all of the user's logins */ LOGIN_LIST: 'loginList', @@ -149,6 +152,12 @@ const ONYXKEYS = { /** The user's cash card and imported cards (including the Expensify Card) */ CARD_LIST: 'cardList', + /** Whether the user has tried focus mode yet */ + NVP_TRY_FOCUS_MODE: 'tryFocusMode', + + /** Boolean flag used to display the focus mode notification */ + FOCUS_MODE_NOTIFICATION: 'focusModeNotification', + /** Stores information about the user's saved statements */ WALLET_STATEMENT: 'walletStatement', @@ -246,6 +255,7 @@ const ONYXKEYS = { POLICY_TAGS: 'policyTags_', POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', + WORKSPACE_INVITE_MESSAGE_DRAFT: 'workspaceInviteMessageDraft_', REPORT: 'report_', // REPORT_METADATA is a perf optimization used to hold loading states (isLoadingInitialReportActions, isLoadingOlderReportActions, isLoadingNewerReportActions). // A lot of components are connected to the Report entity and do not care about the actions. Setting the loading state @@ -261,6 +271,10 @@ const ONYXKEYS = { REPORT_USER_IS_LEAVING_ROOM: 'reportUserIsLeavingRoom_', SECURITY_GROUP: 'securityGroup_', TRANSACTION: 'transactions_', + TRANSACTION_VIOLATIONS: 'transactionViolations_', + + // Holds temporary transactions used during the creation and edit flow + TRANSACTION_DRAFT: 'transactionsDraft_', SPLIT_TRANSACTION_DRAFT: 'splitTransactionDraft_', PRIVATE_NOTES_DRAFT: 'privateNotesDraft_', NEXT_STEP: 'reportNextStep_', @@ -334,6 +348,8 @@ const ONYXKEYS = { REPORT_PHYSICAL_CARD_FORM_DRAFT: 'requestPhysicalCardFormDraft', REPORT_VIRTUAL_CARD_FRAUD: 'reportVirtualCardFraudForm', REPORT_VIRTUAL_CARD_FRAUD_DRAFT: 'reportVirtualCardFraudFormDraft', + GET_PHYSICAL_CARD_FORM: 'getPhysicalCardForm', + GET_PHYSICAL_CARD_FORM_DRAFT: 'getPhysicalCardFormDraft', }, } as const; @@ -366,12 +382,15 @@ type OnyxValues = { [ONYXKEYS.COUNTRY_CODE]: number; [ONYXKEYS.COUNTRY]: string; [ONYXKEYS.USER]: OnyxTypes.User; - [ONYXKEYS.LOGIN_LIST]: OnyxTypes.Login; + [ONYXKEYS.USER_LOCATION]: OnyxTypes.UserLocation; + [ONYXKEYS.LOGIN_LIST]: Record; [ONYXKEYS.SESSION]: OnyxTypes.Session; [ONYXKEYS.BETAS]: OnyxTypes.Beta[]; [ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf; [ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge; [ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string; + [ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean; + [ONYXKEYS.FOCUS_MODE_NOTIFICATION]: boolean; [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: Record; [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoint[]; [ONYXKEYS.PUSH_NOTIFICATIONS_ENABLED]: boolean; @@ -379,7 +398,7 @@ type OnyxValues = { [ONYXKEYS.IS_PLAID_DISABLED]: boolean; [ONYXKEYS.PLAID_LINK_TOKEN]: string; [ONYXKEYS.ONFIDO_TOKEN]: string; - [ONYXKEYS.NVP_PREFERRED_LOCALE]: ValueOf; + [ONYXKEYS.NVP_PREFERRED_LOCALE]: OnyxTypes.Locale; [ONYXKEYS.USER_WALLET]: OnyxTypes.UserWallet; [ONYXKEYS.WALLET_ONFIDO]: OnyxTypes.WalletOnfido; [ONYXKEYS.WALLET_ADDITIONAL_DETAILS]: OnyxTypes.WalletAdditionalDetails; @@ -397,6 +416,7 @@ type OnyxValues = { [ONYXKEYS.IS_LOADING_PAYMENT_METHODS]: boolean; [ONYXKEYS.IS_LOADING_REPORT_DATA]: boolean; [ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN]: boolean; + [ONYXKEYS.IS_LOADING_APP]: boolean; [ONYXKEYS.WALLET_TRANSFER]: OnyxTypes.WalletTransfer; [ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID]: string; [ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT]: boolean; @@ -409,6 +429,7 @@ type OnyxValues = { [ONYXKEYS.MAPBOX_ACCESS_TOKEN]: OnyxTypes.MapboxAccessToken; [ONYXKEYS.ONYX_UPDATES_FROM_SERVER]: OnyxTypes.OnyxUpdatesFromServer; [ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT]: number; + [ONYXKEYS.DEMO_INFO]: OnyxTypes.DemoInfo; [ONYXKEYS.MAX_CANVAS_AREA]: number; [ONYXKEYS.MAX_CANVAS_HEIGHT]: number; [ONYXKEYS.MAX_CANVAS_WIDTH]: number; @@ -500,6 +521,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM_DRAFT]: OnyxTypes.Form; + [ONYXKEYS.FORMS.GET_PHYSICAL_CARD_FORM]: OnyxTypes.Form; + [ONYXKEYS.FORMS.GET_PHYSICAL_CARD_FORM_DRAFT]: OnyxTypes.Form | undefined; }; type OnyxKeyValue = OnyxEntry; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index ed9cc6ae987c..53763d6d7cd1 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1,30 +1,29 @@ -import {ValueOf} from 'type-fest'; +import {IsEqual, ValueOf} from 'type-fest'; import CONST from './CONST'; -/** - * This is a file containing constants for all the routes we want to be able to go to - */ +// This is a file containing constants for all the routes we want to be able to go to /** * Builds a URL with an encoded URI component for the `backTo` param which can be added to the end of URLs */ -function getUrlWithBackToParam(url: string, backTo?: string): string { - const backToParam = backTo ? `${url.includes('?') ? '&' : '?'}backTo=${encodeURIComponent(backTo)}` : ''; - return url + backToParam; +function getUrlWithBackToParam(url: TUrl, backTo?: string): `${TUrl}` | `${TUrl}?backTo=${string}` | `${TUrl}&backTo=${string}` { + const backToParam = backTo ? (`${url.includes('?') ? '&' : '?'}backTo=${encodeURIComponent(backTo)}` as const) : ''; + return `${url}${backToParam}` as const; } -export default { +const ROUTES = { HOME: '', - /** This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated */ + + // This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated CONCIERGE: 'concierge', FLAG_COMMENT: { route: 'flag/:reportID/:reportActionID', - getRoute: (reportID: string, reportActionID: string) => `flag/${reportID}/${reportActionID}`, + getRoute: (reportID: string, reportActionID: string) => `flag/${reportID}/${reportActionID}` as const, }, SEARCH: 'search', DETAILS: { route: 'details', - getRoute: (login: string) => `details?login=${encodeURIComponent(login)}`, + getRoute: (login: string) => `details?login=${encodeURIComponent(login)}` as const, }, PROFILE: { route: 'a/:accountID', @@ -35,7 +34,7 @@ export default { VALIDATE_LOGIN: 'v/:accountID/:validateCode', GET_ASSISTANCE: { route: 'get-assistance/:taskID', - getRoute: (taskID: string) => `get-assistance/${taskID}`, + getRoute: (taskID: string) => `get-assistance/${taskID}` as const, }, UNLINK_LOGIN: 'u/:accountID/:validateCode', APPLE_SIGN_IN: 'sign-in-with-apple', @@ -54,7 +53,7 @@ export default { BANK_ACCOUNT_PERSONAL: 'bank-account/personal', BANK_ACCOUNT_WITH_STEP_TO_OPEN: { route: 'bank-account/:stepToOpen?', - getRoute: (stepToOpen = '', policyID = '', backTo?: string): string => getUrlWithBackToParam(`bank-account/${stepToOpen}?policyID=${policyID}`, backTo), + getRoute: (stepToOpen = '', policyID = '', backTo?: string) => getUrlWithBackToParam(`bank-account/${stepToOpen}?policyID=${policyID}`, backTo), }, SETTINGS: 'settings', @@ -77,28 +76,44 @@ export default { SETTINGS_WALLET: 'settings/wallet', SETTINGS_WALLET_DOMAINCARD: { route: '/settings/wallet/card/:domain', - getRoute: (domain: string) => `/settings/wallet/card/${domain}`, + getRoute: (domain: string) => `/settings/wallet/card/${domain}` as const, }, SETTINGS_REPORT_FRAUD: { route: '/settings/wallet/card/:domain/report-virtual-fraud', - getRoute: (domain: string) => `/settings/wallet/card/${domain}/report-virtual-fraud`, + getRoute: (domain: string) => `/settings/wallet/card/${domain}/report-virtual-fraud` as const, + }, + SETTINGS_WALLET_CARD_GET_PHYSICAL_NAME: { + route: '/settings/wallet/card/:domain/get-physical/name', + getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/name` as const, + }, + SETTINGS_WALLET_CARD_GET_PHYSICAL_PHONE: { + route: '/settings/wallet/card/:domain/get-physical/phone', + getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/phone` as const, + }, + SETTINGS_WALLET_CARD_GET_PHYSICAL_ADDRESS: { + route: '/settings/wallet/card/:domain/get-physical/address', + getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/address` as const, + }, + SETTINGS_WALLET_CARD_GET_PHYSICAL_CONFIRM: { + route: '/settings/wallet/card/:domain/get-physical/confirm', + getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/confirm` as const, }, SETTINGS_ADD_DEBIT_CARD: 'settings/wallet/add-debit-card', SETTINGS_ADD_BANK_ACCOUNT: 'settings/wallet/add-bank-account', SETTINGS_ENABLE_PAYMENTS: 'settings/wallet/enable-payments', SETTINGS_WALLET_CARD_DIGITAL_DETAILS_UPDATE_ADDRESS: { route: 'settings/wallet/card/:domain/digital-details/update-address', - getRoute: (domain: string) => `settings/wallet/card/${domain}/digital-details/update-address`, + getRoute: (domain: string) => `settings/wallet/card/${domain}/digital-details/update-address` as const, }, SETTINGS_WALLET_TRANSFER_BALANCE: 'settings/wallet/transfer-balance', SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT: 'settings/wallet/choose-transfer-account', SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED: { route: '/settings/wallet/card/:domain/report-card-lost-or-damaged', - getRoute: (domain: string) => `/settings/wallet/card/${domain}/report-card-lost-or-damaged`, + getRoute: (domain: string) => `/settings/wallet/card/${domain}/report-card-lost-or-damaged` as const, }, SETTINGS_WALLET_CARD_ACTIVATE: { route: 'settings/wallet/card/:domain/activate', - getRoute: (domain: string) => `settings/wallet/card/${domain}/activate`, + getRoute: (domain: string) => `settings/wallet/card/${domain}/activate` as const, }, SETTINGS_PERSONAL_DETAILS: 'settings/profile/personal-details', SETTINGS_PERSONAL_DETAILS_LEGAL_NAME: 'settings/profile/personal-details/legal-name', @@ -114,10 +129,16 @@ export default { }, SETTINGS_CONTACT_METHOD_DETAILS: { route: 'settings/profile/contact-methods/:contactMethod/details', - getRoute: (contactMethod: string) => `settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details`, + getRoute: (contactMethod: string) => `settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details` as const, + }, + SETTINGS_NEW_CONTACT_METHOD: { + route: 'settings/profile/contact-methods/new', + getRoute: (backTo?: string) => getUrlWithBackToParam('settings/profile/contact-methods/new', backTo), + }, + SETTINGS_2FA: { + route: 'settings/security/two-factor-auth', + getRoute: (backTo?: string) => getUrlWithBackToParam('settings/security/two-factor-auth', backTo), }, - SETTINGS_NEW_CONTACT_METHOD: 'settings/profile/contact-methods/new', - SETTINGS_2FA: 'settings/security/two-factor-auth', SETTINGS_STATUS: 'settings/profile/status', SETTINGS_STATUS_SET: 'settings/profile/status/set', @@ -130,161 +151,238 @@ export default { REPORT: 'r', REPORT_WITH_ID: { route: 'r/:reportID?/:reportActionID?', - getRoute: (reportID: string) => `r/${reportID}`, + getRoute: (reportID: string) => `r/${reportID}` as const, }, EDIT_REQUEST: { route: 'r/:threadReportID/edit/:field', - getRoute: (threadReportID: string, field: ValueOf) => `r/${threadReportID}/edit/${field}`, + getRoute: (threadReportID: string, field: ValueOf) => `r/${threadReportID}/edit/${field}` as const, }, EDIT_CURRENCY_REQUEST: { route: 'r/:threadReportID/edit/currency', - getRoute: (threadReportID: string, currency: string, backTo: string) => `r/${threadReportID}/edit/currency?currency=${currency}&backTo=${backTo}`, + getRoute: (threadReportID: string, currency: string, backTo: string) => `r/${threadReportID}/edit/currency?currency=${currency}&backTo=${backTo}` as const, }, REPORT_WITH_ID_DETAILS_SHARE_CODE: { route: 'r/:reportID/details/shareCode', - getRoute: (reportID: string) => `r/${reportID}/details/shareCode`, + getRoute: (reportID: string) => `r/${reportID}/details/shareCode` as const, }, REPORT_ATTACHMENTS: { route: 'r/:reportID/attachment', - getRoute: (reportID: string, source: string) => `r/${reportID}/attachment?source=${encodeURI(source)}`, + getRoute: (reportID: string, source: string) => `r/${reportID}/attachment?source=${encodeURI(source)}` as const, }, REPORT_PARTICIPANTS: { route: 'r/:reportID/participants', - getRoute: (reportID: string) => `r/${reportID}/participants`, + getRoute: (reportID: string) => `r/${reportID}/participants` as const, }, REPORT_WITH_ID_DETAILS: { route: 'r/:reportID/details', - getRoute: (reportID: string) => `r/${reportID}/details`, + getRoute: (reportID: string) => `r/${reportID}/details` as const, }, REPORT_SETTINGS: { route: 'r/:reportID/settings', - getRoute: (reportID: string) => `r/${reportID}/settings`, + getRoute: (reportID: string) => `r/${reportID}/settings` as const, }, REPORT_SETTINGS_ROOM_NAME: { route: 'r/:reportID/settings/room-name', - getRoute: (reportID: string) => `r/${reportID}/settings/room-name`, + getRoute: (reportID: string) => `r/${reportID}/settings/room-name` as const, }, REPORT_SETTINGS_NOTIFICATION_PREFERENCES: { route: 'r/:reportID/settings/notification-preferences', - getRoute: (reportID: string) => `r/${reportID}/settings/notification-preferences`, + getRoute: (reportID: string) => `r/${reportID}/settings/notification-preferences` as const, }, REPORT_SETTINGS_WRITE_CAPABILITY: { route: 'r/:reportID/settings/who-can-post', - getRoute: (reportID: string) => `r/${reportID}/settings/who-can-post`, + getRoute: (reportID: string) => `r/${reportID}/settings/who-can-post` as const, }, REPORT_WELCOME_MESSAGE: { route: 'r/:reportID/welcomeMessage', - getRoute: (reportID: string) => `r/${reportID}/welcomeMessage`, + getRoute: (reportID: string) => `r/${reportID}/welcomeMessage` as const, }, SPLIT_BILL_DETAILS: { route: 'r/:reportID/split/:reportActionID', - getRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}`, + getRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}` as const, }, EDIT_SPLIT_BILL: { route: `r/:reportID/split/:reportActionID/edit/:field`, - getRoute: (reportID: string, reportActionID: string, field: ValueOf) => `r/${reportID}/split/${reportActionID}/edit/${field}`, + getRoute: (reportID: string, reportActionID: string, field: ValueOf) => `r/${reportID}/split/${reportActionID}/edit/${field}` as const, }, EDIT_SPLIT_BILL_CURRENCY: { route: 'r/:reportID/split/:reportActionID/edit/currency', - getRoute: (reportID: string, reportActionID: string, currency: string, backTo: string) => `r/${reportID}/split/${reportActionID}/edit/currency?currency=${currency}&backTo=${backTo}`, + getRoute: (reportID: string, reportActionID: string, currency: string, backTo: string) => + `r/${reportID}/split/${reportActionID}/edit/currency?currency=${currency}&backTo=${backTo}` as const, }, TASK_TITLE: { route: 'r/:reportID/title', - getRoute: (reportID: string) => `r/${reportID}/title`, + getRoute: (reportID: string) => `r/${reportID}/title` as const, }, TASK_DESCRIPTION: { route: 'r/:reportID/description', - getRoute: (reportID: string) => `r/${reportID}/description`, + getRoute: (reportID: string) => `r/${reportID}/description` as const, }, TASK_ASSIGNEE: { route: 'r/:reportID/assignee', - getRoute: (reportID: string) => `r/${reportID}/assignee`, + getRoute: (reportID: string) => `r/${reportID}/assignee` as const, }, PRIVATE_NOTES_VIEW: { route: 'r/:reportID/notes/:accountID', - getRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}`, + getRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}` as const, }, PRIVATE_NOTES_LIST: { route: 'r/:reportID/notes', - getRoute: (reportID: string) => `r/${reportID}/notes`, + getRoute: (reportID: string) => `r/${reportID}/notes` as const, }, PRIVATE_NOTES_EDIT: { route: 'r/:reportID/notes/:accountID/edit', - getRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}/edit`, + getRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}/edit` as const, }, ROOM_MEMBERS: { route: 'r/:reportID/members', - getRoute: (reportID: string) => `r/${reportID}/members`, + getRoute: (reportID: string) => `r/${reportID}/members` as const, }, ROOM_INVITE: { route: 'r/:reportID/invite', - getRoute: (reportID: string) => `r/${reportID}/invite`, + getRoute: (reportID: string) => `r/${reportID}/invite` as const, }, // To see the available iouType, please refer to CONST.IOU.TYPE MONEY_REQUEST: { route: ':iouType/new/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}` as const, }, MONEY_REQUEST_AMOUNT: { route: ':iouType/new/amount/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/amount/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/amount/${reportID}` as const, }, MONEY_REQUEST_PARTICIPANTS: { route: ':iouType/new/participants/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/participants/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/participants/${reportID}` as const, }, MONEY_REQUEST_CONFIRMATION: { route: ':iouType/new/confirmation/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/confirmation/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/confirmation/${reportID}` as const, }, MONEY_REQUEST_DATE: { route: ':iouType/new/date/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/date/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/date/${reportID}` as const, }, MONEY_REQUEST_CURRENCY: { route: ':iouType/new/currency/:reportID?', - getRoute: (iouType: string, reportID: string, currency: string, backTo: string) => `${iouType}/new/currency/${reportID}?currency=${currency}&backTo=${backTo}`, + getRoute: (iouType: string, reportID: string, currency: string, backTo: string) => `${iouType}/new/currency/${reportID}?currency=${currency}&backTo=${backTo}` as const, }, MONEY_REQUEST_DESCRIPTION: { route: ':iouType/new/description/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/description/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/description/${reportID}` as const, }, MONEY_REQUEST_CATEGORY: { route: ':iouType/new/category/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/category/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/category/${reportID}` as const, }, MONEY_REQUEST_TAG: { route: ':iouType/new/tag/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}` as const, }, MONEY_REQUEST_MERCHANT: { route: ':iouType/new/merchant/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/merchant/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/merchant/${reportID}` as const, }, MONEY_REQUEST_WAYPOINT: { route: ':iouType/new/waypoint/:waypointIndex', - getRoute: (iouType: string, waypointIndex: number) => `${iouType}/new/waypoint/${waypointIndex}`, + getRoute: (iouType: string, waypointIndex: number) => `${iouType}/new/waypoint/${waypointIndex}` as const, }, MONEY_REQUEST_RECEIPT: { route: ':iouType/new/receipt/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/receipt/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/receipt/${reportID}` as const, }, MONEY_REQUEST_DISTANCE: { route: ':iouType/new/address/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/address/${reportID}`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/address/${reportID}` as const, }, MONEY_REQUEST_EDIT_WAYPOINT: { route: 'r/:threadReportID/edit/distance/:transactionID/waypoint/:waypointIndex', - getRoute: (threadReportID: number, transactionID: string, waypointIndex: number) => `r/${threadReportID}/edit/distance/${transactionID}/waypoint/${waypointIndex}`, + getRoute: (threadReportID: number, transactionID: string, waypointIndex: number) => `r/${threadReportID}/edit/distance/${transactionID}/waypoint/${waypointIndex}` as const, }, MONEY_REQUEST_DISTANCE_TAB: { route: ':iouType/new/:reportID?/distance', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}/distance`, + getRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}/distance` as const, }, MONEY_REQUEST_MANUAL_TAB: ':iouType/new/:reportID?/manual', MONEY_REQUEST_SCAN_TAB: ':iouType/new/:reportID?/scan', + MONEY_REQUEST_CREATE: { + route: 'create/:iouType/start/:transactionID/:reportID', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}` as const, + }, + MONEY_REQUEST_STEP_CONFIRMATION: { + route: 'create/:iouType/confirmation/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/confirmation/${transactionID}/${reportID}/` as const, + }, + MONEY_REQUEST_STEP_AMOUNT: { + route: 'create/:iouType/amount/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/amount/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_CATEGORY: { + route: 'create/:iouType/category/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/category/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_CURRENCY: { + route: 'create/:iouType/currency/:transactionID/:reportID/:pageIndex?/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') => + getUrlWithBackToParam(`create/${iouType}/currency/${transactionID}/${reportID}/${pageIndex}`, backTo), + }, + MONEY_REQUEST_STEP_DATE: { + route: 'create/:iouType/date/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/date/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_DESCRIPTION: { + route: 'create/:iouType/description/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/description/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_DISTANCE: { + route: 'create/:iouType/distance/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/distance/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_MERCHANT: { + route: 'create/:iouType/merchante/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/merchante/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_PARTICIPANTS: { + route: 'create/:iouType/participants/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/participants/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_SCAN: { + route: 'create/:iouType/scan/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/scan/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_TAG: { + route: 'create/:iouType/tag/:transactionID/:reportID/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`create/${iouType}/tag/${transactionID}/${reportID}/`, backTo), + }, + MONEY_REQUEST_STEP_WAYPOINT: { + route: 'create/:iouType/waypoint/:transactionID/:reportID/:pageIndex/', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') => + getUrlWithBackToParam(`create/${iouType}/waypoint/${transactionID}/${reportID}/${pageIndex}`, backTo), + }, + MONEY_REQUEST_CREATE_TAB_DISTANCE: { + route: 'create/:iouType/start/:transactionID/:reportID/distance', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}/distance` as const, + }, + MONEY_REQUEST_CREATE_TAB_MANUAL: { + route: 'create/:iouType/start/:transactionID/:reportID/manual', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}/manual` as const, + }, + MONEY_REQUEST_CREATE_TAB_SCAN: { + route: 'create/:iouType/start/:transactionID/:reportID/scan', + getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}/scan` as const, + }, + IOU_REQUEST: 'request/new', IOU_SEND: 'send/new', IOU_SEND_ADD_BANK_ACCOUNT: 'send/new/add-bank-account', @@ -305,58 +403,63 @@ export default { ERECEIPT: { route: 'eReceipt/:transactionID', - getRoute: (transactionID: string) => `eReceipt/${transactionID}`, + getRoute: (transactionID: string) => `eReceipt/${transactionID}` as const, }, WORKSPACE_NEW: 'workspace/new', WORKSPACE_NEW_ROOM: 'workspace/new-room', WORKSPACE_INITIAL: { route: 'workspace/:policyID', - getRoute: (policyID: string) => `workspace/${policyID}`, + getRoute: (policyID: string) => `workspace/${policyID}` as const, }, WORKSPACE_INVITE: { route: 'workspace/:policyID/invite', - getRoute: (policyID: string) => `workspace/${policyID}/invite`, + getRoute: (policyID: string) => `workspace/${policyID}/invite` as const, }, WORKSPACE_INVITE_MESSAGE: { route: 'workspace/:policyID/invite-message', - getRoute: (policyID: string) => `workspace/${policyID}/invite-message`, + getRoute: (policyID: string) => `workspace/${policyID}/invite-message` as const, }, WORKSPACE_SETTINGS: { route: 'workspace/:policyID/settings', - getRoute: (policyID: string) => `workspace/${policyID}/settings`, + getRoute: (policyID: string) => `workspace/${policyID}/settings` as const, }, WORKSPACE_SETTINGS_CURRENCY: { route: 'workspace/:policyID/settings/currency', - getRoute: (policyID: string) => `workspace/${policyID}/settings/currency`, + getRoute: (policyID: string) => `workspace/${policyID}/settings/currency` as const, }, WORKSPACE_CARD: { route: 'workspace/:policyID/card', - getRoute: (policyID: string) => `workspace/${policyID}/card`, + getRoute: (policyID: string) => `workspace/${policyID}/card` as const, }, WORKSPACE_REIMBURSE: { route: 'workspace/:policyID/reimburse', - getRoute: (policyID: string) => `workspace/${policyID}/reimburse`, + getRoute: (policyID: string) => `workspace/${policyID}/reimburse` as const, }, WORKSPACE_RATE_AND_UNIT: { route: 'workspace/:policyID/rateandunit', - getRoute: (policyID: string) => `workspace/${policyID}/rateandunit`, + getRoute: (policyID: string) => `workspace/${policyID}/rateandunit` as const, }, WORKSPACE_BILLS: { route: 'workspace/:policyID/bills', - getRoute: (policyID: string) => `workspace/${policyID}/bills`, + getRoute: (policyID: string) => `workspace/${policyID}/bills` as const, }, WORKSPACE_INVOICES: { route: 'workspace/:policyID/invoices', - getRoute: (policyID: string) => `workspace/${policyID}/invoices`, + getRoute: (policyID: string) => `workspace/${policyID}/invoices` as const, }, WORKSPACE_TRAVEL: { route: 'workspace/:policyID/travel', - getRoute: (policyID: string) => `workspace/${policyID}/travel`, + getRoute: (policyID: string) => `workspace/${policyID}/travel` as const, }, WORKSPACE_MEMBERS: { route: 'workspace/:policyID/members', - getRoute: (policyID: string) => `workspace/${policyID}/members`, + getRoute: (policyID: string) => `workspace/${policyID}/members` as const, + }, + // Referral program promotion + REFERRAL_DETAILS_MODAL: { + route: 'referral/:contentType', + getRoute: (contentType: string) => `referral/${contentType}` as const, }, // These are some one-off routes that will be removed once they're no longer needed (see GH issues for details) @@ -364,3 +467,25 @@ export default { SBE: 'sbe', MONEY2020: 'money2020', } as const; + +export {getUrlWithBackToParam}; +export default ROUTES; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ExtractRouteName = TRoute extends {getRoute: (...args: any[]) => infer TRouteName} ? TRouteName : TRoute; + +type AllRoutes = { + [K in keyof typeof ROUTES]: ExtractRouteName<(typeof ROUTES)[K]>; +}[keyof typeof ROUTES]; + +type RouteIsPlainString = IsEqual; + +/** + * Represents all routes in the app as a union of literal strings. + * + * If this type resolves to `never`, it implies that one or more routes defined within `ROUTES` have not correctly used + * `as const` in their `getRoute` function return value. + */ +type Route = RouteIsPlainString extends true ? never : AllRoutes; + +export type {Route}; diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f7de8cfab4b6..921f57953482 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -2,29 +2,242 @@ * This is a file containing constants for all of the screen names. In most cases, we should use the routes for * navigation. But there are situations where we may need to access screen names directly. */ -export default { +import DeepValueOf from './types/utils/DeepValueOf'; + +const PROTECTED_SCREENS = { HOME: 'Home', - LOADING: 'Loading', - REPORT: 'Report', + CONCIERGE: 'Concierge', REPORT_ATTACHMENTS: 'ReportAttachments', +} as const; + +const SCREENS = { + ...PROTECTED_SCREENS, + REPORT: 'Report', NOT_FOUND: 'not-found', TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps', VALIDATE_LOGIN: 'ValidateLogin', - CONCIERGE: 'Concierge', + UNLINK_LOGIN: 'UnlinkLogin', SETTINGS: { ROOT: 'Settings_Root', - PREFERENCES: 'Settings_Preferences', + SHARE_CODE: 'Settings_Share_Code', WORKSPACES: 'Settings_Workspaces', SECURITY: 'Settings_Security', - STATUS: 'Settings_Status', - WALLET: 'Settings_Wallet', - WALLET_DOMAIN_CARDS: 'Settings_Wallet_DomainCards', + ABOUT: 'Settings_About', + APP_DOWNLOAD_LINKS: 'Settings_App_Download_Links', + LOUNGE_ACCESS: 'Settings_Lounge_Access', + ADD_DEBIT_CARD: 'Settings_Add_Debit_Card', + ADD_BANK_ACCOUNT: 'Settings_Add_Bank_Account', + CLOSE: 'Settings_Close', + TWO_FACTOR_AUTH: 'Settings_TwoFactorAuth', + REPORT_CARD_LOST_OR_DAMAGED: 'Settings_ReportCardLostOrDamaged', + + PROFILE: { + ROOT: 'Settings_Profile', + DISPLAY_NAME: 'Settings_Display_Name', + CONTACT_METHODS: 'Settings_ContactMethods', + CONTACT_METHOD_DETAILS: 'Settings_ContactMethodDetails', + NEW_CONTACT_METHOD: 'Settings_NewContactMethod', + STATUS: 'Settings_Status', + STATUS_SET: 'Settings_Status_Set', + PRONOUNS: 'Settings_Pronouns', + TIMEZONE: 'Settings_Timezone', + TIMEZONE_SELECT: 'Settings_Timezone_Select', + + PERSONAL_DETAILS: { + INITIAL: 'Settings_PersonalDetails_Initial', + LEGAL_NAME: 'Settings_PersonalDetails_LegalName', + DATE_OF_BIRTH: 'Settings_PersonalDetails_DateOfBirth', + ADDRESS: 'Settings_PersonalDetails_Address', + ADDRESS_COUNTRY: 'Settings_PersonalDetails_Address_Country', + }, + }, + + PREFERENCES: { + ROOT: 'Settings_Preferences', + PRIORITY_MODE: 'Settings_Preferences_PriorityMode', + LANGUAGE: 'Settings_Preferences_Language', + THEME: 'Settings_Preferences_Theme', + }, + + WALLET: { + ROOT: 'Settings_Wallet', + DOMAIN_CARD: 'Settings_Wallet_DomainCard', + CARD_GET_PHYSICAL: { + NAME: 'Settings_Card_Get_Physical_Name', + PHONE: 'Settings_Card_Get_Physical_Phone', + ADDRESS: 'Settings_Card_Get_Physical_Address', + CONFIRM: 'Settings_Card_Get_Physical_Confirm', + }, + TRANSFER_BALANCE: 'Settings_Wallet_Transfer_Balance', + CHOOSE_TRANSFER_ACCOUNT: 'Settings_Wallet_Choose_Transfer_Account', + ENABLE_PAYMENTS: 'Settings_Wallet_EnablePayments', + CARD_ACTIVATE: 'Settings_Wallet_Card_Activate', + REPORT_VIRTUAL_CARD_FRAUD: 'Settings_Wallet_ReportVirtualCardFraud', + CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS: 'Settings_Wallet_Cards_Digital_Details_Update_Address', + }, }, SAVE_THE_WORLD: { ROOT: 'SaveTheWorld_Root', }, + RIGHT_MODAL: { + SETTINGS: 'Settings', + NEW_CHAT: 'NewChat', + SEARCH: 'Search', + DETAILS: 'Details', + PROFILE: 'Profile', + REPORT_DETAILS: 'Report_Details', + REPORT_SETTINGS: 'Report_Settings', + REPORT_WELCOME_MESSAGE: 'Report_WelcomeMessage', + PARTICIPANTS: 'Participants', + MONEY_REQUEST: 'MoneyRequest', + NEW_TASK: 'NewTask', + TEACHERS_UNITE: 'TeachersUnite', + TASK_DETAILS: 'Task_Details', + ENABLE_PAYMENTS: 'EnablePayments', + SPLIT_DETAILS: 'SplitDetails', + ADD_PERSONAL_BANK_ACCOUNT: 'AddPersonalBankAccount', + WALLET_STATEMENT: 'Wallet_Statement', + FLAG_COMMENT: 'Flag_Comment', + EDIT_REQUEST: 'EditRequest', + SIGN_IN: 'SignIn', + PRIVATE_NOTES: 'Private_Notes', + ROOM_MEMBERS: 'RoomMembers', + ROOM_INVITE: 'RoomInvite', + REFERRAL: 'Referral', + }, SIGN_IN_WITH_APPLE_DESKTOP: 'AppleSignInDesktop', SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop', DESKTOP_SIGN_IN_REDIRECT: 'DesktopSignInRedirect', SAML_SIGN_IN: 'SAMLSignIn', + + MONEY_REQUEST: { + MANUAL_TAB: 'manual', + SCAN_TAB: 'scan', + DISTANCE_TAB: 'distance', + CREATE: 'Money_Request_Create', + STEP_CONFIRMATION: 'Money_Request_Step_Confirmation', + STEP_AMOUNT: 'Money_Request_Step_Amount', + STEP_CATEGORY: 'Money_Request_Step_Category', + STEP_CURRENCY: 'Money_Request_Step_Currency', + STEP_DATE: 'Money_Request_Step_Date', + STEP_DESCRIPTION: 'Money_Request_Step_Description', + STEP_DISTANCE: 'Money_Request_Step_Distance', + STEP_MERCHANT: 'Money_Request_Step_Merchant', + STEP_PARTICIPANTS: 'Money_Request_Step_Participants', + STEP_SCAN: 'Money_Request_Step_Scan', + STEP_TAG: 'Money_Request_Step_Tag', + STEP_WAYPOINT: 'Money_Request_Step_Waypoint', + ROOT: 'Money_Request', + AMOUNT: 'Money_Request_Amount', + PARTICIPANTS: 'Money_Request_Participants', + CONFIRMATION: 'Money_Request_Confirmation', + CURRENCY: 'Money_Request_Currency', + DATE: 'Money_Request_Date', + DESCRIPTION: 'Money_Request_Description', + CATEGORY: 'Money_Request_Category', + TAG: 'Money_Request_Tag', + MERCHANT: 'Money_Request_Merchant', + WAYPOINT: 'Money_Request_Waypoint', + EDIT_WAYPOINT: 'Money_Request_Edit_Waypoint', + DISTANCE: 'Money_Request_Distance', + RECEIPT: 'Money_Request_Receipt', + }, + + IOU_SEND: { + ADD_BANK_ACCOUNT: 'IOU_Send_Add_Bank_Account', + ADD_DEBIT_CARD: 'IOU_Send_Add_Debit_Card', + ENABLE_PAYMENTS: 'IOU_Send_Enable_Payments', + }, + + REPORT_SETTINGS: { + ROOT: 'Report_Settings_Root', + ROOM_NAME: 'Report_Settings_Room_Name', + NOTIFICATION_PREFERENCES: 'Report_Settings_Notification_Preferences', + WRITE_CAPABILITY: 'Report_Settings_Write_Capability', + }, + + NEW_TASK: { + ROOT: 'NewTask_Root', + TASK_ASSIGNEE_SELECTOR: 'NewTask_TaskAssigneeSelector', + TASK_SHARE_DESTINATION_SELECTOR: 'NewTask_TaskShareDestinationSelector', + DETAILS: 'NewTask_Details', + TITLE: 'NewTask_Title', + DESCRIPTION: 'NewTask_Description', + }, + + TASK: { + TITLE: 'Task_Title', + DESCRIPTION: 'Task_Description', + ASSIGNEE: 'Task_Assignee', + }, + + PRIVATE_NOTES: { + VIEW: 'PrivateNotes_View', + LIST: 'PrivateNotes_List', + EDIT: 'PrivateNotes_Edit', + }, + + REPORT_DETAILS: { + ROOT: 'Report_Details_Root', + SHARE_CODE: 'Report_Details_Share_Code', + }, + + WORKSPACE: { + INITIAL: 'Workspace_Initial', + SETTINGS: 'Workspace_Settings', + CARD: 'Workspace_Card', + REIMBURSE: 'Workspace_Reimburse', + RATE_AND_UNIT: 'Workspace_RateAndUnit', + BILLS: 'Workspace_Bills', + INVOICES: 'Workspace_Invoices', + TRAVEL: 'Workspace_Travel', + MEMBERS: 'Workspace_Members', + INVITE: 'Workspace_Invite', + INVITE_MESSAGE: 'Workspace_Invite_Message', + CURRENCY: 'Workspace_Settings_Currency', + }, + + EDIT_REQUEST: { + ROOT: 'EditRequest_Root', + CURRENCY: 'EditRequest_Currency', + }, + + NEW_CHAT: { + ROOT: 'NewChat_Root', + NEW_CHAT: 'chat', + NEW_ROOM: 'room', + }, + + SPLIT_DETAILS: { + ROOT: 'SplitDetails_Root', + EDIT_REQUEST: 'SplitDetails_Edit_Request', + EDIT_CURRENCY: 'SplitDetails_Edit_Currency', + }, + + I_KNOW_A_TEACHER: 'I_Know_A_Teacher', + INTRO_SCHOOL_PRINCIPAL: 'Intro_School_Principal', + I_AM_A_TEACHER: 'I_Am_A_Teacher', + ENABLE_PAYMENTS_ROOT: 'EnablePayments_Root', + ADD_PERSONAL_BANK_ACCOUNT_ROOT: 'AddPersonalBankAccount_Root', + REIMBURSEMENT_ACCOUNT_ROOT: 'Reimbursement_Account_Root', + WALLET_STATEMENT_ROOT: 'WalletStatement_Root', + SIGN_IN_ROOT: 'SignIn_Root', + DETAILS_ROOT: 'Details_Root', + PROFILE_ROOT: 'Profile_Root', + REPORT_WELCOME_MESSAGE_ROOT: 'Report_WelcomeMessage_Root', + REPORT_PARTICIPANTS_ROOT: 'ReportParticipants_Root', + ROOM_MEMBERS_ROOT: 'RoomMembers_Root', + ROOM_INVITE_ROOT: 'RoomInvite_Root', + SEARCH_ROOT: 'Search_Root', + FLAG_COMMENT_ROOT: 'FlagComment_Root', + REIMBURSEMENT_ACCOUNT: 'ReimbursementAccount', + GET_ASSISTANCE: 'GetAssistance', + REFERRAL_DETAILS: 'Referral_Details', + KEYBOARD_SHORTCUTS: 'KeyboardShortcuts', } as const; + +type Screen = DeepValueOf; + +export default SCREENS; +export {PROTECTED_SCREENS}; +export type {Screen}; diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js index 252c8380b062..4d01fa108e2a 100644 --- a/src/components/AddPaymentMethodMenu.js +++ b/src/components/AddPaymentMethodMenu.js @@ -1,15 +1,18 @@ +import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React from 'react'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; +import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; -import Permissions from '@libs/Permissions'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import * as ReportUtils from '@libs/ReportUtils'; +import iouReportPropTypes from '@pages/iouReportPropTypes'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import * as Expensicons from './Icon/Expensicons'; import PopoverMenu from './PopoverMenu'; import refPropTypes from './refPropTypes'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; import withWindowDimensions from './withWindowDimensions'; const propTypes = { @@ -19,6 +22,12 @@ const propTypes = { /** Callback to execute when the component closes. */ onClose: PropTypes.func.isRequired, + /** Callback to execute when the payment method is selected. */ + onItemSelected: PropTypes.func.isRequired, + + /** The IOU/Expense report we are paying */ + iouReport: iouReportPropTypes, + /** Anchor position for the AddPaymentMenu. */ anchorPosition: PropTypes.shape({ horizontal: PropTypes.number, @@ -31,51 +40,72 @@ const propTypes = { vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)), }), - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - /** Popover anchor ref */ anchorRef: refPropTypes, - ...withLocalizePropTypes, + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user accountID */ + accountID: PropTypes.number, + }), }; const defaultProps = { + iouReport: {}, anchorPosition: {}, anchorAlignment: { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }, - betas: [], anchorRef: () => {}, + session: {}, }; -function AddPaymentMethodMenu(props) { +function AddPaymentMethodMenu({isVisible, onClose, anchorPosition, anchorAlignment, anchorRef, iouReport, onItemSelected, session}) { + const {translate} = useLocalize(); + + // Users can choose to pay with business bank account in case of Expense reports or in case of P2P IOU report + // which then starts a bottom up flow and creates a Collect workspace where the payer is an admin and payee is an employee. + const canUseBusinessBankAccount = + ReportUtils.isExpenseReport(iouReport) || + (ReportUtils.isIOUReport(iouReport) && !ReportActionsUtils.hasRequestFromCurrentAccount(lodashGet(iouReport, 'reportID', 0), lodashGet(session, 'accountID', 0))); + return ( { - props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT); - }, - }, - ...(Permissions.canUseWallet(props.betas) + ...(ReportUtils.isIOUReport(iouReport) ? [ { - text: props.translate('common.debitCard'), - icon: Expensicons.CreditCard, - onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.DEBIT_CARD), + text: translate('common.personalBankAccount'), + icon: Expensicons.Bank, + onSelected: () => { + onItemSelected(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT); + }, }, ] : []), + ...(canUseBusinessBankAccount + ? [ + { + text: translate('common.businessBankAccount'), + icon: Expensicons.Building, + onSelected: () => onItemSelected(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT), + }, + ] + : []), + ...[ + { + text: translate('common.debitCard'), + icon: Expensicons.CreditCard, + onSelected: () => onItemSelected(CONST.PAYMENT_METHODS.DEBIT_CARD), + }, + ], ]} withoutOverlay /> @@ -88,10 +118,9 @@ AddPaymentMethodMenu.displayName = 'AddPaymentMethodMenu'; export default compose( withWindowDimensions, - withLocalize, withOnyx({ - betas: { - key: ONYXKEYS.BETAS, + session: { + key: ONYXKEYS.SESSION, }, }), )(AddPaymentMethodMenu); diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 566b6c709423..68d529c4a78d 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -9,8 +9,8 @@ import useNetwork from '@hooks/useNetwork'; import KeyboardShortcut from '@libs/KeyboardShortcut'; import Log from '@libs/Log'; import {plaidDataPropTypes} from '@pages/ReimbursementAccount/plaidDataPropTypes'; -import styles from '@styles/styles'; -import themeColors from '@styles/themes/default'; +import useTheme from '@styles/themes/useTheme'; +import useThemeStyles from '@styles/useThemeStyles'; import * as App from '@userActions/App'; import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; @@ -83,6 +83,8 @@ function AddPlaidBankAccount({ allowDebit, isPlaidDisabled, }) { + const theme = useTheme(); + const styles = useThemeStyles(); const subscribedKeyboardShortcuts = useRef([]); const previousNetworkState = useRef(); @@ -166,7 +168,7 @@ function AddPlaidBankAccount({ value: account.plaidAccountID, label: `${account.addressName} ${account.mask}`, })); - const {icon, iconSize, iconStyles} = getBankIcon(); + const {icon, iconSize, iconStyles} = getBankIcon({styles}); const plaidErrors = lodashGet(plaidData, 'errors'); const plaidDataErrorMessage = !_.isEmpty(plaidErrors) ? _.chain(plaidErrors).values().first().value() : ''; const bankName = lodashGet(plaidData, 'bankName'); @@ -186,7 +188,7 @@ function AddPlaidBankAccount({ {lodashGet(plaidData, 'isLoading') && ( @@ -207,7 +209,7 @@ function AddPlaidBankAccount({ // Handle Plaid login errors (will potentially reset plaid token and item depending on the error) if (event === 'ERROR') { Log.hmmm('[PlaidLink] Error: ', metadata); - if (bankAccountID && metadata.error_code) { + if (bankAccountID && metadata && metadata.error_code) { BankAccounts.handlePlaidError(bankAccountID, metadata.error_code, metadata.error_message, metadata.request_id); } } diff --git a/src/components/AddressForm.js b/src/components/AddressForm.js new file mode 100644 index 000000000000..1621328d388f --- /dev/null +++ b/src/components/AddressForm.js @@ -0,0 +1,231 @@ +import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST'; +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, {useCallback} from 'react'; +import {View} from 'react-native'; +import _ from 'underscore'; +import useLocalize from '@hooks/useLocalize'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ValidationUtils from '@libs/ValidationUtils'; +import useThemeStyles from '@styles/useThemeStyles'; +import CONST from '@src/CONST'; +import AddressSearch from './AddressSearch'; +import CountrySelector from './CountrySelector'; +import FormProvider from './Form/FormProvider'; +import InputWrapper from './Form/InputWrapper'; +import StatePicker from './StatePicker'; +import TextInput from './TextInput'; + +const propTypes = { + /** Address city field */ + city: PropTypes.string, + + /** Address country field */ + country: PropTypes.string, + + /** Address state field */ + state: PropTypes.string, + + /** Address street line 1 field */ + street1: PropTypes.string, + + /** Address street line 2 field */ + street2: PropTypes.string, + + /** Address zip code field */ + zip: PropTypes.string, + + /** Callback which is executed when the user changes address, city or state */ + onAddressChanged: PropTypes.func, + + /** Callback which is executed when the user submits his address changes */ + onSubmit: PropTypes.func.isRequired, + + /** Whether or not should the form data should be saved as draft */ + shouldSaveDraft: PropTypes.bool, + + /** Text displayed on the bottom submit button */ + submitButtonText: PropTypes.string, + + /** A unique Onyx key identifying the form */ + formID: PropTypes.string.isRequired, +}; + +const defaultProps = { + city: '', + country: '', + onAddressChanged: () => {}, + shouldSaveDraft: false, + state: '', + street1: '', + street2: '', + submitButtonText: '', + zip: '', +}; + +function AddressForm({city, country, formID, onAddressChanged, onSubmit, shouldSaveDraft, state, street1, street2, submitButtonText, zip}) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const zipSampleFormat = lodashGet(CONST.COUNTRY_ZIP_REGEX_DATA, [country, 'samples'], ''); + const zipFormat = translate('common.zipCodeExampleFormat', {zipSampleFormat}); + const isUSAForm = country === CONST.COUNTRY.US; + + /** + * @param {Function} translate - translate function + * @param {Boolean} isUSAForm - selected country ISO code is US + * @param {Object} values - form input values + * @returns {Object} - An object containing the errors for each inputID + */ + const validator = useCallback((values) => { + const errors = {}; + const requiredFields = ['addressLine1', 'city', 'country', 'state']; + + // Check "State" dropdown is a valid state if selected Country is USA + if (values.country === CONST.COUNTRY.US && !COMMON_CONST.STATES[values.state]) { + errors.state = 'common.error.fieldRequired'; + } + + // Add "Field required" errors if any required field is empty + _.each(requiredFields, (fieldKey) => { + if (ValidationUtils.isRequiredFulfilled(values[fieldKey])) { + return; + } + errors[fieldKey] = 'common.error.fieldRequired'; + }); + + // If no country is selected, default value is an empty string and there's no related regex data so we default to an empty object + const countryRegexDetails = lodashGet(CONST.COUNTRY_ZIP_REGEX_DATA, values.country, {}); + + // The postal code system might not exist for a country, so no regex either for them. + const countrySpecificZipRegex = lodashGet(countryRegexDetails, 'regex'); + const countryZipFormat = lodashGet(countryRegexDetails, 'samples'); + + if (countrySpecificZipRegex) { + if (!countrySpecificZipRegex.test(values.zipPostCode.trim().toUpperCase())) { + if (ValidationUtils.isRequiredFulfilled(values.zipPostCode.trim())) { + errors.zipPostCode = ['privatePersonalDetails.error.incorrectZipFormat', {zipFormat: countryZipFormat}]; + } else { + errors.zipPostCode = 'common.error.fieldRequired'; + } + } + } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values.zipPostCode.trim().toUpperCase())) { + errors.zipPostCode = 'privatePersonalDetails.error.incorrectZipFormat'; + } + + return errors; + }, []); + + return ( + + + { + onAddressChanged(data, key); + // This enforces the country selector to use the country from address instead of the country from URL + Navigation.setParams({country: undefined}); + }} + defaultValue={street1 || ''} + renamedInputKeys={{ + street: 'addressLine1', + street2: 'addressLine2', + city: 'city', + state: 'state', + zipCode: 'zipPostCode', + country: 'country', + }} + maxInputLength={CONST.FORM_CHARACTER_LIMIT} + shouldSaveDraft={shouldSaveDraft} + /> + + + + + + + + + {isUSAForm ? ( + + + + ) : ( + + )} + + + + + + ); +} + +AddressForm.defaultProps = defaultProps; +AddressForm.displayName = 'AddressForm'; +AddressForm.propTypes = propTypes; + +export default AddressForm; diff --git a/src/components/AddressSearch/CurrentLocationButton.js b/src/components/AddressSearch/CurrentLocationButton.js index 326b82d31e8f..90d2c15733f1 100644 --- a/src/components/AddressSearch/CurrentLocationButton.js +++ b/src/components/AddressSearch/CurrentLocationButton.js @@ -7,8 +7,8 @@ import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import useLocalize from '@hooks/useLocalize'; import getButtonState from '@libs/getButtonState'; import colors from '@styles/colors'; -import styles from '@styles/styles'; -import * as StyleUtils from '@styles/StyleUtils'; +import useStyleUtils from '@styles/useStyleUtils'; +import useThemeStyles from '@styles/useThemeStyles'; const propTypes = { /** Callback that runs when location button is clicked */ @@ -24,6 +24,8 @@ const defaultProps = { }; function CurrentLocationButton({onPress, isDisabled}) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); return ( diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index c7cd078004de..2fed1d153947 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -1,6 +1,6 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {ActivityIndicator, Keyboard, LogBox, ScrollView, Text, View} from 'react-native'; import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete'; import _ from 'underscore'; @@ -14,9 +14,9 @@ import * as ApiUtils from '@libs/ApiUtils'; import compose from '@libs/compose'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as GooglePlacesUtils from '@libs/GooglePlacesUtils'; -import styles from '@styles/styles'; -import * as StyleUtils from '@styles/StyleUtils'; -import themeColors from '@styles/themes/default'; +import useTheme from '@styles/themes/useTheme'; +import useStyleUtils from '@styles/useStyleUtils'; +import useThemeStyles from '@styles/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import CurrentLocationButton from './CurrentLocationButton'; @@ -140,27 +140,49 @@ const defaultProps = { resultTypes: 'address', }; -// Do not convert to class component! It's been tried before and presents more challenges than it's worth. -// Relevant thread: https://expensify.slack.com/archives/C03TQ48KC/p1634088400387400 -// Reference: https://github.com/FaridSafi/react-native-google-places-autocomplete/issues/609#issuecomment-886133839 -function AddressSearch(props) { +function AddressSearch({ + canUseCurrentLocation, + containerStyles, + defaultValue, + errorText, + hint, + innerRef, + inputID, + isLimitedToUSA, + label, + maxInputLength, + network, + onBlur, + onInputChange, + onPress, + predefinedPlaces, + preferredLocale, + renamedInputKeys, + resultTypes, + shouldSaveDraft, + translate, + value, +}) { + const theme = useTheme(); + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); const [displayListViewBorder, setDisplayListViewBorder] = useState(false); const [isTyping, setIsTyping] = useState(false); const [isFocused, setIsFocused] = useState(false); - const [searchValue, setSearchValue] = useState(props.value || props.defaultValue || ''); + const [searchValue, setSearchValue] = useState(value || defaultValue || ''); const [locationErrorCode, setLocationErrorCode] = useState(null); const [isFetchingCurrentLocation, setIsFetchingCurrentLocation] = useState(false); const shouldTriggerGeolocationCallbacks = useRef(true); const containerRef = useRef(); const query = useMemo( () => ({ - language: props.preferredLocale, - types: props.resultTypes, - components: props.isLimitedToUSA ? 'country:us' : undefined, + language: preferredLocale, + types: resultTypes, + components: isLimitedToUSA ? 'country:us' : undefined, }), - [props.preferredLocale, props.resultTypes, props.isLimitedToUSA], + [preferredLocale, resultTypes, isLimitedToUSA], ); - const shouldShowCurrentLocationButton = props.canUseCurrentLocation && searchValue.trim().length === 0 && isFocused; + const shouldShowCurrentLocationButton = canUseCurrentLocation && searchValue.trim().length === 0 && isFocused; const saveLocationDetails = (autocompleteData, details) => { const addressComponents = details.address_components; @@ -169,7 +191,7 @@ function AddressSearch(props) { // to this component which don't match the usual properties coming from auto-complete. In that case, only a limited // amount of data massaging needs to happen for what the parent expects to get from this function. if (_.size(details)) { - props.onPress({ + onPress({ address: lodashGet(details, 'description'), lat: lodashGet(details, 'geometry.location.lat', 0), lng: lodashGet(details, 'geometry.location.lng', 0), @@ -229,6 +251,7 @@ function AddressSearch(props) { street2: subpremise, // Make sure country is updated first, since city and state will be reset if the country changes country: '', + state: state || stateAutoCompleteFallback, // When locality is not returned, many countries return the city as postalTown (e.g. 5 New Street // Square, London), otherwise as sublocality (e.g. 384 Court Street Brooklyn). If postalTown is // returned, the sublocality will be a city subdivision so shouldn't take precedence (e.g. @@ -236,7 +259,6 @@ function AddressSearch(props) { city: locality || postalTown || sublocality || cityAutocompleteFallback, zipCode, - state: state || stateAutoCompleteFallback, lat: lodashGet(details, 'geometry.location.lat', 0), lng: lodashGet(details, 'geometry.location.lng', 0), address: lodashGet(details, 'formatted_address', ''), @@ -254,9 +276,20 @@ function AddressSearch(props) { values.state = stateFallback; } + // Some edge-case addresses may lack both street_number and route in the API response, resulting in an empty "values.street" + // We are setting up a fallback to ensure "values.street" is populated with a relevant value + if (!values.street && details.adr_address) { + const streetAddressRegex = /([^<]*)<\/span>/; + const adr_address = details.adr_address.match(streetAddressRegex); + const streetAddressFallback = lodashGet(adr_address, [1], null); + if (streetAddressFallback) { + values.street = streetAddressFallback; + } + } + // Not all pages define the Address Line 2 field, so in that case we append any additional address details // (e.g. Apt #) to Address Line 1 - if (subpremise && typeof props.renamedInputKeys.street2 === 'undefined') { + if (subpremise && typeof renamedInputKeys.street2 === 'undefined') { values.street += `, ${subpremise}`; } @@ -265,19 +298,19 @@ function AddressSearch(props) { values.country = country; } - if (props.inputID) { - _.each(values, (value, key) => { - const inputKey = lodashGet(props.renamedInputKeys, key, key); + if (inputID) { + _.each(values, (inputValue, key) => { + const inputKey = lodashGet(renamedInputKeys, key, key); if (!inputKey) { return; } - props.onInputChange(value, inputKey); + onInputChange(inputValue, inputKey); }); } else { - props.onInputChange(values); + onInputChange(values); } - props.onPress(values); + onPress(values); }; /** Gets the user's current location and registers success/error callbacks */ @@ -307,7 +340,7 @@ function AddressSearch(props) { lng: successData.coords.longitude, address: CONST.YOUR_LOCATION_TEXT, }; - props.onPress(location); + onPress(location); }, (errorData) => { if (!shouldTriggerGeolocationCallbacks.current) { @@ -325,16 +358,16 @@ function AddressSearch(props) { }; const renderHeaderComponent = () => - props.predefinedPlaces.length > 0 && ( + predefinedPlaces.length > 0 && ( <> {/* This will show current location button in list if there are some recent destinations */} {shouldShowCurrentLocationButton && ( )} - {!props.value && {props.translate('common.recentDestinations')}} + {!value && {translate('common.recentDestinations')}} ); @@ -346,6 +379,26 @@ function AddressSearch(props) { }; }, []); + const listEmptyComponent = useCallback( + () => + network.isOffline || !isTyping ? null : ( + {translate('common.noResultsFound')} + ), + [network.isOffline, isTyping, styles, translate], + ); + + const listLoader = useCallback( + () => ( + + + + ), + [styles.pv4, theme.spinner], + ); + return ( /* * The GooglePlacesAutocomplete component uses a VirtualizedList internally, @@ -372,20 +425,10 @@ function AddressSearch(props) { fetchDetails suppressDefaultStyles enablePoweredByContainer={false} - predefinedPlaces={props.predefinedPlaces} - listEmptyComponent={ - props.network.isOffline || !isTyping ? null : ( - {props.translate('common.noResultsFound')} - ) - } - listLoaderComponent={ - - - - } + predefinedPlaces={predefinedPlaces} + listEmptyComponent={listEmptyComponent} + listLoaderComponent={listLoader} + renderHeaderComponent={renderHeaderComponent} renderRow={(data) => { const title = data.isPredefinedPlace ? data.name : data.structured_formatting.main_text; const subtitle = data.isPredefinedPlace ? data.description : data.structured_formatting.secondary_text; @@ -396,7 +439,6 @@ function AddressSearch(props) { ); }} - renderHeaderComponent={renderHeaderComponent} onPress={(data, details) => { saveLocationDetails(data, details); setIsTyping(false); @@ -411,34 +453,31 @@ function AddressSearch(props) { query={query} requestUrl={{ useOnPlatform: 'all', - url: props.network.isOffline ? null : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}), + url: network.isOffline ? null : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}), }} textInputProps={{ InputComp: TextInput, ref: (node) => { - if (!props.innerRef) { + if (!innerRef) { return; } - if (_.isFunction(props.innerRef)) { - props.innerRef(node); + if (_.isFunction(innerRef)) { + innerRef(node); return; } // eslint-disable-next-line no-param-reassign - props.innerRef.current = node; + innerRef.current = node; }, - label: props.label, - containerStyles: props.containerStyles, - errorText: props.errorText, - hint: - displayListViewBorder || (props.predefinedPlaces.length === 0 && shouldShowCurrentLocationButton) || (props.canUseCurrentLocation && isTyping) - ? undefined - : props.hint, - value: props.value, - defaultValue: props.defaultValue, - inputID: props.inputID, - shouldSaveDraft: props.shouldSaveDraft, + label, + containerStyles, + errorText, + hint: displayListViewBorder || (predefinedPlaces.length === 0 && shouldShowCurrentLocationButton) || (canUseCurrentLocation && isTyping) ? undefined : hint, + value, + defaultValue, + inputID, + shouldSaveDraft, onFocus: () => { setIsFocused(true); }, @@ -448,24 +487,24 @@ function AddressSearch(props) { setIsFocused(false); setIsTyping(false); } - props.onBlur(); + onBlur(); }, autoComplete: 'off', onInputChange: (text) => { setSearchValue(text); setIsTyping(true); - if (props.inputID) { - props.onInputChange(text); + if (inputID) { + onInputChange(text); } else { - props.onInputChange({street: text}); + onInputChange({street: text}); } // If the text is empty and we have no predefined places, we set displayListViewBorder to false to prevent UI flickering - if (_.isEmpty(text) && _.isEmpty(props.predefinedPlaces)) { + if (_.isEmpty(text) && _.isEmpty(predefinedPlaces)) { setDisplayListViewBorder(false); } }, - maxLength: props.maxInputLength, + maxLength: maxInputLength, spellCheck: false, selectTextOnFocus: true, }} @@ -478,8 +517,8 @@ function AddressSearch(props) { }} numberOfLines={2} isRowScrollable={false} - listHoverColor={themeColors.border} - listUnderlayColor={themeColors.buttonPressedBG} + listHoverColor={theme.border} + listUnderlayColor={theme.buttonPressedBG} onLayout={(event) => { // We use the height of the element to determine if we should hide the border of the listView dropdown // to prevent a lingering border when there are no address suggestions. @@ -487,17 +526,18 @@ function AddressSearch(props) { }} inbetweenCompo={ // We want to show the current location button even if there are no recent destinations - props.predefinedPlaces.length === 0 && shouldShowCurrentLocationButton ? ( + predefinedPlaces.length === 0 && shouldShowCurrentLocationButton ? ( ) : ( <> ) } + placeholder="" /> setLocationErrorCode(null)} diff --git a/src/components/Alert/index.js b/src/components/Alert/index.js index dc3a722c2331..3fc90433f13e 100644 --- a/src/components/Alert/index.js +++ b/src/components/Alert/index.js @@ -5,7 +5,7 @@ import _ from 'underscore'; * * @param {String} title The title of the alert * @param {String} description The description of the alert - * @param {Object[]} options An array of objects with `style` and `onPress` properties + * @param {Object[]} [options] An array of objects with `style` and `onPress` properties */ export default (title, description, options) => { const result = _.filter(window.confirm([title, description], Boolean)).join('\n'); diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js index 43fd5e6a1b98..bd88712432a8 100644 --- a/src/components/AmountTextInput.js +++ b/src/components/AmountTextInput.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; -import styles from '@styles/styles'; +import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; import refPropTypes from './refPropTypes'; import TextInput from './TextInput'; @@ -39,6 +39,7 @@ const defaultProps = { }; function AmountTextInput(props) { + const styles = useThemeStyles(); return ( () => { ReportActionContextMenu.hideContextMenu(); @@ -50,11 +52,12 @@ function BaseAnchorForCommentsOnly({onPressIn, onPressOut, href = '', rel = '', linkProps.href = href; } const defaultTextStyle = DeviceCapabilities.canUseTouchScreen() || isSmallScreenWidth ? {} : {...styles.userSelectText, ...styles.cursorPointer}; - const isEmail = Str.isValidEmailMarkdown(href.replace(/mailto:/i, '')); + const isEmail = Str.isValidEmail(href.replace(/mailto:/i, '')); return ( { ReportActionContextMenu.showContextMenu( diff --git a/src/components/AnimatedStep/AnimatedStepContext.js b/src/components/AnimatedStep/AnimatedStepContext.js deleted file mode 100644 index 30377147fdb8..000000000000 --- a/src/components/AnimatedStep/AnimatedStepContext.js +++ /dev/null @@ -1,5 +0,0 @@ -import {createContext} from 'react'; - -const AnimatedStepContext = createContext(); - -export default AnimatedStepContext; diff --git a/src/components/AnimatedStep/AnimatedStepContext.ts b/src/components/AnimatedStep/AnimatedStepContext.ts new file mode 100644 index 000000000000..3b4c5f79a34f --- /dev/null +++ b/src/components/AnimatedStep/AnimatedStepContext.ts @@ -0,0 +1,15 @@ +import React, {createContext} from 'react'; +import {ValueOf} from 'type-fest'; +import CONST from '@src/CONST'; + +type AnimationDirection = ValueOf; + +type StepContext = { + animationDirection: AnimationDirection; + setAnimationDirection: React.Dispatch>; +}; + +const AnimatedStepContext = createContext(null); + +export default AnimatedStepContext; +export type {StepContext, AnimationDirection}; diff --git a/src/components/AnimatedStep/AnimatedStepProvider.js b/src/components/AnimatedStep/AnimatedStepProvider.tsx similarity index 56% rename from src/components/AnimatedStep/AnimatedStepProvider.js rename to src/components/AnimatedStep/AnimatedStepProvider.tsx index eb4797655344..53b3a0e0a53d 100644 --- a/src/components/AnimatedStep/AnimatedStepProvider.js +++ b/src/components/AnimatedStep/AnimatedStepProvider.tsx @@ -1,18 +1,14 @@ -import PropTypes from 'prop-types'; import React, {useMemo, useState} from 'react'; import CONST from '@src/CONST'; -import AnimatedStepContext from './AnimatedStepContext'; +import ChildrenProps from '@src/types/utils/ChildrenProps'; +import AnimatedStepContext, {AnimationDirection} from './AnimatedStepContext'; -const propTypes = { - children: PropTypes.node.isRequired, -}; - -function AnimatedStepProvider({children}) { - const [animationDirection, setAnimationDirection] = useState(CONST.ANIMATION_DIRECTION.IN); +function AnimatedStepProvider({children}: ChildrenProps): React.ReactNode { + const [animationDirection, setAnimationDirection] = useState(CONST.ANIMATION_DIRECTION.IN); const contextValue = useMemo(() => ({animationDirection, setAnimationDirection}), [animationDirection, setAnimationDirection]); return {children}; } -AnimatedStepProvider.propTypes = propTypes; +AnimatedStepProvider.displayName = 'AnimatedStepProvider'; export default AnimatedStepProvider; diff --git a/src/components/AnimatedStep/index.js b/src/components/AnimatedStep/index.js deleted file mode 100644 index e916cbe1b84c..000000000000 --- a/src/components/AnimatedStep/index.js +++ /dev/null @@ -1,62 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import * as Animatable from 'react-native-animatable'; -import useNativeDriver from '@libs/useNativeDriver'; -import styles from '@styles/styles'; -import CONST from '@src/CONST'; - -const propTypes = { - /** Children to wrap in AnimatedStep. */ - children: PropTypes.node.isRequired, - - /** Styles to be assigned to Container */ - // eslint-disable-next-line react/forbid-prop-types - style: PropTypes.arrayOf(PropTypes.object), - - /** Whether we're animating the step in or out */ - direction: PropTypes.oneOf(['in', 'out']), - - /** Callback to fire when the animation ends */ - onAnimationEnd: PropTypes.func, -}; - -const defaultProps = { - direction: 'in', - style: [], - onAnimationEnd: () => {}, -}; - -function getAnimationStyle(direction) { - let transitionValue; - - if (direction === 'in') { - transitionValue = CONST.ANIMATED_TRANSITION_FROM_VALUE; - } else if (direction === 'out') { - transitionValue = -CONST.ANIMATED_TRANSITION_FROM_VALUE; - } - return styles.makeSlideInTranslation('translateX', transitionValue); -} - -function AnimatedStep(props) { - return ( - { - if (!props.onAnimationEnd) { - return; - } - props.onAnimationEnd(); - }} - duration={CONST.ANIMATED_TRANSITION} - animation={getAnimationStyle(props.direction)} - useNativeDriver={useNativeDriver} - style={props.style} - > - {props.children} - - ); -} - -AnimatedStep.propTypes = propTypes; -AnimatedStep.defaultProps = defaultProps; -AnimatedStep.displayName = 'AnimatedStep'; -export default AnimatedStep; diff --git a/src/components/AnimatedStep/index.tsx b/src/components/AnimatedStep/index.tsx new file mode 100644 index 000000000000..1a87592cba9b --- /dev/null +++ b/src/components/AnimatedStep/index.tsx @@ -0,0 +1,49 @@ +import React, {useMemo} from 'react'; +import {StyleProp, ViewStyle} from 'react-native'; +import * as Animatable from 'react-native-animatable'; +import useNativeDriver from '@libs/useNativeDriver'; +import useThemeStyles from '@styles/useThemeStyles'; +import CONST from '@src/CONST'; +import ChildrenProps from '@src/types/utils/ChildrenProps'; +import {AnimationDirection} from './AnimatedStepContext'; + +type AnimatedStepProps = ChildrenProps & { + /** Styles to be assigned to Container */ + style: StyleProp; + + /** Whether we're animating the step in or out */ + direction: AnimationDirection; + + /** Callback to fire when the animation ends */ + onAnimationEnd: () => void; +}; + +function AnimatedStep({onAnimationEnd, direction = CONST.ANIMATION_DIRECTION.IN, style, children}: AnimatedStepProps) { + const styles = useThemeStyles(); + + const animationStyle = useMemo(() => { + const transitionValue = direction === 'in' ? CONST.ANIMATED_TRANSITION_FROM_VALUE : -CONST.ANIMATED_TRANSITION_FROM_VALUE; + + return styles.makeSlideInTranslation('translateX', transitionValue); + }, [direction, styles]); + + return ( + { + if (!onAnimationEnd) { + return; + } + onAnimationEnd(); + }} + duration={CONST.ANIMATED_TRANSITION} + animation={animationStyle} + useNativeDriver={useNativeDriver} + style={style} + > + {children} + + ); +} + +AnimatedStep.displayName = 'AnimatedStep'; +export default AnimatedStep; diff --git a/src/components/AnimatedStep/useAnimatedStepContext.js b/src/components/AnimatedStep/useAnimatedStepContext.ts similarity index 69% rename from src/components/AnimatedStep/useAnimatedStepContext.js rename to src/components/AnimatedStep/useAnimatedStepContext.ts index e2af9514e20e..3edc71e5289e 100644 --- a/src/components/AnimatedStep/useAnimatedStepContext.js +++ b/src/components/AnimatedStep/useAnimatedStepContext.ts @@ -1,7 +1,7 @@ import {useContext} from 'react'; -import AnimatedStepContext from './AnimatedStepContext'; +import AnimatedStepContext, {StepContext} from './AnimatedStepContext'; -function useAnimatedStepContext() { +function useAnimatedStepContext(): StepContext { const context = useContext(AnimatedStepContext); if (!context) { throw new Error('useAnimatedStepContext must be used within an AnimatedStepContextProvider'); diff --git a/src/components/AnonymousReportFooter.js b/src/components/AnonymousReportFooter.js deleted file mode 100644 index 2dc4159d1627..000000000000 --- a/src/components/AnonymousReportFooter.js +++ /dev/null @@ -1,66 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {Text, View} from 'react-native'; -import reportPropTypes from '@pages/reportPropTypes'; -import styles from '@styles/styles'; -import * as Session from '@userActions/Session'; -import AvatarWithDisplayName from './AvatarWithDisplayName'; -import Button from './Button'; -import ExpensifyWordmark from './ExpensifyWordmark'; -import participantPropTypes from './participantPropTypes'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; - -const propTypes = { - /** The report currently being looked at */ - report: reportPropTypes, - - isSmallSizeLayout: PropTypes.bool, - - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - - ...withLocalizePropTypes, -}; - -const defaultProps = { - report: {}, - isSmallSizeLayout: false, - personalDetails: {}, -}; - -function AnonymousReportFooter(props) { - return ( - - - - - - - - - - {props.translate('anonymousReportFooter.logoTagline')} - - -