[
  {
    "path": ".codecov.yml",
    "content": "coverage:\n  status:\n    project:\n      default:\n        # basic\n        target: 70%\n        threshold: 0%\n        base: auto\n        flags:\n          - unit\n        paths:\n          - 'src'\n        # advanced settings\n        branches:\n          - master\n        if_ci_failed: ignore #error #success, failure, ignore\n        informational: true\n        only_pulls: false\n        paths:\n          - 'src'\n    patch:\n      default:\n        # basic\n        target: 70%\n        threshold: 0%\n        base: auto\n        if_ci_failed: ignore #error #success, failure, ignore\n        informational: true\n        only_pulls: false\n        paths:\n          - 'src'\n"
  },
  {
    "path": ".dockerignore",
    "content": "# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# misc\n.DS_Store\n.netlify\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n/.eslintcache\n\n# vscode settings\n/.vscode\n/.husky/\n/src/redux/validation.json\n"
  },
  {
    "path": ".eslintignore",
    "content": "serviceWorker.js\n\n# don't worry about generated files\n/src/core/data/validate-fns.js\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  settings: {\n    react: {\n      version: 'detect'\n    }\n  },\n  env: {\n    browser: true,\n    es2021: true,\n    node: true\n  },\n  extends: [\n    'plugin:react/recommended',\n    'plugin:@typescript-eslint/recommended',\n    'plugin:@typescript-eslint/recommended-requiring-type-checking',\n    'prettier'\n  ],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaFeatures: {\n      jsx: true\n    },\n    ecmaVersion: 12,\n    sourceType: 'module'\n  },\n  plugins: ['react', '@typescript-eslint', 'prettier'],\n  rules: {\n    'react/jsx-uses-react': 'off',\n    'react/react-in-jsx-scope': 'off',\n    '@typescript-eslint/no-unnecessary-condition': 'warn'\n  },\n  parserOptions: {\n    project: ['./tsconfig.json', './.eslintrc.js']\n  }\n}\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  # regular updates for our established packages\n  - package-ecosystem: \"npm\"\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"daily\"\n    target-branch: \"master\"\n    open-pull-requests-limit: 15\n  - package-ecosystem: \"cargo\"\n    directory: \"/src-tauri/\" # Location of package manifests\n    schedule:\n      interval: \"daily\"\n    target-branch: \"master\"\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!--\nPlease make sure to read the Pull Request Guidelines:\nhttps://github.com/ustaxes/ustaxes/blob/master/.github/CONTRIBUTING.md#pull-request-guidelines\n-->\n\n**What kind of change does this PR introduce?** (delete not applicable)\n- Bugfix\n- Feature\n- Docs\n- Code style update\n- Refactor\n- Build-related changes\n- Other, please describe:\n\n<!-- \nIf this PR resolves a specific issue include \"Fixes #xxx\" in the PR description so the issue is linked and automatically closed on merge.\n\nPlease sign all your commits. See https://github.com/ustaxes/UsTaxes/blob/master/docs/CONTRIBUTING.md#pull-request-guidelines for information on setting this up.\n\n-->\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# Contains unit test, lint, dependabot automerge logic\nname: CI\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\npermissions:\n  pull-requests: write\n  contents: write\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: ['16']\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v2\n      with:\n        node-version: ${{ matrix.node-version }}\n      # installs dependencies\n    - run: npm ci\n      # build\n    - name: Run ESLint\n      run: npm run lint\n    - name: Ensure project builds\n      run: npm run build\n      # run tests\n    - name: Run jest unit tests\n      run: npm run test:report\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v2\n      with:\n        token: ${{ secrets.CODECOV_TOKEN }}\n        directory: ./coverage\n        verbose: true\n\n  dependabot-auto-merge:\n    needs: [test]\n    runs-on: ubuntu-latest\n    if: ${{ github.actor == 'dependabot[bot]' }}\n    steps:\n      - name: Dependabot metadata\n        id: metadata\n        uses: dependabot/fetch-metadata@v1.1.1\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n      - name: Enable auto-merge for Dependabot PRs\n        if: ${{(steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type ==  'version-update:semver-minor')}}\n        run: gh pr merge --auto --squash \"$PR_URL\"\n        env:\n          PR_URL: ${{github.event.pull_request.html_url}}\n          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}"
  },
  {
    "path": ".github/workflows/tauri-release.yml",
    "content": "name: \"publish\"\non:\n  push:\n    tags:\n      - app-v*\njobs:\n  publish-tauri:\n    strategy:\n      fail-fast: false\n      matrix:\n        platform: [macos-latest, ubuntu-latest, windows-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n    - uses: actions/checkout@v2\n    - name: setup node\n      uses: actions/setup-node@v2\n      with:\n        node-version: 16\n    - name: Get the version\n      id: get_version\n      run: echo ::set-output name=VERSION::__VERSION__\n      shell: bash\n      ## https://github.com/tauri-apps/tauri/blob/76187298c1d52dc764c5192c6a770a65f44b82ab/.github/workflows/smoke-test-prod.yml\n      ## Following that example, we cache directories for both cargo and node. \n      ## The cache action will check caches before these directories are required, and update the caches if necessary \n      ## at the end of the job (after cargo install and node install if those are necessary).\n    - name: cache rust bin\n      id: cache_rust_bin\n      uses: actions/cache@v1\n      with:\n        path: ~/.cargo/bin/\n        key: ${{ runner.OS }}-xbuild-bin-${{ hashFiles('**/Cargo.toml') }}\n    - name: cache rust registry/index\n      id: cache_rust_reg_index\n      uses: actions/cache@v1\n      with:\n        path: ~/.cargo/registry/index\n        key: ${{ runner.OS }}-xbuild-reg-index-${{ hashFiles('**/Cargo.toml') }}-\n    - name: cache rust registry/cache\n      id: cache_rust_reg_cache\n      uses: actions/cache@v1\n      with:\n        path: ~/.cargo/registry/cache/\n        key: ${{ runner.OS }}-xbuild-reg-cache-${{ hashFiles('**/Cargo.toml') }}-\n    - name: install Rust stable\n      uses: actions-rs/toolchain@v1\n      with:\n        toolchain: stable\n        profile: minimal\n    - name: install dependencies (ubuntu only)\n      if: matrix.platform == 'ubuntu-latest'\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf\n    - name: install app dependencies\n      run: npm ci\n    - name: build it\n      run: npm run desktop-release\n    - uses: tauri-apps/tauri-action@dev\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        releaseName: App v${{ steps.get_version.outputs.VERSION }}\n        tagName: app-v${{ steps.get_version.outputs.VERSION }}\n        releaseBody: \"See the assets to download this version and install.\"\n        releaseDraft: false\n        prerelease: false\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Local Netlify folder\n.netlify\n\n/.eslintcache\n\n# vscode settings\n/.vscode\n/.devcontainer/\n\n/logs/\n/src/core/data/validate-fns.js\n"
  },
  {
    "path": ".husky/husky.sh",
    "content": "#!/bin/sh\nif [ -z \"$husky_skip_init\" ]; then\n  debug () {\n    if [ \"$HUSKY_DEBUG\" = \"1\" ]; then\n      echo \"husky (debug) - $1\"\n    fi\n  }\n\n  readonly hook_name=\"$(basename \"$0\")\"\n  debug \"starting $hook_name...\"\n\n  if [ \"$HUSKY\" = \"0\" ]; then\n    debug \"HUSKY env variable is set to 0, skipping hook\"\n    exit 0\n  fi\n\n  if [ -f ~/.huskyrc ]; then\n    debug \"sourcing ~/.huskyrc\"\n    . ~/.huskyrc\n  fi\n\n  export readonly husky_skip_init=1\n  sh -e \"$0\" \"$@\"\n  exitCode=\"$?\"\n\n  if [ $exitCode != 0 ]; then\n    echo \"husky - $hook_name hook exited with code $exitCode (error)\"\n  fi\n\n  exit $exitCode\nfi\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/husky.sh\"\n\n# npm test\nnpx lint-staged\n"
  },
  {
    "path": ".npmrc",
    "content": "//.npmrc file\nengine-strict = true"
  },
  {
    "path": ".nvmrc",
    "content": "lts/*\n"
  },
  {
    "path": ".prettierignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n.github\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Local Netlify folder\n.netlify\n\n/.eslintcache\n\n# vscode settings\n/.vscode\n/.devcontainer/\n/.husky/\ntsconfig.json\n.codecov.yml\n\n# don't worry about src-tauri (rust code)\n\n/src-tauri\n\n# don't worry about generated files\n/src/core/data/validate-fns.js\n"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"trailingComma\": \"none\",\n  \"tabWidth\": 2,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"jsxSingleQuote\": false,\n  \"printWidth\": 80\n}\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM rust:1.51-slim-buster\n\nRUN mkdir -p /home/node/app\n\nRUN useradd -rm -d /home/node -s /bin/bash -g root -G sudo -u 1001 node\n\nRUN chown -R node /home/node\n\nRUN apt-get update && apt-get -y upgrade && apt-get install -y curl\n\nUSER node\n# Install nvm, node, npm\nARG NVM_DIR=\"/home/node/.nvm\"\nARG NODE_VERSION=16.7.0\nRUN curl https://raw.githubusercontent.com/creationix/nvm/v0.38.0/install.sh | bash\nRUN . $NVM_DIR/nvm.sh && nvm install $NODE_VERSION --latest-npm\nENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH\n\nWORKDIR /home/node/app\n\nADD ./package.json ./package.json\nADD ./package-lock.json ./package-lock.json\nADD ./scripts ./scripts\nRUN npm ci\n\nADD . .\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>."
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n<h1><a href=\"//ustaxes.org\">USTaxes</a></h1>\n\n[![Netlify Status][netlify-badge]][netlify-url] [![Github Latest Release][release-badge]][github-release] [![discord-badge]][discord-url]\n\n</div>\n\n## What is UsTaxes?\n\nUsTaxes is a free, open-source tax filing application that can be used to file the Federal 1040 form. It is available in both [web](https://ustaxes.org/) and [desktop][desktop-releases] versions. It is provided free of charge and requires no sharing of personal data.\n\n**Interested in contributing? [Get Started](#user-content-get-started)**\n\n## Supported Income data\n\nMost income and deduction information from the following forms are supported for tax years 2020 and 2021.\n\n- W2\n- 1099-INT\n- 1099-DIV\n- 1099-B\n- 1098-E\n- 1099-R: support for normal distributions from IRA and pension accounts.\n- SSA-1099\n\nSo far, this project can attach the following schedules to form 1040:\n\n- Schedule 1 (as to Schedule E and 1098-E data only)\n- Schedule 2\n- Schedule 3 (as to excess FICA tax only)\n- Schedule 8812\n- Schedule B\n- Schedule D\n- Schedule E\n- F1040-V\n- F8949 (Uncovered Investment Transactions)\n- F8889 (Health Savings Accounts)\n- F8959 (Additional Medicare Tax)\n- F8960 (Net Investment Income Tax)\n\n## Supported Credits\n\n- Credit for children and other dependents\n- Earned income credit\n\n## Supported states\n\n### Implemented State returns\n\nThe states below have been implemented partially. See the `/src/stateForms/<state>/<relevant form>` file for details on unimplemented portions.\n\n- Illinois\n\n### Non-filing states\n\nUsers who only have wage income and live in the states below should be able to file taxes using this site, since they do not have state level income tax.\n\n- Alaska\n- Florida\n- Nevada\n- New Hampshire\n- South Dakota\n- Tennessee\n- Texas\n- Washington\n- Wyoming\n\n## Note on using this project\n\nThis project is built by a growing community. If you notice an error in the outputted PDF or any other error, please submit an issue on the Github issues tab. We appreciate your feedback!\n\n## User Data\n\nThe project is available strictly via client side. Data is persisted to the site's localstorage so _no personal information ever leaves the user's computer._ For those who want extra security, the codebase can also be built as a [desktop application](#desktop-application).\n\n## Contributing\n\nThank you for taking the time to contribute; let's make tax filing free for everyone! 🎉\n\nTo ensure the project is fun for every contributor, please review:\n\n- [Code of conduct](docs/CODE_OF_CONDUCT.md)\n- [Contributing guide](docs/CONTRIBUTING.md)\n- [Project Architecture](docs/ARCHITECTURE.md)\n\n## Get Started\n\nThis application can be run as either a web application or a [standalone desktop application](#user-content-desktop-application)\n\n### Web application\n\nThis project runs on Node 16. To ensure you're on the proper version, we recommend [nvm](https://github.com/nvm-sh/nvm#installing-and-updating).\n\nWith `nvm` installed, you may select a version 16 node using:\n\n```sh\nnvm install 16\nnvm use 16\n```\n\nTo run,\n\n```sh\nnpm ci          # install package dependencies\nnpm run start   # run app\n```\n\nNote: To avoid having to set your node versions, we suggest using a tool like [direnv](https://direnv.net). With the following configuration file as `.envrc` in project root:\n\n```sh\nexport NVM_DIR=\"$HOME/.nvm\"\n\n. \"$NVM_DIR/nvm.sh\"  # This loads nvm\n#. \"$NVM_DIR/bash_completion\"  # Optional, nvm bash completion\n\nnvm install 16\nnvm use 16\n```\n\nyour environment will be set up every time you enter the project directory.\n\n#### Docker\n\nIf preferred, a Docker alternative is available:\n\n```sh\ndocker-compose build\ndocker-compose up\n```\n\nOpen a browser to `http://localhost:3000`.\n\nTo stop and remove running containers, run `docker-compose down`.\n\n### Desktop application\n\nThe desktop application is built with [Tauri][tauri-root]. In addition to the above steps, please [follow this reference for setting up your environment for Tauri][tauri-setup].\n\nOnce your environment is set up for Tauri, run, `npm run desktop`. To avoid a browser window being spawned in addition to the desktop window, just set the BROWSER environment variable as in: `BROWSER=none npm run desktop`.\n\nTo build executables, run `npm run desktop-release`.\n\n## Getting help\n\nPlease reach out to us on our [discord][discord-url] if you run into any problems, or [file an issue][github-issues]. Thank you for your support!\n\n[netlify-badge]: https://api.netlify.com/api/v1/badges/41efe456-a85d-4fed-9fcf-55fe4d5aa7fa/deploy-status\n[netlify-url]: https://app.netlify.com/sites/peaceful-joliot-d51349/deploys\n[cargo-docs]: https://doc.rust-lang.org/cargo/getting-started/installation.html\n[discord-badge]: https://img.shields.io/discord/812156892343828500?logo=Discord\n[discord-url]: https://discord.gg/dAaz472mPz\n[github-release]: https://github.com/ustaxes/UsTaxes/releases/latest\n[release-badge]: https://badgen.net/github/release/ustaxes/ustaxes\n[desktop-releases]: https://github.com/ustaxes/UsTaxes/releases/\n[github-issues]: https://github.com/ustaxes/ustaxes/issues\n[tauri-setup]: https://tauri.studio/en/docs/getting-started/intro/#setting-up-your-environment\n[tauri-root]: https://tauri.studio\n"
  },
  {
    "path": "craco.config.js",
    "content": "const path = require('path')\nmodule.exports = {\n  webpack: {\n    alias: {\n      ustaxes: path.resolve(__dirname, './src')\n    }\n  }\n}\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3.7'\n\nservices:\n  app:\n    build: .\n    command: npm run start\n    ports:\n      - '3000:3000'\n    volumes:\n      - ./:/app\n"
  },
  {
    "path": "docs/ARCHITECTURE.md",
    "content": "# Project Architecture\n\nThank you for your interest in this project. The below should summarize the general design framework used in this project, and hopefully guide you in understanding the code and getting ready to contribute to the project. If anything at all is unclear please join the discord linked on the readme and feel free to ask any questions you might have.\n\n## Project design\n\nThere are four main concerns separated in this project:\n\n1. Data must be collected from users (react forms)\n2. Collected data must be stored in a data model (via redux dispatched actions only)\n3. Tax forms must access data model to calculate data required by each form\n4. That calculated data must be must be rendered into a PDF file when the user exports their 1040 and attachments.\n\nData flows in only this one direction, from 1 to 4.\n\n![Data flow](dataflow.svg)\n\nNote the information in the datamodel is automatically synced to browser's LocalStorage so the data is available when the user closes and reopens the page.\n\n### Data model\n\nThe root schema of data stored from form submissions is defined in [src/redux/data.ts](../src/redux/data.ts) as:\n\n```ts\nexport interface Information {\n  f1099s: Supported1099[]\n  w2s: IncomeW2[]\n  refund?: Refund\n  taxPayer: TaxPayer\n}\n```\n\n- **f1099s**: An array of all 1099s that have been added. Note this includes 1099-B which goes to Schedule D, 1099-INT which goes to Schedule B, and 1099-DIV which provides data that goes to both Schedule B and Schedule D. This confusion is not needed at this level of the data model. Later when PDFs are created, the correct data can be accessed by the code managing those schedules.\n- **w2s**: All W-2s that have been added for both primary taxpayer and spouse\n- **refund**: Direct deposit information\n- **taxPayer**: Basic information about user's name, SSN, dependents, spouse\n\n### PDF Export\n\nSupported federal and state forms are included in the source control of this repository.\n\n- [src/irsForms/](../src/irsForms/) includes ts models for all federal forms that can be filled by this project. The PDFs are also included in this project at [pubilc/forms](../public/forms). Each of these form definitions implements this interface:\n\n```ts\ntype Field = string | number | boolean | undefined\nexport default interface Fill {\n  fields: () => Field[]\n}\n```\n\nThis array of `fields` must line up exactly with the fields expected by the PDF that the data will be filled into. Getting this data to line up exactly is error prone and tedious. The only type checking we can do between the PDF and our data is to verify if a field expects a boolean value (checkbox), or a text + numeric value.\n\nIn order to help this error prone process, there's also a script that should be used to add a new form. See the guide for contributing a new form below.\n\n- [src/stateForms](../src/stateForms) includes ts models for all state forms that can be filled. They also implement the same interface.\n\n## Guide for contributing a new form implementation\n\n- Add new data schema if needed\n  - Interfaces in [src/redux/data](../src/redux/data.ts) may need to be expanded if you're collecting additional data from the user\n- For a new UI form that needs its own page, add to routes in [Main.tsx](../src/components/Main.tsx)\n- A UI form can push new data into the state using Redux actions. Define your new action in [src/redux/actions.ts](../src/redux/actions.ts), and add your state updates to [src/redux/reducer.ts](../src/redux/reducer.ts)\n- If there is a new attachment to the 1040:\n\n  - The blank form goes in `public/forms/`. The locations of all supported attachments and logic about what attachments are required, is in [fillPdf.ts](../src/pdfFiller/fillPdf.ts).\n  - The data model for the PDF goes in [irsForms](../src/irsForms), and implements the `Form` interface as above. There is a script we use to generate a base implementation of the form. To generate this base implementation, run\n\n  ```\n  npm run formgen ./public/forms/<name-of-form>.pdf > ./src/irsForms/<name-of-form>.ts\n  ```\n\n  This will provide a function for each field in the PDF. At this point you should have a compilable file that needs the implementations for all those functions filled in.\n\n[npm-install]: https://www.npmjs.com/get-npm\n[tauri-root]: https://tauri.studio/\n[rust-root]: https://www.rust-lang.org/\n[webview2]: https://developer.microsoft.com/en-us/microsoft-edge/webview2/\n"
  },
  {
    "path": "docs/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at grimshawaidan@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "content": "# UsTaxes Contributing Guide\n\nBefore contributing please make sure to take a moment to read through the [Code of Conduct](CODE_OF_CONDUCT.md), as well as relevant documentation for the contribution you intend to make:\n\n- [Issue Reporting Guidelines](#issue-reporting-guidelines)\n- [Pull Request Guidelines](#pull-request-guidelines)\n- [Development Guide](#development-guide)\n\n## Maintaining team\n\n- [Aidan Grimshaw](http://github.com/thegrims)\n- [Zak Patterson](http://github.com/zakpatterson)\n\n## Issue Reporting Guidelines\n\n- The issue list of this repo is for bug reports and feature requests. Please come to the [Discord chat](https://discord.gg/dAaz472mPz) with general questions you may have.\n\n- If your issue is resolved but still open, please close it. In case you found a solution by yourself, it could be helpful to explain how you fixed it.\n\n- Generally, there are many features still remaining to produce a valid 1040 for most people. We hope you will view this project in light of your individual circumstances and expertise and contribute accordingly! For example, if you have a certain type of income or receive a certain credit or deduction, and those are not yet implemented, we would happily assist you in implementing those features.\n\n## Pull Request Guidelines\n\n- For code security, we require signed commits. If you haven't set up signed commits yet, please do the following:\n\n  - Follow [this Github tutorial](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification)\n\n  - To ensure all your commits are signed going forward, `git config --global commit.gpgsign true`,\n\n  - If you have unsigned commits that you would like to sign, you can do so by rebasing. `git rebase master`, followed by `git commit --amend` to redo each commit on the branch.\n\n- The only requirement is that your PR is well described and your intentions are clearly communicated.\n\n- If adding new feature, provide some clear reason to add this feature.\n\n- If fixing a bug:\n\n  - If you are resolving a special issue, add `Fixes: #xxx` (#xxx is the issue id) in your PR body. When your PR is merged, the maintainer will move this information into the final commit message for our release log.\n  - Provide detailed description of the bug in the PR, or link to an issue that does.\n\n- These are just some formatting suggestions, we won't call you out for not following them:\n\n  - Start commits with a capital letter and imperative mood, no period at the end.\n  - Each commit first line should be max 50 characters, followed by a blank line.\n  - Wrap following lines at 80 characters.\n  - Include as much detail as you need in the following lines.\n  - Github PR title style is the same as commit first line style.\n\n- It's OK to have multiple small commits as you work on the PR - we apply squash merges to all PRs at the end. In particular, you are free to rebase your commits so long as your pull request is in draft status. As soon as you take it out of draft status, request a review, or receive a review on your pull request, please do not rebase or force push.\n\n## Development Guide\n\n### General Setup\n\nFirst, [join our Discord server](https://discord.gg/dAaz472mPz) and let us know that you want to contribute. This way we can point you in the right direction and help ensure your contribution will be as helpful as possible.\n\n1. To set up your machine for development, review the [Architecture doc](ARCHITECTURE.md), for required links to set up NPM 8 and Rust.\n\n1. Next, fork and clone this repo.\n\n1. Run `npm ci` to install the package versions referenced in `package-lock.json`. If your feature requires a new dependency, add it using `npm install <package-name>@<version>` to avoid affecting other dependencies in `package-lock.json`.\n\nTry\n\n- `npm run desktop` to try out the desktop application. Setting the environment variable `BROWSER=none` will stop the web browser from also loading for you.\n- `npm run start` will serve the site locally on port 3000, so you can view it at `localhost:3000` in your browser.\n\n#### Stack\n\nThis app uses Typescript React and Redux. The structure of this app should look familiar to you if you have used redux before, and it may seem opaque and confusing to you if you have not used Redux before. [Here is a great guide you can use to learn to about redux](https://redux.js.org/tutorials/fundamentals/part-1-overview)\n\n#### State Management\n\nIn order to manage state between many different components and concerns in a project, we dispatch actions that update a piece of state in a global state object. Each of these actions is received by a reducer that applies that change to the state variable. All of this logic is contained in [src/redux](src/redux).\n\n- `src/redux/actions.ts`: All the actions that can be sent to update our state\n- `src/redux/data.ts`: No functionality, just type definitions for our global state variable.\n- `src/redux/reducer.ts`: All logic for updating our global state.\n\n### Directories Overview\n\n- [`src/components`](../src/components) Contains React forms and **all UI**.\n- [`src/data`](../src/data) Contains static data such as a list of states and a list of tax brackets\n- [`src/irsForms`](../src/irsForms)\n  - These are typescript model implementations of the actual IRS pdfs. Each form provides the data to be filled into the final PDF via an array where each index must match the expected index in the PDF. We use the convention that methods are named after the actual line referred to in the PDF. So `const l1 = (): number = ...` will be the function to call to get the numeric value needed on line 1 of that form.\n  - Also, because the forms closely follow IRS published instructions and worksheets, the tax calculations are also coded in this directory.\n- [`pdfFiller`](../src/pdfFiller): All the logic to actually fill form data into a PDF.\n- [`redux`](../src/redux) All the types and logic to manage global state in the app.\n- [`customTypes`](../src/customTypes) Special purpose definitions needed to give the typescript compiler more type information about some features of our dependencies we use. Ideally these needs would be provided by our dependencies and this folder can be deleted in the future.\n\n## License\n\nUsTaxes is a GPL-licensed open source project. We think this choice is important for a few reasons\n\n- If anyone wants to use the software for any reason, they are welcome to.\n- If anyone wants to sell the software, they can, but they have to provide all the source so users can build the project themselves.\n- If someone wants to improve on the software and sell that, they can, but they also have to provide the source for all their improvements for free.\n\nWe believe this choice will help you know your contributions are valued and will be used responsibly.\n\n## Financial Contribution\n\nIf you do not have time to contribute to UsTaxes directly but would like to financially offer support, we have not yet set up a framework to allow that. We promise however that any future financial contributions will be public and without preconditions. So \"I would like to provide support to develop support for itemized deductions\" is fine, and contributions will be allocated towards those working on that feature. But \"I would like to support the project provided you take steps x and y\" or conditioned on us providing advertising or selling other services will not be ok. If you have any questions about that feel free to private message one of the maintainers on our discord.\n\nThis Contributor guide was adapted from the Tauri project's [Contributing document](https://github.com/tauri-apps/tauri/blob/1d66d00506ea79cf803b0e0d025ece1730ffa242/.github/CONTRIBUTING.md)\n"
  },
  {
    "path": "notice.js",
    "content": "const notice = `\n    ustaxes helps you build your tax return forms for free\n    Copyright (C) 2021  Aidan Grimshaw and contributors\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n`\n\nconsole.log(notice)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"ustaxes\",\n  \"version\": \"0.1.21\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@date-io/date-fns\": \"^1.3.13\",\n    \"@material-ui/core\": \"^4.12.4\",\n    \"@material-ui/icons\": \"^4.11.3\",\n    \"@material-ui/lab\": \"^4.0.0-alpha.61\",\n    \"@material-ui/pickers\": \"^3.3.10\",\n    \"@tauri-apps/api\": \"^1.1.0\",\n    \"@tauri-apps/cli\": \"^1.1.1\",\n    \"ajv\": \"^8.11.0\",\n    \"date-fns\": \"^2.29.3\",\n    \"lodash\": \"^4.17.21\",\n    \"loglevel\": \"^1.8.0\",\n    \"papaparse\": \"^5.3.2\",\n    \"pdf-lib\": \"^1.17.1\",\n    \"react\": \"^17.0.2\",\n    \"react-data-table-component\": \"^7.5.3\",\n    \"react-device-detect\": \"^2.2.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-helmet\": \"^6.1.0\",\n    \"react-hook-form\": \"^7.22.5\",\n    \"react-number-format\": \"^4.9.4\",\n    \"react-redux\": \"^8.0.4\",\n    \"react-router\": \"^6.3.0\",\n    \"react-router-dom\": \"^6.3.0\",\n    \"react-scripts\": \"^4.0.3\",\n    \"redux\": \"^4.2.0\",\n    \"redux-logger\": \"^3.0.6\",\n    \"redux-persist\": \"^6.0.0\",\n    \"rooks\": \"^7.4.0\",\n    \"ts-json-schema-generator\": \"^1.0.0\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"scripts\": {\n    \"start\": \"node ./notice.js && ts-node ./scripts/env.ts && ts-node ./scripts/setup.ts && concurrently npm:dev\",\n    \"dev\": \"craco start\",\n    \"build\": \"ts-node ./scripts/env.ts && ts-node ./scripts/setup.ts && craco build\",\n    \"test\": \"ts-node ./scripts/env.ts && ts-node ./scripts/setup.ts && craco test\",\n    \"eject\": \"craco eject\",\n    \"desktop-release\": \"tauri build\",\n    \"desktop\": \"tauri dev\",\n    \"test:report\": \"ts-node ./scripts/env.ts && npm run test -- --coverage .\",\n    \"tauri\": \"ts-node ./scripts/env.ts && tauri\",\n    \"schema-generate\": \"ts-node ./scripts/env.ts && node ./setup.js\",\n    \"lint\": \"eslint ./src --ext ts,js,tsx,jsx --max-warnings=0 && prettier -c .\",\n    \"lint:fix\": \"eslint ./src --fix --ext ts,js,tsx,jsx && prettier --write .\",\n    \"prettier\": \"prettier --write .\",\n    \"formgen\": \"ts-node ./scripts/formgen.ts\",\n    \"prepare\": \"ts-node ./scripts/env.ts && husky install\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"react-app\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@craco/craco\": \"^6.4.5\",\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"@testing-library/react\": \"^12.1.5\",\n    \"@testing-library/user-event\": \"^13.5.0\",\n    \"@types/jest\": \"^29.1.1\",\n    \"@types/lodash\": \"^4.14.186\",\n    \"@types/node\": \"^18.7.23\",\n    \"@types/papaparse\": \"^5.3.5\",\n    \"@types/react\": \"^17.0.47\",\n    \"@types/react-dom\": \"^18.0.5\",\n    \"@types/react-helmet\": \"^6.1.5\",\n    \"@types/react-redux\": \"^7.1.24\",\n    \"@types/react-router-dom\": \"^5.3.3\",\n    \"@types/redux-logger\": \"^3.0.9\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.38.1\",\n    \"@typescript-eslint/parser\": \"^5.38.1\",\n    \"concurrently\": \"^7.4.0\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"eslint-plugin-import\": \"^2.26.0\",\n    \"eslint-plugin-node\": \"^11.1.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"eslint-plugin-promise\": \"^6.0.1\",\n    \"eslint-plugin-react\": \"^7.31.8\",\n    \"fast-check\": \"^2.25.0\",\n    \"husky\": \"^8.0.1\",\n    \"lint-staged\": \"^13.0.3\",\n    \"prettier\": \"2.7.1\",\n    \"ts-node\": \"^10.9.1\",\n    \"typescript-eslint\": \"0.0.1-alpha.0\"\n  },\n  \"lint-staged\": {\n    \"**/*\": \"prettier --write --ignore-unknown .\",\n    \"*.{ts,js,tsx,jsx}\": \"eslint ./src --cache --fix\"\n  },\n  \"jest\": {\n    \"moduleNameMapper\": {\n      \"^ustaxes/(.*)\": \"<rootDir>/src/$1\"\n    },\n    \"transformIgnorePatterns\": [\n      \"/node_modules/(?!@tauri-apps)\"\n    ]\n  },\n  \"engines\": {\n    \"yarn\": \"please-use-npm\"\n  }\n}\n"
  },
  {
    "path": "public/_redirects",
    "content": "/*  /index.html  200"
  },
  {
    "path": "public/forms/Y2020/states/AK/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/AL/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/AR/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/AZ/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/CA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/CO/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/CT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/DC/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/DE/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/FL/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/GA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/HI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/IA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/ID/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/IL/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/IN/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/KS/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/KY/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/LA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MD/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/ME/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MN/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MO/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MS/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/MT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NC/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/ND/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NE/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NH/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NJ/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NM/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NV/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/NY/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/OH/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/OK/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/OR/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/PA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/RI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/SC/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/SD/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/TN/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/TX/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/UT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/VA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/VT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/WA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/WI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/WV/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2020/states/WY/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/AK/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/AL/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/AR/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/AZ/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/CA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/CO/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/CT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/DC/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/DE/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/FL/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/GA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/HI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/IA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/ID/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/IL/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/IN/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/KS/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/KY/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/LA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MD/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/ME/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MN/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MO/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MS/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/MT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NC/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/ND/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NE/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NH/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NJ/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NM/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NV/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/NY/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/OH/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/OK/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/OR/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/PA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/RI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/SC/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/SD/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/TN/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/TX/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/UT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/VA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/VT/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/WA/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/WI/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/WV/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/forms/Y2021/states/WY/README.md",
    "content": "TODO\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"UsTaxes is an open source webapp for filing US federal income tax. All tax calculations are performed in the browser, so no personal information is stored on external servers!\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>UsTaxes.org</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "public/manifest.json",
    "content": "{\n  \"short_name\": \"US Taxes\",\n  \"name\": \"UsTaxes is an open source webapp for filing US federal income tax. All tax calculations are performed in the browser, so no personal information is stored on external servers!\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "scripts/build-netlify.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\nexport CI=false \n\nnpm run lint\n\nnpm run build\n"
  },
  {
    "path": "scripts/env.ts",
    "content": "import { exec } from 'child_process'\n\n// fs.cp since 16.7\nexport const requiredNodeVersion = [16, 7]\nexport const requiredNpmVersion = [7, 0]\n\nconst showError = (...errLines: string[]): void => {\n  const maxLineLen = 78\n  const displayError = errLines.map((err) => {\n    if (err.length > maxLineLen) {\n      const words = err.split(' ')\n      return words\n        .reduce(\n          (lines, word) => {\n            if (lines.length + 1 + word.length > maxLineLen) {\n              return [...lines, word]\n            } else {\n              return [...lines, lines[lines.length - 1] + ' ' + word]\n            }\n          },\n          ['']\n        )\n        .join('\\n')\n    }\n    return err\n  })\n\n  const lineLen = Math.min(\n    maxLineLen,\n    Math.max(...displayError.map((x) => x.length))\n  )\n\n  const line = (msg: string): string => `| ${msg}`.padEnd(lineLen + 2) + ' |'\n\n  const border = `|${Array.from(Array(lineLen + 2))\n    .map(() => '-')\n    .join('')}|`\n\n  console.error([border, ...displayError.map(line), border].join('\\n'))\n}\n\nexport const checkVersion = (): void => {\n  const [M, m] = process.version\n    .slice(1) // drop 'v'\n    .split('.') // split into major and minor\n    .map((x) => parseInt(x, 10))\n  const [R, r] = requiredNodeVersion\n  if (M < R || (M === R && m < r)) {\n    const requiredStr = requiredNodeVersion.join('.')\n\n    showError(\n      'Required node version not found.',\n      `Required: >= ${requiredStr}`,\n      `Found:       ${process.version}`,\n      'Consider using nvm: https://nvm.sh'\n    )\n\n    process.exit(1)\n  }\n}\n\nconst getNpmVersion = (): Promise<[number, number]> => {\n  return new Promise((resolve, reject) => {\n    exec('npm --version', (error, stdout) => {\n      if (error) {\n        reject(error)\n      } else {\n        const [major, minor] = stdout\n          .trim()\n          .split('.')\n          .map((x) => parseInt(x, 10))\n        resolve([major, minor])\n      }\n    })\n  })\n}\n\nexport const checkNpmVersion = async (): Promise<void> => {\n  const [major, minor] = await getNpmVersion()\n  const [R, r] = requiredNpmVersion\n\n  if (major < R || (major === R && minor < r)) {\n    const requiredStr = requiredNpmVersion.join('.')\n\n    showError(\n      'Required npm version not found.',\n      `Required: >= ${requiredStr}`,\n      `Found:       ${major}.${minor}`,\n      'Consider using nvm: https://nvm.sh'\n    )\n\n    process.exit(1)\n  }\n}\n\nconst main = async (): Promise<void> => {\n  await checkNpmVersion()\n  checkVersion()\n}\n\nexport default main\n\nif (require.main === module) {\n  main()\n}\n"
  },
  {
    "path": "scripts/formgen.ts",
    "content": "import { PDFDocument, PDFField, PDFCheckBox } from 'pdf-lib'\nimport { readFile } from 'fs/promises'\nimport * as path from 'path'\nimport _ from 'lodash'\n\nconst loadFile = async (path: string): Promise<PDFDocument> => {\n  const file = await readFile(path)\n  const bytearray = file.slice(0, file.byteLength)\n  return await PDFDocument.load(bytearray)\n}\n\nconst normalizeName = (name: string): string =>\n  name.replace(/[^a-zA-Z0-9]/g, '')\n\nconst fieldFunction = (field: PDFField, index: number): [string, string] => {\n  const name = normalizeName(field.getName())\n  const isNumeric = name.match(/^[0-9]+[a-z]*$/)\n  const functionName = isNumeric ? `l${name}` : `f${index}`\n\n  const returnType = (() => {\n    if (isNumeric) return 'number'\n    if (field instanceof PDFCheckBox) return 'boolean'\n    return 'string'\n  })()\n\n  const fullReturnType = `${returnType}${\n    field.isRequired() ? '' : ' | undefined'\n  }`\n\n  const defaultValue: string = (() => {\n    if (field.isRequired()) {\n      if (field instanceof PDFCheckBox) {\n        return 'false'\n      }\n      return \"''\"\n    }\n    return 'undefined'\n  })()\n\n  // If the pdfField has a plain numeric name, we'll assume that\n  // it corresponds to a numbered line on the return, and it will be given\n  // a simple implementation like const l5 = (): number | undefined => ...\n  // If a pdffield has a string name, then we'll provide a named implementation like\n  // const spouseSocialNumber = () => ...\n  // and an alias with the pdf index field number.\n  const namedImplementation = `  /**\n   * Index ${index}: ${field.getName()}\n   */\n  const ${isNumeric ? functionName : name} = (): ${fullReturnType} => {\n    return ${defaultValue}\n  }\n`\n\n  const alias = isNumeric\n    ? undefined\n    : `  const ${functionName} = (): ${fullReturnType} => this.${name}()\n`\n\n  const code: string = [namedImplementation, alias]\n    .filter((x) => x !== undefined)\n    .join('\\n')\n\n  return [code, functionName]\n}\n\nconst buildSource = (doc: PDFDocument, formName: string): string => {\n  const functions = doc.getForm().getFields().map(fieldFunction)\n  const [impls, functionNames] = _.unzip(functions)\n  const className = normalizeName(formName)\n\n  return `import Form from '../Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from '../../pdfFiller'\nimport { displayNumber, sumFields } from '../../irsForms/util'\nimport { AccountType, FilingStatus, State } from '../../redux/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class ${className} extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n\n  constructor(f1040: F1040) {\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = '${formName}'\n    this.state = 'AK' // <-- Fill here\n  }\n\n${impls.join('\\n')}\n\n  const fields = (): Field[] => ([\n${functionNames\n  .map((name) =>\n    name.startsWith('l')\n      ? `    displayNumber(this.${name}())`\n      : `    this.${name}()`\n  )\n  .join(',\\n')}\n  ])\n}\n\nconst make${className} = (f1040: F1040): ${className} =>\n  new ${className}(f1040)\n\nexport default make${className}\n`\n}\n\nconst generate = async (\n  inFile: string,\n  outFile: string | undefined = undefined\n): Promise<void> => {\n  const pdf = await loadFile(inFile)\n  const name = path.parse(inFile).name\n  const code = buildSource(pdf, name)\n  if (outFile === undefined) {\n    console.log(code)\n  }\n}\n\nconst help = () => {\n  console.log(`\n    Usage:\n    npm run formgen <form-file>.pdf\n  `)\n}\n\nconst main = () => {\n  const args = process.argv.slice(2)\n  process.argv.forEach((a) => console.log(a))\n\n  if (args.length < 1) {\n    help()\n    process.exit()\n  }\n\n  generate(args[0])\n}\n\nif (require.main === module) {\n  main()\n}\n"
  },
  {
    "path": "scripts/setup.ts",
    "content": "import { createGenerator } from 'ts-json-schema-generator'\nimport fs from 'fs'\nimport Ajv from 'ajv'\n\nimport standaloneCode from 'ajv/dist/standalone'\n\nconst config = {\n  path: 'src/core/data/index.ts',\n  tsconfig: 'tsconfig.json',\n  type: '*' // Or <type-name> if you want to generate schema for that one type only\n}\n\nconst indexSchema = {\n  $id: '#/definitions/index',\n  type: 'number',\n  minimum: 0\n}\n\nconst outputPath = 'src/core/data/validate-fns.js'\n\nconst schema = createGenerator(config).createSchema(config.type)\n\nconst ajv = new Ajv({\n  schemas: [schema, indexSchema],\n  allowUnionTypes: true,\n  code: { source: true, esm: true }\n})\n\nconst moduleCode = standaloneCode(ajv, {\n  Index: '#/definitions/index',\n  PersonRole: '#/definitions/PersonRole',\n  ContactInfo: '#/definitions/ContactInfo',\n  Address: '#/definitions/Address',\n  AccountType: '#/definitions/AccountType',\n  Employer: '#/definitions/Employer',\n  FilingStatus: '#/definitions/FilingStatus',\n  PrimaryPerson: '#/definitions/PrimaryPersonDateString',\n  Spouse: '#/definitions/SpouseDateString',\n  Person: '#/definitions/PersonDateString',\n  Dependent: '#/definitions/DependentDateString',\n  F1099IntData: '#/definitions/F1099IntData',\n  F1099BData: '#/definitions/F1099BData',\n  Income1099Int: '#/definitions/Income1099Int',\n  Income1099B: '#/definitions/Income1099B',\n  Supported1099: '#/definitions/Supported1099',\n  IncomeW2: '#/definitions/IncomeW2',\n  EstimatedTaxPayments: '#/definitions/EstimatedTaxPayments',\n  Refund: '#/definitions/Refund',\n  TaxPayer: '#/definitions/TaxPayerDateString',\n  Information: '#/definitions/InformationDateString',\n  Property: '#/definitions/Property',\n  PropertyType: '#/definitions/PropertyType',\n  F1098e: '#/definitions/F1098e',\n  ItemizedDeductions: '#/definitions/ItemizedDeductions',\n  Responses: '#/definitions/Responses',\n  StateResidency: '#/definitions/StateResidency',\n  HealthSavingsAccount: '#/definitions/HealthSavingsAccountDateString',\n  Ira: '#/definitions/Ira',\n  AssetType: '#/definitions/AssetType',\n  AssetString: '#/definitions/AssetString',\n  TaxYear: '#/definitions/TaxYear',\n\n  EditHSAAction: '#/definitions/EditHSAAction',\n  EditIRAAction: '#/definitions/EditIraAction',\n  Credit: '#/definitions/Credit',\n  EditCreditAction: '#/definitions/EditCreditAction'\n})\n\nfs.writeFileSync(outputPath, moduleCode)\n"
  },
  {
    "path": "src/App.css",
    "content": "body {\n  height: 100vh;\n}\n\n.MuiGrid-container ~ .MuiGrid-container {\n  margin-top: 8px;\n}\n"
  },
  {
    "path": "src/App.tsx",
    "content": "import { ReactElement, useMemo } from 'react'\nimport Main from './components/Main'\nimport './App.css'\nimport { createTheme, ThemeProvider, useMediaQuery } from '@material-ui/core'\n\nconst App = (): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  const theme = useMemo(\n    () =>\n      createTheme({\n        palette: {\n          secondary: prefersDarkMode\n            ? {\n                light: '#4f5b62',\n                main: '#d5d5d5',\n                dark: '#000a12',\n                contrastText: '#ffffff'\n              }\n            : {\n                light: '#4f5b62',\n                main: '#263238',\n                dark: '#000a12',\n                contrastText: '#ffffff'\n              },\n          primary: {\n            light: '#66ffa6',\n            main: '#00e676',\n            dark: '#00b248',\n            contrastText: '#000000'\n          }\n        }\n      }),\n    [prefersDarkMode]\n  )\n\n  return (\n    <div className=\"App\">\n      <ThemeProvider theme={theme}>\n        <Main />\n      </ThemeProvider>\n    </div>\n  )\n}\n\nexport default App\n"
  },
  {
    "path": "src/components/ConditionallyWrap.tsx",
    "content": "import { PropsWithChildren, ReactNode, ReactElement } from 'react'\n\ntype ConditionallyWrapProps = PropsWithChildren<{\n  condition: boolean\n  wrapper: (children: ReactNode) => ReactElement\n}>\n\nconst ConditionallyWrap = ({\n  condition,\n  wrapper,\n  children\n}: ConditionallyWrapProps): ReactElement =>\n  condition ? wrapper(children) : <>{children}</>\n\nexport default ConditionallyWrap\n"
  },
  {
    "path": "src/components/CreatePDF.tsx",
    "content": "import { FormEvent, ReactElement, ReactNode, useEffect, useState } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { usePager } from './pager'\nimport Alert from '@material-ui/lab/Alert'\nimport { useSelector } from 'react-redux'\nimport { Information, Asset, State, TaxYear } from 'ustaxes/core/data'\nimport { YearsTaxesState } from 'ustaxes/redux'\n\nimport yearFormBuilder from 'ustaxes/forms/YearForms'\nimport { intentionallyFloat, run, runAsync } from 'ustaxes/core/util'\nimport { Box, Button } from '@material-ui/core'\nimport Summary from './Summary'\n\nimport { savePDF } from 'ustaxes/pdfHandler'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport Form from 'ustaxes/core/irsForms/Form'\n\nexport default function CreatePDF(): ReactElement {\n  const [irsErrors, updateIrsErrors] = useState<string[]>([])\n  const [stateErrors, updateStateErrors] = useState<string[]>([])\n  const [irsForms, updateIrsForms] = useState<Form[]>([])\n  const [stateForms, updateStateForms] = useState<StateForm[]>([])\n\n  const year: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n  const info: Information = useSelector(\n    (state: YearsTaxesState) => state[state.activeYear]\n  )\n\n  const assets: Asset<Date>[] = useSelector(\n    (state: YearsTaxesState) => state.assets\n  )\n\n  useEffect(() => {\n    const builder = yearFormBuilder(year, info, assets)\n    const f1040Errors = builder.errors()\n\n    updateIrsErrors(f1040Errors)\n    if (f1040Errors.length > 0) {\n      updateStateErrors(['Cannot build state return with IRS errors'])\n      updateStateForms([])\n      updateIrsForms([])\n    } else {\n      const irsRes = builder.f1040()\n      const stateRes = builder.makeStateReturn()\n\n      run(stateRes).fold(updateStateErrors, (stateForms) => {\n        updateStateErrors([])\n        updateStateForms(stateForms)\n      })\n\n      run(irsRes).fold(updateIrsErrors, (f1040Forms) => {\n        updateIrsErrors([])\n        updateIrsForms(f1040Forms)\n      })\n    }\n  }, [info])\n\n  const lastName = info.taxPayer.primaryPerson?.lastName\n  const residency: State | undefined = info.stateResidencies[0]?.state\n\n  const federalFileName = `${lastName ?? 'Tax'}-1040.pdf`\n  const stateFileName = `${lastName ?? 'StateTax'}-${residency}.pdf`\n\n  const { navButtons } = usePager()\n\n  const federalReturn = async (e: FormEvent<Element>): Promise<void> => {\n    e.preventDefault()\n    const builder = yearFormBuilder(year, info, assets)\n\n    const r1 = await runAsync(builder.f1040Bytes())\n    const r2 = await r1.mapAsync((bytes) => savePDF(bytes, federalFileName))\n    return r2.orThrow()\n  }\n\n  const stateReturn = async (): Promise<void> => {\n    const builder = yearFormBuilder(year, info, assets)\n\n    const r1 = await runAsync(builder.stateReturnBytes())\n    const r2 = await r1.mapAsync((bytes) => savePDF(bytes, stateFileName))\n    return r2.orThrow()\n  }\n\n  const printActions: ReactNode = (() => {\n    if (irsErrors.length === 0) {\n      return (\n        <>\n          <h2>Print Copy to File</h2>\n          <h3>Federal</h3>\n          <Box marginBottom={2}>\n            <Button\n              type=\"button\"\n              onClick={intentionallyFloat(federalReturn)}\n              variant=\"contained\"\n              color=\"primary\"\n            >\n              Create Federal 1040\n            </Button>\n          </Box>\n          {(() => {\n            if (info.stateResidencies.length > 0) {\n              return <h3>State: {info.stateResidencies[0].state} </h3>\n            }\n          })()}\n          <Box marginBottom={2}>\n            {(() => {\n              if (stateErrors.length === 0) {\n                return (\n                  <Button\n                    type=\"button\"\n                    onClick={intentionallyFloat(stateReturn)}\n                    variant=\"contained\"\n                    color=\"primary\"\n                  >\n                    Create {residency} Return\n                  </Button>\n                )\n              }\n              return stateErrors.map((e) => (\n                <Alert key={e} severity=\"info\">\n                  {e}\n                </Alert>\n              ))\n            })()}\n          </Box>\n        </>\n      )\n    }\n  })()\n\n  return (\n    <div>\n      <Summary\n        errors={irsErrors}\n        stateErrors={stateErrors}\n        irsForms={irsForms}\n        stateForms={stateForms}\n      />\n      <form tabIndex={-1}>\n        <Helmet>\n          <title>Print Copy to File | Results | UsTaxes.org</title>\n        </Helmet>\n        {printActions}\n        {navButtons}\n      </form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/DataPropagator.tsx",
    "content": "import { ReactElement } from 'react'\nimport { useSelector } from 'react-redux'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport { Information, TaxYears } from 'ustaxes/core/data'\nimport _ from 'lodash'\nimport { enumKeys } from 'ustaxes/core/util'\nimport { useDispatch } from 'ustaxes/redux'\nimport { setInfo } from 'ustaxes/redux/actions'\nimport { Button } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\n\nconst DataPropagator = (): ReactElement => {\n  const wholeState = useSelector((state: YearsTaxesState) => state)\n  const allYears = enumKeys(TaxYears)\n  const yearIndex = _.indexOf(allYears, wholeState.activeYear)\n  const dispatch = useDispatch()\n\n  const currentYear: Information = wholeState[wholeState.activeYear]\n  const priorYear: Information = wholeState[allYears[yearIndex - 1]]\n\n  const canPropagate =\n    yearIndex > 0 &&\n    currentYear.taxPayer.primaryPerson?.firstName === undefined &&\n    priorYear.taxPayer.primaryPerson?.firstName !== undefined\n\n  const onClick = () => {\n    if (canPropagate) {\n      dispatch(setInfo(priorYear))\n    }\n  }\n\n  if (canPropagate) {\n    return (\n      <div>\n        <Alert severity=\"info\">\n          <p>\n            You have data from the prior tax year but no data for the current\n            tax year. Would you like to migrate your data from the prior year?\n          </p>\n          <Button onClick={onClick} variant=\"contained\" color=\"primary\">\n            Migrate\n          </Button>\n        </Alert>\n      </div>\n    )\n  }\n  return <></>\n}\n\nexport default DataPropagator\n"
  },
  {
    "path": "src/components/FormContainer/Context.tsx",
    "content": "import {\n  createContext,\n  useContext,\n  PropsWithChildren,\n  Context,\n  ReactElement\n} from 'react'\n\ninterface FormContainerProps {\n  onSubmit?: () => void\n}\n\nconst getProps = (): FormContainerProps => ({\n  onSubmit: () => null\n})\n\nexport const formContainerContext: Context<FormContainerProps> = createContext(\n  getProps()\n)\n\nexport const FormContainerProvider = ({\n  onSubmit,\n  children\n}: PropsWithChildren<FormContainerProps>): ReactElement => {\n  return (\n    <formContainerContext.Provider value={{ onSubmit }}>\n      {children}\n    </formContainerContext.Provider>\n  )\n}\n\nexport const useFormContainer = (): FormContainerProps =>\n  useContext(formContainerContext)\n"
  },
  {
    "path": "src/components/FormContainer.tsx",
    "content": "import { PropsWithChildren, ReactElement, useState } from 'react'\nimport {\n  createStyles,\n  makeStyles,\n  useMediaQuery,\n  IconButton,\n  List,\n  ListItem,\n  ListItemIcon,\n  ListItemSecondaryAction,\n  ListItemText,\n  Box,\n  Button,\n  Theme\n} from '@material-ui/core'\nimport { Delete, Edit } from '@material-ui/icons'\nimport { DefaultValues, SubmitHandler, useFormContext } from 'react-hook-form'\nimport _ from 'lodash'\nimport { ReactNode } from 'react'\nimport { FormContainerProvider } from './FormContainer/Context'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface FormContainerProps {\n  onDone: () => void\n  onCancel?: () => void\n}\n\nexport const FormContainer = ({\n  onDone,\n  onCancel,\n  children\n}: PropsWithChildren<FormContainerProps>): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  return (\n    <div>\n      <FormContainerProvider onSubmit={onDone}>\n        {children}\n      </FormContainerProvider>\n      <Box\n        display=\"flex\"\n        justifyContent=\"flex-start\"\n        marginTop={2}\n        marginBottom={3}\n      >\n        <Box marginRight={2}>\n          <Button\n            type=\"button\"\n            onClick={onDone}\n            variant=\"contained\"\n            color=\"primary\"\n          >\n            Save\n          </Button>\n        </Box>\n        <Button\n          type=\"button\"\n          onClick={onCancel}\n          color={prefersDarkMode ? 'default' : 'secondary'}\n          variant=\"contained\"\n        >\n          Discard\n        </Button>\n      </Box>\n    </div>\n  )\n}\n\ninterface MutableListItemProps {\n  remove?: () => void\n  onEdit?: () => void\n  primary: string\n  secondary?: string | ReactElement\n  editing?: boolean\n  icon?: ReactElement\n  disableEdit?: boolean\n}\n\nexport const MutableListItem = ({\n  icon,\n  primary,\n  secondary,\n  remove,\n  onEdit,\n  editing = false,\n  disableEdit = false\n}: MutableListItemProps): ReactElement => {\n  const canEdit = !editing && !disableEdit && onEdit !== undefined\n  const canDelete = remove !== undefined && !editing\n\n  const editAction = (() => {\n    if (canEdit) {\n      return (\n        <ListItemIcon>\n          <IconButton onClick={onEdit} edge=\"end\" aria-label=\"edit\">\n            <Edit />\n          </IconButton>\n        </ListItemIcon>\n      )\n    }\n  })()\n\n  const deleteAction = (() => {\n    if (canDelete) {\n      return (\n        <ListItemSecondaryAction>\n          <IconButton onClick={remove} edge=\"end\" aria-label=\"delete\">\n            <Delete />\n          </IconButton>\n        </ListItemSecondaryAction>\n      )\n    }\n  })()\n\n  const status = editing ? 'editing' : undefined\n\n  return (\n    <ListItem>\n      <ListItemIcon>{icon}</ListItemIcon>\n      <ListItemText\n        primary={<strong>{primary}</strong>}\n        secondary={secondary}\n      />\n      {editAction}\n      {deleteAction}\n      {status}\n    </ListItem>\n  )\n}\n\ninterface FormListContainerProps<A> {\n  onSubmitAdd: SubmitHandler<A>\n  onSubmitEdit: (index: number) => SubmitHandler<A>\n  onCancel?: () => void\n\n  // same default values passed to useForm\n  defaultValues: DefaultValues<A>\n  items: A[]\n  disableEditing?: boolean\n  removeItem?: (v: number) => void\n  primary: (a: A) => string\n  secondary?: (a: A) => string | ReactElement\n  max?: number\n  icon?: (a: A) => ReactElement\n  grouping?: (a: A) => number\n  groupHeaders?: (ReactNode | undefined)[]\n}\n\nconst useStyles = makeStyles((theme: Theme) =>\n  createStyles({\n    buttonList: {\n      margin: `${theme.spacing(2)}px 0 ${theme.spacing(3)}px`\n    }\n  })\n)\n\nexport interface OpenableFormContainerProps<A> {\n  onCancel?: () => void\n  onSave: SubmitHandler<A>\n  isOpen?: boolean\n  defaultValues: DefaultValues<A>\n  onOpenStateChange: (isOpen: boolean) => void\n  allowAdd?: boolean\n}\n\nexport const OpenableFormContainer = <A,>(\n  props: PropsWithChildren<OpenableFormContainerProps<A>>\n): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n  const { isOpen = false, allowAdd = true, defaultValues } = props\n  const classes = useStyles()\n\n  // Note useFormContext here instead of useForm reuses the\n  // existing form context from the parent.\n  const { reset, handleSubmit } = useFormContext()\n\n  const closeForm = (): void => {\n    props.onOpenStateChange(false)\n    reset(defaultValues)\n  }\n\n  const onClose = (): void => {\n    if (props.onCancel !== undefined) props.onCancel()\n    closeForm()\n  }\n\n  const onSave: SubmitHandler<A> = (formData): void => {\n    props.onSave(formData)\n    closeForm()\n  }\n\n  const openAddForm = () => {\n    props.onOpenStateChange(true)\n  }\n\n  return (\n    <>\n      {(() => {\n        if (isOpen) {\n          return (\n            <FormContainer\n              onDone={intentionallyFloat(handleSubmit(onSave))}\n              onCancel={onClose}\n            >\n              {props.children}\n            </FormContainer>\n          )\n        } else if (allowAdd) {\n          return (\n            <div className={classes.buttonList}>\n              <Button\n                type=\"button\"\n                onClick={openAddForm}\n                color={prefersDarkMode ? 'default' : 'secondary'}\n                variant=\"contained\"\n              >\n                Add\n              </Button>\n            </div>\n          )\n        }\n      })()}\n    </>\n  )\n}\n\nconst FormListContainer = <A,>(\n  props: PropsWithChildren<FormListContainerProps<A>>\n): ReactElement => {\n  const {\n    children,\n    items,\n    icon,\n    max,\n    primary,\n    defaultValues,\n    secondary,\n    disableEditing = false,\n    removeItem,\n    onSubmitAdd,\n    onSubmitEdit,\n    onCancel = () => {\n      // default do nothing\n    },\n    grouping = () => 0,\n    groupHeaders = []\n  } = props\n  const [isOpen, setOpen] = useState(false)\n  const [editing, setEditing] = useState<number | undefined>(undefined)\n\n  const allowAdd = max === undefined || items.length < max\n\n  // Use the provided grouping function to split the input\n  // array into an array of groups. Each group has a title\n  // and a list of items, along with their original index.\n  const groups: [ReactNode, [A, number][]][] = _.chain(items)\n    .map<[A, number]>((x, n) => [x, n])\n    .groupBy(([x]) => grouping(x))\n    .toPairs()\n    .map<[ReactNode, [A, number][]]>(([k, xs]) => [\n      groupHeaders[parseInt(k)],\n      xs\n    ])\n    .value()\n\n  // Note useFormContext here instead of useForm reuses the\n  // existing form context from the parent.\n  const { reset } = useFormContext()\n\n  const closeForm = (): void => {\n    setEditing(undefined)\n    setOpen(false)\n    reset(defaultValues)\n  }\n\n  const cancel = (): void => {\n    closeForm()\n    onCancel()\n  }\n\n  const onSave: SubmitHandler<A> = (formData): void => {\n    if (editing !== undefined) {\n      onSubmitEdit(editing)(formData)\n    } else {\n      onSubmitAdd(formData)\n    }\n    closeForm()\n  }\n\n  const openEditForm = (n: number): (() => void) | undefined => {\n    if (!disableEditing && editing === undefined) {\n      return () => {\n        setEditing(n)\n        setOpen(true)\n        reset(items[n])\n      }\n    }\n  }\n\n  const itemDisplay = (() => {\n    if (items.length > 0) {\n      return (\n        <List dense={true}>\n          {groups.map(([title, group], i) => (\n            <div key={`group-${i}`}>\n              {title}\n              {group.map(([item, originalIndex], k) => (\n                <MutableListItem\n                  key={k}\n                  primary={primary(item)}\n                  secondary={\n                    secondary !== undefined ? secondary(item) : undefined\n                  }\n                  onEdit={openEditForm(originalIndex)}\n                  disableEdit={isOpen}\n                  editing={editing === originalIndex}\n                  remove={\n                    removeItem !== undefined\n                      ? () => removeItem(originalIndex)\n                      : undefined\n                  }\n                  icon={icon !== undefined ? icon(item) : undefined}\n                />\n              ))}\n            </div>\n          ))}\n        </List>\n      )\n    }\n  })()\n\n  return (\n    <>\n      {itemDisplay}\n      <OpenableFormContainer\n        allowAdd={allowAdd}\n        defaultValues={defaultValues}\n        onSave={onSave}\n        isOpen={isOpen}\n        onOpenStateChange={setOpen}\n        onCancel={cancel}\n      >\n        {children}\n      </OpenableFormContainer>\n    </>\n  )\n}\n\nexport default FormContainer\nexport { FormListContainer }\n"
  },
  {
    "path": "src/components/GettingStarted.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { Link, useMediaQuery } from '@material-ui/core'\nimport { StartButtons, SingleButtons } from './pager'\nimport { isWeb } from 'ustaxes/core/util'\n\nconst urls = {\n  repo: 'https://github.com/ustaxes/UsTaxes',\n  releases: 'https://github.com/ustaxes/UsTaxes/releases',\n  issues: 'https://github.com/ustaxes/ustaxes/issues',\n  twitter: 'https://twitter.com/ustaxesorg',\n  discord: 'https://discord.gg/dAaz472mPz',\n  aidan: 'https://github.com/thegrims',\n  zak: 'https://github.com/zakpatterson',\n  startPage: '/info'\n}\n\nconst doubleButtons: ReactElement = (\n  <StartButtons\n    firstText={'Start Return In Browser'}\n    firstUrl={urls.startPage}\n    secondText={'Download Desktop Version'}\n    secondUrl={urls.releases}\n  />\n)\nconst singleButtons: ReactElement = (\n  <SingleButtons text={'Start Return'} url={urls.startPage} />\n)\n\nexport default function GettingStarted(): ReactElement {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  return (\n    <>\n      <Helmet>\n        <title>Getting Started | UsTaxes.org</title>\n      </Helmet>\n      <h1>UsTaxes.org</h1>\n      <p>\n        UsTaxes is an open source tax filing application that can be used to\n        file the Form 1040 United States individual income tax return and some\n        state individual income tax returns. UsTaxes is provided free of charge\n        and requires no sharing of personal data.\n      </p>\n      <p>\n        Interested in using UsTaxes? The income forms, return attachments,\n        credits, and states of residency are provided below.\n      </p>\n      <h2>Supported Income Forms</h2>\n      The following federal income forms are (mostly) supported:\n      <ul>\n        <li>W2</li>\n        <li>1099-INT</li>\n        <li>1099-DIV</li>\n        <li>1099-B</li>\n        <li>1098-E</li>\n        <li>\n          1099-R: support for normal distributions from IRA and pension\n          accounts.\n        </li>\n        <li>SSA-1099</li>\n      </ul>\n      UsTaxes can attach the following to your 1040:\n      <ul>\n        <li>Schedule 1 (as related to Schedule E and Schedule SE only)</li>\n        <li>Schedule 2</li>\n        <li>Schedule 3 (as related to excess FICA only)</li>\n        <li>Schedule 8812</li>\n        <li>Schedule A</li>\n        <li>Schedule B</li>\n        <li>Schedule D</li>\n        <li>Schedule E</li>\n        <li>Schedule SE</li>\n        <li>F1040-V</li>\n        <li>F6251 (AMT; only supports exercise of incentive stock options)</li>\n        <li>F8889 (Health Savings Accounts)</li>\n        <li>F8949 (Uncovered Investment Transactions)</li>\n        <li>F8959 (Additional Medicare Tax)</li>\n        <li>F8960 (Net Investment Income Tax)</li>\n        <li>F8995/F8995-A (Qualified Business Income Deduction)</li>\n      </ul>\n      These federal income tax credits are supported:\n      <ul>\n        <li>Credit for Children and Other Dependents</li>\n        <li>Earned Income Tax Credit</li>\n      </ul>\n      <h2>State Income Tax</h2>\n      <p>State tax returns are now in development.</p>\n      <p>The following states are currently implemented:</p>\n      <ul>\n        <li>Illinois</li>\n      </ul>\n      Note the following states have no income tax filing:\n      <ul>\n        <li>Alaska</li>\n        <li>Tennessee</li>\n        <li>Wyoming</li>\n        <li>Florida</li>\n        <li>New Hampshire</li>\n        <li>South Dakota</li>\n        <li>Texas</li>\n        <li>Washington</li>\n        <li>Nevada</li>\n      </ul>\n      <p>\n        <strong>10</strong>/51 states are supported. If your types of income and\n        state residency are supported, you should be able to use UsTaxes to\n        paper file your return!\n      </p>\n      <h2>Get Started</h2>\n      {isWeb() ? doubleButtons : singleButtons}\n      <h2>Get Involved!</h2>\n      <p>\n        The success of this project depends on user feedback. If you notice any\n        issues at all with the project, please reach out to us!\n      </p>\n      <ul>\n        <li>\n          File an issue: <Link href={urls.issues}>GitHub Issues</Link>\n        </li>\n        <li>\n          Message us on <Link href={urls.twitter}>Twitter</Link>\n        </li>\n        <li>\n          Think you have something to contribute? Come to our{' '}\n          <Link href={urls.discord}>Discord channel</Link>.\n        </li>\n      </ul>\n      <p>\n        UsTaxes is an open source project maintained by{' '}\n        <Link href={urls.aidan}>Aidan Grimshaw</Link> and{' '}\n        <Link href={urls.zak}>Zak Patterson</Link>.\n      </p>\n      <p>\n        Contributions to the <Link href={urls.repo}>GitHub</Link> repository are\n        welcome.\n      </p>\n      <a href=\"https://www.netlify.com\">\n        <img\n          src={prefersDarkMode ? 'netlify-dark.svg' : 'netlify-light.svg'}\n          alt=\"Deploys by Netlify\"\n        />\n      </a>\n    </>\n  )\n}\n"
  },
  {
    "path": "src/components/HelpAndFeedback.tsx",
    "content": "import { Button, Grid, TextField } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\nimport { ReactElement, useEffect, useState } from 'react'\nimport { useSelector } from 'react-redux'\nimport { intentionallyFloat } from 'ustaxes/core/util'\nimport { USTState } from 'ustaxes/redux/store'\nimport anonymize from '../core/data/anonymize'\n\nconst HelpAndFeedback = (): ReactElement => {\n  const state = useSelector((state: USTState) => state)\n  const [anonymizedState, setAnonymizedState] = useState('')\n  const [copied, doSetCopied] = useState(false)\n\n  useEffect(() => {\n    setAnonymizedState(JSON.stringify(anonymize(state), undefined, 2))\n  }, [state])\n\n  const setCopied = (): void => {\n    doSetCopied(true)\n    setTimeout(() => doSetCopied(false), 5000)\n  }\n\n  const copiedAlert = (() => {\n    if (copied) {\n      return (\n        <Grid item>\n          <Alert severity=\"info\">Copied to clipboard</Alert>\n        </Grid>\n      )\n    }\n  })()\n\n  const copyToClipboard = async () => {\n    await navigator.clipboard.writeText(anonymizedState)\n    setCopied()\n  }\n\n  return (\n    <>\n      <h2>Help and Feedback</h2>\n      <p>Did you notice something wrong?</p>\n      <p>\n        Please email <strong>feedback@ustaxes.org</strong> with any questions or\n        bugs. If your personal data might be helpful, please copy paste the\n        below into the body of the email. Your data below should be properly\n        anonymized.\n      </p>\n      <Grid container spacing={2} direction=\"column\">\n        <Grid item>\n          <Button\n            variant=\"contained\"\n            color=\"primary\"\n            onClick={intentionallyFloat(copyToClipboard)}\n          >\n            Copy to clipboard\n          </Button>\n        </Grid>\n        {copiedAlert}\n        <Grid item>\n          <TextField\n            disabled\n            multiline\n            minRows={40}\n            maxRows={100}\n            fullWidth\n            value={JSON.stringify(anonymize(state), null, 2)}\n          />\n        </Grid>\n      </Grid>{' '}\n    </>\n  )\n}\n\nexport default HelpAndFeedback\n"
  },
  {
    "path": "src/components/Main.tsx",
    "content": "import { PropsWithChildren, ReactElement } from 'react'\nimport {\n  createStyles,\n  makeStyles,\n  CssBaseline,\n  Grid,\n  Theme\n} from '@material-ui/core'\nimport { Routes, Route, Navigate } from 'react-router-dom'\nimport { isMobileOnly as isMobile } from 'react-device-detect'\nimport { PagerProvider } from './pager'\nimport { StateLoader } from './debug'\nimport NoMatchPage from './NoMatchPage'\nimport SkipToLinks from './SkipToLinks'\nimport ScrollTop from './ScrollTop'\nimport Menu, { backPages, drawerSectionsForYear } from './Menu'\nimport { Section, SectionItem } from './ResponsiveDrawer'\n\nimport Urls from 'ustaxes/data/urls'\nimport DataPropagator from './DataPropagator'\nimport YearStatusBar from './YearStatusBar'\nimport { useSelector } from 'react-redux'\nimport { TaxYear } from 'ustaxes/core/data'\nimport { YearsTaxesState } from 'ustaxes/redux'\n\ntype Props = {\n  isMobile: boolean\n}\n\nconst useStyles = makeStyles<Theme, Props>((theme: Theme) =>\n  createStyles({\n    container: {\n      display: 'flex'\n    },\n    content: ({ isMobile }) => ({\n      padding: '1em 2em',\n      [theme.breakpoints.up('sm')]: {\n        borderRadius: '5px',\n        boxShadow: 'rgba(0, 0, 0, 0.2) 0px 20px 30px',\n        margin: theme.spacing(3),\n        padding: '1em 2em'\n      },\n      width: isMobile ? '100%' : undefined\n    }),\n    // necessary for content to be below app bar\n    toolbar: {\n      ...theme.mixins.toolbar,\n      [theme.breakpoints.up('sm')]: {\n        display: 'none'\n      }\n    }\n  })\n)\n\nexport default function Main(): ReactElement {\n  const activeYear: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  const classes = useStyles({ isMobile })\n\n  const steps: SectionItem[] = drawerSectionsForYear(activeYear).flatMap(\n    (section: Section) => section.items\n  )\n\n  const allItems: SectionItem[] = [...steps, ...backPages]\n\n  const Layout = ({\n    showMenu = true,\n    children\n  }: PropsWithChildren<{ showMenu?: boolean }>) => (\n    <>\n      {showMenu ? <Menu /> : undefined}\n      <Grid\n        component=\"main\"\n        tabIndex={-1}\n        container\n        justifyContent=\"center\"\n        direction=\"row\"\n      >\n        <Grid item sm={12} md={8} lg={6}>\n          {showMenu ? (\n            <Grid item className={classes.content}>\n              {' '}\n              <YearStatusBar />\n            </Grid>\n          ) : undefined}\n          <Grid item className={classes.content}>\n            {isMobile && showMenu ? (\n              <div className={classes.toolbar} />\n            ) : undefined}\n            {children}\n          </Grid>\n        </Grid>\n      </Grid>\n    </>\n  )\n\n  return (\n    <>\n      <CssBaseline />\n      <SkipToLinks />\n      <div className={classes.container}>\n        <StateLoader />\n        <PagerProvider pages={steps}>\n          <Routes>\n            <Route path=\"/\" element={<Navigate to={Urls.default} />} />\n            {allItems.map((item) => (\n              <Route\n                key={item.title}\n                path={item.url}\n                element={\n                  <Layout showMenu={!item.url.includes('start')}>\n                    <DataPropagator />\n                    {item.element}\n                  </Layout>\n                }\n              />\n            ))}\n            <Route\n              path=\"*\"\n              element={\n                <Layout>\n                  <NoMatchPage />\n                </Layout>\n              }\n            />\n          </Routes>\n        </PagerProvider>\n        {!isMobile && <ScrollTop />}\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "src/components/Menu.tsx",
    "content": "import { ReactElement, useState } from 'react'\nimport { useLocation } from 'react-router-dom'\n\nimport { useSelector } from 'react-redux'\nimport {\n  createStyles,\n  makeStyles,\n  AppBar,\n  IconButton,\n  Slide,\n  Theme,\n  Toolbar,\n  Typography\n} from '@material-ui/core'\nimport CloseIcon from '@material-ui/icons/Close'\nimport MenuIcon from '@material-ui/icons/Menu'\nimport ResponsiveDrawer, {\n  item,\n  Section,\n  SectionItem\n} from './ResponsiveDrawer'\n\nimport W2JobInfo from './income/W2JobInfo'\nimport CreatePDF from './CreatePDF'\nimport PrimaryTaxpayer from './TaxPayer'\nimport RefundBankAccount from './RefundBankAccount'\nimport SpouseAndDependent from './TaxPayer/SpouseAndDependent'\nimport F1099Info from './income/F1099Info'\nimport EstimatedTaxes from './payments/EstimatedTaxes'\nimport RealEstate from './income/RealEstate'\nimport GettingStarted from './GettingStarted'\nimport F1098eInfo from './deductions/F1098eInfo'\nimport ItemizedDeductions from './deductions/ItemizedDeductions'\nimport Questions from './Questions'\nimport HelpAndFeedback from './HelpAndFeedback'\nimport UserSettings from './UserSettings'\nimport Urls from 'ustaxes/data/urls'\n\nimport { isMobileOnly as isMobile } from 'react-device-detect'\nimport HealthSavingsAccounts from './savingsAccounts/healthSavingsAccounts'\nimport IRA from './savingsAccounts/IRA'\nimport OtherInvestments from './income/OtherInvestments'\nimport { StockOptions } from './income/StockOptions'\nimport { PartnershipIncome } from './income/PartnershipIncome'\nimport { TaxYear } from 'ustaxes/core/data'\nimport { AdvanceChildTaxCredit } from './Y2021/AdvanceChildTaxCredit'\nimport { YearsTaxesState } from 'ustaxes/redux'\n\nconst useStyles = makeStyles((theme: Theme) =>\n  createStyles({\n    root: {\n      flexGrow: 1,\n      zIndex: theme.zIndex.drawer + 1,\n      [theme.breakpoints.up('sm')]: {\n        display: 'none'\n      }\n    },\n    toolbar: {\n      alignItems: 'center'\n    },\n    title: {\n      position: 'absolute',\n      width: '100%',\n      textAlign: 'center',\n      pointerEvents: 'none'\n    },\n    menuButton: {\n      marginRight: theme.spacing(2),\n      [theme.breakpoints.up('sm')]: {\n        display: 'none'\n      }\n    },\n    gutters: {\n      margin: '0 12px',\n      padding: 0\n    }\n  })\n)\n\nconst getTitleAndPage = (currentUrl: string, year: TaxYear): string => {\n  const backPage = backPages.find(({ url }) => url === currentUrl)\n  if (backPage) return backPage.title\n\n  const page = drawerSectionsForYear(year)\n    .flatMap(({ title: sectionTitle, items }) =>\n      items.map(({ title, url }) => ({ sectionTitle, title, url }))\n    )\n    .find(({ url }) => url === currentUrl)\n\n  return `${page?.sectionTitle ?? ''} - ${page?.title ?? ''}`\n}\n\nexport const backPages: SectionItem[] = [\n  {\n    title: 'User Settings',\n    url: Urls.settings,\n    element: <UserSettings />\n  },\n  {\n    title: 'Help and Feedback',\n    url: Urls.help,\n    element: <HelpAndFeedback />\n  }\n]\n\nexport const drawerSections: Section[] = [\n  {\n    title: 'UsTaxes.org',\n    items: [item('Getting Started', Urls.usTaxes.start, <GettingStarted />)]\n  },\n  {\n    title: 'Personal',\n    items: [\n      item('Primary Taxpayer', Urls.taxPayer.info, <PrimaryTaxpayer />),\n      item(\n        'Spouse and Dependents',\n        Urls.taxPayer.spouseAndDependent,\n        <SpouseAndDependent />\n      )\n    ]\n  },\n  {\n    title: 'Income',\n    items: [\n      item('Wages (W2)', Urls.income.w2s, <W2JobInfo />),\n      item('Income (1099)', Urls.income.f1099s, <F1099Info />),\n      item('Rental income', Urls.income.realEstate, <RealEstate />),\n      item(\n        'Other investments',\n        Urls.income.otherInvestments,\n        <OtherInvestments />\n      ),\n      item('Stock options', Urls.income.stockOptions, <StockOptions />),\n      item(\n        'Partnership Income',\n        Urls.income.partnershipIncome,\n        <PartnershipIncome />\n      )\n    ]\n  },\n  {\n    title: 'Payments',\n    items: [\n      item('Estimated Taxes', Urls.payments.estimatedTaxes, <EstimatedTaxes />)\n    ]\n  },\n  {\n    title: 'Deductions',\n    items: [\n      item('Student Loan Interest', Urls.deductions.f1098es, <F1098eInfo />),\n      item(\n        'Itemized Deductions',\n        Urls.deductions.itemized,\n        <ItemizedDeductions />\n      )\n    ]\n  },\n  {\n    title: 'Savings Accounts',\n    items: [\n      item(\n        'Health Savings Account (HSA)',\n        Urls.savingsAccounts.healthSavingsAccounts,\n        <HealthSavingsAccounts />\n      ),\n      item(\n        'Individual Retirement Arrangements (IRA)',\n        Urls.savingsAccounts.ira,\n        <IRA />\n      )\n    ]\n  },\n  {\n    title: 'Results',\n    items: [\n      item('Refund Information', Urls.refund, <RefundBankAccount />),\n      item('Informational Questions', Urls.questions, <Questions />),\n      item('Review and Print', Urls.createPdf, <CreatePDF />)\n    ]\n  }\n]\n\nconst yearSpecificPages: Partial<{ [k in TaxYear]: Section[] }> = {\n  Y2021: [\n    {\n      title: 'Tax Year 2021',\n      items: [\n        item(\n          'Advance Child Tax Credit (Letter 6419)',\n          Urls.Y2021.credits,\n          <AdvanceChildTaxCredit />\n        )\n      ]\n    }\n  ]\n}\n\nexport const drawerSectionsForYear = (year: TaxYear): Section[] => [\n  ...drawerSections.slice(0, -2),\n  ...(yearSpecificPages[year] || []),\n  drawerSections[drawerSections.length - 1]\n]\n\nconst Menu = (): ReactElement => {\n  const classes = useStyles()\n  const [isOpen, setOpen] = useState(!isMobile)\n  const activeYear: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  const allSections = drawerSectionsForYear(activeYear)\n\n  return (\n    <>\n      <AppBar position=\"fixed\" className={classes.root}>\n        <Toolbar\n          className={classes.toolbar}\n          classes={{ gutters: classes.gutters }}\n        >\n          <IconButton\n            color=\"inherit\"\n            aria-label={`${isOpen ? 'close' : 'open'} drawer`}\n            edge=\"start\"\n            onClick={() => setOpen((isOpen) => !isOpen)}\n            className={classes.menuButton}\n          >\n            {isOpen ? <CloseIcon /> : <MenuIcon />}\n          </IconButton>\n          <Slide in={isOpen} direction={'right'}>\n            <Typography className={classes.title}>Menu</Typography>\n          </Slide>\n          <Slide in={!isOpen} direction={'left'}>\n            <Typography className={classes.title}>\n              {getTitleAndPage(useLocation().pathname, activeYear)}\n            </Typography>\n          </Slide>\n        </Toolbar>\n      </AppBar>\n      <ResponsiveDrawer\n        sections={allSections}\n        isOpen={isOpen}\n        setOpen={setOpen}\n      />\n    </>\n  )\n}\n\nexport default Menu\n"
  },
  {
    "path": "src/components/NoMatchPage.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { SingleButtons } from './pager'\n\nexport default function NoMatchPage(): ReactElement {\n  return (\n    <form tabIndex={-1}>\n      <Helmet>\n        <title>404 Page not found | UsTaxes.org</title>\n      </Helmet>\n      <h2>Page not found</h2>\n      <p>\n        We can&apos;t find the page you&apos;re looking for! Don&apos;t worry,\n        your progress has been saved\n      </p>\n      <SingleButtons text={'Go Back Home'} url={'/'} />\n    </form>\n  )\n}\n"
  },
  {
    "path": "src/components/Patterns.ts",
    "content": "import { TaxYear, TaxYears } from 'ustaxes/core/data'\nimport { daysInYear } from 'ustaxes/core/util'\n\nexport interface BasePattern {\n  regexp?: RegExp\n  description?: string\n  format?: string\n}\n\nexport interface NumericPattern extends BasePattern {\n  readonly inputType: 'numeric'\n  thousandSeparator?: boolean\n  mask?: string\n  prefix?: string\n  allowEmptyFormatting?: boolean\n  decimalScale?: number\n  min?: number\n  max?: number\n}\n\nexport interface TextPattern extends BasePattern {\n  readonly inputType: 'text'\n}\n\nexport type PatternConfig = NumericPattern | TextPattern\n\n// Convenience record syntax constructor for numeric patterns\nconst numeric = (\n  regexp: RegExp,\n  description: string,\n  min: number | undefined = undefined,\n  max: number | undefined = undefined,\n  format: string | undefined = undefined,\n  mask = '_',\n  thousandSeparator = false,\n  prefix = '',\n  decimalScale: number | undefined = 0\n): NumericPattern => ({\n  inputType: 'numeric',\n  regexp,\n  description,\n  decimalScale,\n  min,\n  max,\n  format,\n  mask,\n  thousandSeparator,\n  prefix\n})\n\nconst text = (regexp: RegExp, description: string): TextPattern => ({\n  inputType: 'text',\n  regexp,\n  description\n})\n\nexport const isNumeric = (p: PatternConfig): p is NumericPattern =>\n  p.inputType === 'numeric'\nexport const isText = (p: PatternConfig): p is TextPattern =>\n  p.inputType === 'text'\n\nexport const Patterns = {\n  number: numeric(/^\\d+$/, 'Input should be a number'),\n  year: numeric(\n    /[12][0-9]{3}/,\n    'Input should be a four digit year',\n    1900,\n    undefined,\n    '####',\n    '_'\n  ),\n  numMonths: numeric(/[0-9]{1,2}/, 'Input should be 0-12', 0, 12, '##', ''),\n  numDays: (year: TaxYear): NumericPattern =>\n    numeric(\n      /[0-9]{1,3}/,\n      `Input should be 0-${daysInYear(TaxYears[year])}`,\n      0,\n      daysInYear(TaxYears[year]),\n      '###',\n      ''\n    ),\n  name: text(/^[A-Za-z ]+$/i, 'Input should only include letters and spaces'),\n  zip: numeric(\n    /[0-9]{5}([0-9]{4})?/,\n    'Input should be filled with 5 or 9 digits',\n    undefined,\n    undefined,\n    '#####-####'\n  ),\n  ssn: numeric(\n    /[0-9]{9}/,\n    'Input should be filled with 9 digits',\n    undefined,\n    undefined,\n    '###-##-####'\n  ),\n  ein: numeric(\n    /[0-9]{9}/,\n    'Input should be filled with 9 digits',\n    undefined,\n    undefined,\n    '##-#######'\n  ),\n  currency: numeric(\n    /[0-9]+(\\.[0-9]{1,2})?/,\n    'Input should be a numeric value',\n    undefined,\n    undefined,\n    undefined,\n    '_',\n    true,\n    '$',\n    2\n  ),\n  bankAccount: numeric(\n    /[0-9]{4,17}/,\n    'Input should be filled with 4-17 digits',\n    undefined,\n    undefined,\n    '#################',\n    ''\n  ),\n  bankRouting: numeric(\n    /[0-9]{9}/,\n    'Input should be filled with 9 digits',\n    undefined,\n    undefined,\n    '#########',\n    '_'\n  ),\n  usPhoneNumber: numeric(\n    /[2-9][0-9]{9}/,\n    'Input should be 10 digits, not starting with 0 or 1',\n    undefined,\n    undefined,\n    '(###) ###-####'\n  ),\n  plain: text(/.*/, '')\n}\n"
  },
  {
    "path": "src/components/Questions.tsx",
    "content": "import { ReactElement, useEffect } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { Grid, List, ListItem } from '@material-ui/core'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { QuestionTagName, Responses } from 'ustaxes/core/data'\nimport { getRequiredQuestions } from 'ustaxes/core/data/questions'\nimport { LabeledCheckbox, LabeledInput } from './input'\nimport { answerQuestion } from 'ustaxes/redux/actions'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { usePager } from './pager'\nimport _ from 'lodash'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\nconst emptyQuestions: Responses = {\n  CRYPTO: false,\n  FOREIGN_ACCOUNT_EXISTS: false,\n  FINCEN_114: false,\n  FINCEN_114_ACCOUNT_COUNTRY: '',\n  FOREIGN_TRUST_RELATIONSHIP: false,\n  LIVE_APART_FROM_SPOUSE: false\n}\n\nconst Questions = (): ReactElement => {\n  const information = useSelector((state: TaxesState) => state.information)\n\n  const stateAnswers: Responses = {\n    ...emptyQuestions,\n    ...information.questions\n  }\n\n  const methods = useForm<Responses>({ defaultValues: stateAnswers })\n\n  const {\n    handleSubmit,\n    getValues,\n    reset,\n    formState: { isDirty }\n  } = methods\n\n  const currentValues = getValues()\n\n  const { navButtons, onAdvance } = usePager()\n\n  const questions = getRequiredQuestions({\n    ...information,\n    questions: {\n      ...information.questions,\n      ...currentValues\n    }\n  })\n\n  const currentAnswers: Responses = { ...emptyQuestions, ...currentValues }\n\n  // This form can be rerendered because the global state was modified by\n  // another control.\n  useEffect(() => {\n    if (!isDirty && !_.isEqual(currentAnswers, stateAnswers)) {\n      reset(stateAnswers)\n    }\n  }, [])\n\n  const dispatch = useDispatch()\n\n  const onSubmit = (responses: Responses): void => {\n    // fix to remove unrequired answers:\n    const qtags = questions.map((q) => q.tag)\n    const unrequired = Object.keys(responses).filter(\n      (rtag) => qtags.find((t) => t === (rtag as QuestionTagName)) === undefined\n    )\n\n    const newResponses = {\n      ...responses,\n      ...Object.fromEntries(unrequired.map((k) => [k, undefined]))\n    }\n\n    dispatch(answerQuestion(newResponses))\n    onAdvance()\n  }\n\n  const page = (\n    <form tabIndex={-1} onSubmit={intentionallyFloat(handleSubmit(onSubmit))}>\n      <Helmet>\n        <title>Informational Questions | Results | UsTaxes.org</title>\n      </Helmet>\n      <h2>Informational Questions</h2>\n      <p>\n        Based on your prior responses, responses to these questions are\n        required.\n      </p>\n      <Grid container spacing={2}>\n        <List>\n          {questions.map((q, i) => (\n            <ListItem key={i}>\n              {(() => {\n                if (q.valueTag === 'boolean') {\n                  return <LabeledCheckbox name={q.tag} label={q.text} />\n                }\n                return <LabeledInput name={q.tag} label={q.text} />\n              })()}\n            </ListItem>\n          ))}\n        </List>\n      </Grid>\n      {navButtons}\n    </form>\n  )\n  return <FormProvider {...methods}>{page}</FormProvider>\n}\n\nexport default Questions\n"
  },
  {
    "path": "src/components/RefundBankAccount.tsx",
    "content": "import { ReactElement, useEffect } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useForm, FormProvider } from 'react-hook-form'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { LabeledInput, LabeledRadio } from './input'\nimport { Patterns } from './Patterns'\nimport { saveRefundInfo } from 'ustaxes/redux/actions'\nimport _ from 'lodash'\n\nimport { Refund } from 'ustaxes/core/data'\nimport { usePager } from './pager'\nimport { Grid } from '@material-ui/core'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\nconst blankFormData: Partial<Refund> = {\n  routingNumber: '',\n  accountNumber: '',\n  accountType: undefined\n}\n\nexport default function RefundBankAccount(): ReactElement {\n  const refund: Partial<Refund> =\n    useSelector((state: TaxesState) => {\n      return state.information.refund\n    }) ?? {}\n\n  const defaultValues: Partial<Refund> = {\n    ...blankFormData,\n    ...refund\n  }\n\n  const { navButtons, onAdvance } = usePager()\n\n  const methods = useForm<Refund>({ defaultValues })\n  const {\n    handleSubmit,\n    reset,\n    getValues,\n    formState: { isDirty }\n  } = methods\n  // const variable dispatch to allow use inside function\n  const dispatch = useDispatch()\n\n  const currentValues = {\n    ...blankFormData,\n    ...getValues()\n  }\n\n  // This form can be rerendered because the global state was modified by\n  // another control.\n  useEffect(() => {\n    if (!isDirty && !_.isEqual(currentValues, defaultValues)) {\n      return reset(defaultValues)\n    }\n  })\n\n  // component functions\n  const onSubmit = (formData: Refund): void => {\n    dispatch(saveRefundInfo(formData))\n    onAdvance()\n  }\n\n  return (\n    <form tabIndex={-1} onSubmit={intentionallyFloat(handleSubmit(onSubmit))}>\n      <FormProvider {...methods}>\n        <Helmet>\n          <title>Refund Information | Results | UsTaxes.org</title>\n        </Helmet>\n        <h2>Refund Information</h2>\n        <Grid container spacing={2}>\n          <LabeledInput\n            label=\"Bank Routing number\"\n            patternConfig={Patterns.bankRouting}\n            name=\"routingNumber\"\n          />\n\n          <LabeledInput\n            label=\"Bank Account number\"\n            patternConfig={Patterns.bankAccount}\n            name=\"accountNumber\"\n          />\n          <LabeledRadio<Refund>\n            label=\"Account Type\"\n            name=\"accountType\"\n            values={[\n              ['Checking', 'checking'],\n              ['Savings', 'savings']\n            ]}\n          />\n        </Grid>\n        {navButtons}\n      </FormProvider>\n    </form>\n  )\n}\n"
  },
  {
    "path": "src/components/ResponsiveDrawer.tsx",
    "content": "import { Dispatch, Fragment, ReactElement, SetStateAction } from 'react'\nimport { NavLink, Link } from 'react-router-dom'\nimport { isMobileOnly as isMobile } from 'react-device-detect'\nimport {\n  createStyles,\n  makeStyles,\n  useTheme,\n  Divider,\n  SwipeableDrawer,\n  IconButton,\n  List,\n  ListItem,\n  ListItemText,\n  ListSubheader,\n  Theme\n} from '@material-ui/core'\nimport GitHubIcon from '@material-ui/icons/GitHub'\nimport TwitterIcon from '@material-ui/icons/Twitter'\nimport { HelpOutlineRounded, Settings } from '@material-ui/icons'\nimport Urls from 'ustaxes/data/urls'\n\nconst drawerWidth = 240\n\nconst useStyles = makeStyles<Theme, { isMobile: boolean }>((theme) =>\n  createStyles({\n    drawer: {\n      [theme.breakpoints.up('sm')]: {\n        width: drawerWidth,\n        flexShrink: 0\n      }\n    },\n    drawerBackdrop: ({ isMobile }) => ({\n      top: isMobile ? '56px !important' : undefined,\n      height: isMobile ? 'calc(100% - 56px)' : undefined\n    }),\n    drawerContainer: ({ isMobile }) => ({\n      top: isMobile ? '56px !important' : 0\n    }),\n    drawerPaper: ({ isMobile }) => ({\n      top: isMobile ? '56px !important' : undefined,\n      width: isMobile ? '100%' : drawerWidth,\n      height: isMobile ? 'calc(100% - 56px)' : undefined\n    }),\n    listSocial: {\n      display: 'flex',\n      justifyContent: 'flex-end',\n      marginRight: theme.spacing(2)\n    },\n    listItemSocial: {\n      flex: 0,\n      padding: 0\n    },\n    list: {\n      marginLeft: theme.spacing(0),\n      paddingLeft: theme.spacing(0)\n    },\n    listItem: {\n      marginLeft: theme.spacing(0),\n      paddingLeft: theme.spacing(2)\n    },\n    sectionHeader: {\n      marginLeft: theme.spacing(2)\n    }\n  })\n)\n\nexport interface Section {\n  title: string\n  items: SectionItem[]\n}\n\nexport interface SectionItem {\n  title: string\n  url: string\n  element: ReactElement\n}\n\nexport const item = (\n  title: string,\n  url: string,\n  element: ReactElement\n): SectionItem => ({\n  title,\n  url,\n  element\n})\n\nexport interface DrawerItemsProps {\n  sections: Section[]\n  isOpen: boolean\n  setOpen: Dispatch<SetStateAction<boolean>>\n}\n\nfunction ResponsiveDrawer(props: DrawerItemsProps): ReactElement {\n  const classes = useStyles({ isMobile })\n  const theme = useTheme()\n\n  const { sections, isOpen, setOpen } = props\n\n  const drawer = (\n    <>\n      {/* {isMobile && <Toolbar />} */}\n      {sections.map(({ title, items }) => (\n        <Fragment key={`section ${title}`}>\n          <List\n            subheader={<ListSubheader disableSticky>{title}</ListSubheader>}\n            className={classes.list}\n          >\n            {items.map((item) => (\n              <ListItem\n                button\n                classes={{}}\n                key={item.title}\n                component={NavLink}\n                selected={location.pathname === item.url}\n                to={item.url}\n              >\n                <ListItemText primary={`${item.title}`} />\n              </ListItem>\n            ))}\n          </List>\n          <Divider />\n        </Fragment>\n      ))}\n      <List className={classes.listSocial}>\n        <ListItem className={classes.listItemSocial}>\n          <Link to={Urls.help}>\n            <IconButton color=\"secondary\" aria-label=\"help, support, feedback\">\n              <HelpOutlineRounded />\n            </IconButton>\n          </Link>\n          <IconButton\n            color=\"secondary\"\n            aria-label=\"github, opens in new tab\"\n            component=\"a\"\n            href={`https://github.com/ustaxes/UsTaxes`}\n            target=\"_blank\"\n            rel=\"noreferrer noopener\"\n          >\n            <GitHubIcon />\n          </IconButton>\n        </ListItem>\n        <ListItem className={classes.listItemSocial}>\n          <IconButton\n            color=\"secondary\"\n            aria-label=\"twitter, opens in new tab\"\n            component=\"a\"\n            href={`https://www.twitter.com/ustaxesorg`}\n            target=\"_blank\"\n            rel=\"noreferrer noopener\"\n          >\n            <TwitterIcon />\n          </IconButton>\n        </ListItem>\n        <ListItem className={classes.listItemSocial}>\n          <Link to={Urls.settings}>\n            <IconButton color=\"secondary\" aria-label=\"site user settings\">\n              <Settings />\n            </IconButton>\n          </Link>\n        </ListItem>\n      </List>\n    </>\n  )\n\n  return (\n    <nav className={classes.drawer} aria-label=\"primary\">\n      <SwipeableDrawer\n        variant={!isMobile ? 'persistent' : undefined}\n        anchor={theme.direction === 'rtl' ? 'right' : 'left'}\n        open={isOpen}\n        onOpen={() => setOpen(true)}\n        onClose={() => setOpen(false)}\n        classes={{\n          root: classes.drawerContainer,\n          paper: classes.drawerPaper\n        }}\n        ModalProps={{\n          BackdropProps: {\n            classes: { root: classes.drawerBackdrop }\n          }\n          // Disabling for the time being due to scroll position persisting\n          // keepMounted: isMobile ? true : false // Better open performance on mobile.\n        }}\n      >\n        {drawer}\n      </SwipeableDrawer>\n    </nav>\n  )\n}\n\nexport default ResponsiveDrawer\n"
  },
  {
    "path": "src/components/SaveToFile.tsx",
    "content": "import { Button, ButtonProps } from '@material-ui/core'\nimport { PropsWithChildren, ReactElement } from 'react'\nimport { useDispatch } from 'react-redux'\nimport { fsPersist } from 'ustaxes/redux/fs/Actions'\n\nconst SaveToFile = (props: PropsWithChildren<ButtonProps>): ReactElement => {\n  const dispatch = useDispatch()\n\n  const { children, ...rest } = props\n\n  const onClick = () => dispatch(fsPersist())\n\n  return (\n    <Button {...rest} onClick={onClick}>\n      {children}\n    </Button>\n  )\n}\n\nexport default SaveToFile\n"
  },
  {
    "path": "src/components/ScrollTop.tsx",
    "content": "import { ReactElement } from 'react'\nimport { makeStyles, useScrollTrigger, Fab, Zoom } from '@material-ui/core'\nimport KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp'\n\nconst useStyles = makeStyles((theme) => ({\n  root: {\n    position: 'fixed',\n    bottom: theme.spacing(2),\n    right: theme.spacing(2)\n  }\n}))\n\nconst ScrollTop = (): ReactElement => {\n  const classes = useStyles()\n  const trigger = useScrollTrigger({\n    target: window,\n    disableHysteresis: true,\n    threshold: 100\n  })\n\n  const handleClick = () => {\n    window.scrollTo({ top: 0, behavior: 'smooth' })\n  }\n\n  return (\n    <Zoom in={trigger}>\n      <div onClick={handleClick} role=\"presentation\" className={classes.root}>\n        <Fab color=\"default\" size=\"small\" aria-label=\"scroll back to top\">\n          <KeyboardArrowUpIcon />\n        </Fab>\n      </div>\n    </Zoom>\n  )\n}\n\nexport default ScrollTop\n"
  },
  {
    "path": "src/components/SkipToLinks.tsx",
    "content": "import { ReactElement } from 'react'\nimport {\n  makeStyles,\n  Link,\n  Theme,\n  Typography,\n  useMediaQuery\n} from '@material-ui/core'\n\ntype Props = {\n  prefersDarkMode: boolean\n}\n\nconst useStyles = makeStyles<Theme, Props>((theme: Theme) => ({\n  root: {\n    position: 'absolute',\n    display: 'flex',\n    top: 0,\n    left: 0,\n    zIndex: 1201\n  },\n  container: {\n    alignItems: 'center',\n    display: 'flex',\n    overflow: 'hidden'\n  },\n  main: ({ prefersDarkMode }) => ({\n    '&:not(:focus)': {\n      position: 'absolute',\n      clip: 'rect(1px, 1px, 1px, 1px)',\n      overflow: 'hidden',\n      padding: 0\n    },\n    '&:focus': {\n      borderRadius: 2,\n      color: prefersDarkMode ? 'white' : 'rgba(0, 0, 0, 0.54)',\n      backgroundColor: prefersDarkMode ? '#303030' : 'white',\n      border: `1px solid ${theme.palette.primary.main}`,\n      cursor: 'pointer',\n      display: 'inline-block',\n      margin: 12,\n      minHeight: 32,\n      textAlign: 'center',\n      width: 130,\n      padding: 12\n    }\n  })\n}))\n\nconst SkipToLinks = (): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  const classes = useStyles({ prefersDarkMode })\n\n  return (\n    <div className={classes.root}>\n      <div className={classes.container}>\n        <Link\n          className={classes.main}\n          tabIndex={0}\n          onClick={() => {\n            document.getElementsByTagName('main')[0].focus()\n          }}\n          onKeyDown={(e) => {\n            if (e.key === 'Enter') {\n              document.getElementsByTagName('main')[0].focus()\n            }\n          }}\n        >\n          <Typography>Skip to main content</Typography>\n        </Link>\n      </div>\n    </div>\n  )\n}\n\nexport default SkipToLinks\n"
  },
  {
    "path": "src/components/Summary.tsx",
    "content": "import { ReactElement } from 'react'\nimport {\n  Avatar,\n  Box,\n  Grid,\n  List,\n  Typography,\n  TableContainer,\n  Table,\n  TableBody,\n  TableRow,\n  TableCell,\n  Accordion,\n  AccordionSummary,\n  AccordionDetails\n} from '@material-ui/core'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport { TaxYear } from 'ustaxes/core/data'\nimport { Check, Close, ExpandMore } from '@material-ui/icons'\nimport Alert from '@material-ui/lab/Alert'\nimport { useSelector } from 'react-redux'\nimport { createSummary, SummaryData } from './SummaryData'\nimport { Currency } from './input'\nimport { displayRound } from 'ustaxes/core/irsForms/util'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport Form from 'ustaxes/core/irsForms/Form'\ninterface BinaryStateListItemProps {\n  active: boolean\n  children: string | ReactElement | ReactElement[]\n}\n\nconst BinaryStateListItem = ({\n  active,\n  children\n}: BinaryStateListItemProps): ReactElement => {\n  return (\n    <Grid container spacing={3}>\n      <Grid item style={{ margin: 'auto' }}>\n        <Avatar>\n          {active ? (\n            <Check titleAccess=\"Eligible\" />\n          ) : (\n            <Close titleAccess=\"Ineligible\" />\n          )}\n        </Avatar>\n      </Grid>\n      <Grid item xs zeroMinWidth>\n        {children}\n      </Grid>\n    </Grid>\n  )\n}\n\ninterface F1040SummaryProps {\n  summary: SummaryData\n}\n\nconst F1040Summary = ({ summary }: F1040SummaryProps): ReactElement => (\n  <>\n    {(() => {\n      if (summary.amountOwed !== undefined && summary.amountOwed > 0) {\n        return (\n          <div>\n            <Typography variant=\"body2\" color=\"textSecondary\">\n              Amount Owed: <Currency value={-summary.amountOwed} />\n            </Typography>\n          </div>\n        )\n      }\n      if (summary.refundAmount !== undefined && summary.refundAmount > 0) {\n        return (\n          <div>\n            <Typography variant=\"body2\" color=\"textSecondary\">\n              Refund Amount: <Currency value={summary.refundAmount} />\n            </Typography>\n          </div>\n        )\n      }\n    })()}\n\n    <h3>Credits</h3>\n    <Grid container>\n      <Grid item zeroMinWidth>\n        <List>\n          {summary.credits.map((credit) => (\n            <BinaryStateListItem key={credit.name} active={credit.allowed}>\n              <Typography variant=\"body2\" color=\"textPrimary\">\n                {credit.name}\n              </Typography>\n              {(() => {\n                if (credit.value !== undefined) {\n                  return (\n                    <Typography variant=\"body2\" color=\"textSecondary\">\n                      Credit: <Currency value={credit.value} />\n                    </Typography>\n                  )\n                }\n                return <></>\n              })()}\n            </BinaryStateListItem>\n          ))}\n        </List>\n      </Grid>\n    </Grid>\n\n    {(() => {\n      if (summary.worksheets.length > 0) {\n        return (\n          <Grid container>\n            <Grid item zeroMinWidth>\n              <h3>Worksheets</h3>\n              <List>\n                {summary.worksheets.map((worksheet, idx) => (\n                  <Accordion key={idx}>\n                    <AccordionSummary expandIcon={<ExpandMore />}>\n                      {worksheet.name}\n                    </AccordionSummary>\n                    <AccordionDetails>\n                      <TableContainer>\n                        <Table size=\"small\">\n                          <TableBody>\n                            {worksheet.lines.map((line) => (\n                              <TableRow key={line.line}>\n                                <TableCell component=\"th\">\n                                  Line {line.line}\n                                </TableCell>\n                                <TableCell>\n                                  {typeof line.value === 'number' ? (\n                                    <Currency\n                                      value={displayRound(line.value) ?? 0}\n                                    />\n                                  ) : (\n                                    line.value\n                                  )}\n                                </TableCell>\n                              </TableRow>\n                            ))}\n                          </TableBody>\n                        </Table>\n                      </TableContainer>\n                    </AccordionDetails>\n                  </Accordion>\n                ))}\n              </List>\n            </Grid>\n          </Grid>\n        )\n      }\n      return <></>\n    })()}\n  </>\n)\n\ninterface SummaryProps {\n  errors: string[]\n  stateErrors?: string[]\n  irsForms: Form[]\n  stateForms?: StateForm[]\n}\n\nconst Summary = ({ errors, irsForms }: SummaryProps): ReactElement => {\n  const year: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  const summaryBody = (\n    <>\n      <h3>Federal</h3>\n      {(() => {\n        if (errors.length > 0) {\n          return (\n            <Box marginBottom={2}>\n              {errors.map((error, i) => (\n                <Alert key={i} severity=\"warning\">\n                  {error}\n                </Alert>\n              ))}\n            </Box>\n          )\n        } else {\n          const summary = createSummary(year, irsForms)\n          if (summary === undefined) {\n            return undefined\n          }\n          return <F1040Summary summary={summary} />\n        }\n      })()}\n    </>\n  )\n\n  return (\n    <div>\n      <h2>Summary</h2>\n      {summaryBody}\n    </div>\n  )\n}\n\nexport default Summary\n"
  },
  {
    "path": "src/components/SummaryData.ts",
    "content": "import Form from 'ustaxes/core/irsForms/Form'\nimport { TaxYear } from 'ustaxes/core/data'\nimport F1040For2020 from 'ustaxes/forms/Y2020/irsForms/F1040'\nimport F1040For2021 from 'ustaxes/forms/Y2021/irsForms/F1040'\n\ninterface Credit {\n  name: string\n  value?: number\n  notes?: string\n  allowed: boolean\n}\n\nexport interface WorksheetLine {\n  line: number | string\n  value: string | number | undefined\n}\nexport interface WorksheetData {\n  name: string\n  lines: WorksheetLine[]\n}\n\nexport interface SummaryData {\n  credits: Credit[]\n  worksheets: WorksheetData[]\n  refundAmount?: number\n  amountOwed?: number\n}\n\ninterface SummaryCreator<A> {\n  summary: (a: A) => SummaryData\n}\n\nconst emptySummary = {\n  credits: [],\n  worksheets: []\n}\n\nexport const SummaryCreatorFor2020: SummaryCreator<F1040For2020> = {\n  summary: (f: F1040For2020): SummaryData => ({\n    credits: [\n      {\n        name: 'Earned Income Credit',\n        value: f.scheduleEIC.credit(),\n        allowed: f.scheduleEIC.allowed()\n      },\n      {\n        name: 'Children and Other Dependents',\n        value: f.childTaxCreditWorksheet.credit(),\n        allowed: f.childTaxCreditWorksheet.isAllowed()\n      }\n    ],\n    worksheets: [],\n    refundAmount: f.l35a(),\n    amountOwed: f.l37()\n  })\n}\n\nexport const SummaryCreatorFor2021: SummaryCreator<F1040For2021> = {\n  summary: (f: F1040For2021): SummaryData => ({\n    credits: [\n      {\n        name: 'Earned income credit',\n        value: f.scheduleEIC.credit(),\n        allowed: f.scheduleEIC.allowed()\n      }\n    ],\n    worksheets: [\n      ...(f.qualifiedAndCapGainsWorksheet !== undefined\n        ? [f.qualifiedAndCapGainsWorksheet.getSummaryData()]\n        : [])\n    ],\n    refundAmount: f.l35a(),\n    amountOwed: f.l37()\n  })\n}\n\nexport const createSummary = (\n  year: TaxYear,\n  forms: Form[]\n): SummaryData | undefined => {\n  const f1040 = forms.find((f) => f.tag === 'f1040')\n  if (f1040 === undefined) {\n    return undefined\n  }\n\n  switch (year) {\n    case 'Y2019': {\n      return emptySummary\n    }\n    case 'Y2020': {\n      return SummaryCreatorFor2020.summary(f1040 as F1040For2020)\n    }\n    case 'Y2021': {\n      return SummaryCreatorFor2021.summary(f1040 as F1040For2021)\n    }\n  }\n}\n"
  },
  {
    "path": "src/components/TaxPayer/Address.tsx",
    "content": "import { ReactElement } from 'react'\nimport { useFormContext, useWatch } from 'react-hook-form'\nimport {\n  LabeledCheckbox,\n  LabeledInput,\n  USStateDropDown\n} from 'ustaxes/components/input'\nimport { CountryDropDown } from 'ustaxes/components/input/LabeledDropdown'\nimport { Patterns } from 'ustaxes/components/Patterns'\n\ninterface AddressProps {\n  autofocus?: boolean\n  checkboxText: string\n  allowForeignCountry?: boolean\n}\n\nexport default function AddressFields(props: AddressProps): ReactElement {\n  const {\n    autofocus,\n    checkboxText = 'Check if you have a foreign address',\n    allowForeignCountry = true\n  } = props\n\n  const { control } = useFormContext<{ isForeignCountry: boolean }>()\n\n  const isForeignCountry = useWatch({\n    name: 'isForeignCountry',\n    control\n  })\n\n  const csz: ReactElement = (() => {\n    if (!allowForeignCountry || !isForeignCountry) {\n      return (\n        <>\n          <USStateDropDown\n            label=\"State\"\n            name=\"address.state\"\n            required={!isForeignCountry}\n          />\n          <LabeledInput\n            label=\"Zip\"\n            name=\"address.zip\"\n            patternConfig={Patterns.zip}\n            required={!isForeignCountry}\n          />\n        </>\n      )\n    }\n    return (\n      <>\n        <LabeledInput\n          label=\"Province\"\n          name=\"address.province\"\n          required={isForeignCountry}\n        />\n        <LabeledInput\n          name=\"address.postalCode\"\n          label=\"Postal Code\"\n          required={isForeignCountry}\n        />\n        <CountryDropDown\n          name=\"address.foreignCountry\"\n          label=\"Country\"\n          required={isForeignCountry}\n        />\n      </>\n    )\n  })()\n\n  return (\n    <>\n      <LabeledInput\n        autofocus={autofocus}\n        label=\"Address\"\n        name=\"address.address\"\n        required={true}\n      />\n      <LabeledInput label=\"Unit No\" name=\"address.aptNo\" required={false} />\n      <LabeledInput\n        label=\"City\"\n        name=\"address.city\"\n        patternConfig={Patterns.name}\n      />\n      {(() => {\n        if (allowForeignCountry) {\n          return (\n            <LabeledCheckbox label={checkboxText} name=\"isForeignCountry\" />\n          )\n        }\n      })()}\n      {csz}\n    </>\n  )\n}\n"
  },
  {
    "path": "src/components/TaxPayer/PersonFields.tsx",
    "content": "import { PropsWithChildren, ReactElement } from 'react'\nimport {\n  IconButton,\n  List,\n  ListItem,\n  ListItemIcon,\n  ListItemSecondaryAction\n} from '@material-ui/core'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport {\n  formatSSID,\n  LabeledInput,\n  LabeledCheckbox,\n  DatePicker\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { removeDependent } from 'ustaxes/redux/actions'\nimport { Person } from 'ustaxes/core/data'\nimport DeleteIcon from '@material-ui/icons/Delete'\nimport EditIcon from '@material-ui/icons/Edit'\nimport ListItemText from '@material-ui/core/ListItemText'\nimport PersonIcon from '@material-ui/icons/Person'\n\nexport const labels = {\n  fname: 'First Name and Initial',\n  lname: 'Last Name',\n  dateOfBirth: 'Date of Birth',\n  ssn: 'SSN / TIN'\n}\n\nexport const PersonFields = ({\n  children,\n  autofocus\n}: PropsWithChildren<{ autofocus?: boolean }>): ReactElement => {\n  return (\n    <>\n      <LabeledInput\n        autofocus={autofocus}\n        label={labels.fname}\n        name=\"firstName\"\n        required={true}\n      />\n      <LabeledInput label={labels.lname} name=\"lastName\" required={true} />\n      <LabeledInput\n        label={labels.ssn}\n        name=\"ssid\"\n        patternConfig={Patterns.ssn}\n      />\n      <LabeledCheckbox label=\"Is this person blind?\" name=\"isBlind\" />\n      <DatePicker\n        name=\"dateOfBirth\"\n        label={labels.dateOfBirth}\n        required={true}\n        minDate={new Date(1900, 0, 1)}\n        maxDate={new Date()}\n      />\n      {children}\n    </>\n  )\n}\n\ninterface PersonListItemProps {\n  person: Person\n  remove: () => void\n  onEdit?: () => void\n  editing?: boolean\n}\n\nexport const PersonListItem = ({\n  person,\n  remove,\n  onEdit,\n  editing = false\n}: PersonListItemProps): ReactElement => (\n  <ListItem className={editing ? 'active' : ''}>\n    <ListItemIcon>\n      <PersonIcon />\n    </ListItemIcon>\n    <ListItemText\n      primary={`${person.firstName} ${person.lastName}`}\n      secondary={formatSSID(person.ssid)}\n    />\n    {(() => {\n      if (editing) {\n        return (\n          <ListItemIcon>\n            <IconButton onClick={onEdit} edge=\"end\" aria-label=\"edit\">\n              <EditIcon />\n            </IconButton>\n          </ListItemIcon>\n        )\n      }\n    })()}\n    <ListItemSecondaryAction>\n      <IconButton onClick={remove} edge=\"end\" aria-label=\"delete\">\n        <DeleteIcon />\n      </IconButton>\n    </ListItemSecondaryAction>\n  </ListItem>\n)\n\ninterface ListDependentsProps {\n  onEdit?: (index: number) => void\n  editing?: number\n}\n\nexport function ListDependents({\n  onEdit = () => {\n    /* default do nothing */\n  },\n  editing\n}: ListDependentsProps): ReactElement {\n  const dependents = useSelector(\n    (state: TaxesState) => state.information.taxPayer.dependents\n  )\n\n  const dispatch = useDispatch()\n\n  const drop = (i: number): void => dispatch(removeDependent(i))\n\n  return (\n    <List dense={true}>\n      {dependents.map((p, i) => (\n        <PersonListItem\n          key={i}\n          remove={() => drop(i)}\n          person={p}\n          editing={editing === i}\n          onEdit={() => onEdit(i)}\n        />\n      ))}\n    </List>\n  )\n}\n"
  },
  {
    "path": "src/components/TaxPayer/SpouseAndDependent.tsx",
    "content": "import { ReactElement, useEffect, useState } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useForm, FormProvider } from 'react-hook-form'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport {\n  LabeledInput,\n  LabeledCheckbox,\n  formatSSID,\n  GenericLabeledDropdown\n} from 'ustaxes/components/input'\nimport {\n  TaxPayer,\n  Dependent,\n  Spouse,\n  PersonRole,\n  FilingStatus,\n  FilingStatusTexts,\n  filingStatuses\n} from 'ustaxes/core/data'\nimport {\n  addDependent,\n  addSpouse,\n  editDependent,\n  removeDependent,\n  removeSpouse,\n  saveFilingStatusInfo\n} from 'ustaxes/redux/actions'\nimport { PersonFields } from './PersonFields'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { usePager } from 'ustaxes/components/pager'\nimport { Box, Grid } from '@material-ui/core'\nimport { Person } from '@material-ui/icons'\nimport { Alert } from '@material-ui/lab'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface UserPersonForm {\n  firstName: string\n  lastName: string\n  ssid: string\n  isBlind: boolean\n  dateOfBirth?: Date\n}\n\nconst blankUserPersonForm: UserPersonForm = {\n  firstName: '',\n  lastName: '',\n  ssid: '',\n  isBlind: false,\n  dateOfBirth: undefined\n}\n\ninterface UserDependentForm extends UserPersonForm {\n  relationship: string\n  isStudent: boolean\n  numberOfMonths: string\n}\n\nconst blankUserDependentForm: UserDependentForm = {\n  ...blankUserPersonForm,\n  relationship: '',\n  isStudent: false,\n  numberOfMonths: ''\n}\n\nconst toDependent = (formData: UserDependentForm): Dependent<string> => {\n  const { isStudent, numberOfMonths, ...rest } = formData\n  if (formData.dateOfBirth === undefined) {\n    throw new Error('Called with undefined date of birth')\n  }\n\n  return {\n    ...rest,\n    role: PersonRole.DEPENDENT,\n    qualifyingInfo: {\n      numberOfMonths: parseInt(numberOfMonths),\n      isStudent\n    },\n    dateOfBirth: formData.dateOfBirth.toISOString()\n  }\n}\n\nconst toDependentForm = (dependent: Dependent): UserDependentForm => {\n  const { qualifyingInfo, dateOfBirth, ...rest } = dependent\n\n  return {\n    ...rest,\n    numberOfMonths: qualifyingInfo?.numberOfMonths.toString() ?? '',\n    isStudent: qualifyingInfo?.isStudent ?? false,\n    dateOfBirth\n  }\n}\n\ninterface UserSpouseForm extends UserPersonForm {\n  isTaxpayerDependent: boolean\n}\n\nconst blankUserSpouseForm = {\n  ...blankUserPersonForm,\n  isTaxpayerDependent: false\n}\n\nconst toSpouse = (formData: UserSpouseForm): Spouse<string> => {\n  if (formData.dateOfBirth === undefined) {\n    throw new Error('Called with undefined date of birth')\n  }\n\n  return {\n    ...formData,\n    role: PersonRole.SPOUSE,\n    dateOfBirth: formData.dateOfBirth.toISOString()\n  }\n}\n\nconst toSpouseForm = (spouse: Spouse): UserSpouseForm => ({\n  ...spouse,\n  dateOfBirth: new Date(spouse.dateOfBirth)\n})\n\nexport const AddDependentForm = (): ReactElement => {\n  const dependents = useSelector(\n    (state: TaxesState) => state.information.taxPayer.dependents\n  )\n\n  const defaultValues = blankUserDependentForm\n\n  const dispatch = useDispatch()\n\n  const methods = useForm<UserDependentForm>({\n    defaultValues\n  })\n\n  const onSubmitAdd = (formData: UserDependentForm): void => {\n    dispatch(addDependent(toDependent(formData)))\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: UserDependentForm): void => {\n      dispatch(\n        editDependent({\n          index,\n          value: toDependent(formData)\n        })\n      )\n    }\n\n  const page = (\n    <FormListContainer<UserDependentForm>\n      defaultValues={defaultValues}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      items={dependents.map((a) => toDependentForm(a))}\n      primary={(a) => `${a.firstName} ${a.lastName}`}\n      secondary={(a) => formatSSID(a.ssid)}\n      icon={() => <Person />}\n      removeItem={(i) => dispatch(removeDependent(i))}\n    >\n      <Grid container spacing={2}>\n        <PersonFields />\n        <LabeledInput\n          label=\"Relationship to Taxpayer\"\n          name=\"relationship\"\n          patternConfig={Patterns.name}\n        />\n        <LabeledInput\n          label=\"How many months did you live together this year?\"\n          patternConfig={Patterns.numMonths}\n          name=\"numberOfMonths\"\n        />\n        <LabeledCheckbox\n          label=\"Is this person a full-time student?\"\n          name=\"isStudent\"\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  return <FormProvider {...methods}>{page}</FormProvider>\n}\n\nexport const SpouseInfo = (): ReactElement => {\n  const defaultValues = blankUserSpouseForm\n  const methods = useForm<UserSpouseForm>({\n    defaultValues\n  })\n  const { getValues } = methods\n  const dispatch = useDispatch()\n\n  const spouse: Spouse | undefined = useSelector((state: TaxesState) => {\n    return state.information.taxPayer.spouse\n  })\n\n  const onSubmit = (): void => {\n    dispatch(addSpouse(toSpouse(getValues())))\n  }\n\n  const onSubmitEdit = (): (() => void) => onSubmit\n\n  const page = (\n    <FormListContainer\n      defaultValues={defaultValues}\n      items={spouse !== undefined ? [toSpouseForm(spouse)] : []}\n      primary={(s) => `${s.firstName} ${s.lastName}`}\n      secondary={(s) => formatSSID(s.ssid)}\n      icon={() => <Person />}\n      onSubmitAdd={onSubmit}\n      onSubmitEdit={onSubmitEdit}\n      max={1}\n      removeItem={() => dispatch(removeSpouse)}\n    >\n      <Grid container spacing={2}>\n        <PersonFields autofocus={true}>\n          <LabeledCheckbox\n            label=\"Check if your spouse is a dependent\"\n            name=\"isTaxpayerDependent\"\n          />\n        </PersonFields>\n      </Grid>\n    </FormListContainer>\n  )\n\n  return <FormProvider {...methods}>{page}</FormProvider>\n}\n\nexport const FilingStatusDropdown = (): ReactElement => {\n  const dispatch = useDispatch()\n\n  const onSubmit = (formData: { filingStatus: FilingStatus }): void => {\n    dispatch(saveFilingStatusInfo(formData.filingStatus))\n    onAdvance()\n  }\n  const taxPayer: TaxPayer | undefined = useSelector((state: TaxesState) => {\n    return state.information.taxPayer\n  })\n\n  const allowedFilingStatuses = filingStatuses(taxPayer)\n\n  const { onAdvance, navButtons } = usePager()\n\n  const defaultValues: { filingStatus: FilingStatus | '' } = {\n    filingStatus: (() => {\n      if (\n        taxPayer.filingStatus !== undefined &&\n        allowedFilingStatuses.includes(taxPayer.filingStatus)\n      ) {\n        return taxPayer.filingStatus\n      }\n      return ''\n    })()\n  }\n\n  const methods = useForm({\n    defaultValues\n  })\n\n  const [error, setError] = useState<ReactElement | undefined>(undefined)\n\n  const {\n    handleSubmit,\n    getValues,\n    reset,\n    watch,\n    formState: { isDirty }\n  } = methods\n\n  const currentFilingStatus = getValues().filingStatus\n\n  const newValue = watch()\n\n  useEffect(() => {\n    // Handle state updates outside this control\n    if (!isDirty && currentFilingStatus !== defaultValues.filingStatus) {\n      reset(defaultValues)\n    }\n    // Handle other state updates that cause current\n    // value to be invalid\n    else if (\n      currentFilingStatus !== '' &&\n      !allowedFilingStatuses.includes(currentFilingStatus)\n    ) {\n      reset({})\n      setError(\n        <Box paddingTop={2}>\n          <Alert severity=\"warning\">\n            Filing status was set to {FilingStatusTexts[currentFilingStatus]}{' '}\n            which is no longer allowed due to your inputs. Make another\n            selection.\n          </Alert>\n        </Box>\n      )\n    } else if (currentFilingStatus !== '' || newValue.filingStatus !== '') {\n      setError(undefined)\n    }\n  }, [defaultValues.filingStatus, currentFilingStatus])\n\n  return (\n    <FormProvider {...methods}>\n      <form tabIndex={-1} onSubmit={intentionallyFloat(handleSubmit(onSubmit))}>\n        <Box marginBottom={2}>\n          <GenericLabeledDropdown<FilingStatus, { filingStatus: FilingStatus }>\n            label=\"Filing Status\"\n            dropDownData={allowedFilingStatuses}\n            valueMapping={(x) => x}\n            keyMapping={(x, i) => i}\n            textMapping={(status) => FilingStatusTexts[status]}\n            name=\"filingStatus\"\n          />\n        </Box>\n        {error}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n\nconst SpouseAndDependent = (): ReactElement => (\n  <>\n    <Helmet>\n      <title>Family Information | Personal | UsTaxes.org</title>\n    </Helmet>\n    <h2>Family Information</h2>\n    <h3>Spouse Information</h3>\n    <SpouseInfo />\n\n    <h3>Dependent Information</h3>\n    <AddDependentForm />\n\n    <FilingStatusDropdown />\n  </>\n)\n\nexport default SpouseAndDependent\n"
  },
  {
    "path": "src/components/TaxPayer/TaxPayer.tsx",
    "content": "import { ReactElement, useEffect } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport _ from 'lodash'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\n\nimport {\n  savePrimaryPersonInfo,\n  saveStateResidencyInfo,\n  saveContactInfo\n} from 'ustaxes/redux/actions'\nimport {\n  Address,\n  ContactInfo,\n  PersonRole,\n  PrimaryPerson,\n  State,\n  StateResidency,\n  TaxPayer\n} from 'ustaxes/core/data'\nimport { PersonFields } from './PersonFields'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  LabeledCheckbox,\n  USStateDropDown,\n  LabeledInput\n} from 'ustaxes/components/input'\nimport AddressFields from './Address'\nimport { Grid } from '@material-ui/core'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface TaxPayerUserForm {\n  firstName: string\n  lastName: string\n  ssid: string\n  contactPhoneNumber?: string\n  contactEmail?: string\n  role: PersonRole\n  address: Address\n  isForeignCountry: boolean\n  isTaxpayerDependent: boolean\n  stateResidency?: State\n  isBlind: boolean\n  dateOfBirth?: Date\n}\n\nconst defaultTaxpayerUserForm: TaxPayerUserForm = {\n  firstName: '',\n  lastName: '',\n  ssid: '',\n  contactPhoneNumber: '',\n  contactEmail: '',\n  role: PersonRole.PRIMARY,\n  isForeignCountry: false,\n  address: {\n    address: '',\n    city: '',\n    aptNo: '',\n    state: undefined,\n    zip: undefined\n  },\n  isTaxpayerDependent: false,\n  isBlind: false,\n  dateOfBirth: undefined\n}\n\nconst asPrimaryPerson = (formData: TaxPayerUserForm): PrimaryPerson<string> => {\n  if (formData.dateOfBirth === undefined) {\n    throw new Error('Called with undefined date of birth')\n  }\n  return {\n    address: formData.address,\n    firstName: formData.firstName,\n    lastName: formData.lastName,\n    ssid: formData.ssid.replace(/-/g, ''),\n    isTaxpayerDependent: formData.isTaxpayerDependent,\n    role: PersonRole.PRIMARY,\n    dateOfBirth: formData.dateOfBirth.toISOString(),\n    isBlind: formData.isBlind\n  }\n}\n\nconst asContactInfo = (formData: TaxPayerUserForm): ContactInfo => ({\n  contactPhoneNumber: formData.contactPhoneNumber,\n  contactEmail: formData.contactEmail\n})\n\nconst asTaxPayerUserForm = (person: PrimaryPerson): TaxPayerUserForm => ({\n  ...person,\n  isForeignCountry: person.address.foreignCountry !== undefined,\n  role: PersonRole.PRIMARY,\n  dateOfBirth: new Date(person.dateOfBirth)\n})\n\nexport default function PrimaryTaxpayer(): ReactElement {\n  // const variable dispatch to allow use inside function\n  const dispatch = useDispatch()\n\n  const { onAdvance, navButtons } = usePager()\n\n  const taxPayer: TaxPayer | undefined = useSelector((state: TaxesState) => {\n    return state.information.taxPayer\n  })\n\n  const stateResidency: StateResidency[] = useSelector(\n    (state: TaxesState) => state.information.stateResidencies\n  )\n\n  const newTpForm: TaxPayerUserForm = {\n    ...defaultTaxpayerUserForm,\n    ...(taxPayer.primaryPerson !== undefined\n      ? {\n          ...asTaxPayerUserForm(taxPayer.primaryPerson),\n          contactPhoneNumber: taxPayer.contactPhoneNumber,\n          contactEmail: taxPayer.contactEmail,\n          stateResidency:\n            stateResidency[0]?.state ?? taxPayer.primaryPerson.address.state\n        }\n      : {})\n  }\n\n  const methods = useForm<TaxPayerUserForm>({\n    defaultValues: newTpForm\n  })\n\n  const {\n    handleSubmit,\n    getValues,\n    reset,\n    formState: { isDirty }\n  } = methods\n\n  // This form can be rerendered because the global state was modified by\n  // another control.\n  const currentValues = { ...defaultTaxpayerUserForm, ...getValues() }\n\n  useEffect(() => {\n    if (!isDirty && !_.isEqual(currentValues, newTpForm)) {\n      return reset(newTpForm)\n    }\n  })\n\n  const onSubmit = (form: TaxPayerUserForm): void => {\n    dispatch(savePrimaryPersonInfo(asPrimaryPerson(form)))\n    dispatch(saveContactInfo(asContactInfo(form)))\n    dispatch(saveStateResidencyInfo({ state: form.stateResidency as State }))\n    onAdvance()\n  }\n\n  const page = (\n    <form tabIndex={-1} onSubmit={intentionallyFloat(handleSubmit(onSubmit))}>\n      <Helmet>\n        <title>Primary Taxpayer Information | Personal | UsTaxes.org</title>\n      </Helmet>\n      <h2>Primary Taxpayer Information</h2>\n      <Grid container spacing={2}>\n        <PersonFields />\n        <LabeledInput\n          label=\"Contact phone number\"\n          patternConfig={Patterns.usPhoneNumber}\n          name=\"contactPhoneNumber\"\n        />\n        <LabeledInput\n          label=\"Contact email address\"\n          required={true}\n          name=\"contactEmail\"\n        />\n        <LabeledCheckbox\n          label=\"Check if you are a dependent\"\n          name=\"isTaxpayerDependent\"\n        />\n        <AddressFields checkboxText=\"Do you have a foreign address?\" />\n        <USStateDropDown label=\"Residency State\" name=\"stateResidency\" />\n      </Grid>\n      {navButtons}\n    </form>\n  )\n  return <FormProvider {...methods}>{page}</FormProvider>\n}\n"
  },
  {
    "path": "src/components/TaxPayer/index.tsx",
    "content": "import TaxPayer from './TaxPayer'\nexport default TaxPayer\n"
  },
  {
    "path": "src/components/UserSettings.tsx",
    "content": "import { Check } from '@material-ui/icons'\nimport { ReactElement, useState } from 'react'\nimport { useDispatch } from 'react-redux'\nimport { fsRecover } from 'ustaxes/redux/fs/Actions'\nimport { LoadRaw } from 'ustaxes/redux/fs/Load'\nimport SaveToFile from './SaveToFile'\n\nconst UserSettings = (): ReactElement => {\n  const dispatch = useDispatch()\n  const [done, setDone] = useState(false)\n\n  return (\n    <>\n      <h2>User Settings</h2>\n      <h3>Save data</h3>\n      <p>Save your data for backup or to import into desktop application</p>\n      <SaveToFile variant=\"contained\" color=\"primary\">\n        Save data to file\n      </SaveToFile>\n      <h3>Load data</h3>\n      <p>\n        Load your saved data from a file. Warning, this will overwrite present\n        state.\n      </p>\n      <LoadRaw\n        startIcon={done ? <Check /> : undefined}\n        accept=\"*.json\"\n        handleData={(state) => {\n          if (!done) {\n            dispatch(fsRecover(state))\n            setDone(true)\n          }\n        }}\n        variant=\"contained\"\n        color=\"primary\"\n      >\n        Load\n      </LoadRaw>\n    </>\n  )\n}\n\nexport default UserSettings\n"
  },
  {
    "path": "src/components/Y2021/AdvanceChildTaxCredit.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Grid } from '@material-ui/core'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { Credit, CreditType, Person, PersonRole } from 'ustaxes/core/data'\nimport { useDispatch, useSelector } from 'ustaxes/redux'\nimport { addCredit, editCredit } from 'ustaxes/redux/actions'\nimport { FormListContainer } from '../FormContainer'\nimport { Currency, GenericLabeledDropdown, LabeledInput } from '../input'\nimport { usePager } from '../pager'\nimport { Patterns } from '../Patterns'\n\ninterface CreditUserInput {\n  recipient: PersonRole\n  amount: string\n}\n\nconst blankCreditUserInput: Partial<CreditUserInput> = {\n  amount: ''\n}\n\nconst toCredit = (u: CreditUserInput): Credit => {\n  const amount = parseFloat(u.amount)\n  return {\n    type: CreditType.AdvanceChildTaxCredit,\n    amount,\n    recipient: u.recipient\n  }\n}\n\nconst toCreditUserInput = (c: Credit): CreditUserInput => {\n  return {\n    ...blankCreditUserInput,\n    ...c,\n    amount: c.amount.toFixed(2)\n  }\n}\n\nexport const AdvanceChildTaxCredit = (): ReactElement => {\n  const defaultValues = blankCreditUserInput\n  const credits = useSelector(({ information }) => information.credits)\n  const taxPayer = useSelector(({ information }) => information.taxPayer)\n  const spouse = taxPayer.spouse\n\n  const blank = { firstName: '', lastName: '' }\n  const { firstName: primaryFirst, lastName: primaryLast } =\n    taxPayer.primaryPerson ?? blank\n  const { firstName: spouseFirst, lastName: spouseLast } =\n    taxPayer.spouse ?? blank\n\n  const primaryName = `${primaryFirst} ${primaryLast}`\n  const spouseName = `${spouseFirst} ${spouseLast}`\n\n  const { navButtons, onAdvance } = usePager()\n\n  const advanceChildTaxCredits = credits\n    .map<[number, Credit]>((c, i) => [i, c])\n    .filter(([, c]) => c.type === CreditType.AdvanceChildTaxCredit)\n\n  const dispatch = useDispatch()\n\n  const methods = useForm<CreditUserInput>({\n    defaultValues\n  })\n\n  const onSubmitAdd = (formData: CreditUserInput): void => {\n    dispatch(addCredit(toCredit(formData)))\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: CreditUserInput): void => {\n      dispatch(editCredit({ index, value: toCredit(formData) }))\n    }\n\n  // People for recipient selector\n  const people: Person[] = [taxPayer.primaryPerson, spouse].flatMap((p) =>\n    p !== undefined ? [p as Person] : []\n  )\n\n  return (\n    <FormProvider {...methods}>\n      <h2>Advance Child Tax Credit Payments</h2>\n      <p>\n        Enter the advance Child Tax Credit payments you received, if any,\n        indicated on Letter 6419.\n      </p>\n      <FormListContainer<CreditUserInput>\n        defaultValues={defaultValues}\n        primary={(c) =>\n          c.recipient === PersonRole.PRIMARY ? primaryName : spouseName\n        }\n        secondary={(c) => <Currency value={parseFloat(c.amount)} />}\n        items={advanceChildTaxCredits.map(([, c]) => toCreditUserInput(c))}\n        onSubmitAdd={onSubmitAdd}\n        onSubmitEdit={onSubmitEdit}\n      >\n        <Grid container direction=\"column\" spacing={2}>\n          <LabeledInput\n            label=\"Amount\"\n            name=\"amount\"\n            patternConfig={Patterns.currency}\n          />\n          <GenericLabeledDropdown\n            dropDownData={people}\n            label=\"Recipient\"\n            required={true}\n            valueMapping={(p: Person, i: number) =>\n              [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n            }\n            name=\"recipient\"\n            keyMapping={(p: Person, i: number) => i}\n            textMapping={(p) => `${p.firstName} ${p.lastName}`}\n          />\n        </Grid>\n      </FormListContainer>\n      <form onSubmit={onAdvance}>{navButtons}</form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/components/YearDropDown.tsx",
    "content": "import { Button, Grid } from '@material-ui/core'\nimport { ReactElement } from 'react'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { useSelector } from 'react-redux'\nimport { setActiveYear } from 'ustaxes/redux/actions'\nimport { YearsTaxesState, useDispatch } from 'ustaxes/redux'\nimport { enumKeys, intentionallyFloat } from 'ustaxes/core/util'\nimport { GenericLabeledDropdown } from './input'\nimport { TaxYear, TaxYears } from 'ustaxes/core/data'\n\ninterface YearForm {\n  year: TaxYear\n}\n\ninterface YearDropProps {\n  onDone?: () => void\n}\n\nconst YearDropDown = (props: YearDropProps): ReactElement => {\n  const {\n    onDone = () => {\n      // default do nothing\n    }\n  } = props\n  const year = useSelector((state: YearsTaxesState) => state.activeYear)\n  const methods = useForm<YearForm>({\n    defaultValues: { year }\n  })\n\n  const { handleSubmit, watch } = methods\n\n  const selected = watch('year')\n  const dirty = selected !== year\n\n  const dispatch = useDispatch()\n\n  const onSubmit = ({ year }: YearForm) => {\n    dispatch(setActiveYear(year))\n    onDone()\n  }\n\n  return (\n    <FormProvider {...methods}>\n      <Grid container spacing={1} alignItems=\"center\">\n        <GenericLabeledDropdown<TaxYear, YearForm>\n          dropDownData={enumKeys(TaxYears)}\n          name=\"year\"\n          label=\"Select Tax Year\"\n          valueMapping={(x) => x}\n          keyMapping={(x) => x}\n          textMapping={(x) => `${TaxYears[x]}`}\n          sizes={{ xs: 9 }}\n        />\n        <Grid item>\n          <Button\n            variant=\"contained\"\n            color={dirty ? 'primary' : 'secondary'}\n            onClick={intentionallyFloat(handleSubmit(onSubmit))}\n          >\n            Update\n          </Button>\n        </Grid>\n      </Grid>\n    </FormProvider>\n  )\n}\n\nexport default YearDropDown\n"
  },
  {
    "path": "src/components/YearStatusBar.tsx",
    "content": "import { Link } from '@material-ui/core'\nimport { ReactElement, useState } from 'react'\nimport { useSelector } from 'react-redux'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport { TaxYears } from 'ustaxes/core/data'\nimport YearDropDown from './YearDropDown'\n\nconst YearStatusBar = (): ReactElement => {\n  const year = useSelector((state: YearsTaxesState) => state.activeYear)\n  const [isOpen, setOpen] = useState(false)\n\n  const openButton = (\n    <Link\n      href=\"\"\n      data-testid=\"year-dropdown-button\"\n      onClick={(e) => {\n        e.preventDefault()\n        setOpen(true)\n      }}\n    >\n      {TaxYears[year]}\n    </Link>\n  )\n\n  return (\n    <div>\n      <h3>Editing Information for {isOpen ? TaxYears[year] : openButton}</h3>\n      {isOpen ? <YearDropDown onDone={() => setOpen(false)} /> : undefined}\n    </div>\n  )\n}\n\nexport default YearStatusBar\n"
  },
  {
    "path": "src/components/debug.tsx",
    "content": "import { ReactElement } from 'react'\nimport { IconButton, makeStyles } from '@material-ui/core'\nimport { Star } from '@material-ui/icons'\nimport fc from 'fast-check'\nimport { useDispatch, YearsTaxesState } from 'ustaxes/redux'\nimport { setInfo } from 'ustaxes/redux/actions'\nimport { Information, TaxYears } from 'ustaxes/core/data'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport * as prand from 'pure-rand'\nimport { useSelector } from 'react-redux'\n\nconst useStyles = makeStyles(() => ({\n  root: {\n    position: 'absolute',\n    top: '0px',\n    right: '30px'\n  },\n  button: {}\n}))\n\nexport const StateLoader = (): ReactElement => {\n  if (process.env.NODE_ENV === 'production') {\n    return <></>\n  }\n  const dispatch = useDispatch()\n  const year = useSelector((state: YearsTaxesState) => state.activeYear)\n\n  const classes = useStyles()\n\n  const gen = new fc.Random(prand.mersenne(new Date().getMilliseconds()))\n\n  const information = arbitraries.forYear(TaxYears[year]).information()\n\n  const generator = (): Information =>\n    information.noShrink().generate(gen).value\n\n  return (\n    <div className={classes.root}>\n      <IconButton\n        className={classes.button}\n        onClick={() => dispatch(setInfo(generator()))}\n      >\n        <Star />\n        Seed random state\n      </IconButton>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/components/deductions/F1098eInfo.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport SchoolIcon from '@material-ui/icons/School'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { add1098e, edit1098e, remove1098e } from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport { Currency, LabeledInput } from 'ustaxes/components/input'\nimport { F1098e } from 'ustaxes/core/data'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid } from '@material-ui/core'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\nconst showInterest = (a: F1098e): ReactElement => {\n  return <Currency value={a.interest} />\n}\n\ninterface F1098EUserInput {\n  lender: string\n  interest: string | number\n}\n\nconst blankUserInput: F1098EUserInput = {\n  lender: '',\n  interest: ''\n}\n\nconst toUserInput = (f: F1098e): F1098EUserInput => ({\n  ...blankUserInput,\n  lender: f.lender,\n  interest: f.interest\n})\n\nconst toF1098e = (f: F1098EUserInput): F1098e => {\n  return {\n    lender: f.lender,\n    interest: Number(f.interest)\n  }\n}\n\nexport default function F1098eInfo(): ReactElement {\n  const f1098es = useSelector((state: TaxesState) => state.information.f1098es)\n\n  const defaultValues: F1098EUserInput = blankUserInput\n\n  const { onAdvance, navButtons } = usePager()\n\n  const methods = useForm<F1098EUserInput>({ defaultValues })\n  const { handleSubmit } = methods\n\n  const dispatch = useDispatch()\n\n  const onAdd1098e = (formData: F1098EUserInput): void => {\n    dispatch(add1098e(toF1098e(formData)))\n  }\n\n  const onEdit1098e =\n    (index: number) =>\n    (formData: F1098EUserInput): void => {\n      dispatch(edit1098e({ value: toF1098e(formData), index }))\n    }\n\n  const form: ReactElement | undefined = (\n    <FormListContainer\n      defaultValues={defaultValues}\n      onSubmitAdd={onAdd1098e}\n      onSubmitEdit={onEdit1098e}\n      items={f1098es.map((a) => toUserInput(a))}\n      removeItem={(i) => dispatch(remove1098e(i))}\n      primary={(f) => f.lender}\n      secondary={(f) => showInterest(toF1098e(f))}\n      icon={() => <SchoolIcon />}\n    >\n      <p>Input data from 1098-E</p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          autofocus={true}\n          label=\"Enter name of Lender\"\n          required={true}\n          name=\"lender\"\n        />\n        <LabeledInput\n          label=\"Student Interest Paid\"\n          patternConfig={Patterns.currency}\n          name=\"interest\"\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>1098-E Information | Deductions | UsTaxes.org</title>\n        </Helmet>\n        <h2>1098-E Information</h2>\n        {form}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/components/deductions/ItemizedDeductions.tsx",
    "content": "import { ReactElement, ReactNode } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { setItemizedDeductions } from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport { LabeledInput, LabeledCheckbox } from 'ustaxes/components/input'\nimport { ItemizedDeductions } from 'ustaxes/core/data'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { Grid, Box } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface ItemizedDeductionUserInput {\n  medicalAndDental: string | number\n  stateAndLocalTaxes: string | number\n  isSalesTax: boolean\n  stateAndLocalRealEstateTaxes: string | number\n  stateAndLocalPropertyTaxes: string | number\n  interest8a: string | number\n  interest8b: string | number\n  interest8c: string | number\n  interest8d: string | number\n  investmentInterest: string | number\n  charityCashCheck: string | number\n  charityOther: string | number\n}\n\nconst blankUserInput: ItemizedDeductionUserInput = {\n  medicalAndDental: '',\n  stateAndLocalTaxes: '',\n  isSalesTax: false,\n  stateAndLocalRealEstateTaxes: '',\n  stateAndLocalPropertyTaxes: '',\n  interest8a: '',\n  interest8b: '',\n  interest8c: '',\n  interest8d: '',\n  investmentInterest: '',\n  charityCashCheck: '',\n  charityOther: ''\n}\n\nconst toUserInput = (f: ItemizedDeductions): ItemizedDeductionUserInput => ({\n  ...blankUserInput,\n  medicalAndDental: f.medicalAndDental,\n  stateAndLocalTaxes: f.stateAndLocalTaxes,\n  isSalesTax: f.isSalesTax,\n  stateAndLocalRealEstateTaxes: f.stateAndLocalRealEstateTaxes,\n  stateAndLocalPropertyTaxes: f.stateAndLocalPropertyTaxes,\n  interest8a: f.interest8a,\n  interest8b: f.interest8b,\n  interest8c: f.interest8c,\n  interest8d: f.interest8d,\n  investmentInterest: f.investmentInterest,\n  charityCashCheck: f.charityCashCheck,\n  charityOther: f.charityOther\n})\n\nconst toItemizedDeductions = (\n  f: ItemizedDeductionUserInput\n): ItemizedDeductions => {\n  return {\n    medicalAndDental: Number(f.medicalAndDental),\n    stateAndLocalTaxes: Number(f.stateAndLocalTaxes),\n    isSalesTax: f.isSalesTax,\n    stateAndLocalPropertyTaxes: Number(f.stateAndLocalPropertyTaxes),\n    stateAndLocalRealEstateTaxes: Number(f.stateAndLocalRealEstateTaxes),\n    interest8a: Number(f.interest8a),\n    interest8b: Number(f.interest8b),\n    interest8c: Number(f.interest8c),\n    interest8d: Number(f.interest8d),\n    investmentInterest: Number(f.investmentInterest),\n    charityCashCheck: Number(f.charityCashCheck),\n    charityOther: Number(f.charityOther)\n  }\n}\n\nexport const ItemizedDeductionsInfo = (): ReactElement => {\n  const itemizedDeductions: ItemizedDeductions | undefined = useSelector(\n    (state: TaxesState) => {\n      return state.information.itemizedDeductions\n    }\n  )\n\n  const defaultValues: ItemizedDeductionUserInput = {\n    ...blankUserInput,\n    ...(itemizedDeductions !== undefined ? toUserInput(itemizedDeductions) : {})\n  }\n\n  const { onAdvance, navButtons } = usePager()\n\n  const methods = useForm<ItemizedDeductionUserInput>({ defaultValues })\n  const { handleSubmit, watch } = methods\n\n  const dispatch = useDispatch()\n\n  const onSubmit = (form: ItemizedDeductionUserInput): void => {\n    dispatch(setItemizedDeductions(toItemizedDeductions(form)))\n    onAdvance()\n  }\n\n  const charityCashCheck: string | number = watch('charityCashCheck')\n\n  const charityWarning: ReactNode = (() => {\n    if (Number(charityCashCheck || 0) > 0) {\n      return (\n        <div>\n          <Box marginBottom={3}>\n            <Alert className=\"inner\" severity=\"warning\">\n              See Pub. 526 to figure the amount of your deduction if any of the\n              following applies.\n              <br />\n              1. Your cash contributions or contributions of ordinary income\n              property are more than 30% of the amount on Form 1040 or 1040-SR,\n              line 11.\n              <br />\n              2. Your gifts of capital gain property are more than 20% of the\n              amount on Form 1040 or 1040-SR, line 11.\n              <br />\n              3. You gave gifts of property that increased in value or gave\n              gifts of the use of property.\n            </Alert>\n          </Box>\n        </div>\n      )\n    }\n  })()\n\n  // Limit charity to $500\n  const currencyMax500Pattern = Object.assign({}, Patterns.currency)\n  currencyMax500Pattern.max = 500\n\n  const form: ReactElement | undefined = (\n    <div>\n      <p>Medical and Dental Expenses</p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          label=\"Medical and Dental Expenses\"\n          patternConfig={Patterns.currency}\n          name=\"medicalAndDental\"\n          required={false}\n        />\n      </Grid>\n      <p>Taxes You Paid</p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          label=\"State and Local Taxes\"\n          patternConfig={Patterns.currency}\n          name=\"stateAndLocalTaxes\"\n          required={false}\n        />\n        <LabeledCheckbox\n          label=\" If you elect to include general sales taxes instead of income taxes, check this box\"\n          name=\"isSalesTax\"\n        />\n        <LabeledInput\n          label=\"State and Local Real Estate Taxes\"\n          patternConfig={Patterns.currency}\n          name=\"stateAndLocalRealEstateTaxes\"\n          required={false}\n        />\n        <LabeledInput\n          label=\"State and Local Personal Property Taxes\"\n          patternConfig={Patterns.currency}\n          name=\"stateAndLocalPropertyTaxes\"\n          required={false}\n        />\n      </Grid>\n      <p>Interest You Paid</p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          label=\"Home mortgage interest and points reported to you on Form 1098\"\n          patternConfig={Patterns.currency}\n          name=\"interest8a\"\n          required={false}\n        />\n        <LabeledInput\n          label=\"Home mortgage interest not reported to you on Form 1098\"\n          patternConfig={Patterns.currency}\n          name=\"interest8b\"\n          required={false}\n        />\n        <LabeledInput\n          label=\"Points not reported to you on Form 1098\"\n          patternConfig={Patterns.currency}\n          name=\"interest8c\"\n          required={false}\n        />\n        <LabeledInput\n          label=\"Mortgage insurance premiums\"\n          patternConfig={Patterns.currency}\n          name=\"interest8d\"\n          required={false}\n        />\n        <LabeledInput\n          label=\"Investment interest\"\n          patternConfig={Patterns.currency}\n          name=\"investmentInterest\"\n          required={false}\n        />\n      </Grid>\n      <p>Gifts To Charity</p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          label=\"Gifts by Cash or Check\"\n          patternConfig={Patterns.currency}\n          name=\"charityCashCheck\"\n          required={false}\n        />\n        {charityWarning}\n        <LabeledInput\n          label=\"Other than Cash or Check (Limit $500)\"\n          patternConfig={currencyMax500Pattern}\n          name=\"charityOther\"\n          required={false}\n        />\n      </Grid>\n    </div>\n  )\n\n  return (\n    <form tabIndex={-1} onSubmit={intentionallyFloat(handleSubmit(onSubmit))}>\n      <p>\n        If you do not wish to itemize, you can skip this form. The itemized\n        deductions will only be used if they result in a higher deduction than\n        the standard deduction.\n      </p>\n      <FormProvider {...methods}>\n        <Helmet>\n          <title>\n            Itemized Deduction Information | Deductions | UsTaxes.org\n          </title>\n        </Helmet>\n        <h2>Itemized Deduction Information</h2>\n        {form}\n        {navButtons}\n      </FormProvider>\n    </form>\n  )\n}\n\nexport default ItemizedDeductionsInfo\n"
  },
  {
    "path": "src/components/income/F1099Info.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { Link } from 'react-router-dom'\nimport Alert from '@material-ui/lab/Alert'\nimport { useForm, FormProvider } from 'react-hook-form'\nimport { Icon, Grid } from '@material-ui/core'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { add1099, edit1099, remove1099 } from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  Person,\n  PersonRole,\n  Supported1099,\n  Income1099Type,\n  PlanType1099,\n  PlanType1099Texts\n} from 'ustaxes/core/data'\nimport {\n  Currency,\n  formatSSID,\n  GenericLabeledDropdown,\n  LabeledInput,\n  boxLabel\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\nconst showIncome = (a: Supported1099): ReactElement => {\n  switch (a.type) {\n    case Income1099Type.INT: {\n      return <Currency value={a.form.income} />\n    }\n    case Income1099Type.B: {\n      const ltg = a.form.longTermProceeds - a.form.longTermCostBasis\n      const stg = a.form.shortTermProceeds - a.form.shortTermCostBasis\n      return (\n        <span>\n          Long term: <Currency value={ltg} />\n          <br />\n          Short term: <Currency value={stg} />\n        </span>\n      )\n    }\n    case Income1099Type.DIV: {\n      return <Currency value={a.form.dividends} />\n    }\n    case Income1099Type.R: {\n      return (\n        <span>\n          Plan Type: {a.form.planType}\n          <br />\n          Gross Distribution: <Currency value={a.form.grossDistribution} />\n          <br />\n          Taxable Amount: <Currency value={a.form.taxableAmount} />\n          <br />\n          Federal Income Tax Withheld:{' '}\n          <Currency value={a.form.federalIncomeTaxWithheld} />\n        </span>\n      )\n    }\n    case Income1099Type.SSA: {\n      return (\n        <span>\n          {/* Benefits Paid: <Currency value={a.form.benefitsPaid} />\n          <br />\n          Benefits Repaid: <Currency value={a.form.benefitsRepaid} />\n          <br /> */}\n          Net Benefits: <Currency value={a.form.netBenefits} />\n          <br />\n          Federal Income Tax Withweld:{' '}\n          <Currency value={a.form.federalIncomeTaxWithheld} />\n        </span>\n      )\n    }\n  }\n}\n\ninterface F1099UserInput {\n  formType: Income1099Type | undefined\n  payer: string\n  // Int fields\n  interest: string | number\n  // B Fields\n  shortTermProceeds: string | number\n  shortTermCostBasis: string | number\n  longTermProceeds: string | number\n  longTermCostBasis: string | number\n  // Div fields\n  dividends: string | number\n  qualifiedDividends: string | number\n  totalCapitalGainsDistributions: string | number\n  personRole?: PersonRole.PRIMARY | PersonRole.SPOUSE\n  // R fields\n  grossDistribution: string | number\n  taxableAmount: string | number\n  federalIncomeTaxWithheld: string | number\n  RPlanType: PlanType1099\n  // SSA fields\n  // benefitsPaid: string | number\n  // benefitsRepaid: string | number\n  netBenefits: string | number\n}\n\nconst blankUserInput: F1099UserInput = {\n  formType: undefined,\n  payer: '',\n  interest: '',\n  // B Fields\n  shortTermProceeds: '',\n  shortTermCostBasis: '',\n  longTermProceeds: '',\n  longTermCostBasis: '',\n  // Div fields\n  dividends: '',\n  qualifiedDividends: '',\n  totalCapitalGainsDistributions: '',\n  // R fields\n  grossDistribution: '',\n  taxableAmount: '',\n  federalIncomeTaxWithheld: '',\n  RPlanType: PlanType1099.Pension,\n  // SSA fields\n  // benefitsPaid: '',\n  // benefitsRepaid: '',\n  netBenefits: ''\n}\n\nconst toUserInput = (f: Supported1099): F1099UserInput => ({\n  ...blankUserInput,\n  formType: f.type,\n  payer: f.payer,\n  personRole: f.personRole,\n\n  ...(() => {\n    switch (f.type) {\n      case Income1099Type.INT: {\n        return {\n          interest: f.form.income\n        }\n      }\n      case Income1099Type.B: {\n        return f.form\n      }\n      case Income1099Type.DIV: {\n        return f.form\n      }\n      case Income1099Type.R: {\n        return f.form\n      }\n      case Income1099Type.SSA: {\n        return f.form\n      }\n    }\n  })()\n})\n\nconst toF1099 = (input: F1099UserInput): Supported1099 | undefined => {\n  switch (input.formType) {\n    case Income1099Type.INT: {\n      return {\n        payer: input.payer,\n        personRole: input.personRole ?? PersonRole.PRIMARY,\n        type: input.formType,\n        form: {\n          income: Number(input.interest)\n        }\n      }\n    }\n    case Income1099Type.B: {\n      return {\n        payer: input.payer,\n        personRole: input.personRole ?? PersonRole.PRIMARY,\n        type: input.formType,\n        form: {\n          shortTermCostBasis: Number(input.shortTermCostBasis),\n          shortTermProceeds: Number(input.shortTermProceeds),\n          longTermCostBasis: Number(input.longTermCostBasis),\n          longTermProceeds: Number(input.longTermProceeds)\n        }\n      }\n    }\n    case Income1099Type.DIV: {\n      return {\n        payer: input.payer,\n        personRole: input.personRole ?? PersonRole.PRIMARY,\n        type: input.formType,\n        form: {\n          dividends: Number(input.dividends),\n          qualifiedDividends: Number(input.qualifiedDividends),\n          totalCapitalGainsDistributions: Number(\n            input.totalCapitalGainsDistributions\n          )\n        }\n      }\n    }\n    case Income1099Type.R: {\n      return {\n        payer: input.payer,\n        personRole: input.personRole ?? PersonRole.PRIMARY,\n        type: input.formType,\n        form: {\n          grossDistribution: Number(input.grossDistribution),\n          taxableAmount: Number(input.taxableAmount),\n          federalIncomeTaxWithheld: Number(input.federalIncomeTaxWithheld),\n          planType: PlanType1099.Pension\n        }\n      }\n    }\n    case Income1099Type.SSA: {\n      return {\n        payer: input.payer,\n        personRole: input.personRole ?? PersonRole.PRIMARY,\n        type: input.formType,\n        form: {\n          // benefitsPaid: Number(input.benefitsPaid),\n          // benefitsRepaid: Number(input.benefitsRepaid),\n          netBenefits: Number(input.netBenefits),\n          federalIncomeTaxWithheld: Number(input.federalIncomeTaxWithheld)\n        }\n      }\n    }\n  }\n}\n\nexport default function F1099Info(): ReactElement {\n  const f1099s = useSelector((state: TaxesState) => state.information.f1099s)\n\n  const defaultValues = blankUserInput\n\n  const methods = useForm<F1099UserInput>({ defaultValues })\n  const { handleSubmit, watch } = methods\n  const selectedType: Income1099Type | undefined = watch('formType')\n\n  const dispatch = useDispatch()\n\n  const { onAdvance, navButtons } = usePager()\n\n  const onSubmitAdd = (formData: F1099UserInput): void => {\n    const payload = toF1099(formData)\n    if (payload !== undefined) {\n      dispatch(add1099(payload))\n    }\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: F1099UserInput): void => {\n      const payload = toF1099(formData)\n      if (payload !== undefined) {\n        dispatch(edit1099({ value: payload, index }))\n      }\n    }\n\n  const people: Person[] = useSelector((state: TaxesState) => [\n    state.information.taxPayer.primaryPerson,\n    state.information.taxPayer.spouse\n  ])\n    .filter((p) => p !== undefined)\n    .map((p) => p as Person)\n\n  const intFields = (\n    <Grid container spacing={2}>\n      <LabeledInput\n        label={\n          <>\n            <strong>Box 1</strong> - Interest Income\n          </>\n        }\n        patternConfig={Patterns.currency}\n        name=\"interest\"\n      />\n    </Grid>\n  )\n\n  const bFields = (\n    <>\n      <h3>Long Term Covered Transactions</h3>\n      <Grid container spacing={2}>\n        <LabeledInput\n          label=\"Proceeds\"\n          patternConfig={Patterns.currency}\n          name=\"longTermProceeds\"\n          sizes={{ xs: 6 }}\n        />\n        <LabeledInput\n          label=\"Cost basis\"\n          patternConfig={Patterns.currency}\n          name=\"longTermCostBasis\"\n          sizes={{ xs: 6 }}\n        />\n      </Grid>\n      <h3>Short Term Covered Transactions</h3>\n      <Grid container spacing={2}>\n        <LabeledInput\n          label=\"Proceeds\"\n          patternConfig={Patterns.currency}\n          name=\"shortTermProceeds\"\n          sizes={{ xs: 6 }}\n        />\n        <LabeledInput\n          label=\"Cost basis\"\n          patternConfig={Patterns.currency}\n          name=\"shortTermCostBasis\"\n          sizes={{ xs: 6 }}\n        />\n      </Grid>\n    </>\n  )\n\n  const divFields = (\n    <Grid container spacing={2}>\n      <LabeledInput\n        label={boxLabel('1a', 'Total Dividends')}\n        patternConfig={Patterns.currency}\n        name=\"dividends\"\n      />\n      <LabeledInput\n        label={boxLabel('1b', 'Qualified Dividends')}\n        patternConfig={Patterns.currency}\n        name=\"qualifiedDividends\"\n      />\n      <LabeledInput\n        label={boxLabel('2a', 'Total capital gains distributions')}\n        patternConfig={Patterns.currency}\n        name=\"totalCapitalGainsDistributions\"\n      />\n    </Grid>\n  )\n\n  const rFields = (\n    <Grid container spacing={2}>\n      <Alert severity=\"warning\">\n        Use this form only for 1099-R forms related to your 401(k) or other\n        retirement plans. If you have 1099-R forms from IRA accounts please see\n        the <Link to=\"/savingsaccounts/ira\">IRA page</Link>\n      </Alert>\n      <LabeledInput\n        label={boxLabel('1', 'Gross Distribution')}\n        patternConfig={Patterns.currency}\n        name=\"grossDistribution\"\n      />\n      <LabeledInput\n        label={boxLabel('2a', 'Taxable Amount')}\n        patternConfig={Patterns.currency}\n        name=\"taxableAmount\"\n      />\n      <LabeledInput\n        label={boxLabel('4', 'Federal Income Tax Withheld')}\n        patternConfig={Patterns.currency}\n        name=\"federalIncomeTaxWithheld\"\n      />\n      <GenericLabeledDropdown<PlanType1099, F1099UserInput>\n        label=\"Type of 1099-R\"\n        dropDownData={Object.values(PlanType1099)}\n        valueMapping={(x) => x}\n        keyMapping={(_, i) => i}\n        textMapping={(status) => PlanType1099Texts[status]}\n        name=\"RPlanType\"\n      />\n    </Grid>\n  )\n\n  const ssaFields = (\n    <Grid container spacing={2}>\n      {/* <LabeledInput\n        label=\"Box 3 - Benefits Paid\"\n        patternConfig={Patterns.currency}\n        name=\"benefitsPaid\"\n      />\n      <LabeledInput\n        label=\"Box 4 - Benefits Repaid\"\n        patternConfig={Patterns.currency}\n        name=\"benefitsRepaid\"\n      /> */}\n      <LabeledInput\n        label={\n          <>\n            <strong>Box 5</strong> - Net Benefits\n          </>\n        }\n        patternConfig={Patterns.currency}\n        name=\"netBenefits\"\n      />\n      <LabeledInput\n        label={\n          <>\n            <strong>Box 6</strong> - Voluntary Federal Income Tax Withheld\n          </>\n        }\n        patternConfig={Patterns.currency}\n        name=\"federalIncomeTaxWithheld\"\n      />\n    </Grid>\n  )\n\n  const specificFields = {\n    [Income1099Type.INT]: intFields,\n    [Income1099Type.B]: bFields,\n    [Income1099Type.DIV]: divFields,\n    [Income1099Type.R]: rFields,\n    [Income1099Type.SSA]: ssaFields\n  }\n\n  const titles = {\n    [Income1099Type.INT]: '1099-INT',\n    [Income1099Type.B]: '1099-B',\n    [Income1099Type.DIV]: '1099-DIV',\n    [Income1099Type.R]: '1099-R',\n    [Income1099Type.SSA]: 'SSA-1099'\n  }\n\n  const form: ReactElement | undefined = (\n    <FormListContainer\n      defaultValues={defaultValues}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      items={f1099s.map((a) => toUserInput(a))}\n      removeItem={(i) => dispatch(remove1099(i))}\n      primary={(f) => f.payer}\n      secondary={(f) => {\n        const form = toF1099(f)\n        if (form !== undefined) {\n          return showIncome(form)\n        }\n        return ''\n      }}\n      icon={(f) => (\n        <Icon\n          style={{ lineHeight: 1 }}\n          title={f.formType !== undefined ? titles[f.formType] : undefined}\n        >\n          {f.formType}\n        </Icon>\n      )}\n    >\n      <p>Input data from 1099</p>\n      <Grid container spacing={2}>\n        <GenericLabeledDropdown\n          autofocus={true}\n          dropDownData={Object.values(Income1099Type)}\n          label=\"Form Type\"\n          valueMapping={(v: Income1099Type) => v}\n          name=\"formType\"\n          keyMapping={(_, i: number) => i}\n          textMapping={(name: string) => `1099-${name}`}\n        />\n\n        <LabeledInput\n          label=\"Enter name of bank, broker firm, or other payer\"\n          required={true}\n          name=\"payer\"\n        />\n      </Grid>\n      {selectedType !== undefined ? specificFields[selectedType] : undefined}\n      <Grid container spacing={2}>\n        <GenericLabeledDropdown\n          dropDownData={people}\n          label=\"Recipient\"\n          valueMapping={(p: Person, i: number) =>\n            [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n          }\n          name=\"personRole\"\n          keyMapping={(p: Person, i: number) => i}\n          textMapping={(p: Person) =>\n            `${p.firstName} ${p.lastName} (${formatSSID(p.ssid)})`\n          }\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>1099 Information | Income | UsTaxes.org</title>\n        </Helmet>\n        <h2>1099 Information</h2>\n        {form}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/components/income/OtherInvestments.tsx",
    "content": "import { ReactElement, useState } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useForm, FormProvider } from 'react-hook-form'\nimport { useDispatch, YearsTaxesState } from 'ustaxes/redux'\nimport { useSelector } from 'react-redux'\nimport { addAsset } from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport { Asset, AssetType, State, TaxYears } from 'ustaxes/core/data'\nimport {\n  GenericLabeledDropdown,\n  USStateDropDown,\n  LabeledInput\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { OpenableFormContainer } from 'ustaxes/components/FormContainer'\nimport { Grid } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\nimport { TransactionImporter } from './assets/TransactionImporter'\nimport FilteredAssetsTable from './assets/FilteredAssetsTable'\nimport { DatePicker } from '../input/DatePicker'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\nconst showAssetType = (p: AssetType) => {\n  switch (p) {\n    case 'Security':\n      return 'Security (Stock, bond, option, mutual fund, etc.)'\n    case 'Real Estate':\n      return 'Real Estate'\n  }\n}\n\ninterface AssetUserInput {\n  name: string\n  positionType: AssetType\n  openDate?: Date\n  closeDate?: Date\n  openPrice: string\n  closePrice?: string\n  openFee: string\n  closeFee: string\n  quantity: string\n  state?: State\n}\n\nconst blankAssetUserInput: AssetUserInput = {\n  name: '',\n  positionType: 'Security',\n  openPrice: '',\n  openFee: '',\n  closeFee: '',\n  quantity: ''\n}\n\nconst toAsset = (input: AssetUserInput): Asset<Date> | undefined => {\n  const {\n    name,\n    openDate,\n    closeDate,\n    openPrice,\n    closePrice,\n    quantity,\n    state,\n    openFee,\n    closeFee,\n    positionType\n  } = input\n  if (name === '' || openDate === undefined) {\n    return undefined\n  }\n  return {\n    positionType,\n    name,\n    openDate,\n    closeDate,\n    openFee: Number(openFee),\n    closeFee: Number(closeFee),\n    openPrice: Number(openPrice),\n    closePrice: Number(closePrice),\n    quantity: input.positionType === 'Real Estate' ? 1 : Number(quantity),\n    state\n  }\n}\n\nexport const OtherInvestments = (): ReactElement => {\n  const year = useSelector((state: YearsTaxesState) => state.activeYear)\n  const [isOpen, setOpen] = useState(false)\n  const defaultValues = blankAssetUserInput\n  const methods = useForm<AssetUserInput>({ defaultValues })\n  const { handleSubmit, watch } = methods\n  const positionType = watch('positionType')\n  const closeDate = watch('closeDate')\n  const dispatch = useDispatch()\n\n  const { onAdvance, navButtons } = usePager()\n\n  const onSubmitAdd = (formData: AssetUserInput): void => {\n    const payload = toAsset(formData)\n    if (payload !== undefined) {\n      dispatch(addAsset(payload))\n    }\n  }\n\n  const form: ReactElement | undefined = (\n    <OpenableFormContainer\n      defaultValues={defaultValues}\n      isOpen={isOpen}\n      onOpenStateChange={setOpen}\n      onSave={onSubmitAdd}\n    >\n      <Grid container spacing={2}>\n        <h3>Add Assets</h3>\n        <GenericLabeledDropdown<AssetType, AssetUserInput>\n          label=\"Asset Type\"\n          name=\"positionType\"\n          dropDownData={['Security', 'Real Estate']}\n          keyMapping={(x) => x}\n          textMapping={showAssetType}\n          valueMapping={(x) => x}\n        />\n        <LabeledInput\n          label={positionType === 'Real Estate' ? 'Address' : 'Name'}\n          name=\"name\"\n        />\n        <DatePicker\n          maxDate={new Date(2021, 12, 31)}\n          label=\"Date acquired\"\n          name=\"openDate\"\n        />\n        <DatePicker\n          maxDate={new Date(2021, 12, 31)}\n          label=\"Date sold or disposed of\"\n          name=\"closeDate\"\n        />\n        {(() => {\n          if (positionType === 'Real Estate') {\n            return (\n              <>\n                <LabeledInput\n                  label=\"Cost basis\"\n                  patternConfig={Patterns.currency}\n                  name=\"openPrice\"\n                />\n                <LabeledInput\n                  label=\"Proceeds (sales price)\"\n                  patternConfig={Patterns.currency}\n                  name=\"closePrice\"\n                />\n                <USStateDropDown label=\"Property state\" name=\"state\" />\n              </>\n            )\n          } else {\n            return (\n              <>\n                <LabeledInput\n                  label=\"Price per unit\"\n                  patternConfig={Patterns.currency}\n                  name=\"openPrice\"\n                />\n                <LabeledInput\n                  label=\"Quantity\"\n                  patternConfig={Patterns.number}\n                  name=\"quantity\"\n                />\n                <LabeledInput\n                  label=\"Fee / comissions at purchase\"\n                  patternConfig={Patterns.number}\n                  name=\"openFee\"\n                />\n                <LabeledInput\n                  label=\"Proceeds (sales price)\"\n                  patternConfig={Patterns.currency}\n                  name=\"closePrice\"\n                />\n                <LabeledInput\n                  label=\"Fee / comissions at sale\"\n                  patternConfig={Patterns.number}\n                  name=\"closeFee\"\n                />\n              </>\n            )\n          }\n        })()}\n        {(() => {\n          if (\n            closeDate !== undefined &&\n            closeDate.getFullYear() !== TaxYears[year]\n          ) {\n            return (\n              <Alert severity=\"warning\">\n                This asset will not be included in the current year&apos;s\n                return because you have not selected a date in the current year.\n              </Alert>\n            )\n          }\n        })()}\n      </Grid>\n    </OpenableFormContainer>\n  )\n\n  return (\n    <>\n      <Helmet>\n        <title>Other Investments | Income | UsTaxes.org</title>\n      </Helmet>\n      <h2>Other Investments</h2>\n      <FilteredAssetsTable />\n      <FormProvider {...methods}>\n        <form\n          tabIndex={-1}\n          onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n        >\n          {form}\n          {navButtons}\n        </form>\n      </FormProvider>\n      <TransactionImporter />\n    </>\n  )\n}\n\nexport default OtherInvestments\n"
  },
  {
    "path": "src/components/income/PartnershipIncome.tsx",
    "content": "import { ReactElement, ReactNode } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useForm, FormProvider } from 'react-hook-form'\nimport { TaxesState, useSelector, useDispatch } from 'ustaxes/redux'\nimport {\n  addScheduleK1Form1065,\n  editScheduleK1Form1065,\n  removeScheduleK1Form1065\n} from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  boxLabel,\n  LabeledInput,\n  GenericLabeledDropdown,\n  formatSSID,\n  LabeledCheckbox,\n  formatEIN\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid, Box } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\nimport { Business } from '@material-ui/icons'\nimport {\n  ScheduleK1Form1065,\n  FilingStatus,\n  Information,\n  Person,\n  PersonRole,\n  PrimaryPerson,\n  Spouse\n} from 'ustaxes/core/data'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface ScheduleK1Form1065UserInput {\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  partnershipName: string\n  partnershipEin: string\n  partnerOrSCorp: 'P' | 'S'\n  isForeign: boolean\n  isPassive: boolean\n  ordinaryBusinessIncome: string\n  interestIncome: string\n  guaranteedPaymentsForServices: string\n  guaranteedPaymentsForCapital: string\n  selfEmploymentEarningsA: string\n  selfEmploymentEarningsB: string\n  selfEmploymentEarningsC: string\n  distributionsCodeAAmount: string\n  section199AQBI: string\n}\n\nconst blankUserInput: ScheduleK1Form1065UserInput = {\n  personRole: PersonRole.PRIMARY,\n  partnershipName: '',\n  partnershipEin: '',\n  partnerOrSCorp: 'P',\n  isForeign: false,\n  isPassive: false,\n  ordinaryBusinessIncome: '',\n  interestIncome: '',\n  guaranteedPaymentsForServices: '',\n  guaranteedPaymentsForCapital: '',\n  selfEmploymentEarningsA: '',\n  selfEmploymentEarningsB: '',\n  selfEmploymentEarningsC: '',\n  distributionsCodeAAmount: '',\n  section199AQBI: ''\n}\n\nconst toUserInput = (k1: ScheduleK1Form1065): ScheduleK1Form1065UserInput => ({\n  ...blankUserInput,\n  personRole: k1.personRole,\n  partnershipName: k1.partnershipName.toString(),\n  partnershipEin: k1.partnershipEin.toString(),\n  partnerOrSCorp: k1.partnerOrSCorp,\n  isForeign: k1.isForeign,\n  isPassive: k1.isPassive,\n  ordinaryBusinessIncome: k1.ordinaryBusinessIncome.toString(),\n  interestIncome: k1.interestIncome.toString(),\n  guaranteedPaymentsForServices: k1.guaranteedPaymentsForServices.toString(),\n  guaranteedPaymentsForCapital: k1.guaranteedPaymentsForCapital.toString(),\n  selfEmploymentEarningsA: k1.selfEmploymentEarningsA.toString(),\n  selfEmploymentEarningsB: k1.selfEmploymentEarningsB.toString(),\n  selfEmploymentEarningsC: k1.selfEmploymentEarningsC.toString(),\n  distributionsCodeAAmount: k1.distributionsCodeAAmount.toString(),\n  section199AQBI: k1.section199AQBI.toString()\n})\n\nconst toScheduleK1Form1065 = (\n  input: ScheduleK1Form1065UserInput\n): ScheduleK1Form1065 | undefined => {\n  const {\n    personRole,\n    partnershipName,\n    partnershipEin,\n    partnerOrSCorp,\n    isForeign,\n    isPassive,\n    ordinaryBusinessIncome,\n    interestIncome,\n    guaranteedPaymentsForServices,\n    guaranteedPaymentsForCapital,\n    selfEmploymentEarningsA,\n    selfEmploymentEarningsB,\n    selfEmploymentEarningsC,\n    distributionsCodeAAmount,\n    section199AQBI\n  } = input\n  if (partnershipName === '') {\n    return undefined\n  }\n  return {\n    personRole: personRole,\n    partnershipName: partnershipName,\n    partnershipEin: partnershipEin,\n    partnerOrSCorp: partnerOrSCorp,\n    isForeign: isForeign,\n    isPassive: isPassive,\n    ordinaryBusinessIncome: Number(ordinaryBusinessIncome),\n    interestIncome: Number(interestIncome),\n    guaranteedPaymentsForServices: Number(guaranteedPaymentsForServices),\n    guaranteedPaymentsForCapital: Number(guaranteedPaymentsForCapital),\n    selfEmploymentEarningsA: Number(selfEmploymentEarningsA),\n    selfEmploymentEarningsB: Number(selfEmploymentEarningsB),\n    selfEmploymentEarningsC: Number(selfEmploymentEarningsC),\n    distributionsCodeAAmount: Number(distributionsCodeAAmount),\n    section199AQBI: Number(section199AQBI)\n  }\n}\n\nexport const PartnershipIncome = (): ReactElement => {\n  const information: Information = useSelector(\n    (state: TaxesState) => state.information\n  )\n  const ScheduleK1Form1065s = information.scheduleK1Form1065s\n  const spouseScheduleK1Form1065s = ScheduleK1Form1065s.filter(\n    (k1) => k1.personRole === PersonRole.SPOUSE\n  )\n\n  const spouse: Spouse | undefined = information.taxPayer.spouse\n\n  const primary: PrimaryPerson | undefined = information.taxPayer.primaryPerson\n\n  const filingStatus: FilingStatus | undefined =\n    information.taxPayer.filingStatus\n\n  // People for employee selector\n  const people: Person[] = [primary, spouse].flatMap((p) =>\n    p !== undefined ? [p as Person] : []\n  )\n\n  const defaultValues = blankUserInput\n\n  const methods = useForm<ScheduleK1Form1065UserInput>({ defaultValues })\n  const { handleSubmit } = methods\n  const dispatch = useDispatch()\n\n  const { onAdvance, navButtons } = usePager()\n\n  const onSubmitAdd = (formData: ScheduleK1Form1065UserInput): void => {\n    const payload = toScheduleK1Form1065(formData)\n    if (payload !== undefined) {\n      dispatch(addScheduleK1Form1065(payload))\n    }\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: ScheduleK1Form1065UserInput): void => {\n      const payload = toScheduleK1Form1065(formData)\n      if (payload !== undefined) {\n        dispatch(editScheduleK1Form1065({ value: payload, index }))\n      }\n    }\n\n  const form: ReactElement | undefined = (\n    <FormListContainer<ScheduleK1Form1065UserInput>\n      defaultValues={defaultValues}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      items={ScheduleK1Form1065s.map((a) => toUserInput(a))}\n      removeItem={(i) => dispatch(removeScheduleK1Form1065(i))}\n      icon={() => <Business />}\n      primary={(k1) => k1.partnershipName}\n      secondary={(k1) => {\n        const scheduleK1Form1065 = toScheduleK1Form1065(k1)\n        if (scheduleK1Form1065 === undefined) return ''\n        return <span>{formatEIN(scheduleK1Form1065.partnershipEin)}</span>\n      }}\n    >\n      {' '}\n      <Grid container spacing={2}>\n        <h3>Partnership Income from Schedule K1 (Form 1065)</h3>\n        <LabeledInput label=\"Partnership name\" name=\"partnershipName\" />\n        <LabeledInput\n          label=\"Partnership EIN\"\n          name=\"partnershipEin\"\n          patternConfig={Patterns.ein}\n        />\n        <GenericLabeledDropdown\n          dropDownData={['Partnership', 'S Corporation']}\n          label=\"Partnership or S Corporation\"\n          required={true}\n          valueMapping={(t) => t.substring(0, 1)}\n          name=\"partnerOrSCorp\"\n          keyMapping={(k: string, i: number) => i}\n          textMapping={(t) => t}\n        />\n        <LabeledCheckbox\n          label=\" If a foreign partner, check this box\"\n          name=\"isForeign\"\n        />\n        <LabeledCheckbox\n          label=\" If you are a passive partner, check this box\"\n          name=\"isPassive\"\n        />\n        <LabeledInput\n          label={boxLabel('1', 'Ordinary business income (loss)')}\n          patternConfig={Patterns.currency}\n          name=\"ordinaryBusinessIncome\"\n        />\n        <LabeledInput\n          label={boxLabel('4a', 'Guaranteed payments for services')}\n          patternConfig={Patterns.currency}\n          name=\"guaranteedPaymentsForServices\"\n        />\n        <LabeledInput\n          label={boxLabel('4b', 'Guaranteed payments for capital')}\n          patternConfig={Patterns.currency}\n          name=\"guaranteedPaymentsForCapital\"\n        />\n        <LabeledInput\n          label={boxLabel('5', 'Interest Income')}\n          patternConfig={Patterns.currency}\n          name=\"interestIncome\"\n        />\n        <LabeledInput\n          label={boxLabel('14', 'Self-employment earnings (loss) - Code A')}\n          patternConfig={Patterns.currency}\n          name=\"selfEmploymentEarningsA\"\n        />\n        <LabeledInput\n          label={boxLabel('14', 'Self-employment earnings (loss) - Code B')}\n          patternConfig={Patterns.currency}\n          name=\"selfEmploymentEarningsB\"\n        />\n        <LabeledInput\n          label={boxLabel('14', 'Self-employment earnings (loss) - Code C')}\n          patternConfig={Patterns.currency}\n          name=\"selfEmploymentEarningsC\"\n        />\n        <LabeledInput\n          label={boxLabel('19', 'Distributions - Code A')}\n          patternConfig={Patterns.currency}\n          name=\"distributionsCodeAAmount\"\n        />\n        <LabeledInput\n          label={boxLabel('20', 'Other information - Code Z')}\n          patternConfig={Patterns.currency}\n          name=\"section199AQBI\"\n        />\n        <GenericLabeledDropdown\n          dropDownData={people}\n          label=\"Employee\"\n          required={true}\n          valueMapping={(p: Person, i: number) =>\n            [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n          }\n          name=\"personRole\"\n          keyMapping={(p: Person, i: number) => i}\n          textMapping={(p) =>\n            `${p.firstName} ${p.lastName} (${formatSSID(p.ssid)})`\n          }\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  const spouseScheduleK1Form1065Message: ReactNode = (() => {\n    if (\n      spouse !== undefined &&\n      spouseScheduleK1Form1065s.length > 0 &&\n      filingStatus === FilingStatus.MFS\n    ) {\n      return (\n        <div>\n          <Box marginBottom={3}>\n            <Alert className=\"inner\" severity=\"warning\">\n              Filing status is set to Married Filing Separately.{' '}\n              <strong>{spouse.firstName}</strong>\n              &apos;s ScheduleK1Form1065s will not be added to the return.\n            </Alert>\n          </Box>\n        </div>\n      )\n    }\n  })()\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>Partnership Income | Income | UsTaxes.org</title>\n        </Helmet>\n        <h2>Partnership Income</h2>\n        <p>\n          If you received Schedule K-1 (Form 1065), enter the information here.\n        </p>\n        {form}\n        {spouseScheduleK1Form1065Message}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n\nexport default PartnershipIncome\n"
  },
  {
    "path": "src/components/income/RealEstate.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Message, useForm, useWatch, FormProvider } from 'react-hook-form'\nimport { useDispatch } from 'ustaxes/redux'\nimport { useYearSelector } from 'ustaxes/redux/yearDispatch'\nimport { useSelector } from 'react-redux'\nimport { Helmet } from 'react-helmet'\n\nimport {\n  addProperty,\n  editProperty,\n  removeProperty\n} from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  Property,\n  Address,\n  PropertyExpenseType,\n  PropertyExpenseTypeName,\n  PropertyType,\n  PropertyTypeName,\n  TaxYear,\n  TaxYears\n} from 'ustaxes/core/data'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport AddressFields from 'ustaxes/components/TaxPayer/Address'\nimport {\n  Currency,\n  GenericLabeledDropdown,\n  LabeledCheckbox,\n  LabeledInput\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { daysInYear, enumKeys, intentionallyFloat } from 'ustaxes/core/util'\nimport { HouseOutlined } from '@material-ui/icons'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid } from '@material-ui/core'\nimport _ from 'lodash'\n\ninterface PropertyAddForm {\n  address?: Address\n  rentReceived?: number\n  rentalDays?: number\n  personalUseDays?: number\n  qualifiedJointVenture: boolean\n  propertyType?: PropertyTypeName\n  otherPropertyType?: string\n  expenses: Partial<{ [K in PropertyExpenseTypeName]: number }>\n  otherExpenseType?: string\n}\n\nconst blankAddForm: PropertyAddForm = {\n  qualifiedJointVenture: false,\n  expenses: {}\n}\n\nconst displayExpense = (k: PropertyExpenseType): string => {\n  const lookup = {\n    [PropertyExpenseType.advertising]: 'Advertising',\n    [PropertyExpenseType.auto]: 'Auto and travel',\n    [PropertyExpenseType.cleaning]: 'Cleaning and maintenance',\n    [PropertyExpenseType.commissions]: 'Commissions',\n    [PropertyExpenseType.insurance]: 'Insurance',\n    [PropertyExpenseType.legal]: 'Legal and other professional fees',\n    [PropertyExpenseType.management]: 'Management fees',\n    [PropertyExpenseType.mortgage]: 'Mortgage interest paid to banks, etc',\n    [PropertyExpenseType.otherInterest]: 'Other interest',\n    [PropertyExpenseType.repairs]: 'Repairs',\n    [PropertyExpenseType.supplies]: 'Supplies',\n    [PropertyExpenseType.taxes]: 'Taxes',\n    [PropertyExpenseType.utilities]: 'Utilities',\n    [PropertyExpenseType.depreciation]: 'Depreciation expense or depletion',\n    [PropertyExpenseType.other]: 'Other'\n  }\n  return lookup[k]\n}\n\nconst displayPropertyType = (k: PropertyType): string => {\n  const lookup = {\n    [PropertyType.singleFamily]: 'Single family',\n    [PropertyType.multiFamily]: 'Multifamily',\n    [PropertyType.vacation]: 'Vacation',\n    [PropertyType.commercial]: 'Commercial',\n    [PropertyType.land]: 'Land',\n    [PropertyType.selfRental]: 'Self rental',\n    [PropertyType.other]: 'Other'\n  }\n  return lookup[k]\n}\n\nconst toProperty = (formData: PropertyAddForm): Property => {\n  const {\n    address,\n    rentReceived,\n    rentalDays,\n    qualifiedJointVenture,\n    propertyType,\n    otherPropertyType,\n    personalUseDays,\n    expenses,\n    otherExpenseType\n  } = formData\n\n  if (address === undefined || propertyType === undefined) {\n    throw new Error('Validation failed')\n  }\n\n  const newExpenses: Partial<{ [K in PropertyExpenseTypeName]: number }> =\n    Object.fromEntries(\n      enumKeys(PropertyExpenseType)\n        .filter((e) => e in expenses && (expenses[e] as number) > 0)\n        .map((e) => [e, Number(expenses[e])])\n    )\n\n  return {\n    address,\n    rentalDays: Number(rentalDays),\n    qualifiedJointVenture,\n    rentReceived: Number(rentReceived),\n    personalUseDays: Number(personalUseDays),\n    propertyType,\n    otherPropertyType,\n    expenses: newExpenses,\n    otherExpenseType\n  }\n}\n\nconst toUserInput = (property: Property): PropertyAddForm => {\n  return {\n    ...blankAddForm,\n    address: property.address,\n    rentReceived: property.rentReceived,\n    rentalDays: property.rentalDays,\n    personalUseDays: property.personalUseDays,\n    qualifiedJointVenture: property.qualifiedJointVenture,\n    propertyType: property.propertyType,\n    otherPropertyType: property.otherPropertyType,\n    expenses: property.expenses,\n    otherExpenseType: property.otherExpenseType\n  }\n}\n\nexport default function RealEstate(): ReactElement {\n  const defaultValues = blankAddForm\n  const methods = useForm<PropertyAddForm>({ defaultValues })\n  const { handleSubmit, control, getValues } = methods\n\n  const dispatch = useDispatch()\n\n  const { onAdvance, navButtons } = usePager()\n\n  const activeYear: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  const properties: Property[] = useYearSelector(\n    (state) => state.information.realEstate\n  )\n\n  const propertyType = useWatch({\n    control,\n    name: 'propertyType'\n  })\n\n  const otherExpensesEntered: number | undefined = useWatch({\n    control,\n    name: 'expenses.other'\n  })\n\n  const validateDays = (n: number, other: number): Message | true => {\n    const days = daysInYear(TaxYears[activeYear])\n    return n + other <= days ? true : `Total use days must be less than ${days}`\n  }\n\n  const validatePersonal = (n: number): Message | true =>\n    validateDays(n, Number(getValues().rentalDays ?? 0))\n\n  const validateRental = (n: number): Message | true =>\n    validateDays(n, Number(getValues().personalUseDays ?? 0))\n\n  const deleteProperty = (n: number): void => {\n    dispatch(removeProperty(n))\n  }\n\n  const onAddProperty = (formData: PropertyAddForm): void => {\n    dispatch(addProperty(toProperty(formData)))\n  }\n\n  const onEditProperty =\n    (index: number) =>\n    (formData: PropertyAddForm): void => {\n      dispatch(editProperty({ value: toProperty(formData), index }))\n    }\n\n  const expenseFields: ReactElement[] = enumKeys(PropertyExpenseType).map(\n    (k, i) => (\n      <LabeledInput\n        key={i}\n        label={displayExpense(PropertyExpenseType[k])}\n        name={`expenses.${k.toString()}`}\n        patternConfig={Patterns.currency}\n        required={false}\n      />\n    )\n  )\n\n  const otherExpenseDescription = (() => {\n    if ((otherExpensesEntered ?? 0) !== 0) {\n      return (\n        <LabeledInput\n          key={enumKeys(PropertyExpenseType).length}\n          label=\"Other description\"\n          name=\"otherExpenseType\"\n          required={true}\n        />\n      )\n    }\n  })()\n\n  const form = (\n    <FormListContainer\n      defaultValues={defaultValues}\n      items={properties.map((a) => toUserInput(a))}\n      icon={() => <HouseOutlined />}\n      primary={(p) => toProperty(p).address.address}\n      secondary={(p) => <Currency value={toProperty(p).rentReceived} />}\n      onSubmitAdd={onAddProperty}\n      onSubmitEdit={onEditProperty}\n      removeItem={(i) => deleteProperty(i)}\n    >\n      <h3>Property Location</h3>\n      <Grid container spacing={2}>\n        <AddressFields\n          autofocus={true}\n          checkboxText=\"Does the property have a foreign address\"\n          allowForeignCountry={false}\n        />\n        <GenericLabeledDropdown\n          dropDownData={enumKeys(PropertyType)}\n          label=\"Property type\"\n          textMapping={(t) => displayPropertyType(PropertyType[t])}\n          keyMapping={(_, n) => n}\n          name=\"propertyType\"\n          valueMapping={(n) => n}\n        />\n        {(() => {\n          if (propertyType === 'other') {\n            return (\n              <LabeledInput\n                name=\"otherPropertyType\"\n                label=\"Short property type description\"\n                required={true}\n              />\n            )\n          }\n        })()}\n      </Grid>\n      <h3>Use</h3>\n      <Grid container spacing={2}>\n        <LabeledInput\n          name=\"rentalDays\"\n          rules={{ validate: (n: string) => validateRental(Number(n)) }}\n          label=\"Number of days in the year used for rental\"\n          patternConfig={Patterns.numDays(activeYear)}\n        />\n        <LabeledInput\n          name=\"personalUseDays\"\n          rules={{ validate: (n: string) => validatePersonal(Number(n)) }}\n          label=\"Number of days in the year for personal use\"\n          patternConfig={Patterns.numDays(activeYear)}\n        />\n        <LabeledCheckbox\n          name=\"qualifiedJointVenture\"\n          label=\"Is this a qualified joint venture\"\n        />\n      </Grid>\n      <h3>Property Financials</h3>\n      <h4>Income</h4>\n      <Grid container spacing={2}>\n        <LabeledInput\n          name=\"rentReceived\"\n          label=\"Rent received\"\n          patternConfig={Patterns.currency}\n        />\n      </Grid>\n      <h4>Expenses</h4>\n      <Grid container spacing={2}>\n        {_.chain([...expenseFields, otherExpenseDescription])\n          .chunk(2)\n          .map((segment, i) =>\n            segment.map((item, k) => (\n              <Grid item key={`${i}-${k}`} xs={12} sm={6}>\n                {item}\n              </Grid>\n            ))\n          )\n          .value()}\n      </Grid>\n    </FormListContainer>\n  )\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>Real Estate | Income | UsTaxes.org</title>\n        </Helmet>\n        <h2>Properties</h2>\n        {form}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/components/income/StockOptions.tsx",
    "content": "import { ReactElement, ReactNode } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useForm, FormProvider } from 'react-hook-form'\nimport { TaxesState, useSelector, useDispatch } from 'ustaxes/redux'\nimport { addF3921, editF3921, removeF3921 } from 'ustaxes/redux/actions'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  LabeledInput,\n  GenericLabeledDropdown,\n  formatSSID\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Currency } from 'ustaxes/components/input'\nimport { Grid, Box } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\nimport { ShowChartOutlined as StockIcon } from '@material-ui/icons'\nimport {\n  F3921,\n  FilingStatus,\n  Information,\n  Person,\n  PersonRole,\n  PrimaryPerson,\n  Spouse\n} from 'ustaxes/core/data'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface F3921UserInput {\n  name: string\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  exercisePricePerShare?: string\n  fmv?: string\n  numShares?: string\n}\n\nconst blankUserInput: F3921UserInput = {\n  name: '',\n  personRole: PersonRole.PRIMARY,\n  exercisePricePerShare: '',\n  fmv: '',\n  numShares: ''\n}\n\nconst toUserInput = (f: F3921): F3921UserInput => ({\n  ...blankUserInput,\n  name: f.name,\n  personRole: f.personRole,\n  exercisePricePerShare: f.exercisePricePerShare.toString(),\n  fmv: f.fmv.toString(),\n  numShares: f.numShares.toString()\n})\n\nconst toF3921 = (input: F3921UserInput): F3921 | undefined => {\n  const { name, personRole, exercisePricePerShare, fmv, numShares } = input\n  if (name === '') {\n    return undefined\n  }\n  return {\n    name,\n    personRole: personRole,\n    exercisePricePerShare: Number(exercisePricePerShare),\n    fmv: Number(fmv),\n    numShares: Number(numShares)\n  }\n}\n\nexport const StockOptions = (): ReactElement => {\n  const defaultValues = blankUserInput\n  const information: Information = useSelector(\n    (state: TaxesState) => state.information\n  )\n  const f3921s = information.f3921s\n  const spouseF3921s = f3921s.filter(\n    (f3921) => f3921.personRole === PersonRole.SPOUSE\n  )\n\n  const spouse: Spouse | undefined = information.taxPayer.spouse\n\n  const primary: PrimaryPerson | undefined = information.taxPayer.primaryPerson\n\n  const filingStatus: FilingStatus | undefined =\n    information.taxPayer.filingStatus\n\n  // People for employee selector\n  const people: Person[] = [primary, spouse].flatMap((p) =>\n    p !== undefined ? [p as Person] : []\n  )\n\n  const methods = useForm<F3921UserInput>({ defaultValues })\n  const { handleSubmit } = methods\n  const dispatch = useDispatch()\n\n  const { onAdvance, navButtons } = usePager()\n\n  const onSubmitAdd = (formData: F3921UserInput): void => {\n    const payload = toF3921(formData)\n    if (payload !== undefined) {\n      dispatch(addF3921(payload))\n    }\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: F3921UserInput): void => {\n      const payload = toF3921(formData)\n      if (payload !== undefined) {\n        dispatch(editF3921({ value: payload, index }))\n      }\n    }\n\n  const form: ReactElement | undefined = (\n    <FormListContainer<F3921UserInput>\n      defaultValues={defaultValues}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      items={f3921s.map((a) => toUserInput(a))}\n      removeItem={(i) => dispatch(removeF3921(i))}\n      icon={() => <StockIcon />}\n      primary={(f) => f.name}\n      secondary={(f) => {\n        const f3921 = toF3921(f)\n        if (f3921 === undefined) return ''\n        return (\n          <span>\n            {f3921.numShares} shares @{' '}\n            <Currency plain={true} value={f3921.exercisePricePerShare} />;{' '}\n            <Currency plain={true} value={f3921.fmv} /> FMV\n          </span>\n        )\n      }}\n    >\n      {' '}\n      <Grid container spacing={2}>\n        <h3>Manage Stock Options</h3>\n        <LabeledInput label=\"Company name\" name=\"name\" />\n        <LabeledInput\n          label=\"Exercise price per share\"\n          patternConfig={Patterns.currency}\n          name=\"exercisePricePerShare\"\n        />\n        <LabeledInput\n          label=\"Fair Market Value (FMV)\"\n          patternConfig={Patterns.currency}\n          name=\"fmv\"\n        />\n        <LabeledInput\n          label=\"Number of shares transferred\"\n          patternConfig={Patterns.number}\n          name=\"numShares\"\n        />\n        <GenericLabeledDropdown\n          dropDownData={people}\n          label=\"Employee\"\n          required={true}\n          valueMapping={(p: Person, i: number) =>\n            [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n          }\n          name=\"personRole\"\n          keyMapping={(p: Person, i: number) => i}\n          textMapping={(p) =>\n            `${p.firstName} ${p.lastName} (${formatSSID(p.ssid)})`\n          }\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  const spouseF3921Message: ReactNode = (() => {\n    if (\n      spouse !== undefined &&\n      spouseF3921s.length > 0 &&\n      filingStatus === FilingStatus.MFS\n    ) {\n      return (\n        <div>\n          <Box marginBottom={3}>\n            <Alert className=\"inner\" severity=\"warning\">\n              Filing status is set to Married Filing Separately.{' '}\n              <strong>{spouse.firstName}</strong>\n              &apos;s F3921s will not be added to the return.\n            </Alert>\n          </Box>\n        </div>\n      )\n    }\n  })()\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>Stock Options | Income | UsTaxes.org</title>\n        </Helmet>\n        <h2>Stock Options</h2>\n        <p>If you received Form 3921, enter the information here.</p>\n        {form}\n        {spouseF3921Message}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n\nexport default StockOptions\n"
  },
  {
    "path": "src/components/income/W2JobInfo.tsx",
    "content": "import { Fragment, ReactElement, ReactNode, useState } from 'react'\nimport _ from 'lodash'\nimport { useDispatch, useSelector, TaxesState } from 'ustaxes/redux'\nimport { Helmet } from 'react-helmet'\nimport { FormProvider, useForm, useFormContext } from 'react-hook-form'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  IncomeW2,\n  Person,\n  PersonRole,\n  Employer,\n  Spouse,\n  PrimaryPerson,\n  FilingStatus,\n  Information,\n  State,\n  W2Box12Info,\n  W2Box12Code,\n  W2Box12CodeDescriptions\n} from 'ustaxes/core/data'\nimport {\n  boxLabel,\n  Currency,\n  formatSSID,\n  GenericLabeledDropdown,\n  LabeledInput,\n  USStateDropDown\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid, Box, Button, Paper } from '@material-ui/core'\nimport { Work } from '@material-ui/icons'\nimport { addW2, editW2, removeW2 } from 'ustaxes/redux/actions'\nimport { Alert } from '@material-ui/lab'\nimport {\n  enumKeys,\n  parseFormNumber,\n  parseFormNumberOrThrow\n} from 'ustaxes/core/util'\n\ninterface IncomeW2UserInput {\n  employer?: Employer\n  occupation: string\n  income: string\n  medicareIncome: string\n  fedWithholding: string\n  ssWages: string\n  ssWithholding: string\n  medicareWithholding: string\n  personRole?: PersonRole.PRIMARY | PersonRole.SPOUSE\n  state?: State\n  stateWages: string\n  stateWithholding: string\n  box12: W2Box12Info<string>\n}\n\nconst blankW2UserInput: IncomeW2UserInput = {\n  employer: {\n    EIN: ''\n  },\n  occupation: '',\n  income: '',\n  medicareIncome: '',\n  fedWithholding: '',\n  ssWages: '',\n  ssWithholding: '',\n  medicareWithholding: '',\n  stateWages: '',\n  stateWithholding: '',\n  box12: {}\n}\n\nconst toIncomeW2 = (formData: IncomeW2UserInput): IncomeW2 => ({\n  ...formData,\n  // Note we are not error checking here because\n  // we are already in the input validated happy path\n  // of handleSubmit.\n  income: parseFormNumberOrThrow(formData.income),\n  medicareIncome: parseFormNumberOrThrow(formData.medicareIncome),\n  fedWithholding: parseFormNumberOrThrow(formData.fedWithholding),\n  ssWages: parseFormNumberOrThrow(formData.ssWages),\n  ssWithholding: parseFormNumberOrThrow(formData.ssWithholding),\n  medicareWithholding: parseFormNumberOrThrow(formData.medicareWithholding),\n  state: formData.state,\n  stateWages: parseFormNumberOrThrow(formData.stateWages),\n  stateWithholding: parseFormNumberOrThrow(formData.stateWithholding),\n  personRole: formData.personRole ?? PersonRole.PRIMARY,\n  box12: _.mapValues(formData.box12, (v) => parseFormNumber(v))\n})\n\nconst toIncomeW2UserInput = (data: IncomeW2): IncomeW2UserInput => ({\n  ...blankW2UserInput,\n  ...data,\n  income: data.income.toString(),\n  medicareIncome: data.medicareIncome.toString(),\n  fedWithholding: data.fedWithholding.toString(),\n  ssWages: data.ssWages.toString(),\n  ssWithholding: data.ssWithholding.toString(),\n  medicareWithholding: data.medicareWithholding.toString(),\n  state: data.state,\n  stateWages: data.stateWages?.toString() ?? '',\n  stateWithholding: data.stateWithholding?.toString() ?? '',\n  box12: _.mapValues(data.box12, (v) => v?.toString())\n})\n\nconst Box12Data = (): ReactElement => {\n  const [editBox12, setEditBox12] = useState(false)\n\n  const { getValues } = useFormContext<IncomeW2UserInput>()\n\n  const { box12 } = getValues()\n\n  const box12Fields = (\n    <>\n      {enumKeys(W2Box12Code).map((code) => (\n        <Fragment key={`box-12-${code}`}>\n          <p>\n            <strong>Code {code}</strong>: {W2Box12CodeDescriptions[code]}\n          </p>\n          <LabeledInput\n            label={code}\n            name={`box12.${code}`}\n            patternConfig={Patterns.currency}\n            required={false}\n          />\n        </Fragment>\n      ))}\n    </>\n  )\n\n  const openCloseButton = (\n    <Button\n      type=\"button\"\n      variant=\"contained\"\n      color={editBox12 ? 'secondary' : 'default'}\n      onClick={() => setEditBox12(!editBox12)}\n    >\n      {editBox12 ? 'Done' : 'Edit'}\n    </Button>\n  )\n\n  const box12Data = (\n    <ul>\n      {enumKeys(W2Box12Code)\n        .filter((code) => box12[code] !== undefined)\n        .map((code) => (\n          <li key={`box-12-data-${code}`}>\n            {code}: <Currency plain value={parseFormNumber(box12[code]) ?? 0} />{' '}\n            ({W2Box12CodeDescriptions[code]})\n          </li>\n        ))}\n    </ul>\n  )\n\n  return (\n    <Paper>\n      <Box padding={2} paddingTop={2}>\n        <h4>Box 12 Information</h4>\n        {editBox12 ? box12Fields : box12Data}\n        <Box paddingTop={1}>{openCloseButton}</Box>\n      </Box>\n    </Paper>\n  )\n}\n\nexport default function W2JobInfo(): ReactElement {\n  const dispatch = useDispatch()\n  const defaultValues = blankW2UserInput\n  const methods = useForm<IncomeW2UserInput>({\n    defaultValues\n  })\n\n  const { navButtons, onAdvance } = usePager()\n\n  const information: Information = useSelector(\n    (state: TaxesState) => state.information\n  )\n\n  const spouse: Spouse | undefined = information.taxPayer.spouse\n\n  const primary: PrimaryPerson | undefined = information.taxPayer.primaryPerson\n\n  const filingStatus: FilingStatus | undefined =\n    information.taxPayer.filingStatus\n\n  // People for employee selector\n  const people: Person[] = [primary, spouse].flatMap((p) =>\n    p !== undefined ? [p as Person] : []\n  )\n\n  const w2s: IncomeW2[] = information.w2s\n  const spouseW2s = w2s.filter((w2) => w2.personRole === PersonRole.SPOUSE)\n\n  const onSubmitAdd = (formData: IncomeW2UserInput): void => {\n    dispatch(addW2(toIncomeW2(formData)))\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: IncomeW2UserInput): void => {\n      dispatch(editW2({ index, value: toIncomeW2(formData) }))\n    }\n\n  const w2sBlock = (\n    <FormListContainer<IncomeW2UserInput>\n      defaultValues={defaultValues}\n      items={w2s.map((a) => toIncomeW2UserInput(a))}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      removeItem={(i) => dispatch(removeW2(i))}\n      icon={() => <Work />}\n      primary={(w2: IncomeW2UserInput) =>\n        w2.employer?.employerName ?? w2.occupation\n      }\n      secondary={(w2: IncomeW2UserInput) => (\n        <span>\n          Income: <Currency value={toIncomeW2(w2).income} />\n        </span>\n      )}\n      grouping={(w2) => (w2.personRole === PersonRole.PRIMARY ? 0 : 1)}\n      groupHeaders={[primary?.firstName, spouse?.firstName].map((x) =>\n        x !== undefined ? <h2>{x}&apos; W2s</h2> : undefined\n      )}\n    >\n      <p>Input data from W-2</p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          autofocus={true}\n          label=\"Employer name\"\n          required={true}\n          name=\"employer.employerName\"\n          sizes={{ xs: 12 }}\n        />\n        <LabeledInput\n          label={boxLabel('b', \"Employer's Identification Number\")}\n          patternConfig={Patterns.ein}\n          name=\"employer.EIN\"\n          sizes={{ xs: 12 }}\n        />\n        <LabeledInput\n          label=\"Occupation\"\n          patternConfig={Patterns.name}\n          name=\"occupation\"\n          sizes={{ xs: 12 }}\n        />\n        <LabeledInput\n          name=\"income\"\n          label={boxLabel('1', ' Wages, tips, other compensation')}\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"fedWithholding\"\n          label={boxLabel('2', 'Federal income tax withheld')}\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"ssWages\"\n          label={boxLabel('3', 'Social security wages')}\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"ssWithholding\"\n          label={boxLabel('4', 'Social security tax withheld')}\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"medicareIncome\"\n          label={boxLabel('5', 'Medicare Income')}\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"medicareWithholding\"\n          label={boxLabel('6', 'Medicare tax withheld')}\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <USStateDropDown name=\"state\" label={boxLabel('15', 'State')} />\n        <Grid item xs={12} lg={12}>\n          <Box12Data />\n        </Grid>\n        <LabeledInput\n          name=\"stateWages\"\n          label={boxLabel('16', 'State wages, tips, etc')}\n          patternConfig={Patterns.currency}\n          required={true}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"stateWithholding\"\n          label={boxLabel('17', 'State income tax')}\n          patternConfig={Patterns.currency}\n          required={true}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <GenericLabeledDropdown\n          dropDownData={people}\n          label=\"Employee\"\n          required={true}\n          valueMapping={(p: Person, i: number) =>\n            [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n          }\n          name=\"personRole\"\n          keyMapping={(p: Person, i: number) => i}\n          textMapping={(p) =>\n            `${p.firstName} ${p.lastName} (${formatSSID(p.ssid)})`\n          }\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  const spouseW2Message: ReactNode = (() => {\n    if (\n      spouse !== undefined &&\n      spouseW2s.length > 0 &&\n      filingStatus === FilingStatus.MFS\n    ) {\n      return (\n        <div>\n          <Box marginBottom={3}>\n            <Alert className=\"inner\" severity=\"warning\">\n              Filing status is set to Married Filing Separately.{' '}\n              <strong>{spouse.firstName}</strong>\n              &apos;s W2s will not be added to the return.\n            </Alert>\n          </Box>\n        </div>\n      )\n    }\n  })()\n\n  const form: ReactElement = (\n    <>\n      {w2sBlock}\n      {spouseW2Message}\n    </>\n  )\n\n  return (\n    <FormProvider {...methods}>\n      <form tabIndex={-1} onSubmit={onAdvance}>\n        <Helmet>\n          <title>Job Information | Income | UsTaxes.org</title>\n        </Helmet>\n        <h2>Job Information</h2>\n        {form}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/components/income/assets/AssetSummary.tsx",
    "content": "import { useMediaQuery } from '@material-ui/core'\nimport { ReactElement } from 'react'\nimport DataTable, { TableColumn } from 'react-data-table-component'\nimport { Currency } from 'ustaxes/components/input'\nimport { Asset } from 'ustaxes/core/data'\nimport { numberOfDaysBetween } from 'ustaxes/core/util'\n\ninterface AssetSummaryProps {\n  title: string\n  assets: Asset<Date>[]\n}\n\ntype Row = {\n  name: string\n  shortTerm: number\n  longTerm: number\n}\n\nconst AssetSummary = ({ title, assets }: AssetSummaryProps): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  const totals = assets.reduce(\n    (acc, a) => {\n      const isLongTerm =\n        numberOfDaysBetween(\n          a.openDate,\n          a.closeDate !== undefined ? a.closeDate : new Date()\n        ) > 365\n\n      return {\n        ...acc,\n        longTermCostBasis:\n          isLongTerm && a.closePrice !== undefined\n            ? acc.longTermCostBasis + a.openPrice * a.quantity + a.openFee\n            : acc.longTermCostBasis,\n        shortTermCostBasis:\n          !isLongTerm && a.closePrice !== undefined\n            ? acc.shortTermCostBasis + a.openPrice * a.quantity + a.openFee\n            : acc.shortTermCostBasis,\n        longTermProceeds:\n          isLongTerm && a.closePrice !== undefined\n            ? acc.longTermProceeds +\n              a.closePrice * a.quantity -\n              (a.closeFee ?? 0)\n            : acc.longTermProceeds,\n        shortTermProceeds:\n          !isLongTerm && a.closePrice !== undefined\n            ? acc.shortTermProceeds +\n              a.closePrice * a.quantity -\n              (a.closeFee ?? 0)\n            : acc.shortTermProceeds,\n        openCostBasis:\n          a.closeDate === undefined\n            ? acc.openCostBasis + a.openPrice * a.quantity + a.openFee\n            : acc.openCostBasis\n      }\n    },\n    {\n      longTermCostBasis: 0,\n      longTermProceeds: 0,\n      shortTermCostBasis: 0,\n      shortTermProceeds: 0,\n      openCostBasis: 0\n    }\n  )\n\n  const columns: TableColumn<Row>[] = [\n    {\n      name: '',\n      selector: ({ name }) => name\n    },\n    {\n      name: 'Short Term',\n      cell: ({ shortTerm }) => <Currency value={shortTerm} />\n    },\n    {\n      name: 'Long Term',\n      cell: ({ longTerm }) => <Currency value={longTerm} />\n    },\n    {\n      name: 'Total',\n      cell: ({ shortTerm, longTerm }) => (\n        <Currency value={shortTerm + longTerm} />\n      )\n    }\n  ]\n\n  const data: Array<{ name: string; shortTerm: number; longTerm: number }> = [\n    {\n      name: 'Cost Basis',\n      shortTerm: totals.shortTermCostBasis,\n      longTerm: totals.longTermCostBasis\n    },\n    {\n      name: 'Proceeds',\n      shortTerm: totals.shortTermProceeds,\n      longTerm: totals.longTermProceeds\n    },\n    {\n      name: 'Gain/Loss',\n      shortTerm: totals.shortTermProceeds - totals.shortTermCostBasis,\n      longTerm: totals.longTermProceeds - totals.longTermCostBasis\n    }\n  ]\n\n  const totalFees = assets.reduce(\n    (acc, a) => acc + a.openFee + (a.closeFee ?? 0),\n    0\n  )\n\n  return (\n    <>\n      <DataTable\n        title={title}\n        columns={columns}\n        data={data}\n        theme={prefersDarkMode ? 'dark' : 'normal'}\n      />\n      {(() => {\n        if (totalFees > 0) {\n          return (\n            <p>\n              Cost basis and proceeds include{' '}\n              <Currency plain value={totalFees} /> in fees.\n            </p>\n          )\n        }\n      })()}\n    </>\n  )\n}\n\nexport default AssetSummary\n"
  },
  {
    "path": "src/components/income/assets/ConfigurableDataTable.tsx",
    "content": "import { Grid, TextField, useMediaQuery } from '@material-ui/core'\nimport { Alert } from '@material-ui/lab'\nimport { ReactElement } from 'react'\nimport DataTable, {\n  ConditionalStyles,\n  TableColumn\n} from 'react-data-table-component'\nimport useStyles from '../../input/styles'\nimport { columnInputStyles, useRowStyles } from './DataTableStyle'\n\ninterface ColumnHeaderDropProps {\n  fields: string[]\n  value?: string\n  onChange: (field: string) => void\n  undefinedName?: string\n}\n\nconst ColumnHeaderDropDown = ({\n  fields,\n  value,\n  onChange,\n  undefinedName = ''\n}: ColumnHeaderDropProps) => {\n  const columnClasses = columnInputStyles()\n\n  return (\n    <TextField\n      className={columnClasses.column}\n      select\n      fullWidth\n      variant=\"filled\"\n      SelectProps={{\n        native: true,\n        value,\n        onChange: (e) => onChange(e.target.value as string)\n      }}\n      InputLabelProps={{\n        shrink: true\n      }}\n    >\n      <option value={undefined}>{undefinedName}</option>\n      {fields.map((field) => (\n        <option value={field} key={field}>\n          {field}\n        </option>\n      ))}\n    </TextField>\n  )\n}\n\nexport interface ColumnDef {\n  name: string\n  required?: boolean\n}\n\ninterface ConfigurableDataTableProps {\n  fields: ColumnDef[]\n  fieldAssignments: (string | undefined)[]\n  rows: string[][]\n  assignField: (colIndex: number, field: string | undefined) => void\n  dropFirstNRows?: number\n  updateDropFirstNRows: (dropFirstNRows: number) => void\n}\n\nexport const ConfigurableDataTable = ({\n  fieldAssignments,\n  fields,\n  assignField,\n  rows,\n  dropFirstNRows = 0,\n  updateDropFirstNRows\n}: ConfigurableDataTableProps): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n  const firstRow = rows[0]\n  const classes = useStyles()\n\n  const rowClasses = useRowStyles({ prefersDarkMode })\n\n  const conditionalCellStyles: ConditionalStyles<[number, string[]]>[] = [\n    {\n      when: ([index]) => index < dropFirstNRows,\n      classNames: [rowClasses.disabledRow]\n    },\n    {\n      when: ([index]) => index >= dropFirstNRows,\n      classNames: [rowClasses.normal]\n    }\n  ]\n\n  const columns: TableColumn<[number, string[]]>[] = firstRow.map((c, i) => ({\n    name: (\n      <ColumnHeaderDropDown\n        fields={fields.map((f) => f.name)}\n        onChange={(field) => assignField(i, field)}\n        value={fieldAssignments[i]}\n        undefinedName={`Col ${i + 1}`}\n      />\n    ),\n    selector: ([, row]) => row[i],\n    conditionalCellStyles\n  }))\n\n  const unassignedColumns = fields.filter(\n    (c) => c.required && !fieldAssignments.includes(c.name)\n  )\n  const errorColumns = fields.filter(\n    (c) => c.required && fieldAssignments.filter((f) => f === c.name).length > 1\n  )\n\n  const assignAlert = (() => {\n    if (unassignedColumns.length > 0) {\n      return (\n        <Alert severity=\"info\">\n          Assign the following fields:\n          <ul>\n            {unassignedColumns.map((c) => (\n              <li key={c.name}>{c.name}</li>\n            ))}\n          </ul>\n        </Alert>\n      )\n    }\n  })()\n\n  const errorAlert = (() => {\n    if (errorColumns.length > 0) {\n      return (\n        <Alert severity=\"warning\">\n          {errorColumns.map((c) => c.name).join(', ') +\n            (errorColumns.length > 1 ? ' fields are' : ' field is')}{' '}\n          assigned more than once.\n        </Alert>\n      )\n    }\n  })()\n\n  const dropFirstNRowsInput = (\n    <TextField\n      className={classes.root}\n      label=\"Drop first n rows\"\n      value={dropFirstNRows}\n      onChange={(v) => {\n        const newv = parseInt(v.target.value)\n        updateDropFirstNRows(isNaN(newv) ? 0 : newv)\n      }}\n    />\n  )\n\n  return (\n    <Grid container spacing={2} direction=\"column\">\n      <Grid item>\n        {assignAlert}\n        {errorAlert}\n      </Grid>\n      <Grid item xs={12}>\n        {dropFirstNRowsInput}\n      </Grid>\n      <Grid item xs={12}>\n        <DataTable<[number, string[]]>\n          data={rows.map((r, i) => [i, r])}\n          columns={columns}\n          theme={prefersDarkMode ? 'dark' : 'normal'}\n        />\n      </Grid>\n    </Grid>\n  )\n}\n\nexport default ConfigurableDataTable\n"
  },
  {
    "path": "src/components/income/assets/DataTableStyle.ts",
    "content": "import { createStyles, makeStyles, Theme } from '@material-ui/core'\nimport { createTheme } from 'react-data-table-component'\n\ntype DarkModeProps = {\n  prefersDarkMode: boolean\n}\n\ncreateTheme('normal', {\n  backgroundColor: 'white',\n  color: 'rgba(0, 0, 0, 0.54)',\n  '& .MuiFilledInput-input': {\n    fontSize: '.8rem',\n    fontWeight: 'bold',\n    padding: '0.9rem 0rem'\n  }\n})\n\ncreateTheme(\n  'dark',\n  {\n    backgroundColor: '#303030',\n    color: 'white',\n    '& .MuiFilledInput-input': {\n      fontSize: '.8rem',\n      fontWeight: 'bold',\n      padding: '0.9rem 0rem'\n    }\n  },\n  'normal'\n)\n\nexport const baseCellStyle = (\n  prefersDarkMode = false\n): { [k: string]: string } => ({\n  color: prefersDarkMode ? 'white' : 'rgba(0, 0, 0, 0.54)',\n  backgroundColor: prefersDarkMode ? '#303030' : 'white'\n})\n\nexport const useRowStyles = makeStyles<Theme, DarkModeProps>(() =>\n  createStyles({\n    disabledRow: {\n      backgroundColor: '#aaaaaa',\n      color: 'black'\n    },\n    normal: ({ prefersDarkMode }) => baseCellStyle(prefersDarkMode)\n  })\n)\n\nexport const columnInputStyles = makeStyles(() =>\n  createStyles({\n    column: {\n      '& .MuiFilledInput-input': {\n        fontSize: '.8rem',\n        fontWeight: 'bold',\n        padding: '0.9rem 0rem'\n      }\n    }\n  })\n)\n"
  },
  {
    "path": "src/components/income/assets/FilteredAssetsTable.tsx",
    "content": "import { Button, Grid, useMediaQuery } from '@material-ui/core'\nimport { ReactElement, useMemo, useState } from 'react'\nimport DataTable, { TableColumn } from 'react-data-table-component'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { useDispatch, useSelector } from 'react-redux'\nimport {\n  Currency,\n  GenericLabeledDropdown,\n  LabeledInput\n} from 'ustaxes/components/input'\nimport { Asset, AssetType, TaxYear, TaxYears } from 'ustaxes/core/data'\nimport { enumKeys } from 'ustaxes/core/util'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport * as actions from 'ustaxes/redux/actions'\nimport AssetSummary from './AssetSummary'\n\ntype CloseYear = TaxYear | 'none' | 'all'\ninterface AssetFilter {\n  securityName: string\n  positionType: AssetType\n  closeYear: string | undefined\n}\n\nconst blankFilter: AssetFilter = {\n  securityName: '',\n  positionType: 'Security',\n  closeYear: 'none'\n}\n\ntype Row = WithIndex<Asset<Date>>\nconst assetTableColumns: TableColumn<Row>[] = [\n  {\n    name: 'Security',\n    selector: ({ name }) => name,\n    sortable: true\n  },\n  {\n    name: 'Open Date',\n    selector: ({ openDate }) => openDate.toISOString().slice(0, 10),\n    sortable: true\n  },\n  {\n    name: 'Sale Date',\n    selector: ({ closeDate }) => closeDate?.toISOString().slice(0, 10) ?? '',\n    sortable: true\n  },\n  {\n    name: 'Cost basis',\n    sortFunction: (a, b) => a.openPrice * a.quantity - b.openPrice * b.quantity,\n    cell: ({ openPrice, quantity }) => (\n      <Currency value={openPrice * quantity} />\n    ),\n    sortable: true\n  },\n  {\n    name: 'Proceeds',\n    sortFunction: (a, b) =>\n      (a.closePrice ?? 0) * a.quantity - (b.closePrice ?? 0) * b.quantity,\n    cell: ({ closePrice, quantity }) =>\n      closePrice !== undefined ? (\n        <Currency value={closePrice * quantity} />\n      ) : (\n        ''\n      ),\n    sortable: true\n  }\n]\n\ntype SelectionEvent<T> = {\n  allSelected: boolean\n  selectedCount: number\n  selectedRows: T[]\n}\n\ntype WithIndex<A> = {\n  idx: number\n} & A\n\ninterface DisplayAssetsProps {\n  assets: WithIndex<Asset<Date>>[]\n  deleteRows: (rows: number[]) => void\n}\n\nconst DisplayAssets = ({\n  assets,\n  deleteRows\n}: DisplayAssetsProps): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  const [selectedRows, setSelectedRows] = useState<number[]>([])\n  const [cleared, setCleared] = useState(false)\n\n  const handleRowSelected = (event: SelectionEvent<WithIndex<Asset<Date>>>) => {\n    setSelectedRows(event.selectedRows.map(({ idx }) => idx))\n  }\n\n  const contextActions = useMemo(() => {\n    const handleDelete = () => {\n      const promptResult = window.confirm(\n        `Are you sure you want to delete ${selectedRows.length} positions?`\n      )\n      if (promptResult) {\n        setCleared(!cleared)\n        deleteRows(selectedRows)\n      }\n    }\n\n    return (\n      <Button\n        variant=\"contained\"\n        color=\"primary\"\n        onClick={handleDelete}\n        style={{ backgroundColor: 'red' }}\n      >\n        Delete\n      </Button>\n    )\n  }, [selectedRows, cleared])\n\n  return (\n    <DataTable\n      title=\"Assets\"\n      columns={assetTableColumns}\n      data={assets}\n      selectableRows\n      pagination\n      onSelectedRowsChange={handleRowSelected}\n      contextActions={contextActions}\n      clearSelectedRows={cleared}\n      theme={prefersDarkMode ? 'dark' : 'normal'}\n    />\n  )\n}\n\nconst FilteredAssetsTable = (): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n  const activeYear: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n  const dispatch = useDispatch()\n  const assets = useSelector((state: YearsTaxesState) => state.assets)\n  const allAssets: WithIndex<Asset<Date>>[] = assets.map((a, i) => ({\n    ...a,\n    idx: i\n  }))\n  const methods = useForm<AssetFilter>({\n    defaultValues: { ...blankFilter, closeYear: activeYear }\n  })\n  const closeYear = methods.watch('closeYear')\n  const securityName = methods.watch('securityName')\n\n  const yearFilter = (a: Asset<Date>): boolean =>\n    closeYear === 'all' ||\n    (a.closeDate === undefined && closeYear === 'none') ||\n    (a.closeDate !== undefined &&\n      closeYear !== 'none' &&\n      a.closeDate.getFullYear() === TaxYears[closeYear as TaxYear])\n\n  const securityFilter = (a: Asset<Date>): boolean =>\n    securityName === '' || a.name.toLowerCase() === securityName.toLowerCase()\n\n  const displayAssets = allAssets.filter(\n    (a) => yearFilter(a) && securityFilter(a)\n  )\n\n  const title = [\n    ['Summary of'],\n    securityName !== '' ? [securityName] : [],\n    closeYear === 'all'\n      ? ['all time']\n      : closeYear === 'none'\n      ? ['current holdings']\n      : [`sales in ${TaxYears[closeYear as TaxYear]}`]\n  ]\n    .flat()\n    .join(' ')\n\n  const filterForm = (() => {\n    // Show filter if there are any assets to filter from\n    if (assets.length > 0) {\n      return (\n        <FormProvider {...methods}>\n          <h3>Filter by</h3>\n          <Grid container direction=\"row\" spacing={2}>\n            <LabeledInput\n              sizes={{ xs: 6 }}\n              label=\"Asset Name\"\n              name=\"securityName\"\n            />\n            <GenericLabeledDropdown<[string, CloseYear], AssetFilter>\n              noUndefined\n              sizes={{ xs: 6 }}\n              label=\"Sale Year\"\n              name=\"closeYear\"\n              dropDownData={[\n                ['All', 'all'],\n                ['Still open', 'none'],\n                ...enumKeys(TaxYears).map<[string, TaxYear]>((x) => [\n                  TaxYears[x].toString(),\n                  x\n                ])\n              ]}\n              keyMapping={(x) => x[1].toString()}\n              valueMapping={(x) => x[1]}\n              textMapping={(x) => x[0]}\n            />\n          </Grid>\n        </FormProvider>\n      )\n    }\n  })()\n\n  const assetSummary = (() => {\n    if (assets.length > 0) {\n      return <AssetSummary title={title} assets={displayAssets} />\n    }\n  })()\n\n  const asCsv = (): string[] =>\n    [\n      [\n        'Security',\n        'Quantity',\n        'Open Date',\n        'Open Price',\n        'Open Fee',\n        'Cost basis',\n        'Close Date',\n        'Close Price',\n        'Close Fee',\n        'Proceeds',\n        'Gain / Loss'\n      ],\n      ...displayAssets.map((a) => [\n        a.name,\n        a.quantity,\n        a.openDate.toISOString().slice(0, 10),\n        a.openPrice,\n        a.openFee,\n        a.openPrice * a.quantity + a.openFee,\n        a.closeDate?.toISOString().slice(0, 10) ?? '',\n        a.closePrice,\n        a.closeFee,\n        a.closePrice === undefined\n          ? ''\n          : a.closePrice * a.quantity - (a.closeFee ?? 0),\n        a.closePrice === undefined\n          ? ''\n          : (a.closePrice - a.openPrice) * a.quantity -\n            (a.closeFee ?? 0) -\n            a.openFee\n      ])\n    ].map((line) => line.join(','))\n\n  const exportView = (() => {\n    if (displayAssets.length > 0) {\n      return (\n        <Grid item>\n          <Button\n            color={prefersDarkMode ? 'default' : 'secondary'}\n            variant=\"contained\"\n            onClick={() => {\n              const csv = asCsv().join('\\n')\n              const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' })\n              const url = URL.createObjectURL(blob)\n              const link = document.createElement('a')\n              link.setAttribute('href', url)\n              link.setAttribute('download', 'assets.csv')\n              document.body.appendChild(link)\n              link.click()\n              document.body.removeChild(link)\n            }}\n          >\n            Export {displayAssets.length} Assets\n          </Button>\n        </Grid>\n      )\n    }\n  })()\n\n  return (\n    <Grid container spacing={1} direction=\"column\">\n      <Grid item>{filterForm}</Grid>\n      <Grid item>{assetSummary}</Grid>\n      {exportView}\n\n      <Grid item>\n        <DisplayAssets\n          assets={displayAssets}\n          deleteRows={(rows) =>\n            dispatch(actions.removeAssets(rows)(activeYear))\n          }\n        />\n      </Grid>\n    </Grid>\n  )\n}\n\nexport default FilteredAssetsTable\n"
  },
  {
    "path": "src/components/income/assets/TransactionImporter.tsx",
    "content": "import { ReactElement, useState } from 'react'\nimport { Button, Grid, useMediaQuery } from '@material-ui/core'\nimport { useDispatch } from 'ustaxes/redux'\nimport * as actions from 'ustaxes/redux/actions'\nimport { preflightCsv, preflightCsvAll } from 'ustaxes/data/csvImport'\nimport { LoadRaw } from 'ustaxes/redux/fs/Load'\nimport DataTable, { TableColumn } from 'react-data-table-component'\nimport { Alert } from '@material-ui/lab'\nimport {\n  Portfolio,\n  Position,\n  processTransactions,\n  Side,\n  Transaction,\n  TransactionError\n} from 'ustaxes/data/transactions'\nimport {\n  Either,\n  EitherMethods,\n  isLeft,\n  left,\n  pure,\n  pureLeft,\n  right,\n  run\n} from 'ustaxes/core/util'\nimport { Asset } from 'ustaxes/core/data'\nimport ConfigurableDataTable, { ColumnDef } from './ConfigurableDataTable'\n\ninterface PortfolioTableProps {\n  portfolio: Portfolio\n}\n\nexport const PortfolioTable = ({\n  portfolio\n}: PortfolioTableProps): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  const columns: TableColumn<Position>[] = [\n    {\n      name: 'Asset Name',\n      selector: (p) => p.security.name\n    },\n    {\n      name: 'Open Date',\n      selector: (p) => p.openDate\n    },\n    {\n      name: 'Quantity',\n      selector: (p) => p.quantity\n    },\n    {\n      name: 'Price per unit',\n      selector: (p) => p.price\n    },\n    {\n      name: 'Basis',\n      selector: (p) => p.price * p.quantity\n    },\n    {\n      name: 'Close Date',\n      selector: (p) => p.closeDate ?? ''\n    },\n    {\n      name: 'Close Fee',\n      selector: (p) => (p.closeDate === undefined ? '' : p.closeFee ?? 0)\n    },\n    {\n      name: 'Proceeds',\n      selector: (p) =>\n        p.closePrice !== undefined ? p.quantity * p.closePrice : ''\n    },\n    {\n      name: 'Gain or Loss',\n      selector: (p) =>\n        p.closePrice !== undefined ? (p.closePrice - p.price) * p.quantity : ''\n    }\n  ]\n\n  return (\n    <DataTable\n      columns={columns}\n      data={portfolio.positions}\n      theme={prefersDarkMode ? 'dark' : 'normal'}\n    />\n  )\n}\n\nconst field = (name: string, required = true): ColumnDef => ({ name, required })\n\n// The fields that must be set by the user after importing a CSV file\nconst fields: ColumnDef[] = [\n  field('Asset Name'),\n  field('Transaction date'),\n  field('Buy or Sell'),\n  field('Price per unit'),\n  field('Quantity'),\n  field('Fee / commissions', false)\n]\n\nexport const TransactionImporter = (): ReactElement => {\n  const [preflightTransactions, setPreflightTransactions] = useState<\n    string[][]\n  >([])\n\n  // FieldAssignements will be an array of column indices in the imported CSV\n  // to the string name of the field we want to assign to that column.\n  const [fieldAssignments, setFieldAssignments] = useState<\n    (string | undefined)[]\n  >([])\n\n  const [dropFirstNRows, setDropFirstNRows] = useState<number>(0)\n  const [rawContents, setRawContents] = useState<string>('')\n  const [portfolio, setPortfolio] = useState<Portfolio>({ positions: [] })\n  const [portfolioError, setPortfolioError] = useState<\n    TransactionError | undefined\n  >(undefined)\n\n  const dispatch = useDispatch()\n\n  const ready = () =>\n    fields.every(\n      (f) =>\n        !f.required || fieldAssignments.filter((a) => a === f.name).length === 1\n    )\n\n  const assignField = (colIndex: number, field: string | undefined) => {\n    const newFieldAssignments = [...fieldAssignments]\n    while (newFieldAssignments.length <= colIndex) {\n      newFieldAssignments.push(undefined)\n    }\n    newFieldAssignments[colIndex] = field\n    setFieldAssignments(newFieldAssignments)\n  }\n\n  const onHandle = (contents: string): void => {\n    setRawContents(contents)\n    run(preflightCsv(contents)).fold(\n      (e) => console.error(\"Couldn't parse CSV\", e),\n      setPreflightTransactions\n    )\n  }\n\n  const parseRow = (row: string[]): Either<string[], Transaction> => {\n    const assignments = fieldAssignments as string[]\n\n    const date: Either<string, Date> = (() => {\n      const dateStr = row[assignments.indexOf('Transaction date')]\n      try {\n        return right(new Date(dateStr.slice(0, 10)))\n      } catch (e) {\n        return left(\n          `Parsing transaction date value (${\n            row[assignments.indexOf('Transaction date')]\n          }) as date failed`\n        )\n      }\n    })()\n\n    const quantity: Either<string, number> = (() => {\n      const quantityStr = row[assignments.indexOf('Quantity')]\n      const v = parseFloat(quantityStr)\n      if (isNaN(v)) {\n        return left(`Could not parse quantity value (${quantityStr}) as number`)\n      } else {\n        return right(v)\n      }\n    })()\n\n    const price: Either<string, number> = (() => {\n      const priceStr = row[assignments.indexOf('Price per unit')]\n      const v = parseFloat(priceStr)\n      if (isNaN(v)) {\n        return left(`Could not parse price value (${priceStr}) as number`)\n      } else {\n        return right(v)\n      }\n    })()\n\n    const side: Either<string, Side> = (() => {\n      const cell = row[assignments.indexOf('Buy or Sell')].toLowerCase()\n      if (cell === 'buy') {\n        return right('BUY')\n      }\n      if (cell === 'sell') {\n        return right('SELL')\n      }\n      return left(`Could not parse value ${cell} as buy or sell`)\n    })()\n\n    const feeIdx = assignments.indexOf('Fee / commissions')\n\n    const fee: Either<string, number | undefined> = (() => {\n      if (feeIdx < 0) {\n        return right(undefined)\n      }\n      const feeStr = row[feeIdx]\n      const v = parseFloat(feeStr)\n      if (isNaN(v)) {\n        return left(`Could not parse fee value (${feeStr}) as number`)\n      } else {\n        return right(v)\n      }\n    })()\n\n    // Either is a fail-fast construct, so\n    // we dont (yet) have a way to nicely combine\n    // errors.\n    const errors = []\n\n    if (isLeft(date)) {\n      errors.push(date.left)\n    }\n    if (isLeft(quantity)) {\n      errors.push(quantity.left)\n    }\n    if (isLeft(price)) {\n      errors.push(price.left)\n    }\n    if (isLeft(side)) {\n      errors.push(side.left)\n    }\n\n    // bad if condition necessary for typechecking below.\n    if (\n      isLeft(date) ||\n      isLeft(quantity) ||\n      isLeft(price) ||\n      isLeft(side) ||\n      isLeft(fee)\n    ) {\n      return left(errors)\n    } else {\n      return right({\n        security: {\n          name: row[assignments.indexOf('Asset Name')]\n        },\n        date: date.right.toISOString().slice(0, 10),\n        quantity: quantity.right,\n        price: price.right,\n        side: side.right,\n        fee: fee.right\n      })\n    }\n  }\n\n  const addToPortfolio = () =>\n    run(preflightCsvAll(rawContents)).fold(\n      (csvReadErrors) => {\n        setPortfolioError({\n          messages: ['Could not parse CSV', csvReadErrors[0].message],\n          errorIndex: csvReadErrors[0].row\n        })\n      },\n      (rows) => {\n        const accumulatedErrors = rows.reduce((acc, row, idx) => {\n          // Skip configured header rows\n          if (idx < dropFirstNRows) {\n            return acc\n          }\n          return run(parseRow(row)).fold(\n            (e) =>\n              acc.fold(\n                (errors) =>\n                  pureLeft(errors.concat({ errorIndex: idx, messages: e })),\n                () =>\n                  pureLeft([\n                    {\n                      errorIndex: idx,\n                      messages: e\n                    }\n                  ])\n              ),\n            (res) => acc.map((ts) => ts.concat(res))\n          )\n        }, pure<TransactionError[], Transaction[]>([]))\n\n        const processedTransactions: EitherMethods<\n          TransactionError[],\n          Portfolio\n        > = accumulatedErrors.chain((transactions) =>\n          run(processTransactions(portfolio, transactions))\n            .mapLeft((e) => [\n              {\n                ...e,\n                messages: [\n                  'This usually means you have sell transactions in excess of securities you hold at the time of sale. Either these are short sales, which are not yet supported here, or buy transactions that predate these sales are missing. If this is the case, add the required positions as BUY transactions at the beginning of this CSV file and try again.'\n                ]\n              }\n            ])\n            .value()\n        )\n\n        processedTransactions.fold(\n          (errors) => {\n            setPortfolioError(errors[0])\n          },\n          (portfolio) => {\n            setPortfolioError(undefined)\n            setPortfolio(portfolio)\n          }\n        )\n      }\n    )\n\n  const readyButton = (() => {\n    if (ready() && portfolio.positions.length === 0) {\n      return (\n        <Grid item>\n          <Button variant=\"contained\" color=\"primary\" onClick={addToPortfolio}>\n            Build Portfolio\n          </Button>\n        </Grid>\n      )\n    }\n  })()\n\n  const importable = () =>\n    portfolio.positions.length > 0 && portfolioError === undefined\n\n  const resetPortfolioBuildingState = () => {\n    setPortfolio({ positions: [] })\n    setRawContents('')\n    setDropFirstNRows(0)\n    setFieldAssignments([])\n    setPreflightTransactions([])\n    setPortfolioError(undefined)\n  }\n\n  const addAssets = () => {\n    const assets: Asset[] = portfolio.positions.map((position) => ({\n      name: position.security.name,\n      openDate: new Date(position.openDate),\n      openPrice: position.price,\n      positionType: 'Security',\n      quantity: position.quantity,\n      openFee: position.openFee,\n      closeFee: position.closeFee,\n      closeDate:\n        position.closeDate !== undefined\n          ? new Date(position.closeDate)\n          : undefined,\n      closePrice: position.closePrice\n    }))\n\n    dispatch(actions.addAssets(assets))\n    resetPortfolioBuildingState()\n  }\n\n  const addAssetsButton = (() => {\n    if (importable()) {\n      return (\n        <Grid item>\n          <Button variant=\"contained\" color=\"primary\" onClick={addAssets}>\n            Add Sales and Assets\n          </Button>\n        </Grid>\n      )\n    }\n  })()\n\n  const resetButton = (() => {\n    if (\n      preflightTransactions.length > 0 ||\n      portfolioError !== undefined ||\n      portfolio.positions.length > 0\n    ) {\n      return (\n        <Grid item>\n          <Button\n            variant=\"contained\"\n            color=\"secondary\"\n            onClick={resetPortfolioBuildingState}\n          >\n            Reset\n          </Button>\n        </Grid>\n      )\n    }\n  })()\n\n  return (\n    <Grid container spacing={2}>\n      <Grid item xs={12}>\n        <LoadRaw\n          variant=\"contained\"\n          color=\"primary\"\n          handleData={(contents: string) => onHandle(contents)}\n        >\n          Load CSV File\n        </LoadRaw>\n      </Grid>\n\n      {(() => {\n        if (preflightTransactions.length > 0) {\n          return (\n            <>\n              <Grid item xs={12}>\n                <h3>Import Transactions</h3>\n              </Grid>\n              <Grid item xs={12}>\n                <ConfigurableDataTable\n                  fieldAssignments={fieldAssignments}\n                  assignField={assignField}\n                  fields={fields}\n                  rows={preflightTransactions}\n                  updateDropFirstNRows={(num) => setDropFirstNRows(num)}\n                  dropFirstNRows={dropFirstNRows}\n                />\n              </Grid>\n              <Grid container spacing={2} direction=\"row\">\n                {readyButton}\n                {resetButton}\n                {addAssetsButton}\n              </Grid>\n            </>\n          )\n        }\n      })()}\n      {(() => {\n        if (portfolioError) {\n          const { errorTransaction, previousPortfolio } = portfolioError\n\n          const errorTransactionMessage = (() => {\n            if (errorTransaction !== undefined) {\n              const {\n                side,\n                security: { name },\n                quantity,\n                price,\n                date\n              } = errorTransaction\n\n              return (\n                <>\n                  <h4>Erroneous transaction</h4>\n                  <div>\n                    <ul>\n                      <li>Line {portfolioError.errorIndex + 1}</li>\n                      <li>Date: {date}</li>\n                      <li>{`${side} ${name} ${quantity}@${price}`}</li>\n                    </ul>\n                  </div>\n                </>\n              )\n            }\n          })()\n\n          const prevPortfolioMessage = (() => {\n            if (previousPortfolio !== undefined) {\n              return (\n                <>\n                  <h4>Portfolio before erroneous transaction</h4>\n                  <PortfolioTable\n                    portfolio={previousPortfolio}\n                  ></PortfolioTable>\n                </>\n              )\n            }\n          })()\n\n          return (\n            <Grid item xs={12}>\n              <Alert severity=\"error\">\n                <h3>Transaction List Import Failed</h3>\n                {errorTransactionMessage}\n                {portfolioError.messages.map((message, i) => (\n                  <p key={i}>{message}</p>\n                ))}\n              </Alert>\n              {prevPortfolioMessage}\n            </Grid>\n          )\n        }\n      })()}\n      {(() => {\n        if (portfolio.positions.length > 0) {\n          return (\n            <Grid item xs={12}>\n              <h3>Portfolio</h3>\n              <PortfolioTable portfolio={portfolio} />\n            </Grid>\n          )\n        }\n      })()}\n    </Grid>\n  )\n}\n"
  },
  {
    "path": "src/components/input/Currency.tsx",
    "content": "import { ReactElement } from 'react'\nimport { CurrencyProps } from './types'\nimport NumberFormat from 'react-number-format'\nimport { makeStyles } from '@material-ui/core/styles'\n\nconst useStyles = makeStyles(() => ({\n  positive: {\n    color: 'green'\n  },\n  negative: {\n    color: 'red'\n  }\n}))\n\nexport default function Currency(props: CurrencyProps): ReactElement {\n  const { prefix = '', value, plain = false } = props\n  const classes = useStyles()\n\n  const className: string | undefined = (() => {\n    if (plain) {\n      return undefined\n    }\n    if (value > 0) {\n      return classes.positive\n    } else if (value < 0) {\n      return classes.negative\n    }\n  })()\n\n  const showValue = (() => {\n    if (value === Math.trunc(value)) {\n      return Math.abs(value)\n    }\n    return Math.abs(value).toFixed(2)\n  })()\n\n  return (\n    <NumberFormat\n      className={className}\n      thousandSeparator={true}\n      prefix={`${prefix}  $`}\n      value={showValue}\n      displayType=\"text\"\n    />\n  )\n}\n"
  },
  {
    "path": "src/components/input/DatePicker.tsx",
    "content": "import { ReactElement } from 'react'\nimport { FormControl, Grid } from '@material-ui/core'\nimport { Controller, useFormContext } from 'react-hook-form'\nimport useStyles from './styles'\nimport ConditionallyWrap from 'ustaxes/components/ConditionallyWrap'\nimport {\n  MuiPickersUtilsProvider,\n  KeyboardDatePicker as MuiDatePicker\n} from '@material-ui/pickers'\nimport DateFnsUtils from '@date-io/date-fns'\nimport { DatePickerProps } from './types'\n\nexport function DatePicker<TFormValues>(\n  props: DatePickerProps<TFormValues>\n): ReactElement {\n  const {\n    label,\n    required = false,\n    name,\n    minDate = new Date(1900, 0, 1),\n    maxDate,\n    useGrid = true,\n    sizes = { xs: 12 }\n  } = props\n\n  const classes = useStyles()\n  const {\n    control,\n    formState: { isSubmitted }\n  } = useFormContext<TFormValues>()\n\n  return (\n    <ConditionallyWrap\n      condition={useGrid}\n      wrapper={(children) => (\n        <Grid item {...sizes}>\n          {children}\n        </Grid>\n      )}\n    >\n      <Controller\n        name={name}\n        control={control}\n        rules={{\n          required\n        }}\n        render={({ field: { value, onChange } }) => {\n          const forceError: boolean | undefined =\n            (isSubmitted &&\n              required &&\n              ((value as string | undefined | null) ?? undefined) ===\n                undefined) ||\n            value === ''\n\n          const forceErrorProps = forceError\n            ? {\n                helperText: 'Input is required',\n                error: true\n              }\n            : {}\n\n          return (\n            <div className={classes.root}>\n              <FormControl component=\"fieldset\">\n                <MuiPickersUtilsProvider utils={DateFnsUtils}>\n                  <MuiDatePicker\n                    {...forceErrorProps}\n                    data-testid={name}\n                    label={label}\n                    InputLabelProps={{\n                      shrink: true\n                    }}\n                    inputVariant=\"filled\"\n                    minDate={minDate}\n                    maxDate={maxDate}\n                    maxDateMessage={`Date cannot be after ${maxDate.toLocaleDateString()}`}\n                    minDateMessage={`Date cannot be before ${minDate.toLocaleDateString()}`}\n                    // invalid date message can be shown once user has attempted to submit\n                    invalidDateMessage={\n                      isSubmitted ? 'Invalid date format' : undefined\n                    }\n                    value={(value as string | undefined) ?? null}\n                    placeholder=\"mm/dd/yyyy\"\n                    onChange={onChange}\n                    format=\"MM/dd/yyyy\"\n                  />\n                </MuiPickersUtilsProvider>\n              </FormControl>\n            </div>\n          )\n        }}\n      />\n    </ConditionallyWrap>\n  )\n}\n"
  },
  {
    "path": "src/components/input/LabeledCheckbox.tsx",
    "content": "import { ReactElement } from 'react'\nimport {\n  Checkbox,\n  FormControl,\n  FormControlLabel,\n  FormGroup,\n  Grid\n} from '@material-ui/core'\nimport { Controller, useFormContext } from 'react-hook-form'\nimport { LabeledCheckboxProps } from './types'\nimport ConditionallyWrap from 'ustaxes/components/ConditionallyWrap'\n\nexport function LabeledCheckbox<TFormValues>(\n  props: LabeledCheckboxProps<TFormValues>\n): ReactElement {\n  const { label, name, useGrid = true, sizes = { xs: 12 } } = props\n  const { control } = useFormContext<TFormValues>()\n\n  return (\n    <ConditionallyWrap\n      condition={useGrid}\n      wrapper={(children) => (\n        <Grid item {...sizes}>\n          {children}\n        </Grid>\n      )}\n    >\n      <Controller\n        name={name}\n        render={({ field: { value, onChange } }) => (\n          <FormControl component=\"fieldset\">\n            <FormGroup>\n              <FormControlLabel\n                control={\n                  <Checkbox\n                    name={name}\n                    checked={value as boolean}\n                    onChange={(_, checked) => onChange(checked)}\n                    color=\"primary\"\n                  />\n                }\n                label={label}\n                value={value}\n              />\n            </FormGroup>\n          </FormControl>\n        )}\n        control={control}\n      />\n    </ConditionallyWrap>\n  )\n}\n\nexport default LabeledCheckbox\n"
  },
  {
    "path": "src/components/input/LabeledDropdown.tsx",
    "content": "import { useEffect, useRef, ReactElement } from 'react'\nimport _ from 'lodash'\nimport { useForkRef } from 'rooks'\nimport { Grid, TextField } from '@material-ui/core'\nimport { Controller, useFormContext } from 'react-hook-form'\nimport locationPostalCodes from 'ustaxes/core/data/locationPostalCodes'\nimport countries from 'ustaxes/core/data/countries'\nimport { State } from 'ustaxes/core/data'\nimport useStyles from './styles'\nimport { BaseDropdownProps, LabeledDropdownProps } from './types'\nimport ConditionallyWrap from 'ustaxes/components/ConditionallyWrap'\n\nexport function GenericLabeledDropdown<A, TFormValues>(\n  props: LabeledDropdownProps<A, TFormValues>\n): ReactElement {\n  const classes = useStyles()\n  const {\n    control,\n    formState: { errors }\n  } = useFormContext<TFormValues>()\n  const {\n    autofocus,\n    label,\n    dropDownData,\n    valueMapping,\n    keyMapping,\n    textMapping,\n    noUndefined = false,\n    required = true,\n    name,\n    useGrid = true,\n    sizes = { xs: 12 }\n  } = props\n\n  const error: string | undefined = _.get(errors, name, undefined) as\n    | string\n    | undefined\n  const inputRef = useRef<HTMLElement | null>(null)\n\n  useEffect(() => {\n    if (autofocus && inputRef.current) {\n      inputRef.current.focus()\n    }\n  }, [inputRef.current])\n\n  return (\n    <ConditionallyWrap\n      condition={useGrid}\n      wrapper={(children) => (\n        <Grid item {...sizes}>\n          {children}\n        </Grid>\n      )}\n    >\n      <Controller\n        render={({ field: { name, onChange, ref, value } }) => (\n          <TextField\n            inputRef={autofocus ? useForkRef(ref, inputRef) : ref}\n            id={name}\n            name={name}\n            className={classes.root}\n            label={label}\n            select\n            fullWidth\n            variant=\"filled\"\n            helperText={error !== undefined ? 'Make a selection' : undefined}\n            error={error !== undefined}\n            SelectProps={{\n              native: true,\n              value,\n              onChange\n            }}\n            InputLabelProps={{\n              shrink: true\n            }}\n          >\n            {(() => {\n              if (!noUndefined) {\n                return <option value={''} />\n              }\n            })()}\n            {dropDownData.map((dropDownItem: A, i: number) => (\n              <option\n                value={valueMapping(dropDownItem, i)}\n                key={keyMapping(dropDownItem, i)}\n              >\n                {textMapping(dropDownItem, i)}\n              </option>\n            ))}\n          </TextField>\n        )}\n        name={name}\n        rules={{ required: required }}\n        control={control}\n      />\n    </ConditionallyWrap>\n  )\n}\n\n/**\n * A specialized version of a dropdown that just handles an array of strings\n *\n * @param props\n */\nexport const LabeledDropdown = <TFormValues,>(\n  props: BaseDropdownProps<TFormValues> & { dropDownData: string[] }\n): ReactElement => (\n  <GenericLabeledDropdown<string, TFormValues>\n    {...props}\n    valueMapping={(x) => x}\n    keyMapping={(x, n) => n}\n    textMapping={(x) => x}\n  />\n)\n\nexport const USStateDropDown = <TFormValues,>(\n  props: BaseDropdownProps<TFormValues>\n): ReactElement => (\n  <GenericLabeledDropdown<[string, State], TFormValues>\n    {...props}\n    dropDownData={locationPostalCodes}\n    valueMapping={([, code]) => code}\n    keyMapping={([, code]) => code}\n    textMapping={([name, code]) => `${code} - ${name}`}\n  />\n)\n\nexport const CountryDropDown = <TFormValues,>(\n  props: BaseDropdownProps<TFormValues>\n): ReactElement => (\n  <GenericLabeledDropdown<string, TFormValues>\n    {...props}\n    dropDownData={countries}\n    valueMapping={(name) => name}\n    keyMapping={(_, idx) => idx}\n    textMapping={(name) => name}\n  />\n)\n\nexport default LabeledDropdown\n"
  },
  {
    "path": "src/components/input/LabeledInput.tsx",
    "content": "import { useEffect, useRef, KeyboardEvent, ReactElement } from 'react'\nimport { useForkRef } from 'rooks'\nimport { InputAdornment, Grid, TextField } from '@material-ui/core'\nimport { LabeledInputProps } from './types'\nimport NumberFormat from 'react-number-format'\nimport { Controller, FieldError, useFormContext } from 'react-hook-form'\nimport { isNumeric, Patterns } from 'ustaxes/components/Patterns'\nimport ConditionallyWrap from 'ustaxes/components/ConditionallyWrap'\nimport useStyles from './styles'\nimport { useFormContainer } from 'ustaxes/components/FormContainer/Context'\nimport { getNestedValue } from 'ustaxes/core/util'\n\nexport function LabeledInput<TFormValues>(\n  props: LabeledInputProps<TFormValues>\n): ReactElement {\n  const { onSubmit } = useFormContainer()\n  const { label, patternConfig: patternConfigDefined, name, rules = {} } = props\n  const { required = patternConfigDefined !== undefined } = props\n  const {\n    autofocus,\n    patternConfig = Patterns.plain,\n    useGrid = true,\n    sizes = { xs: 12 }\n  } = props\n  const classes = useStyles()\n  const inputRef = useRef<HTMLElement | null>(null)\n\n  useEffect(() => {\n    if (autofocus && inputRef.current) {\n      inputRef.current.focus()\n    }\n  }, [inputRef.current])\n\n  const {\n    control,\n    handleSubmit,\n    register,\n    formState: { errors }\n  } = useFormContext<TFormValues>()\n\n  const error: FieldError | undefined = getNestedValue(errors, name, undefined)\n\n  const errorMessage: string | undefined = (() => {\n    if (error?.message !== undefined && error.message !== '') {\n      return error.message\n    }\n    if (isNumeric(patternConfig)) {\n      if (error?.type === 'max' && patternConfig.max !== undefined) {\n        return `Input must be less than or equal to ${\n          patternConfig.prefix ?? ''\n        }${patternConfig.max}`\n      }\n      if (error?.type === 'min' && patternConfig.min !== undefined) {\n        return `Input must be greater than or equal to ${\n          patternConfig.prefix ?? ''\n        }${patternConfig.min}`\n      }\n    }\n  })()\n\n  const input: ReactElement = (() => {\n    if (isNumeric(patternConfig)) {\n      return (\n        <Controller\n          name={name}\n          control={control}\n          render={({ field: { name, onChange, ref, value } }) => (\n            <NumberFormat\n              customInput={TextField}\n              inputRef={autofocus ? useForkRef(ref, inputRef) : ref}\n              id={name}\n              name={name}\n              className={classes.root}\n              label={label}\n              mask={patternConfig.mask}\n              thousandSeparator={patternConfig.thousandSeparator}\n              // prefix={patternConfig.prefix}\n              allowEmptyFormatting={true}\n              format={patternConfig.format}\n              isNumericString={false}\n              onValueChange={(v) => onChange(v.value)}\n              value={value as number}\n              error={error !== undefined}\n              fullWidth\n              helperText={errorMessage}\n              variant=\"filled\"\n              InputLabelProps={{\n                shrink: true\n              }}\n              InputProps={{\n                startAdornment: patternConfig.prefix ? (\n                  <InputAdornment position=\"start\">\n                    {patternConfig.prefix}\n                  </InputAdornment>\n                ) : undefined,\n                onKeyDown: (e: KeyboardEvent) => {\n                  if (e.key === 'Enter') {\n                    onSubmit?.()\n                    void handleSubmit(() => {\n                      //do nothing\n                    })()\n                  }\n                }\n              }}\n            />\n          )}\n          rules={{\n            ...rules,\n            min: patternConfig.min,\n            max: patternConfig.max,\n            required: required ? 'Input is required' : undefined,\n            pattern: {\n              value: patternConfig.regexp ?? (required ? /.+/ : /.*/),\n              message:\n                patternConfig.description ??\n                (required ? 'Input is required' : '')\n            }\n          }}\n        />\n      )\n    }\n\n    return (\n      <Controller\n        control={control}\n        name={name}\n        render={({ field: { name, onChange, ref, value } }) => (\n          <TextField\n            {...register(name, {\n              ...rules,\n              required: required ? 'Input is required' : undefined,\n              pattern: {\n                value: patternConfig.regexp ?? (required ? /.+/ : /.*/),\n                message:\n                  patternConfig.description ??\n                  (required ? 'Input is required' : '')\n              }\n            })}\n            inputRef={autofocus ? useForkRef(ref, inputRef) : ref}\n            id={name}\n            name={name}\n            className={classes.root}\n            label={label}\n            value={value}\n            onChange={onChange}\n            onKeyDown={(e) => {\n              if (e.key === 'Enter') {\n                void handleSubmit(() => {\n                  // do nothing\n                })()\n                onSubmit?.()\n              }\n            }}\n            fullWidth\n            helperText={error?.message}\n            error={error !== undefined}\n            variant=\"filled\"\n            InputLabelProps={{\n              shrink: true\n            }}\n          />\n        )}\n      />\n    )\n  })()\n\n  return (\n    <ConditionallyWrap\n      condition={useGrid}\n      wrapper={(children) => (\n        <Grid item {...sizes}>\n          {children}\n        </Grid>\n      )}\n    >\n      {input}\n    </ConditionallyWrap>\n  )\n}\n\nexport default LabeledInput\n"
  },
  {
    "path": "src/components/input/LabeledRadio.tsx",
    "content": "import { ReactElement } from 'react'\nimport {\n  FormControl,\n  FormControlLabel,\n  FormLabel,\n  Grid,\n  Radio,\n  RadioGroup\n} from '@material-ui/core'\nimport { Controller, useFormContext } from 'react-hook-form'\nimport { LabeledRadioProps } from './types'\nimport useStyles from './styles'\nimport ConditionallyWrap from 'ustaxes/components/ConditionallyWrap'\n\nexport function LabeledRadio<A>(props: LabeledRadioProps<A>): ReactElement {\n  const { label, name, values, useGrid = true, sizes = { xs: 12 } } = props\n\n  const classes = useStyles()\n  const { control } = useFormContext<A>()\n\n  return (\n    <ConditionallyWrap\n      condition={useGrid}\n      wrapper={(children) => (\n        <Grid item {...sizes}>\n          {children}\n        </Grid>\n      )}\n    >\n      <Controller\n        name={name}\n        render={({ field: { value, onChange } }) => (\n          <div className={classes.root}>\n            <FormControl component=\"fieldset\">\n              <FormLabel>{label}</FormLabel>\n              <RadioGroup name={name} value={value} onChange={onChange}>\n                {values.map(([rowLabel, rowValue], i) => (\n                  <FormControlLabel\n                    key={i}\n                    value={rowValue}\n                    control={<Radio color=\"primary\" />}\n                    label={rowLabel}\n                  />\n                ))}\n              </RadioGroup>\n            </FormControl>\n          </div>\n        )}\n        control={control}\n      />\n    </ConditionallyWrap>\n  )\n}\n"
  },
  {
    "path": "src/components/input/boxLabel.tsx",
    "content": "import { ReactElement } from 'react'\n\nconst boxLabel = (box: string, description: string): ReactElement => (\n  <>\n    <strong>Box {box}</strong> - {description}\n  </>\n)\n\nexport default boxLabel\n"
  },
  {
    "path": "src/components/input/index.ts",
    "content": "import Currency from './Currency'\nimport LabeledInput from './LabeledInput'\nimport { LabeledCheckbox } from './LabeledCheckbox'\nimport { LabeledRadio } from './LabeledRadio'\nimport LabeledDropdown, {\n  GenericLabeledDropdown,\n  USStateDropDown\n} from './LabeledDropdown'\nimport boxLabel from './boxLabel'\nimport { DatePicker } from './DatePicker'\n\nconst ssid = /^([0-9]{3})([0-9]{2})([0-9]{4}$)/\nconst ein = /^([0-9]{2})([0-9]{7})/\n\n/**\n * Format a string like \"123456789\" as \"123-45-6789\". If the string is not\n * exactly 9 digits long, it returns empty string\n */\nconst formatSSID = (a: string): string =>\n  (ssid.exec(a) ?? []).slice(1).join('-')\n\n/**\n * Format a string like \"123456789\" as \"12-3456789\". If the string is not\n * exactly 9 digits long, it returns empty string\n */\nconst formatEIN = (a: string): string => (ein.exec(a) ?? []).slice(1).join('-')\n\nexport {\n  boxLabel,\n  Currency,\n  formatSSID,\n  formatEIN,\n  LabeledInput,\n  LabeledCheckbox,\n  LabeledDropdown,\n  LabeledRadio,\n  GenericLabeledDropdown,\n  USStateDropDown,\n  DatePicker\n}\n"
  },
  {
    "path": "src/components/input/styles.ts",
    "content": "import { createStyles, makeStyles, Theme } from '@material-ui/core'\n\nconst useStyles = makeStyles(({ palette: { type: themeType } }: Theme) =>\n  createStyles({\n    root: {\n      '& .MuiFormLabel-root': {\n        color:\n          themeType === 'dark'\n            ? 'rgba(255, 255, 255, 0.7)'\n            : 'rgba(0, 0, 0, 0.54)'\n      }\n    }\n  })\n)\n\nexport default useStyles\n"
  },
  {
    "path": "src/components/input/types.ts",
    "content": "import { ReactElement } from 'react'\nimport { Path, RegisterOptions } from 'react-hook-form'\nimport { PatternConfig } from 'ustaxes/components/Patterns'\nimport { GridSize } from '@material-ui/core/Grid'\nexport interface BaseDropdownProps<TFormValues> {\n  label: string | ReactElement\n  required?: boolean\n  name: Path<TFormValues>\n}\n\nexport interface CurrencyProps {\n  prefix?: string\n  value: number\n  plain?: boolean\n}\n\ninterface SizeList {\n  xs?: boolean | GridSize\n  sm?: boolean | GridSize\n  md?: boolean | GridSize\n  lg?: boolean | GridSize\n}\n\nexport interface LabeledDropdownProps<A, TFormValues>\n  extends BaseDropdownProps<TFormValues> {\n  autofocus?: boolean\n  useGrid?: boolean\n  sizes?: SizeList\n  dropDownData: A[]\n  valueMapping: (a: A, n: number) => string\n  keyMapping: (a: A, n: number) => string | number\n  textMapping: (a: A, n: number) => string\n  noUndefined?: boolean\n}\n\nexport interface LabeledInputProps<TFormValues> {\n  autofocus?: boolean\n  useGrid?: boolean\n  sizes?: SizeList\n  patternConfig?: PatternConfig\n  label: string | ReactElement\n  required?: boolean\n  name: Path<TFormValues>\n  defaultValue?: string\n  rules?: Exclude<\n    RegisterOptions<TFormValues>,\n    'valueAsNumber' | 'valueAsDate' | 'setValueAs'\n  >\n}\n\nexport interface LabeledFormProps<TFormValues> {\n  name: Path<TFormValues>\n  label: string\n  useGrid?: boolean\n  sizes?: SizeList\n}\n\nexport type LabeledCheckboxProps<TFormValues> = LabeledFormProps<TFormValues>\n\nexport interface LabeledRadioProps<TFormValues>\n  extends LabeledFormProps<TFormValues> {\n  values: Array<[string, string]>\n}\n\nexport interface DatePickerProps<TFormValues>\n  extends LabeledFormProps<TFormValues> {\n  required?: boolean\n  minDate?: Date\n  maxDate: Date\n}\n"
  },
  {
    "path": "src/components/pager.tsx",
    "content": "import {\n  createContext,\n  useContext,\n  PropsWithChildren,\n  ReactElement,\n  ReactNode\n} from 'react'\nimport { useMediaQuery, Button, Grid } from '@material-ui/core'\nimport { isMobileOnly as isMobile } from 'react-device-detect'\nimport { Link } from 'react-router-dom'\nimport { useLocation, useNavigate } from 'react-router'\n\nexport interface PagerProps {\n  onAdvance: () => void\n  navButtons?: ReactElement\n}\n\nexport const PagerContext = createContext<PagerProps>({\n  onAdvance: () => {\n    // do nothing\n  }\n})\n\ninterface PagerProviderProps<A> {\n  pages: A[]\n}\n\ninterface Page {\n  url: string\n}\n\nexport const PagerProvider = <A extends Page>({\n  children,\n  pages\n}: PropsWithChildren<PagerProviderProps<A>>): ReactElement => {\n  const lookup = new Map(pages.map((p, i) => [p.url, i]))\n\n  const currentLoc = useLocation()\n  const currentPage = lookup.get(currentLoc.pathname) ?? 0\n\n  const navigate = useNavigate()\n\n  const onAdvance: (() => void) | undefined = (() => {\n    if (currentPage < pages.length - 1) {\n      return () => navigate(pages[currentPage + 1].url)\n    }\n  })()\n\n  const prev = currentPage > 0 ? pages[currentPage - 1] : undefined\n\n  const navButtons: ReactElement = (\n    <PagerButtons\n      previousUrl={prev?.url}\n      submitText={onAdvance !== undefined ? 'Save and Continue' : undefined}\n    />\n  )\n\n  return (\n    <PagerContext.Provider\n      value={{\n        onAdvance:\n          onAdvance ??\n          (() => {\n            // end of pages\n          }),\n        navButtons\n      }}\n    >\n      {children}\n    </PagerContext.Provider>\n  )\n}\n\ninterface PagerButtonsProps {\n  previousUrl?: string\n  nextUrl?: string\n  submitText?: string\n}\n\nexport const PagerButtons = ({\n  submitText,\n  previousUrl\n}: PagerButtonsProps): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n  const backButton = (() => {\n    if (previousUrl !== undefined && previousUrl !== '/start') {\n      return (\n        <Grid item xs={isMobile && 12}>\n          <Button\n            component={Link}\n            to={previousUrl}\n            variant=\"contained\"\n            color={prefersDarkMode ? 'default' : 'secondary'}\n            fullWidth\n          >\n            Previous\n          </Button>\n        </Grid>\n      )\n    }\n  })()\n\n  const submitButton: ReactNode = (() => {\n    if (submitText !== undefined) {\n      return (\n        <Grid item xs={isMobile ? 12 : undefined}>\n          <Button\n            type=\"submit\"\n            name=\"submit\"\n            variant=\"contained\"\n            color=\"primary\"\n            fullWidth\n          >\n            {submitText}\n          </Button>\n        </Grid>\n      )\n    }\n  })()\n\n  return (\n    <Grid container spacing={2} direction={isMobile ? 'row-reverse' : 'row'}>\n      {backButton}\n      {submitButton}\n    </Grid>\n  )\n}\n\ninterface StartButtonsProps {\n  firstUrl: string\n  firstText: string\n  secondUrl: string\n  secondText: string\n}\n\nexport const StartButtons = ({\n  firstUrl,\n  firstText,\n  secondUrl,\n  secondText\n}: StartButtonsProps): ReactElement => {\n  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)')\n\n  return (\n    <Grid container spacing={2}>\n      <Grid item xs={12} sm={6}>\n        <Button\n          component={Link}\n          to={firstUrl}\n          variant=\"contained\"\n          color=\"primary\"\n          fullWidth\n        >\n          {firstText}\n        </Button>\n      </Grid>\n      <Grid item xs={12} sm={6}>\n        <Button\n          href={secondUrl}\n          variant=\"contained\"\n          fullWidth\n          color={prefersDarkMode ? 'default' : 'secondary'}\n        >\n          {secondText}\n        </Button>\n      </Grid>\n    </Grid>\n  )\n}\n\ninterface SingleButtonsProps {\n  url: string\n  text: string\n}\n\nexport const SingleButtons = ({\n  url,\n  text\n}: SingleButtonsProps): ReactElement => {\n  return (\n    <Grid container spacing={2}>\n      <Grid item xs={12}>\n        <Button\n          component={Link}\n          to={url}\n          variant=\"contained\"\n          color=\"primary\"\n          fullWidth\n        >\n          {text}\n        </Button>\n      </Grid>\n    </Grid>\n  )\n}\n\nexport const usePager = (): PagerProps => useContext(PagerContext)\n"
  },
  {
    "path": "src/components/payments/EstimatedTaxes.tsx",
    "content": "import { ReactElement } from 'react'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { usePager } from 'ustaxes/components/pager'\nimport { EstimatedTaxPayments, TaxYear } from 'ustaxes/core/data'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport { Currency, LabeledInput } from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid } from '@material-ui/core'\nimport { Work } from '@material-ui/icons'\nimport {\n  addEstimatedPayment,\n  editEstimatedPayment,\n  removeEstimatedPayment\n} from 'ustaxes/redux/actions'\nimport { useDispatch } from 'ustaxes/redux'\nimport { useSelector } from 'react-redux'\nimport { useYearSelector } from 'ustaxes/redux/yearDispatch'\n\ninterface EstimatedTaxesUserInput {\n  label: string\n  payment: string\n}\n\nconst blankUserInput: EstimatedTaxesUserInput = {\n  label: '',\n  payment: ''\n}\n\nconst toPayments = (\n  formData: EstimatedTaxesUserInput\n): EstimatedTaxPayments => ({\n  ...formData,\n  // Note we are not error checking here because\n  // we are already in the input validated happy path\n  // of handleSubmit.\n  label: formData.label,\n  payment: parseInt(formData.payment)\n})\n\nconst toEstimatedTaxesUserInput = (\n  data: EstimatedTaxPayments\n): EstimatedTaxesUserInput => ({\n  ...blankUserInput,\n  ...data,\n  label: data.label,\n  payment: data.payment.toString()\n})\n\nexport default function EstimatedTaxes(): ReactElement {\n  const defaultValues = blankUserInput\n  const activeYear: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  const estimatedTaxes = useYearSelector(\n    (state) => state.information.estimatedTaxes\n  )\n\n  const dispatch = useDispatch()\n\n  const methods = useForm<EstimatedTaxesUserInput>({ defaultValues })\n\n  const { navButtons, onAdvance } = usePager()\n\n  const onSubmitAdd = (formData: EstimatedTaxesUserInput): void => {\n    dispatch(addEstimatedPayment(toPayments(formData)))\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: EstimatedTaxesUserInput): void => {\n      dispatch(editEstimatedPayment({ index, value: toPayments(formData) }))\n    }\n\n  const w2sBlock = (\n    <FormListContainer<EstimatedTaxesUserInput>\n      defaultValues={defaultValues}\n      items={estimatedTaxes.map((a) => toEstimatedTaxesUserInput(a))}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      removeItem={(i) => dispatch(removeEstimatedPayment(i))}\n      icon={() => <Work />}\n      primary={(estimatedTaxes: EstimatedTaxesUserInput) =>\n        estimatedTaxes.label\n      }\n      secondary={(estimatedTaxes: EstimatedTaxesUserInput) => (\n        <span>\n          Payment: <Currency value={toPayments(estimatedTaxes).payment} />\n        </span>\n      )}\n    >\n      <Grid container spacing={2}>\n        <LabeledInput\n          name=\"label\"\n          label=\"label or date of this payment\"\n          patternConfig={Patterns.plain}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"payment\"\n          label=\"Estimated tax payment\"\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  const form: ReactElement = <>{w2sBlock}</>\n\n  return (\n    <form tabIndex={-1} onSubmit={onAdvance}>\n      <h2>Estimated Taxes</h2>\n      <p>\n        Did you already make payments towards your {activeYear} taxes this year\n        or last year?\n      </p>\n      <FormProvider {...methods}>{form}</FormProvider>\n      {navButtons}\n    </form>\n  )\n}\n"
  },
  {
    "path": "src/components/savingsAccounts/IRA.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useYearSelector, useYearDispatch } from 'ustaxes/redux/yearDispatch'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  Ira,\n  IraPlanType,\n  IraPlanTypeTexts,\n  Person,\n  PersonRole\n} from 'ustaxes/core/data'\n\nimport {\n  Currency,\n  LabeledInput,\n  GenericLabeledDropdown,\n  formatSSID,\n  LabeledCheckbox,\n  boxLabel\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid } from '@material-ui/core'\nimport { Work } from '@material-ui/icons'\nimport { TaxesState } from 'ustaxes/redux'\nimport { addIRA, editIRA, removeIRA } from 'ustaxes/redux/actions'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface IraUserInput {\n  payer: string\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  // fields about distributions from form 1099-R\n  grossDistribution?: string // 1099-R box 1\n  taxableAmount?: string // 1099-R box 2a\n  taxableAmountNotDetermined?: boolean // 1099-R box 2b\n  totalDistribution?: boolean // 1099-R box 2b\n  federalIncomeTaxWithheld?: string // 1099-R box 4\n  planType: IraPlanType\n  // fields about contributions from form 5498\n  contributions?: string // 5498 box 1\n  rolloverContributions?: string // 5498 box 2\n  rothIraConversion?: string // 5498 box 3\n  recharacterizedContributions?: string // 5498 box 4\n  requiredMinimumDistributions?: string // 5498 box 12b\n  lateContributions?: string // 5498 box 13a\n  repayments?: string // 5498 box 14a\n}\n\nconst blankUserInput: IraUserInput = {\n  payer: '',\n  personRole: PersonRole.PRIMARY,\n  grossDistribution: '',\n  taxableAmount: '',\n  taxableAmountNotDetermined: false,\n  totalDistribution: false,\n  federalIncomeTaxWithheld: '',\n  planType: IraPlanType.IRA,\n  // fields about contributions from form 5498\n  contributions: '',\n  rolloverContributions: '',\n  rothIraConversion: '',\n  recharacterizedContributions: '',\n  requiredMinimumDistributions: '',\n  lateContributions: '',\n  repayments: ''\n}\n\nconst toIra = (formData: IraUserInput): Ira => ({\n  ...formData,\n  // Note we are not error checking here because\n  // we are already in the input validated happy path\n  // of handleSubmit.\n  payer: formData.payer,\n  personRole: formData.personRole,\n  grossDistribution: Number(formData.grossDistribution),\n  taxableAmount: Number(formData.taxableAmount),\n  taxableAmountNotDetermined: formData.taxableAmountNotDetermined ?? false,\n  totalDistribution: formData.totalDistribution ?? false,\n  federalIncomeTaxWithheld: Number(formData.federalIncomeTaxWithheld),\n  planType: formData.planType,\n  // fields about contributions from form 5498\n  contributions: Number(formData.contributions),\n  rolloverContributions: Number(formData.rolloverContributions),\n  rothIraConversion: Number(formData.rothIraConversion),\n  recharacterizedContributions: Number(formData.recharacterizedContributions),\n  requiredMinimumDistributions: Number(formData.requiredMinimumDistributions),\n  lateContributions: Number(formData.lateContributions),\n  repayments: Number(formData.repayments)\n})\n\nconst toIraUserInput = (data: Ira): IraUserInput => ({\n  ...blankUserInput,\n  ...data,\n\n  grossDistribution: data.grossDistribution.toString(),\n  taxableAmount: data.taxableAmount.toString(),\n  federalIncomeTaxWithheld: data.federalIncomeTaxWithheld.toString(),\n  // fields about contributions from form 5498\n  contributions: data.contributions.toString(),\n  rolloverContributions: data.rolloverContributions.toString(),\n  rothIraConversion: data.rothIraConversion.toString(),\n  recharacterizedContributions: data.recharacterizedContributions.toString(),\n  requiredMinimumDistributions: data.requiredMinimumDistributions.toString(),\n  lateContributions: data.lateContributions.toString(),\n  repayments: data.repayments.toString()\n})\n\nexport default function IRA(): ReactElement {\n  const defaultValues = blankUserInput\n  const ira = useYearSelector(\n    (state: TaxesState) => state.information.individualRetirementArrangements\n  )\n\n  const people: Person[] = useYearSelector((state: TaxesState) => [\n    state.information.taxPayer.primaryPerson,\n    state.information.taxPayer.spouse\n  ])\n    .filter((p) => p !== undefined)\n    .map((p) => p as Person)\n\n  const dispatch = useYearDispatch()\n\n  const methods = useForm<IraUserInput>({ defaultValues })\n  const { handleSubmit } = methods\n\n  const { navButtons, onAdvance } = usePager()\n\n  const onSubmitAdd = (formData: IraUserInput): void => {\n    dispatch(addIRA(toIra(formData)))\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: IraUserInput): void => {\n      dispatch(editIRA({ index, value: toIra(formData) }))\n    }\n\n  const hsaBlock = (\n    <FormListContainer<IraUserInput>\n      defaultValues={defaultValues}\n      items={ira.map((a) => toIraUserInput(a))}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      removeItem={(i) => dispatch(removeIRA(i))}\n      icon={() => <Work />}\n      primary={(ira: IraUserInput) => ira.payer}\n      secondary={(ira: IraUserInput) => (\n        <span>\n          {IraPlanTypeTexts[ira.planType]}\n          <br />\n          gross distribution: <Currency value={toIra(ira).grossDistribution} />\n          <br />\n          contribution: <Currency value={toIra(ira).contributions} />\n          <br />\n        </span>\n      )}\n    >\n      <Grid container spacing={2}>\n        <LabeledInput<IraUserInput>\n          name=\"payer\"\n          label=\"Payer for this account\"\n          patternConfig={Patterns.plain}\n          sizes={{ xs: 12, lg: 12 }}\n        />\n        <GenericLabeledDropdown<IraPlanType, IraUserInput>\n          label=\"IRA Type\"\n          dropDownData={Object.values(IraPlanType)}\n          valueMapping={(x) => x}\n          keyMapping={(_, i) => i}\n          textMapping={(status) => IraPlanTypeTexts[status]}\n          name=\"planType\"\n        />\n        <GenericLabeledDropdown<Person, IraUserInput>\n          dropDownData={people}\n          label=\"Recipient\"\n          valueMapping={(p: Person, i: number) =>\n            [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n          }\n          name=\"personRole\"\n          keyMapping={(p: Person, i: number) => i}\n          textMapping={(p: Person) =>\n            `${p.firstName} ${p.lastName} (${formatSSID(p.ssid)})`\n          }\n        />\n      </Grid>\n      <h3>Contributions (Form 5498)</h3>\n      <p>\n        If you made no contributions you may not have received form 5498 for\n        this account and may leave these fields blank.\n      </p>\n      <Grid container spacing={2}>\n        <LabeledInput\n          name=\"contributions\"\n          label=\"Contributions\"\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"rolloverContributions\"\n          label={boxLabel('2', 'Rollover contributions')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"rothIraConversion\"\n          label={boxLabel('3', 'Amount converted to Roth IRA')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"recharacterizedContributions\"\n          label={boxLabel('4', 'Recharacterized contributions')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"requiredMinimumDistributions\"\n          label={boxLabel('12b', 'Required minimum distributions')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"lateContributions\"\n          label={boxLabel('13a', 'Late contributions')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"repayments\"\n          label={boxLabel('14a', 'Repayments to this account')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n      </Grid>\n      <h3>Distributions (Form 1099-R)</h3>\n      <p>\n        If you have no distributions from this account then you may not have\n        received form 1099-R and may leave these fields blank.\n      </p>\n\n      <Grid container spacing={2}>\n        <LabeledInput\n          name=\"grossDistribution\"\n          label={boxLabel('1', 'Total distributions')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"taxableAmount\"\n          label={boxLabel(\n            '2a',\n            'This part of the distribution is generally taxable'\n          )}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput\n          name=\"federalIncomeTaxWithheld\"\n          label={boxLabel('4a', 'Federal income tax withheld')}\n          patternConfig={Patterns.currency}\n          required={false}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledCheckbox\n          name=\"taxableAmountNotDetermined\"\n          label=\"Check if the payer was unable to determine the taxable amount\"\n        />\n        <LabeledCheckbox\n          name=\"totalDistribution\"\n          label=\"This distribution closed out your account\"\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  const form: ReactElement = <>{hsaBlock}</>\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>\n            Individual Retirement Arrangements (IRA) | Savings Accounts |\n            UsTaxes.org\n          </title>\n        </Helmet>\n        <h2>Individual Retirement Arrangements (IRA)</h2>\n        {form}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/components/savingsAccounts/healthSavingsAccounts.tsx",
    "content": "import { ReactElement } from 'react'\nimport { Helmet } from 'react-helmet'\nimport { useSelector } from 'react-redux'\nimport { useYearSelector, useYearDispatch } from 'ustaxes/redux/yearDispatch'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { usePager } from 'ustaxes/components/pager'\nimport {\n  HealthSavingsAccount,\n  Person,\n  PersonRole,\n  TaxYear,\n  TaxYears\n} from 'ustaxes/core/data'\n\nimport {\n  Currency,\n  LabeledInput,\n  GenericLabeledDropdown,\n  LabeledDropdown,\n  formatSSID,\n  DatePicker\n} from 'ustaxes/components/input'\nimport { Patterns } from 'ustaxes/components/Patterns'\nimport { FormListContainer } from 'ustaxes/components/FormContainer'\nimport { Grid } from '@material-ui/core'\nimport { Work } from '@material-ui/icons'\nimport { TaxesState } from 'ustaxes/redux'\nimport { addHSA, editHSA, removeHSA } from 'ustaxes/redux/actions'\nimport { YearsTaxesState } from 'ustaxes/redux'\n\nimport { format } from 'date-fns'\nimport { intentionallyFloat } from 'ustaxes/core/util'\n\ninterface HSAUserInput {\n  label: string\n  coverageType: 'self-only' | 'family'\n  contributions: string\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  startDate: Date\n  endDate: Date\n  totalDistributions: string\n  qualifiedDistributions: string\n}\n\nconst blankUserInput: HSAUserInput = {\n  label: '',\n  coverageType: 'self-only',\n  contributions: '',\n  personRole: PersonRole.PRIMARY,\n  startDate: new Date(),\n  endDate: new Date(),\n  totalDistributions: '',\n  qualifiedDistributions: ''\n}\n\nconst toHSA = (formData: HSAUserInput): HealthSavingsAccount<string> => ({\n  ...formData,\n  // Note we are not error checking here because\n  // we are already in the input validated happy path\n  // of handleSubmit.\n  label: formData.label,\n  coverageType: formData.coverageType,\n  contributions: parseInt(formData.contributions),\n  personRole: formData.personRole,\n  startDate: formData.startDate.toISOString(),\n  endDate: formData.endDate.toISOString(),\n  totalDistributions: parseInt(formData.totalDistributions),\n  qualifiedDistributions: parseInt(formData.qualifiedDistributions)\n})\n\nconst toHSAUserInput = (data: HealthSavingsAccount): HSAUserInput => ({\n  ...blankUserInput,\n  ...data,\n  coverageType: data.coverageType,\n  contributions: data.contributions.toString(),\n  startDate: new Date(data.startDate),\n  endDate: new Date(data.endDate),\n  totalDistributions: data.totalDistributions.toString(),\n  qualifiedDistributions: data.qualifiedDistributions.toString()\n})\n\nexport default function HealthSavingsAccounts(): ReactElement {\n  const defaultValues = blankUserInput\n  const hsa = useYearSelector(\n    (state: TaxesState) => state.information.healthSavingsAccounts\n  )\n\n  const people: Person[] = useYearSelector((state: TaxesState) => [\n    state.information.taxPayer.primaryPerson,\n    state.information.taxPayer.spouse\n  ])\n    .filter((p) => p !== undefined)\n    .map((p) => p as Person)\n\n  const dispatch = useYearDispatch()\n\n  const methods = useForm<HSAUserInput>({ defaultValues })\n  const { handleSubmit } = methods\n\n  const activeYear: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  const { navButtons, onAdvance } = usePager()\n\n  const onSubmitAdd = (formData: HSAUserInput): void => {\n    dispatch(addHSA(toHSA(formData)))\n  }\n\n  const onSubmitEdit =\n    (index: number) =>\n    (formData: HSAUserInput): void => {\n      dispatch(editHSA({ index, value: toHSA(formData) }))\n    }\n\n  const hsaBlock = (\n    <FormListContainer<HSAUserInput>\n      defaultValues={defaultValues}\n      items={hsa.map((a) => toHSAUserInput(a))}\n      onSubmitAdd={onSubmitAdd}\n      onSubmitEdit={onSubmitEdit}\n      removeItem={(i) => dispatch(removeHSA(i))}\n      icon={() => <Work />}\n      primary={(hsa: HSAUserInput) => hsa.label}\n      secondary={(hsa: HSAUserInput) => (\n        <span>\n          contributions: <Currency value={toHSA(hsa).contributions} />\n          <br />\n          total distributions:{' '}\n          <Currency value={toHSA(hsa).totalDistributions} />\n          <br />\n          qualified distributions:{' '}\n          <Currency value={toHSA(hsa).qualifiedDistributions} />\n          <br />\n          coverage type: {hsa.coverageType}\n          <br />\n          coverage span: {format(hsa.startDate, 'MMMM do, yyyy')} to{' '}\n          {format(hsa.endDate, 'MMMM do, yyyy')}\n        </span>\n      )}\n    >\n      <Grid container spacing={2}>\n        <LabeledInput<HSAUserInput>\n          name=\"label\"\n          label=\"label for this account\"\n          patternConfig={Patterns.plain}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput<HSAUserInput>\n          name=\"contributions\"\n          label=\"Your total contributions to this account.\"\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput<HSAUserInput>\n          name=\"totalDistributions\"\n          label=\"Total distributions from this account.\"\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledInput<HSAUserInput>\n          name=\"qualifiedDistributions\"\n          label=\"Qualified medical distributions from this account.\"\n          patternConfig={Patterns.currency}\n          sizes={{ xs: 12, lg: 6 }}\n        />\n        <LabeledDropdown<HSAUserInput>\n          dropDownData={['self-only', 'family']}\n          label=\"Coverage Type\"\n          name=\"coverageType\"\n        />\n        <GenericLabeledDropdown<Person, HSAUserInput>\n          dropDownData={people}\n          label=\"Recipient\"\n          valueMapping={(p: Person, i: number) =>\n            [PersonRole.PRIMARY, PersonRole.SPOUSE][i]\n          }\n          name=\"personRole\"\n          keyMapping={(p: Person, i: number) => i}\n          textMapping={(p: Person) =>\n            `${p.firstName} ${p.lastName} (${formatSSID(p.ssid)})`\n          }\n        />\n        <DatePicker\n          name=\"startDate\"\n          label=\"Starting Date\"\n          sizes={{ xs: 12, lg: 6 }}\n          minDate={new Date(TaxYears[activeYear], 0, 1)}\n          maxDate={new Date(TaxYears[activeYear], 11, 31)}\n        />\n        <DatePicker\n          name=\"endDate\"\n          label=\"Ending Date\"\n          sizes={{ xs: 12, lg: 6 }}\n          minDate={new Date(TaxYears[activeYear], 0, 1)}\n          maxDate={new Date(TaxYears[activeYear], 11, 31)}\n        />\n      </Grid>\n    </FormListContainer>\n  )\n\n  const form: ReactElement = <>{hsaBlock}</>\n\n  return (\n    <FormProvider {...methods}>\n      <form\n        tabIndex={-1}\n        onSubmit={intentionallyFloat(handleSubmit(onAdvance))}\n      >\n        <Helmet>\n          <title>\n            Health Savings Accounts (HSA) | Savings Accounts | UsTaxes.org\n          </title>\n        </Helmet>\n        <h2>Health Savings Accounts (HSA)</h2>\n        {form}\n        {navButtons}\n      </form>\n    </FormProvider>\n  )\n}\n"
  },
  {
    "path": "src/core/data/anonymize.ts",
    "content": "import { YearsTaxesState } from 'ustaxes/redux'\nimport {\n  F3921,\n  Ira,\n  Supported1099,\n  Dependent,\n  Employer,\n  F1098e,\n  Information,\n  Person,\n  PersonRole,\n  TaxPayer,\n  Address,\n  IncomeW2,\n  Property,\n  ScheduleK1Form1065\n} from '.'\n\nconst anonymizePerson = (person: Person): Person => {\n  const roles = [\n    PersonRole.PRIMARY,\n    PersonRole.SPOUSE,\n    PersonRole.DEPENDENT,\n    PersonRole.EMPLOYER\n  ]\n\n  return {\n    ...person,\n    ssid: `${100000000 + roles.findIndex((r) => r === person.role)}`,\n    firstName: `${person.role}first`,\n    lastName: `${person.role}last`\n  }\n}\n\nconst anonymizeDependent = (dependent: Dependent, idx: number): Dependent => {\n  return {\n    ...dependent,\n    ...anonymizePerson(dependent),\n    ssid: `${200000000 + idx}`,\n    firstName: `dependent-${idx}-first`,\n    lastName: `dependent-${idx}-first`\n  }\n}\n\nconst anonymizeAddress = (address: Address, prefix = ''): Address => ({\n  ...address,\n  address: `${prefix} address`,\n  city: `${prefix} city`,\n  aptNo: address.aptNo !== undefined ? `${prefix} apt` : undefined,\n  zip: address.zip !== undefined ? '99999' : undefined,\n  foreignCountry:\n    address.foreignCountry === undefined\n      ? undefined\n      : `${prefix} foreign country`,\n  postalCode: address.postalCode !== undefined ? `${prefix} postal` : undefined,\n  province: address.province !== undefined ? `${prefix} province` : undefined\n})\n\nconst anonymizeEmployer = (employer: Employer): Employer => ({\n  ...employer,\n  EIN: '999999999',\n  employerName: 'anonymous employer',\n  address:\n    employer.address === undefined\n      ? undefined\n      : anonymizeAddress(employer.address, 'employer')\n})\n\nconst anonymizeF1098e = (f: F1098e): F1098e => ({\n  ...f,\n  lender: 'lender'\n})\n\nconst anonymizeF1099 = (f: Supported1099, idx: number): Supported1099 => ({\n  ...f,\n  payer: `payer ${idx}`\n})\n\nconst anonymizeF3921 = (f: F3921, idx: number): F3921 => ({\n  ...f,\n  name: `3921 name ${idx}`\n})\n\nconst anonymizeIra = (ira: Ira, idx: number): Ira => ({\n  ...ira,\n  payer: `ira payer ${idx}`\n})\n\nconst anonymizeTaxPayer = (tp: TaxPayer): TaxPayer => ({\n  ...tp,\n  contactEmail: tp.contactEmail === undefined ? undefined : 'a@b.com',\n  contactPhoneNumber:\n    tp.contactPhoneNumber === undefined ? undefined : '1234567890',\n  dependents: tp.dependents.map(anonymizeDependent),\n  primaryPerson:\n    tp.primaryPerson === undefined\n      ? undefined\n      : { ...tp.primaryPerson, ...anonymizePerson(tp.primaryPerson) },\n  spouse:\n    tp.spouse === undefined\n      ? undefined\n      : { ...tp.spouse, ...anonymizePerson(tp.spouse) }\n})\n\nconst anonymizeW2 = (w2: IncomeW2): IncomeW2 => ({\n  ...w2,\n  employer:\n    w2.employer === undefined ? undefined : anonymizeEmployer(w2.employer),\n  occupation: 'occupation'\n})\n\nconst anonymizeRealEstate = (realEstate: Property): Property => ({\n  ...realEstate,\n  address: anonymizeAddress(realEstate.address, 'property')\n})\n\nconst anonymizeK1 = (\n  k1: ScheduleK1Form1065,\n  idx: number\n): ScheduleK1Form1065 => ({\n  ...k1,\n  partnershipName: `partnership ${idx}`,\n  partnershipEin: '888888888'\n})\n\nexport const anonymizeInformation = (info: Information): Information => ({\n  ...info,\n  f1098es: info.f1098es.map(anonymizeF1098e),\n  f1099s: info.f1099s.map(anonymizeF1099),\n  f3921s: info.f3921s.map(anonymizeF3921),\n  individualRetirementArrangements:\n    info.individualRetirementArrangements.map(anonymizeIra),\n  refund:\n    info.refund === undefined\n      ? undefined\n      : {\n          ...info.refund,\n          accountNumber: '123456789',\n          routingNumber: '123456789'\n        },\n  taxPayer: anonymizeTaxPayer(info.taxPayer),\n  w2s: info.w2s.map(anonymizeW2),\n  realEstate: info.realEstate.map(anonymizeRealEstate),\n  scheduleK1Form1065s: info.scheduleK1Form1065s.map(anonymizeK1)\n})\n\nexport default (input: YearsTaxesState): YearsTaxesState => ({\n  ...input,\n  Y2019: anonymizeInformation(input.Y2019),\n  Y2020: anonymizeInformation(input.Y2020),\n  Y2021: anonymizeInformation(input.Y2021)\n})\n"
  },
  {
    "path": "src/core/data/countries.ts",
    "content": "const countries: string[] = [\n  'Afghanistan',\n  'Åland Islands',\n  'Albania',\n  'Algeria',\n  'American Samoa',\n  'Andorra',\n  'Angola',\n  'Anguilla',\n  'Antarctica',\n  'Antigua and Barbuda',\n  'Argentina',\n  'Armenia',\n  'Aruba',\n  'Australia',\n  'Austria',\n  'Azerbaijan',\n  'Bahamas',\n  'Bahrain',\n  'Bangladesh',\n  'Barbados',\n  'Belarus',\n  'Belgium',\n  'Belize',\n  'Benin',\n  'Bermuda',\n  'Bhutan',\n  'Bolivia (Plurinational State of)',\n  'Bonaire, Sint Eustatius and Saba',\n  'Bosnia and Herzegovina',\n  'Botswana',\n  'Bouvet Island',\n  'Brazil',\n  'British Indian Ocean Territory',\n  'United States Minor Outlying Islands',\n  'Virgin Islands (British)',\n  'Virgin Islands (U.S.)',\n  'Brunei Darussalam',\n  'Bulgaria',\n  'Burkina Faso',\n  'Burundi',\n  'Cambodia',\n  'Cameroon',\n  'Canada',\n  'Cabo Verde',\n  'Cayman Islands',\n  'Central African Republic',\n  'Chad',\n  'Chile',\n  'China',\n  'Christmas Island',\n  'Cocos (Keeling) Islands',\n  'Colombia',\n  'Comoros',\n  'Congo',\n  'Congo (Democratic Republic of the)',\n  'Cook Islands',\n  'Costa Rica',\n  'Croatia',\n  'Cuba',\n  'Curaçao',\n  'Cyprus',\n  'Czech Republic',\n  'Denmark',\n  'Djibouti',\n  'Dominica',\n  'Dominican Republic',\n  'Ecuador',\n  'Egypt',\n  'El Salvador',\n  'Equatorial Guinea',\n  'Eritrea',\n  'Estonia',\n  'Ethiopia',\n  'Falkland Islands (Malvinas)',\n  'Faroe Islands',\n  'Fiji',\n  'Finland',\n  'France',\n  'French Guiana',\n  'French Polynesia',\n  'French Southern Territories',\n  'Gabon',\n  'Gambia',\n  'Georgia',\n  'Germany',\n  'Ghana',\n  'Gibraltar',\n  'Greece',\n  'Greenland',\n  'Grenada',\n  'Guadeloupe',\n  'Guam',\n  'Guatemala',\n  'Guernsey',\n  'Guinea',\n  'Guinea-Bissau',\n  'Guyana',\n  'Haiti',\n  'Heard Island and McDonald Islands',\n  'Holy See',\n  'Honduras',\n  'Hong Kong',\n  'Hungary',\n  'Iceland',\n  'India',\n  'Indonesia',\n  \"Côte d'Ivoire\",\n  'Iran (Islamic Republic of)',\n  'Iraq',\n  'Ireland',\n  'Isle of Man',\n  'Israel',\n  'Italy',\n  'Jamaica',\n  'Japan',\n  'Jersey',\n  'Jordan',\n  'Kazakhstan',\n  'Kenya',\n  'Kiribati',\n  'Kuwait',\n  'Kyrgyzstan',\n  \"Lao People's Democratic Republic\",\n  'Latvia',\n  'Lebanon',\n  'Lesotho',\n  'Liberia',\n  'Libya',\n  'Liechtenstein',\n  'Lithuania',\n  'Luxembourg',\n  'Macao',\n  'Macedonia (the former Yugoslav Republic of)',\n  'Madagascar',\n  'Malawi',\n  'Malaysia',\n  'Maldives',\n  'Mali',\n  'Malta',\n  'Marshall Islands',\n  'Martinique',\n  'Mauritania',\n  'Mauritius',\n  'Mayotte',\n  'Mexico',\n  'Micronesia (Federated States of)',\n  'Moldova (Republic of)',\n  'Monaco',\n  'Mongolia',\n  'Montenegro',\n  'Montserrat',\n  'Morocco',\n  'Mozambique',\n  'Myanmar',\n  'Namibia',\n  'Nauru',\n  'Nepal',\n  'Netherlands',\n  'New Caledonia',\n  'New Zealand',\n  'Nicaragua',\n  'Niger',\n  'Nigeria',\n  'Niue',\n  'Norfolk Island',\n  \"Korea (Democratic People's Republic of)\",\n  'Northern Mariana Islands',\n  'Norway',\n  'Oman',\n  'Pakistan',\n  'Palau',\n  'Palestine, State of',\n  'Panama',\n  'Papua New Guinea',\n  'Paraguay',\n  'Peru',\n  'Philippines',\n  'Pitcairn',\n  'Poland',\n  'Portugal',\n  'Puerto Rico',\n  'Qatar',\n  'Republic of Kosovo',\n  'Réunion',\n  'Romania',\n  'Russian Federation',\n  'Rwanda',\n  'Saint Barthélemy',\n  'Saint Helena, Ascension and Tristan da Cunha',\n  'Saint Kitts and Nevis',\n  'Saint Lucia',\n  'Saint Martin (French part)',\n  'Saint Pierre and Miquelon',\n  'Saint Vincent and the Grenadines',\n  'Samoa',\n  'San Marino',\n  'Sao Tome and Principe',\n  'Saudi Arabia',\n  'Senegal',\n  'Serbia',\n  'Seychelles',\n  'Sierra Leone',\n  'Singapore',\n  'Sint Maarten (Dutch part)',\n  'Slovakia',\n  'Slovenia',\n  'Solomon Islands',\n  'Somalia',\n  'South Africa',\n  'South Georgia and the South Sandwich Islands',\n  'Korea (Republic of)',\n  'South Sudan',\n  'Spain',\n  'Sri Lanka',\n  'Sudan',\n  'Suriname',\n  'Svalbard and Jan Mayen',\n  'Swaziland',\n  'Sweden',\n  'Switzerland',\n  'Syrian Arab Republic',\n  'Taiwan',\n  'Tajikistan',\n  'Tanzania, United Republic of',\n  'Thailand',\n  'Timor-Leste',\n  'Togo',\n  'Tokelau',\n  'Tonga',\n  'Trinidad and Tobago',\n  'Tunisia',\n  'Turkey',\n  'Turkmenistan',\n  'Turks and Caicos Islands',\n  'Tuvalu',\n  'Uganda',\n  'Ukraine',\n  'United Arab Emirates',\n  'United Kingdom of Great Britain and Northern Ireland',\n  'United States of America',\n  'Uruguay',\n  'Uzbekistan',\n  'Vanuatu',\n  'Venezuela (Bolivarian Republic of)',\n  'Viet Nam',\n  'Wallis and Futuna',\n  'Western Sahara',\n  'Yemen',\n  'Zambia',\n  'Zimbabwe'\n]\n\nexport default countries\n"
  },
  {
    "path": "src/core/data/index.ts",
    "content": "import { enumKeys } from '../util'\n\nexport enum TaxYears {\n  Y2019 = 2019,\n  Y2020 = 2020,\n  Y2021 = 2021\n}\n\nexport type TaxYear = keyof typeof TaxYears\n\nexport enum PersonRole {\n  PRIMARY = 'PRIMARY',\n  SPOUSE = 'SPOUSE',\n  DEPENDENT = 'DEPENDENT',\n  EMPLOYER = 'EMPLOYER'\n}\n\n/**\n * Types such as the following are generic with respect to the Date\n * type. AJV tests the typed serialization of these interfaces\n * in JSON, and Date is not a valid type in JSON. So when our data\n * is serialized in and out of local storage, or to a JSON file,\n * these data must be parsed / serialized from / to strings.\n *\n * Our AJV schema generator ignores generic types.\n */\nexport interface Person<D = Date> {\n  firstName: string\n  lastName: string\n  ssid: string\n  role: PersonRole\n  isBlind: boolean\n  dateOfBirth: D\n}\n\n// Concrete type for our AJV schema generator.\nexport type PersonDateString = Person<string>\n\nexport interface QualifyingInformation {\n  numberOfMonths: number\n  isStudent: boolean\n}\n\nexport interface Dependent<D = Date> extends Person<D> {\n  relationship: string\n  qualifyingInfo?: QualifyingInformation\n}\n\nexport type DependentDateString = Dependent<string>\n\nexport interface Address {\n  address: string\n  aptNo?: string\n  city: string\n  state?: State\n  zip?: string\n  foreignCountry?: string\n  province?: string\n  postalCode?: string\n}\n\nexport interface PrimaryPerson<D = Date> extends Person<D> {\n  address: Address\n  isTaxpayerDependent: boolean\n}\nexport type PrimaryPersonDateString = PrimaryPerson<string>\n\nexport interface Spouse<D = Date> extends Person<D> {\n  isTaxpayerDependent: boolean\n}\n\nexport type SpouseDateString = Spouse<string>\n\nexport interface Employer {\n  EIN?: string\n  employerName?: string\n  address?: Address\n}\n\nexport enum AccountType {\n  checking = 'checking',\n  savings = 'savings'\n}\n\nexport interface Refund {\n  routingNumber: string\n  accountNumber: string\n  accountType: AccountType\n}\n\nexport interface IncomeW2 {\n  occupation: string\n  income: number\n  medicareIncome: number\n  fedWithholding: number\n  ssWages: number\n  ssWithholding: number\n  medicareWithholding: number\n  employer?: Employer\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  state?: State\n  stateWages?: number\n  stateWithholding?: number\n  box12?: W2Box12Info\n}\n\nexport interface EstimatedTaxPayments {\n  label: string\n  payment: number\n}\n\nexport enum Income1099Type {\n  B = 'B',\n  INT = 'INT',\n  DIV = 'DIV',\n  R = 'R',\n  SSA = 'SSA'\n}\n\nexport interface F1099BData {\n  shortTermProceeds: number\n  shortTermCostBasis: number\n  longTermProceeds: number\n  longTermCostBasis: number\n}\n\nexport interface F1099IntData {\n  income: number\n}\n\nexport interface F1099DivData {\n  dividends: number\n  qualifiedDividends: number\n  totalCapitalGainsDistributions: number\n}\n/*\n TODO: Add in logic for various different distributions\n that should go in box 4a and 5a. Will need to implement\n form 8606 and Schedule 1 line 19.\n */\nexport enum PlanType1099 {\n  /* IRA includes a traditional IRA, Roth IRA,\n   * simplified employee pension (SEP) IRA,\n   * and a savings incentive match plan for employees (SIMPLE) IRA\n   */\n  IRA = 'IRA',\n  RothIRA = 'RothIRA',\n  SepIRA = 'SepIRA',\n  SimpleIRA = 'SimpleIRA',\n  // Pension and annuity payments include distributions from 401(k), 403(b), and governmental 457(b) plans.\n  Pension = 'Pension'\n}\n\nexport const PlanType1099Texts: { [k in keyof typeof PlanType1099]: string } = {\n  IRA: 'traditional IRA',\n  RothIRA: 'Roth IRA',\n  SepIRA: 'simplified employee pension (SEP) IRA',\n  SimpleIRA: 'savings incentive match plan for employees (SIMPLE) IRA',\n  Pension: '401(k), 403(b), or 457(b) plan'\n}\n\nexport interface F1099RData {\n  grossDistribution: number\n  taxableAmount: number\n  federalIncomeTaxWithheld: number\n  planType: PlanType1099\n}\n\nexport interface F1099SSAData {\n  // benefitsPaid: number\n  // benefitsRepaid: number\n  netBenefits: number\n  federalIncomeTaxWithheld: number\n}\n\nexport interface Income1099<T, D> {\n  payer: string\n  type: T\n  form: D\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n}\nexport enum W2Box12Code {\n  A = 'A', // Uncollected social security or RRTA tax on tips.\n  B = 'B', // Uncollected Medicare tax on tips.\n  C = 'C', // Taxable cost of group-term life insurance over $50,000.\n  D = 'D', // Elective deferrals under a section 401(k) cash or deferred arrangement (plan).\n  E = 'E', // Elective deferrals under a section 403(b) salary reduction agreement.\n  F = 'F', // Elective deferrals under a section 408(k)(6) salary reduction SEP.\n  G = 'G', // Elective deferrals and employer contributions (including nonelective deferrals) to any governmental or nongovernmental section 457(b) deferred compensation plan.\n  H = 'H', // Elective deferrals under section 501(c)(18)(D) tax-exempt organization plan.\n  J = 'J', // Nontaxable sick pay.\n  K = 'K', // 20% excise tax on excess golden parachute payments (not applicable to Forms W-2AS, W-2CM, W-2GU, or W-2VI).\n  L = 'L', // Substantiated employee business expense reimbursements.\n  M = 'M', // Uncollected social security or RRTA tax on taxable cost of group-term life insurance over $50,000 (for former employees).\n  N = 'N', // Uncollected Medicare tax on taxable cost of group-term life insurance over $50,000 (for former employees).\n  P = 'P', // Excludable moving expense reimbursements paid directly to a member of the U.S. Armed Forces.\n  Q = 'Q', // Nontaxable combat pay.\n  R = 'R', // Employer contributions to an Archer MSA.\n  S = 'S', // Employee salary reduction contributions under a section 408(p) SIMPLE plan.\n  T = 'T', // Adoption benefits.\n  V = 'V', // Income from the exercise of nonstatutory stock option(s).\n  W = 'W', // Employer contributions to a health savings account (HSA).\n  Y = 'Y', // Deferrals under a section 409A nonqualified deferred compensation plan.\n  Z = 'Z', // Income under a nonqualified deferred compensation plan that fails to satisfy section 409A.\n  AA = 'AA', // Designated Roth contributions under a section 401(k) plan.\n  BB = 'BB', // Designated Roth contributions under a section 403(b) plan.\n  DD = 'DD', // Cost of employer-sponsored health coverage.\n  EE = 'EE', // Designated Roth contributions under a governmental section 457(b) plan.\n  FF = 'FF', // Permitted benefits under a qualified small employer health reimbursement arrangement.\n  GG = 'GG', // Income from qualified equity grants under section 83(i).\n  HH = 'HH' // Aggregate deferrals under section 83(i) elections as of the close of the calendar year.}\n}\n\nexport const W2Box12CodeDescriptions: { [key in W2Box12Code]: string } = {\n  A: 'Uncollected social security or RRTA tax on tips.',\n  B: 'Uncollected Medicare tax on tips.',\n  C: 'Taxable cost of group-term life insurance over $50,000.',\n  D: 'Elective deferrals under a section 401(k) cash or deferred arrangement plan.',\n  E: 'Elective deferrals under a section 403(b) salary reduction agreement.',\n  F: 'Elective deferrals under a section 408(k)(6) salary reduction SEP.',\n  G: 'Elective deferrals and employer contributions (including nonelective deferrals) to any governmental or nongovernmental section 457(b) deferred compensation plan.',\n  H: 'Elective deferrals under section 501(c)(18)(D) tax-exempt organization plan.',\n  J: 'Nontaxable sick pay.',\n  K: '20% excise tax on excess golden parachute payments (not applicable to Forms W-2AS, W-2CM, W-2GU, or W-2VI).',\n  L: 'Substantiated employee business expense reimbursements.',\n  M: 'Uncollected social security or RRTA tax on taxable cost of group-term life insurance over $50,000 (for former employees).',\n  N: 'Uncollected Medicare tax on taxable cost of group-term life insurance over $50,000 (for former employees).',\n  P: 'Excludable moving expense reimbursements paid directly to a member of the U.S. Armed Forces.',\n  Q: 'Nontaxable combat pay.',\n  R: 'Employer contributions to an Archer MSA.',\n  S: 'Employee salary reduction contributions under a section 408(p) SIMPLE plan.',\n  T: 'Adoption benefits.',\n  V: 'Income from the exercise of nonstatutory stock option(s).',\n  W: 'Employer contributions to a health savings account (HSA).',\n  Y: 'Deferrals under a section 409A nonqualified deferred compensation plan.',\n  Z: 'Income under a nonqualified deferred compensation plan that fails to satisfy section 409A.',\n  AA: 'Designated Roth contributions under a section 401(k) plan.',\n  BB: 'Designated Roth contributions under a section 403(b) plan.',\n  DD: 'Cost of employer-sponsored health coverage.',\n  EE: 'Designated Roth contributions under a governmental section 457(b) plan.',\n  FF: 'Permitted benefits under a qualified small employer health reimbursement arrangement.',\n  GG: 'Income from qualified equity grants under section 83(i).',\n  HH: 'Aggregate deferrals under section 83(i) elections as of the close of the calendar year.'\n}\n\nexport type W2Box12Info<A = number> = { [key in W2Box12Code]?: A }\n\nexport interface HealthSavingsAccount<D = Date> {\n  label: string\n  coverageType: 'self-only' | 'family'\n  contributions: number\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  startDate: D\n  endDate: D\n  totalDistributions: number\n  qualifiedDistributions: number\n}\n\nexport type HealthSavingsAccountDateString = HealthSavingsAccount<string>\n\nexport enum IraPlanType {\n  IRA = 'IRA',\n  RothIRA = 'RothIRA',\n  SepIRA = 'SepIRA',\n  SimpleIRA = 'SimpleIRA'\n}\n\nexport const IraPlanTypeTexts = {\n  [IraPlanType.IRA]: 'Traditional IRA',\n  [IraPlanType.RothIRA]: 'Roth IRA',\n  [IraPlanType.SepIRA]: 'Simplified employee pension (SEP) IRA',\n  [IraPlanType.SimpleIRA]:\n    'Savings incentive match plan for employees (SIMPLE) IRA'\n}\n\nexport type IraPlanName = keyof typeof IraPlanType\n\nexport const iraPlanNames: IraPlanName[] = enumKeys(IraPlanType)\n// export const iraPlanNames: IraPlanName[] = [\n//   'IRA',\n//   'RothIRA',\n//   'SepIRA',\n//   'SimpleIRA'\n// ]\n\nexport interface Ira {\n  payer: string\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  // fields about distributions from form 1099-R\n  grossDistribution: number // 1099-R box 1\n  taxableAmount: number // 1099-R box 2a\n  taxableAmountNotDetermined: boolean // 1099-R box 2b\n  totalDistribution: boolean // 1099-R box 2b\n  federalIncomeTaxWithheld: number // 1099-R box 4\n  planType: IraPlanType\n  // fields about contributions from form 5498\n  contributions: number // contributions depending on the plan type\n  rolloverContributions: number // 5498 box 2\n  rothIraConversion: number // 5498 box 3\n  recharacterizedContributions: number // 5498 box 4\n  requiredMinimumDistributions: number // 5498 box 12b\n  lateContributions: number // 5498 box 13a\n  repayments: number // 5498 box 14a\n}\n\nexport enum FilingStatus {\n  S = 'S',\n  MFJ = 'MFJ',\n  MFS = 'MFS',\n  HOH = 'HOH',\n  W = 'W'\n}\n\nexport type FilingStatusName = keyof typeof FilingStatus\n\nexport const FilingStatusTexts = {\n  [FilingStatus.S]: 'Single',\n  [FilingStatus.MFJ]: 'Married Filing Jointly',\n  [FilingStatus.MFS]: 'Married Filing Separately',\n  [FilingStatus.HOH]: 'Head of Household',\n  [FilingStatus.W]: 'Widow(er)'\n}\n\nexport const filingStatuses = <D>(\n  p: TaxPayer<D> | undefined\n): FilingStatus[] => {\n  let withDependents: FilingStatus[] = []\n  let spouseStatuses: FilingStatus[] = []\n\n  if ((p?.dependents ?? []).length > 0) {\n    withDependents = [FilingStatus.HOH]\n  }\n  if (p?.spouse !== undefined) {\n    spouseStatuses = [FilingStatus.MFJ, FilingStatus.MFS]\n    // HoH not available if married\n    withDependents = []\n  } else {\n    spouseStatuses = [FilingStatus.S, FilingStatus.W]\n  }\n  return [...spouseStatuses, ...withDependents]\n}\n\nexport interface ContactInfo {\n  contactPhoneNumber?: string\n  contactEmail?: string\n}\n\nexport interface TaxPayer<D = Date> extends ContactInfo {\n  filingStatus?: FilingStatus\n  primaryPerson?: PrimaryPerson<D>\n  spouse?: Spouse<D>\n  dependents: Dependent<D>[]\n}\n\nexport type TaxPayerDateString = TaxPayer<string>\n\nexport type Income1099Int = Income1099<Income1099Type.INT, F1099IntData>\nexport type Income1099B = Income1099<Income1099Type.B, F1099BData>\nexport type Income1099Div = Income1099<Income1099Type.DIV, F1099DivData>\nexport type Income1099R = Income1099<Income1099Type.R, F1099RData>\nexport type Income1099SSA = Income1099<Income1099Type.SSA, F1099SSAData>\n\nexport type Supported1099 =\n  | Income1099Int\n  | Income1099B\n  | Income1099Div\n  | Income1099R\n  | Income1099SSA\n\nexport enum PropertyType {\n  singleFamily,\n  multiFamily,\n  vacation,\n  commercial,\n  land,\n  selfRental,\n  other\n}\n\nexport type PropertyTypeName = keyof typeof PropertyType\n\nexport enum PropertyExpenseType {\n  advertising,\n  auto,\n  cleaning,\n  commissions,\n  insurance,\n  legal,\n  management,\n  mortgage,\n  otherInterest,\n  repairs,\n  supplies,\n  taxes,\n  utilities,\n  depreciation,\n  other\n}\n\nexport type PropertyExpenseTypeName = keyof typeof PropertyExpenseType\n\nexport interface Property {\n  address: Address\n  rentalDays: number\n  personalUseDays: number\n  rentReceived: number\n  propertyType: PropertyTypeName\n  otherPropertyType?: string\n  qualifiedJointVenture: boolean\n  expenses: Partial<{ [K in PropertyExpenseTypeName]: number }>\n  otherExpenseType?: string\n}\n\nexport interface F1098e {\n  lender: string\n  interest: number\n}\n\nexport interface F3921 {\n  name: string\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  exercisePricePerShare: number\n  fmv: number\n  numShares: number\n}\n\n// See https://www.irs.gov/instructions/i1065sk1\nexport interface ScheduleK1Form1065 {\n  personRole: PersonRole.PRIMARY | PersonRole.SPOUSE\n  partnershipName: string\n  partnershipEin: string\n  partnerOrSCorp: 'P' | 'S'\n  isForeign: boolean\n  isPassive: boolean\n  ordinaryBusinessIncome: number // Schedule E (Form 1040), line 28, column (i) or (k).\n  interestIncome: number // Form 1040, line 2b\n  guaranteedPaymentsForServices: number // Schedule E (Form 1040), line 28, column (k)\n  guaranteedPaymentsForCapital: number // Schedule E (Form 1040), line 28, column (k)\n  selfEmploymentEarningsA: number // Schedule SE (Form 1040)\n  selfEmploymentEarningsB: number // Schedule SE (Form 1040)\n  selfEmploymentEarningsC: number // Schedule SE (Form 1040)\n  distributionsCodeAAmount: number // If the amount shown as code A exceeds the adjusted basis of your partnership interest immediately before the distribution, the excess is treated as gain from the sale or exchange of your partnership interest. Generally, this gain is treated as gain from the sale of a capital asset and should be reported on Form 8949 and the Schedule D for your return.\n  section199AQBI: number // Form 8995 or 8995-A\n}\n\nexport interface ItemizedDeductions {\n  medicalAndDental: string | number\n  stateAndLocalTaxes: string | number\n  isSalesTax: boolean\n  stateAndLocalRealEstateTaxes: string | number\n  stateAndLocalPropertyTaxes: string | number\n  interest8a: string | number\n  interest8b: string | number\n  interest8c: string | number\n  interest8d: string | number\n  investmentInterest: string | number\n  charityCashCheck: string | number\n  charityOther: string | number\n}\n\nexport type State =\n  | 'AL'\n  | 'AK'\n  | 'AZ'\n  | 'CO'\n  | 'DC'\n  | 'FL'\n  | 'HI'\n  | 'ID'\n  | 'IN'\n  | 'KY'\n  | 'MA'\n  | 'ME'\n  | 'MN'\n  | 'MS'\n  | 'NC'\n  | 'NE'\n  | 'NJ'\n  | 'NV'\n  | 'OH'\n  | 'OR'\n  | 'RI'\n  | 'SD'\n  | 'TX'\n  | 'VA'\n  | 'WA'\n  | 'WV'\n  | 'AR'\n  | 'CA'\n  | 'CT'\n  | 'DE'\n  | 'GA'\n  | 'IA'\n  | 'IL'\n  | 'KS'\n  | 'LA'\n  | 'MD'\n  | 'MI'\n  | 'MO'\n  | 'MT'\n  | 'ND'\n  | 'NH'\n  | 'NM'\n  | 'NY'\n  | 'OK'\n  | 'PA'\n  | 'SC'\n  | 'TN'\n  | 'UT'\n  | 'VT'\n  | 'WI'\n  | 'WY'\n\n// Hold information about state residency\n// TODO: Support part-year state residency\nexport interface StateResidency {\n  state: State\n}\n\n// Defines usable tag names for each question later defined,\n// and maps to a type which is the expected response type.\nexport interface QuestionTag {\n  CRYPTO: boolean\n  FOREIGN_ACCOUNT_EXISTS: boolean\n  FINCEN_114: boolean\n  FINCEN_114_ACCOUNT_COUNTRY: string\n  FOREIGN_TRUST_RELATIONSHIP: boolean\n  LIVE_APART_FROM_SPOUSE: boolean\n}\n\nexport type QuestionTagName = keyof QuestionTag\n\n// Typescript provides no way to access\n// keys of an interface at runtime.\nexport const questionTagNames: QuestionTagName[] = [\n  'CRYPTO',\n  'FOREIGN_ACCOUNT_EXISTS',\n  'FINCEN_114',\n  'FINCEN_114_ACCOUNT_COUNTRY',\n  'FOREIGN_TRUST_RELATIONSHIP',\n  'LIVE_APART_FROM_SPOUSE'\n]\n\nexport type ValueTag = 'string' | 'boolean'\n\nexport type Responses = Partial<QuestionTag> // Defines usable tag names for each question later defined,\n\nexport enum CreditType {\n  AdvanceChildTaxCredit = 'CreditType/AdvanceChildTaxCredit',\n  Other = 'CreditType/Other'\n}\n\nexport interface Credit {\n  recipient: PersonRole\n  amount: number\n  type: CreditType\n}\n\nexport interface Information<D = Date> {\n  f1099s: Supported1099[]\n  w2s: IncomeW2[]\n  realEstate: Property[]\n  estimatedTaxes: EstimatedTaxPayments[]\n  f1098es: F1098e[]\n  f3921s: F3921[]\n  scheduleK1Form1065s: ScheduleK1Form1065[]\n  itemizedDeductions: ItemizedDeductions | undefined\n  refund?: Refund\n  taxPayer: TaxPayer<D>\n  questions: Responses\n  credits: Credit[]\n  stateResidencies: StateResidency[]\n  healthSavingsAccounts: HealthSavingsAccount<D>[]\n  individualRetirementArrangements: Ira[]\n}\n\nexport type InformationDateString = Information<string>\n\n/**\n * An asset can be anything that is transactable, such as a stock,\n * bond, mutual fund, real estate, or cryptocurrency, which is not reported\n * on 1099-B. A position always has an open date. A position may\n * be sold, at which time its gain or loss will be reported,\n * or it may be gifted to another person, at which time its\n * gain or loss will not be reported.\n *\n * An asset can be carried across multiple tax years,\n * so it should not be a sibling rather than a member of `Information`.\n *\n * If a position is real estate, then it has a state, which will\n * require state apportionment.\n *\n * \"Closing an asset\" can result in a long-term or short-term capital\n * gain. An asset is closed when it gets a closeDate.\n */\nexport type AssetType = 'Security' | 'Real Estate'\nexport interface Asset<D = Date> {\n  name: string\n  positionType: AssetType\n  openDate: D\n  closeDate?: D\n  giftedDate?: D\n  openPrice: number\n  openFee: number\n  closePrice?: number\n  closeFee?: number\n  quantity: number\n  state?: State\n}\n\nexport type SoldAsset<D> = Asset<D> & {\n  closePrice: number\n  closeDate: D\n}\n\nexport const isSold = <D>(p: Asset<D>): p is SoldAsset<D> => {\n  return p.closeDate !== undefined && p.closePrice !== undefined\n}\n\nexport type AssetString = Asset<string>\n\n// Validated action types:\n\nexport interface ArrayItemEditAction<A> {\n  index: number\n  value: A\n}\n\nexport type EditDependentAction = ArrayItemEditAction<DependentDateString>\nexport type EditW2Action = ArrayItemEditAction<IncomeW2>\nexport type EditEstimatedTaxesAction = ArrayItemEditAction<EstimatedTaxPayments>\nexport type Edit1099Action = ArrayItemEditAction<Supported1099>\nexport type EditPropertyAction = ArrayItemEditAction<Property>\nexport type Edit1098eAction = ArrayItemEditAction<F1098e>\nexport type EditHSAAction = ArrayItemEditAction<HealthSavingsAccountDateString>\nexport type EditIraAction = ArrayItemEditAction<Ira>\nexport type EditAssetAction = ArrayItemEditAction<Asset<Date>>\nexport type EditF3921Action = ArrayItemEditAction<F3921>\nexport type EditScheduleK1Form1065Action =\n  ArrayItemEditAction<ScheduleK1Form1065>\nexport type EditCreditAction = ArrayItemEditAction<Credit>\n"
  },
  {
    "path": "src/core/data/locationPostalCodes.ts",
    "content": "import { State } from '.'\n\nconst locationPostalCodes: Array<[string, State]> = [\n  ['Alabama', 'AL'],\n  ['Alaska', 'AK'],\n  ['Arizona', 'AZ'],\n  ['Arkansas', 'AR'],\n  ['California', 'CA'],\n  ['Colorado', 'CO'],\n  ['Connecticut', 'CT'],\n  ['Delaware', 'DE'],\n  ['Florida', 'FL'],\n  ['Georgia', 'GA'],\n  ['Hawaii', 'HI'],\n  ['Idaho', 'ID'],\n  ['Illinois', 'IL'],\n  ['Indiana', 'IN'],\n  ['Iowa', 'IA'],\n  ['Kansas', 'KS'],\n  ['Kentucky', 'KY'],\n  ['Louisiana', 'LA'],\n  ['Maine', 'ME'],\n  ['Maryland', 'MD'],\n  ['Massachusetts', 'MA'],\n  ['Michigan', 'MI'],\n  ['Minnesota', 'MN'],\n  ['Mississippi', 'MS'],\n  ['Missouri', 'MO'],\n  ['Montana', 'MT'],\n  ['Nebraska', 'NE'],\n  ['Nevada', 'NV'],\n  ['New Hampshire', 'NH'],\n  ['New Jersey', 'NJ'],\n  ['New Mexico', 'NM'],\n  ['New York', 'NY'],\n  ['North Carolina', 'NC'],\n  ['North Dakota', 'ND'],\n  ['Ohio', 'OH'],\n  ['Oklahoma', 'OK'],\n  ['Oregon', 'OR'],\n  ['Pennsylvania', 'PA'],\n  ['Rhode Island', 'RI'],\n  ['South Carolina', 'SC'],\n  ['South Dakota', 'SD'],\n  ['Tennessee', 'TN'],\n  ['Texas', 'TX'],\n  ['Utah', 'UT'],\n  ['Vermont', 'VT'],\n  ['Virginia', 'VA'],\n  ['Washington', 'WA'],\n  ['West Virginia', 'WV'],\n  ['Wisconsin', 'WI'],\n  ['Wyoming', 'WY'],\n  ['District of Columbia', 'DC']\n]\nexport default locationPostalCodes\n"
  },
  {
    "path": "src/core/data/questions.ts",
    "content": "import {\n  FilingStatus,\n  Income1099Type,\n  Information,\n  QuestionTagName,\n  ValueTag\n} from '.'\n\nexport interface Question {\n  text: string\n  required?: (state: Information) => boolean\n  tag: QuestionTagName\n  // This is repeated effort, as it has to mirror value type from QuestionTag:\n  readonly valueTag: ValueTag\n}\n\nfunction q(\n  tag: QuestionTagName,\n  text: string,\n  valueTag: ValueTag,\n  required: (s: Information) => boolean\n): Question {\n  return { text, tag, required, valueTag }\n}\n\nfunction qr(\n  tag: QuestionTagName,\n  text: string,\n  valueTag: ValueTag = 'boolean'\n): Question {\n  return { text, tag, valueTag }\n}\n\nexport const questions: Question[] = [\n  qr('CRYPTO', 'Do you have any crypto-currency transactions?'),\n  qr(\n    'FOREIGN_ACCOUNT_EXISTS',\n    'At any time in this year, did you have a financial interest in or signature authority over a financial account such as a bank account, securities account, or brokerage account) located in a foreign country?'\n  ),\n  q(\n    'FINCEN_114',\n    'Are you required to file FinCEN Form 114, Report of Foreign Bank and Financial Accounts (FBAR), to report that financial interest or signature authority? See FinCEN Form 114 and its instructions for filing requirements and exceptions to those requirements',\n    'boolean',\n    (s: Information) => s.questions.FOREIGN_ACCOUNT_EXISTS ?? false\n  ),\n  q(\n    'FINCEN_114_ACCOUNT_COUNTRY',\n    'Enter the name of the foreign country where the financial account is located',\n    'string',\n    (s: Information) => s.questions.FINCEN_114 ?? false\n  ),\n  qr(\n    'FOREIGN_TRUST_RELATIONSHIP',\n    'During this tax year, did you receive a distribution from, or were you the grantor of, or a transferor to, a foreign trust?'\n  ),\n  q(\n    'LIVE_APART_FROM_SPOUSE',\n    `Did you live apart from your spouse for all of the year?`,\n    'boolean',\n    (s: Information) =>\n      s.taxPayer.filingStatus == FilingStatus.MFS &&\n      s.f1099s.some((i) => i.type == Income1099Type.SSA)\n  )\n]\n\nexport const getRequiredQuestions = (state: Information): Question[] =>\n  questions.filter((q) => q.required === undefined || q.required(state))\n"
  },
  {
    "path": "src/core/data/validate.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport { DefinedError, ValidateFunction } from 'ajv'\nimport log from '../log'\nimport * as fns from './validate-fns'\nimport * as types from 'ustaxes/core/data'\n\n// We will simply throw a runtime error if the data does not\n// validate against the schema.definitions.\nexport const checkType = <A>(data: A, validate: ValidateFunction<A>): A => {\n  validate(data)\n  if ((validate.errors ?? undefined) !== undefined) {\n    // Taken from doc example: The type cast is needed to allow user-defined keywords and errors\n    // You can extend this type to include your error types as needed.\n\n    const errs = validate.errors as DefinedError[]\n\n    for (const err of errs) {\n      log.error(err.message)\n    }\n\n    log.error(validate.errors)\n    log.error(data)\n\n    const errorMessage =\n      validate.errors\n        ?.map((e) => `${e.instancePath}: ${e.message ?? ''}`)\n        .join('\\n') ?? 'Unknown error'\n\n    validate.errors?.forEach(console.error)\n    throw new Error(`Validation Failed: ${errorMessage}`)\n  }\n\n  return data\n}\n\nexport const index = fns.Index as ValidateFunction<number>\nexport const personRole = fns.PersonRole as ValidateFunction<types.PersonRole>\nexport const contactInfo =\n  fns.ContactInfo as ValidateFunction<types.ContactInfo>\nexport const address = fns.Address as ValidateFunction<types.Address>\nexport const accountType =\n  fns.AccountType as ValidateFunction<types.AccountType>\nexport const employer = fns.Employer as ValidateFunction<types.Employer>\nexport const filingStatus =\n  fns.FilingStatus as ValidateFunction<types.FilingStatus>\nexport const primaryPerson =\n  fns.PrimaryPerson as ValidateFunction<types.PrimaryPersonDateString>\nexport const spouse = fns.Spouse as ValidateFunction<types.SpouseDateString>\nexport const person = fns.Person as ValidateFunction<types.PersonDateString>\nexport const dependent =\n  fns.Dependent as ValidateFunction<types.DependentDateString>\nexport const f1099IntData =\n  fns.F1099IntData as ValidateFunction<types.F1099IntData>\nexport const f1099BData = fns.F1099BData as ValidateFunction<types.F1099BData>\nexport const income1099Int =\n  fns.Income1099Int as ValidateFunction<types.Income1099Int>\nexport const income1099B =\n  fns.Income1099B as ValidateFunction<types.Income1099B>\nexport const supported1099 =\n  fns.Supported1099 as ValidateFunction<types.Supported1099>\nexport const incomeW2 = fns.IncomeW2 as ValidateFunction<types.IncomeW2>\nexport const estimatedTaxPayments =\n  fns.EstimatedTaxPayments as ValidateFunction<types.EstimatedTaxPayments>\nexport const refund = fns.Refund as ValidateFunction<types.Refund>\nexport const taxPayer =\n  fns.TaxPayer as ValidateFunction<types.TaxPayerDateString>\nexport const information =\n  fns.Information as ValidateFunction<types.InformationDateString>\nexport const property = fns.Property as ValidateFunction<types.Property>\nexport const propertyType =\n  fns.PropertyType as ValidateFunction<types.PropertyType>\nexport const f1098e = fns.F1098e as ValidateFunction<types.F1098e>\nexport const itemizedDeductions =\n  fns.ItemizedDeductions as ValidateFunction<types.ItemizedDeductions>\nexport const responses = fns.Responses as ValidateFunction<types.Responses>\nexport const stateResidency =\n  fns.StateResidency as ValidateFunction<types.StateResidency>\nexport const healthSavingsAccount =\n  fns.HealthSavingsAccount as ValidateFunction<types.HealthSavingsAccountDateString>\nexport const ira = fns.Ira as ValidateFunction<types.Ira>\nexport const assetType = fns.AssetType as ValidateFunction<types.AssetType>\nexport const assetString =\n  fns.AssetString as ValidateFunction<types.AssetString>\nexport const taxYear = fns.TaxYear as ValidateFunction<types.TaxYear>\nexport const credit = fns.Credit as ValidateFunction<types.Credit>\n\nexport const editIraAction =\n  fns.EditIRAAction as ValidateFunction<types.EditIraAction>\nexport const editHSAAction =\n  fns.EditHSAAction as ValidateFunction<types.EditHSAAction>\nexport const editCreditAction =\n  fns.EditCreditAction as ValidateFunction<types.EditCreditAction>\n"
  },
  {
    "path": "src/core/irsForms/Form.ts",
    "content": "import Fill from '../pdfFiller/Fill'\n\nexport type FormTag = string\n\n/**\n * Base interface for what every form implementation should include.\n * Any PDF can be filled from an array of values.\n *\n */\nexport default abstract class Form extends Fill {\n  // Match the filename without extension when downloaded from IRS\n  abstract tag: FormTag\n  // Match the sequence number in the header of the PDF.\n  abstract sequenceIndex: number\n\n  public toString = (): string => `\n    Form ${this.tag}, at sequence ${this.sequenceIndex}\n  `\n}\n"
  },
  {
    "path": "src/core/irsForms/index.ts",
    "content": "import { PDFDocument } from 'pdf-lib'\nimport _ from 'lodash'\nimport { getPdfs, PDFDownloader } from '../pdfFiller/pdfHandler'\nimport Form from './Form'\n\nexport const insertFormDataToPdfs = async (\n  forms: Form[],\n  downloader: PDFDownloader\n): Promise<PDFDocument[]> => {\n  const pdfs: PDFDocument[] = await Promise.all(\n    forms.map(async (f) => await downloader(`/irs/${f.tag}.pdf`))\n  )\n\n  return getPdfs(_.zipWith(forms, pdfs, (a, b) => [a, b]))\n}\n"
  },
  {
    "path": "src/core/irsForms/util.ts",
    "content": "export const displayRound = (n: number | undefined): number | undefined =>\n  Math.round(n ?? 0) === 0 ? undefined : Math.round(n ?? 0)\n\nexport const displayNegPos = (n: number | undefined): string => {\n  const r = Math.round(n ?? 0)\n  if (r === 0) return ''\n  if (r < 0) return `(${Math.abs(r)})`\n  return r.toString()\n}\n\nexport const sumFields = (fs: Array<number | undefined>): number =>\n  fs.reduce<number>((l, r) => l + (r ?? 0), 0)\n"
  },
  {
    "path": "src/core/log.ts",
    "content": "import log from 'loglevel'\n\nconst { TRACE, ERROR } = log.levels\n\nlog.setDefaultLevel(process.env.NODE_ENV === 'development' ? TRACE : ERROR)\n\nexport default log\n"
  },
  {
    "path": "src/core/pdfFiller/Fill.ts",
    "content": "import { Field, RenderedField } from '.'\n\nexport const fieldIsNumber = (field: Field): field is number =>\n  typeof field === 'number' || (!Number.isNaN(field) && Number.isFinite(field))\n\nexport default abstract class Fill {\n  abstract fields: () => Field[]\n\n  renderedFields = (): RenderedField[] =>\n    this.fields().map((field) => {\n      if (fieldIsNumber(field)) {\n        if (Number.isInteger(field)) {\n          return field.toString()\n        }\n        return field.toFixed(2).toString()\n      } else {\n        return field\n      }\n    })\n}\n"
  },
  {
    "path": "src/core/pdfFiller/fillPdf.ts",
    "content": "import { PDFDocument, PDFCheckBox, PDFTextField, PDFName } from 'pdf-lib'\nimport { Field } from '.'\nimport { displayRound } from '../irsForms/util'\nimport _ from 'lodash'\n\n/**\n * Attempt to fill fields in a PDF from a Form,\n * checking one by one that each pdf field and Form value\n * Make sense by type (checkbox => boolean, textField => string / number)\n * Side-effecting! Modifies the pdf document.\n */\nexport function fillPDF(pdf: PDFDocument, fieldValues: Field[]): PDFDocument {\n  const formFields = pdf.getForm().getFields()\n\n  formFields.forEach((pdfField, index) => {\n    const value: Field = fieldValues[index]\n\n    const error = (expected: string): Error => {\n      return new Error(\n        `Field ${index}, ${pdfField.getName()} expected ${expected}`\n      )\n    }\n    // First handle radio groups. If the value for this field\n    // is a RadioSelect object, then assume the pdfField\n    // has children, and check the correct box given the index value.\n    // Idea taken from this comment:\n    // https://github.com/Hopding/pdf-lib/issues/780#issuecomment-771453157\n    // Note, this is for cases such as the 2021 IL-1040 where the field\n    // behaves as a radio group, but the pdfField is a PDFCheckbox\n    // instead of a PDFRadioGroup.\n    if (_.isObject(value)) {\n      const children = pdfField.acroField.getWidgets()\n      if (value.select >= children.length) {\n        throw new Error(\n          `Error in field ${index}, expected to select child at index ${value.select} but this node has only ${children.length} children.`\n        )\n      }\n      const setValue = children[value.select].getOnValue()\n      if (setValue !== undefined) {\n        pdfField.acroField.dict.set(PDFName.of('V'), setValue)\n        children[value.select].setAppearanceState(setValue)\n      } else {\n        console.error(children)\n        throw new Error(\n          `Error handling RadioGroup, could not set index ${value.select}`\n        )\n      }\n    } else if (pdfField instanceof PDFCheckBox) {\n      if (value === true) {\n        pdfField.check()\n      } else if (value !== false && value !== undefined) {\n        throw error('boolean')\n      }\n    } else if (pdfField instanceof PDFTextField) {\n      try {\n        const showValue = !isNaN(value as number)\n          ? displayRound(value as number | undefined)?.toString()\n          : value?.toString()\n        pdfField.setText(showValue)\n      } catch (err) {\n        throw error('text field')\n      }\n    } else if (value !== undefined) {\n      throw error('unknown')\n    }\n    pdfField.enableReadOnly()\n  })\n\n  return pdf\n}\n"
  },
  {
    "path": "src/core/pdfFiller/index.ts",
    "content": "export interface RadioSelect {\n  select: number\n}\nexport type Field = string | number | boolean | RadioSelect | undefined\nexport type RenderedField = string | boolean | RadioSelect | undefined\n"
  },
  {
    "path": "src/core/pdfFiller/pdfHandler.ts",
    "content": "import { PDFDocument } from 'pdf-lib'\nimport Fill from './Fill'\nimport { fillPDF } from './fillPdf'\n\nexport interface FileDownloader<T> {\n  (url: string): Promise<T>\n}\n\nexport type PDFDownloader = FileDownloader<PDFDocument>\n\nexport const downloadPDF: PDFDownloader = async (url) => {\n  const download = await fetch(url)\n  const buffer = await download.arrayBuffer()\n  return await PDFDocument.load(buffer)\n}\n\nexport const combinePdfs = async (\n  pdfFiles: PDFDocument[]\n): Promise<PDFDocument> => {\n  const [head, ...rest] = await Promise.all(\n    pdfFiles.map(async (pdf) => PDFDocument.load(await pdf.save()))\n  )\n\n  // Make sure we combine the documents from left to right and preserve order\n  return rest.reduce(async (l, r) => {\n    const doc = await PDFDocument.load(await (await l).save())\n    return await doc.copyPages(r, r.getPageIndices()).then((pgs) => {\n      pgs.forEach((p) => doc.addPage(p))\n      return doc\n    })\n  }, Promise.resolve(head))\n}\n\nexport const getPdfs = async (\n  formData: Array<[Fill, PDFDocument]>\n): Promise<PDFDocument[]> => {\n  // Insert the values from each field into the PDF\n  const pdfFiles: Array<Promise<PDFDocument>> = formData.map(\n    async ([data, f]) => {\n      fillPDF(f, data.renderedFields())\n      const pageBytes = await f.save()\n      return await PDFDocument.load(pageBytes)\n    }\n  )\n\n  return await Promise.all(pdfFiles)\n}\n"
  },
  {
    "path": "src/core/stateForms/Form.ts",
    "content": "import Fill from '../pdfFiller/Fill'\nimport { IncomeW2, State } from '../data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\n/**\n * Represents a state's income tax form, or schedule\n */\nexport default abstract class Form extends Fill {\n  abstract state: State\n  abstract formName: string\n  abstract formOrder: number\n  abstract attachments: () => Form[]\n  abstract info: ValidatedInformation\n}\n\n/**\n * Methods that would apply to any state tax form\n */\nexport class FormMethods {\n  form: Form\n\n  constructor(form: Form) {\n    this.form = form\n  }\n\n  stateW2s = (): IncomeW2[] =>\n    this.form.info.w2s.filter((w2) => w2.state === this.form.state)\n\n  stateWithholding = (): number =>\n    this.stateW2s().reduce(\n      (withholding, w2) => withholding + (w2.stateWithholding ?? 0),\n      0\n    )\n\n  witholdingForState = (state: State) =>\n    this.stateW2s()\n      .filter((w2) => w2.state === state)\n      .reduce((withholding, w2) => withholding + (w2.stateWithholding ?? 0), 0)\n}\n"
  },
  {
    "path": "src/core/stateForms/index.ts",
    "content": "import _ from 'lodash'\nimport { PDFDocument } from 'pdf-lib'\nimport { fillPDF } from '../pdfFiller/fillPdf'\nimport { combinePdfs, PDFDownloader } from '../pdfFiller/pdfHandler'\nimport Form from './Form'\n\nexport const createStatePDF =\n  (forms: Form[]) =>\n  async (downloader: PDFDownloader): Promise<PDFDocument> => {\n    const filenames = forms.map(\n      (form) => `/states/${form.state}/${form.formName}.pdf`\n    )\n\n    const pdfs = filenames.map(downloader)\n\n    const filled: Array<Promise<PDFDocument>> = _.zipWith(\n      pdfs,\n      forms,\n      async (pdf, form) => {\n        fillPDF(await pdf, form.fields())\n        return pdf\n      }\n    )\n\n    return combinePdfs(await Promise.all(filled))\n  }\n"
  },
  {
    "path": "src/core/tests/LocalForms.ts",
    "content": "import { PDFDocument } from 'pdf-lib'\nimport {\n  FileDownloader,\n  PDFDownloader\n} from 'ustaxes/core/pdfFiller/pdfHandler'\nimport fs from 'fs/promises'\nimport path from 'path'\nimport { TaxYear } from 'ustaxes/core/data'\n\nconst localPath = (url: string) => path.join(__dirname, '../../../public', url)\n\nexport const localFiles: FileDownloader<Uint8Array> = (\n  url: string\n): Promise<Uint8Array> => fs.readFile(localPath(url))\n\nconst compiledPDFs: { [key: string]: PDFDocument } = {}\n\nexport const localPDFs =\n  (y: TaxYear): PDFDownloader =>\n  async (url: string): Promise<PDFDocument> => {\n    const fileUrl = `/forms/${y}/${url}`\n\n    const lookedUpAt = localPath(fileUrl)\n\n    if (lookedUpAt in compiledPDFs) {\n      return compiledPDFs[lookedUpAt]\n    }\n\n    const bytes = await localFiles(fileUrl)\n\n    const pdf = await PDFDocument.load(bytes.buffer)\n\n    compiledPDFs[lookedUpAt] = pdf\n\n    return pdf\n  }\n"
  },
  {
    "path": "src/core/tests/arbitraries.ts",
    "content": "import * as fc from 'fast-check'\nimport { Arbitrary } from 'fast-check'\nimport locationPostalCodes from '../data/locationPostalCodes'\nimport { QuestionTagName, questionTagNames, Responses } from '../data'\nimport * as types from '../data'\nimport * as util from '../util'\nimport _ from 'lodash'\nimport {\n  ValidatedInformation,\n  ValidatedTaxpayer\n} from 'ustaxes/forms/F1040Base'\nimport { blankYearTaxesState, YearsTaxesState } from 'ustaxes/redux'\n\nconst lower: Arbitrary<string> = fc\n  .integer({ min: 0x61, max: 0x7a })\n  .map((n) => String.fromCharCode(n))\n\nconst upper: Arbitrary<string> = fc\n  .integer({ min: 0x41, max: 0x5a })\n  .map((n) => String.fromCharCode(n))\n\nexport const word: Arbitrary<string> = fc\n  .array(fc.oneof(lower, upper))\n  .map((xs) => xs.join(''))\n\nexport const words: Arbitrary<string> = fc.array(word).map((xs) => xs.join(' '))\n\nconst maxWords = (max: number): Arbitrary<string> =>\n  fc\n    .integer({ min: 1, max })\n    .chain((maxLength) =>\n      fc.array(word, { minLength: 1, maxLength }).map((xs) => xs.join(' '))\n    )\n\nconst natStr: Arbitrary<string> = fc.nat().map((n) => n.toString())\n\nconst numStr = (len: number): Arbitrary<string> =>\n  fc\n    .array(fc.nat({ max: 9 }), { minLength: len, maxLength: len })\n    .map((x) => x.join(''))\n\nexport const state = fc.constantFrom(\n  ...locationPostalCodes.map(([, code]) => code)\n)\n\nconst concat = (\n  as: Arbitrary<string>,\n  bs: Arbitrary<string>,\n  sep = ' '\n): Arbitrary<string> => as.chain((a) => bs.map((b) => `${a}${sep}${b}`))\n\n// Ideally these would be normally distributed...\nconst wages: Arbitrary<number> = fc.nat({ max: 10000000 })\nconst posCurrency = (max: number): Arbitrary<number> =>\n  fc.nat({ max: max * 100 }).map((x) => x / 100)\nconst posNegCurrency = (max: number): Arbitrary<number> =>\n  fc\n    .integer({\n      min: -max * 100,\n      max: max * 100\n    })\n    .map((x) => x / 100)\nconst investment = posCurrency(100000)\nconst investmentResult = posNegCurrency(100000)\nconst expense: Arbitrary<number> = posCurrency(10000)\nconst interest: Arbitrary<number> = posCurrency(10000)\nconst payment: Arbitrary<number> = fc.nat({ max: 100000 })\nconst ssWitholding: Arbitrary<number> = fc.nat({ max: 10000 })\n\nconst payerName: Arbitrary<string> = maxWords(3)\n\nconst ein: Arbitrary<string> = numStr(9)\nconst zip: Arbitrary<string> = fc.oneof(numStr(5), numStr(9))\nconst routing: Arbitrary<string> = numStr(9)\nconst account: Arbitrary<string> = fc\n  .integer({ min: 4, max: 17 })\n  .chain((len) => numStr(len))\n\nconst email = fc\n  .tuple(word, word, word)\n  .map(([w1, w2, w3]) => `${w1}@${w2}.${w3}`)\nconst phoneNumber = numStr(10)\n\nconst address: Arbitrary<types.Address> = fc\n  .tuple(concat(natStr, words), natStr, words, state, zip)\n  .map(([address, aptNo, city, state, zip]) => ({\n    address,\n    aptNo,\n    city,\n    state,\n    zip\n  }))\n\nconst employer: Arbitrary<types.Employer> = fc\n  .tuple(ein, fc.string({ minLength: 1 }), address)\n  .map(([EIN, employerName, address]) => ({\n    EIN,\n    employerName,\n    address\n  }))\n\nconst w2Box12Info = (max: number): Arbitrary<types.W2Box12Info> =>\n  fc.dictionary(\n    fc.constantFrom(...util.enumKeys(types.W2Box12Code)),\n    fc.nat({ max })\n  )\n\nconst w2: Arbitrary<types.IncomeW2> = wages.chain((income) =>\n  fc\n    .tuple(\n      maxWords(2),\n      fc.nat({ max: 2 * income }),\n      fc.nat({ max: income }),\n      fc.nat({ max: income }),\n      ssWitholding,\n      fc.nat({ max: income }),\n      employer,\n      w2Box12Info(income),\n      state,\n      fc.nat({ max: income }),\n      fc.nat({ max: income })\n    )\n    .map(\n      ([\n        occupation,\n        medicareIncome,\n        fedWithholding,\n        ssWages,\n        ssWithholding,\n        medicareWithholding,\n        employer,\n        box12,\n        state,\n        stateWages,\n        stateWithholding\n      ]) => ({\n        occupation,\n        income,\n        medicareIncome,\n        fedWithholding,\n        employer,\n        personRole: types.PersonRole.PRIMARY,\n        ssWages,\n        ssWithholding,\n        medicareWithholding,\n        state,\n        stateWages,\n        stateWithholding,\n        box12\n      })\n    )\n)\n\nexport const f1099IntData: Arbitrary<types.F1099IntData> = fc\n  .nat()\n  .map((income) => ({ income }))\n\nexport const f1099DivData: Arbitrary<types.F1099DivData> = interest.chain(\n  (dividends) =>\n    fc\n      .tuple(fc.nat({ max: Math.round(dividends * 100) }), posCurrency(100000))\n      .map(([qdiv, totalCapitalGainsDistributions]) => ({\n        dividends,\n        qualifiedDividends: qdiv / 100,\n        totalCapitalGainsDistributions\n      }))\n)\n\nexport const f1099BData: Arbitrary<types.F1099BData> = fc\n  .tuple(investmentResult, investment, investmentResult, investment)\n  .map(\n    ([\n      shortTermProceeds,\n      shortTermCostBasis,\n      longTermProceeds,\n      longTermCostBasis\n    ]) => ({\n      shortTermProceeds,\n      shortTermCostBasis,\n      longTermProceeds,\n      longTermCostBasis\n    })\n  )\n\nexport const f1099Int: Arbitrary<types.Income1099Int> = fc\n  .tuple(payerName, f1099IntData)\n  .map(([payer, form]) => ({\n    type: types.Income1099Type.INT,\n    form,\n    payer,\n    personRole: types.PersonRole.PRIMARY\n  }))\n\nexport const f1099B: Arbitrary<types.Income1099B> = fc\n  .tuple(payerName, f1099BData)\n  .map(([payer, form]) => ({\n    type: types.Income1099Type.B,\n    form,\n    payer,\n    personRole: types.PersonRole.PRIMARY\n  }))\n\nexport const f1099Div: Arbitrary<types.Income1099Div> = fc\n  .tuple(payerName, f1099DivData)\n  .map(([payer, form]) => ({\n    type: types.Income1099Type.DIV,\n    form,\n    payer,\n    personRole: types.PersonRole.PRIMARY\n  }))\n\nexport const f1099: Arbitrary<types.Supported1099> = fc.oneof(\n  f1099B,\n  f1099Div,\n  f1099Int\n)\n\nconst propExpenseTypeName: Arbitrary<types.PropertyExpenseTypeName> =\n  fc.constantFrom(...util.enumKeys(types.PropertyExpenseType))\n\nconst propertyType: Arbitrary<types.PropertyTypeName> = fc.constantFrom(\n  ...util.enumKeys(types.PropertyType)\n)\n\nconst propertyExpenses: Arbitrary<\n  Partial<{ [K in types.PropertyExpenseTypeName]: number }>\n> = fc.set(propExpenseTypeName).chain((es) =>\n  fc\n    .array(expense, { minLength: es.length, maxLength: es.length })\n    .map((nums) =>\n      _.chain(es)\n        .zipWith(nums, (e, num) => [e, num])\n        .fromPairs()\n        .value()\n    )\n)\n\nconst f1098e: Arbitrary<types.F1098e> = fc\n  .tuple(maxWords(2), interest)\n  .map(([lender, interest]) => ({\n    lender,\n    interest\n  }))\n\nconst f3921: Arbitrary<types.F3921> = fc\n  .tuple(maxWords(2), posCurrency(100), fc.integer({ min: 1, max: 500 }))\n  .map(([name, exercisePricePerShare, numShares]) => {\n    const fmv = exercisePricePerShare + 1\n    return {\n      name,\n      personRole: types.PersonRole.PRIMARY,\n      exercisePricePerShare,\n      fmv,\n      numShares\n    }\n  })\n\nconst scheduleK1Form1065: Arbitrary<types.ScheduleK1Form1065> = fc\n  .tuple(\n    maxWords(2),\n    ein,\n    posCurrency(1000000),\n    posCurrency(100000),\n    posCurrency(100000),\n    posCurrency(100000),\n    posCurrency(100000),\n    posCurrency(100000),\n    posCurrency(100000),\n    posCurrency(100000),\n    posCurrency(100000)\n  )\n  .map(\n    ([\n      partnershipName,\n      ein,\n      ordinaryBusinessIncome,\n      interestIncome,\n      guaranteedPaymentsForServices,\n      guaranteedPaymentsForCapital,\n      selfEmploymentEarningsA,\n      selfEmploymentEarningsB,\n      selfEmploymentEarningsC,\n      distributionsCodeAAmount,\n      section199AQBI\n    ]) => {\n      return {\n        personRole: types.PersonRole.PRIMARY,\n        partnershipName,\n        partnershipEin: ein,\n        partnerOrSCorp: 'P',\n        isForeign: false,\n        isPassive: false,\n        ordinaryBusinessIncome,\n        interestIncome,\n        guaranteedPaymentsForServices,\n        guaranteedPaymentsForCapital,\n        selfEmploymentEarningsA,\n        selfEmploymentEarningsB,\n        selfEmploymentEarningsC,\n        distributionsCodeAAmount,\n        section199AQBI\n      }\n    }\n  )\n\nconst itemizedDeductions: Arbitrary<types.ItemizedDeductions> = fc\n  .tuple(\n    posCurrency(2500),\n    posCurrency(12500),\n    fc.boolean(),\n    posCurrency(10000),\n    posCurrency(5000),\n    posCurrency(10000),\n    posCurrency(10000),\n    posCurrency(10000),\n    posCurrency(10000),\n    posCurrency(10000),\n    posCurrency(7500),\n    posCurrency(2500),\n    posCurrency(1000)\n  )\n  .map(\n    ([\n      medicalAndDental,\n      stateAndLocalTaxes,\n      isSalesTax,\n      stateAndLocalRealEstateTaxes,\n      stateAndLocalPropertyTaxes,\n      interest8a,\n      interest8b,\n      interest8c,\n      interest8d,\n      investmentInterest,\n      charityCashCheck,\n      charityOther\n    ]) => ({\n      medicalAndDental,\n      stateAndLocalTaxes,\n      isSalesTax,\n      stateAndLocalRealEstateTaxes,\n      stateAndLocalPropertyTaxes,\n      interest8a,\n      interest8b,\n      interest8c,\n      interest8d,\n      investmentInterest,\n      charityCashCheck,\n      charityOther\n    })\n  )\n\nconst estTax: Arbitrary<types.EstimatedTaxPayments> = fc\n  .tuple(maxWords(5), payment)\n  .map(([label, payment]) => ({\n    label,\n    payment\n  }))\n\nexport const accountType: Arbitrary<types.AccountType> = fc.constantFrom(\n  types.AccountType.checking,\n  types.AccountType.savings\n)\n\nexport const refund: Arbitrary<types.Refund> = fc\n  .tuple(routing, account, accountType)\n  .map(([routingNumber, accountNumber, accountType]) => ({\n    routingNumber,\n    accountNumber,\n    accountType\n  }))\n\nexport const filingStatus: Arbitrary<types.FilingStatus> = fc.constantFrom(\n  ...util.enumKeys(types.FilingStatus).map((x) => types.FilingStatus[x])\n)\n\nexport const person: Arbitrary<types.Person> = fc\n  .tuple(\n    word,\n    word,\n    ein,\n    fc.boolean(),\n    fc.date({\n      min: new Date(1900, 0, 1),\n      max: new Date()\n    })\n  )\n  .map(([firstName, lastName, ssid, isBlind, dateOfBirth]) => ({\n    firstName,\n    lastName,\n    ssid,\n    isBlind,\n    dateOfBirth,\n    role: types.PersonRole.PRIMARY\n  }))\n\nexport const primaryPerson: Arbitrary<types.PrimaryPerson> = fc\n  .tuple(person, address, fc.boolean())\n  .map(([person, address, isTaxpayerDependent]) => ({\n    ...person,\n    address,\n    isTaxpayerDependent\n  }))\n\nexport const spouse: Arbitrary<types.Spouse> = fc\n  .tuple(person, fc.boolean())\n  .map(([person, isTaxpayerDependent]) => ({\n    ...person,\n    isTaxpayerDependent\n  }))\n\nconst questionTag: Arbitrary<QuestionTagName> = fc.constantFrom(\n  ...questionTagNames\n)\n\n// make sure that the question tag maps to values of correct type.\nconst questionTagArbs = {\n  CRYPTO: fc.boolean(),\n  FOREIGN_ACCOUNT_EXISTS: fc.boolean(),\n  FINCEN_114: fc.boolean(),\n  FINCEN_114_ACCOUNT_COUNTRY: words,\n  FOREIGN_TRUST_RELATIONSHIP: fc.boolean(),\n  LIVE_APART_FROM_SPOUSE: fc.boolean()\n}\n\nexport const questions: Arbitrary<Responses> = fc\n  .uniqueArray(questionTag, { comparator: 'IsStrictlyEqual' })\n  .chain((tags) =>\n    fc\n      .tuple(...tags.map((t) => questionTagArbs[t].map((v) => [t, v])))\n      .map((kvs) => Object.fromEntries(kvs) as Responses)\n  )\n\n// const iraPlan: Arbitrary<IraPlanName> = fc.constantFrom(...iraPlanNames)\n\nexport class Arbitraries {\n  currentYear: number\n\n  constructor(currentYear: number) {\n    this.currentYear = currentYear\n  }\n\n  daysInYear = (): Arbitrary<number> =>\n    fc.nat({\n      max: util.daysInYear(this.currentYear)\n    })\n\n  daysInYearPair = (): Arbitrary<[number, number]> =>\n    this.daysInYear().chain((d) =>\n      fc\n        .nat({ max: util.daysInYear(this.currentYear) - d })\n        .map((d2) => [d, d2])\n    )\n\n  birthYear = (): Arbitrary<number> =>\n    fc.integer({\n      min: 1900,\n      max: this.currentYear\n    })\n\n  property = (): Arbitrary<types.Property> =>\n    fc\n      .tuple(\n        address,\n        this.daysInYearPair(),\n        investment,\n        propertyType,\n        words,\n        fc.boolean(),\n        propertyExpenses\n      )\n      .map(\n        ([\n          address,\n          [rentalDays, personalUseDays],\n          rentReceived,\n          propertyType,\n          otherPropertyType,\n          qualifiedJointVenture,\n          expenses\n        ]) => ({\n          address,\n          rentalDays,\n          personalUseDays,\n          rentReceived,\n          propertyType,\n          otherPropertyType,\n          qualifiedJointVenture,\n          expenses\n        })\n      )\n\n  qualifyingInformation = (): Arbitrary<types.QualifyingInformation> =>\n    fc\n      .tuple(fc.nat({ max: 12 }), fc.boolean())\n      .map(([numberOfMonths, isStudent]) => ({\n        numberOfMonths,\n        isStudent\n      }))\n\n  dependent = (): Arbitrary<types.Dependent> =>\n    fc\n      .tuple(person, word, this.qualifyingInformation())\n      .map(([person, relationship, qualifyingInfo]) => ({\n        ...person,\n        relationship,\n        qualifyingInfo\n      }))\n\n  taxPayer = (): Arbitrary<ValidatedTaxpayer> =>\n    fc\n      .tuple(\n        filingStatus,\n        primaryPerson,\n        fc.oneof(spouse, fc.constant(undefined)),\n        fc.array(this.dependent()),\n        email,\n        phoneNumber\n      )\n      .map(\n        ([\n          filingStatus,\n          primaryPerson,\n          spouse,\n          dependents,\n          contactEmail,\n          contactPhoneNumber\n        ]) => ({\n          filingStatus,\n          primaryPerson,\n          spouse,\n          dependents,\n          contactEmail,\n          contactPhoneNumber\n        })\n      )\n      // Ensure we don't generate an invalid filing status.\n      .chain((tp) =>\n        fc\n          .constantFrom(...types.filingStatuses(tp))\n          .map((fs) => ({ ...tp, filingStatus: fs }))\n      )\n\n  healthSavingsAccount = (): Arbitrary<types.HealthSavingsAccount> =>\n    fc\n      .tuple(\n        words,\n        fc.constantFrom<'self-only' | 'family'>('self-only', 'family'),\n        fc.nat({ max: 100000 }),\n        fc.constantFrom<types.PersonRole.PRIMARY | types.PersonRole.SPOUSE>(\n          types.PersonRole.PRIMARY,\n          types.PersonRole.SPOUSE\n        ),\n        fc.date({\n          min: new Date(this.currentYear, 0, 1),\n          max: new Date(this.currentYear, 11, 31)\n        }),\n        fc.date({\n          min: new Date(this.currentYear, 0, 1),\n          max: new Date(this.currentYear, 11, 31)\n        }),\n        fc.nat({ max: 100000 }),\n        fc.nat({ max: 100000 })\n      )\n      .map(\n        ([\n          label,\n          coverageType,\n          contributions,\n          personRole,\n          startDate,\n          endDate,\n          totalDistributions,\n          qualifiedDistributions\n        ]) => ({\n          label,\n          coverageType,\n          contributions,\n          personRole,\n          startDate,\n          endDate,\n          totalDistributions,\n          qualifiedDistributions\n        })\n      )\n\n  ira = (): Arbitrary<types.Ira> =>\n    fc\n      .tuple(\n        words, //payer\n        fc.constantFrom<types.PersonRole.PRIMARY | types.PersonRole.SPOUSE>(\n          types.PersonRole.PRIMARY,\n          types.PersonRole.SPOUSE\n        ),\n        fc.nat({ max: 100000 }), // gross distribution\n        fc.nat({ max: 100000 }), // taxable amount\n        fc.boolean(), // taxable amount not determined\n        fc.boolean(), // total distribution\n        fc.nat({ max: 100000 }), // federal income tax withheld\n        fc.constantFrom<types.IraPlanType>(\n          types.IraPlanType.IRA,\n          types.IraPlanType.SepIRA,\n          types.IraPlanType.SimpleIRA,\n          types.IraPlanType.RothIRA\n        ), // plan type\n        fc.nat({ max: 100000 }), // contributions\n        fc.nat({ max: 100000 }), // rollover contributions\n        fc.nat({ max: 100000 }), // roth IRA conversion\n        fc.nat({ max: 100000 }), // recharacterized contributions\n        fc.nat({ max: 100000 }), // required minimum distributions\n        fc.nat({ max: 100000 }), // late contributions\n        fc.nat({ max: 100000 })\n      )\n      .map(\n        ([\n          payer,\n          personRole,\n          grossDistribution,\n          taxableAmount,\n          taxableAmountNotDetermined,\n          totalDistribution,\n          federalIncomeTaxWithheld,\n          planType,\n          contributions,\n          rolloverContributions,\n          rothIraConversion,\n          recharacterizedContributions,\n          requiredMinimumDistributions,\n          lateContributions,\n          repayments\n        ]) => ({\n          payer,\n          personRole,\n          grossDistribution,\n          taxableAmount,\n          taxableAmountNotDetermined,\n          totalDistribution,\n          federalIncomeTaxWithheld,\n          planType,\n          contributions,\n          rolloverContributions,\n          rothIraConversion,\n          recharacterizedContributions,\n          requiredMinimumDistributions,\n          lateContributions,\n          repayments\n        })\n      )\n\n  credit = (): Arbitrary<types.Credit> =>\n    fc.tuple(fc.nat({ max: 100000 }).map((x) => x / 100)).map(([amount]) => ({\n      recipient: types.PersonRole.PRIMARY,\n      amount,\n      type: types.CreditType.AdvanceChildTaxCredit\n    }))\n\n  information = (): Arbitrary<ValidatedInformation> =>\n    fc\n      .tuple(\n        fc.array(f1099),\n        fc.array(w2),\n        fc.array(this.property()),\n        fc.array(estTax),\n        fc.array(f1098e),\n        fc.array(f3921),\n        fc.array(scheduleK1Form1065),\n        itemizedDeductions,\n        refund,\n        this.taxPayer(),\n        questions,\n        state,\n        fc.array(this.healthSavingsAccount()),\n        fc.array(this.credit(), { maxLength: 2 }),\n        fc.array(this.ira())\n      )\n      .map(\n        ([\n          f1099s,\n          w2s,\n          realEstate,\n          estimatedTaxes,\n          f1098es,\n          f3921s,\n          scheduleK1Form1065s,\n          itemizedDeductions,\n          refund,\n          taxPayer,\n          questions,\n          state,\n          healthSavingsAccounts,\n          credits,\n          individualRetirementArrangements\n        ]) => ({\n          f1099s,\n          w2s,\n          realEstate,\n          estimatedTaxes,\n          f1098es,\n          f3921s,\n          scheduleK1Form1065s,\n          itemizedDeductions,\n          refund,\n          taxPayer,\n          questions,\n          stateResidencies: [{ state }],\n          healthSavingsAccounts,\n          credits,\n          individualRetirementArrangements\n        })\n      )\n}\n\nexport const forYear = (year: number): Arbitraries => new Arbitraries(year)\n\nexport const asset: Arbitrary<types.Asset> = fc\n  .tuple(\n    fc.string(),\n    fc.constantFrom<types.AssetType>('Security', 'Real Estate'),\n    fc.date(),\n    fc.nat({ max: 100000 }),\n    fc.nat({ max: 100 }),\n    fc.nat({ max: 100 })\n  )\n  .map(([name, positionType, openDate, openPrice, openFee, quantity]) => ({\n    name,\n    positionType,\n    openPrice,\n    openDate,\n    openFee,\n    quantity\n  }))\n\nexport const yearsTaxesState: Arbitrary<YearsTaxesState> = fc\n  .tuple(forYear(2021).information(), fc.array(asset))\n  .map(([Y2021, assets]) => ({\n    ...blankYearTaxesState,\n    Y2021,\n    assets,\n    activeYear: 'Y2021'\n  }))\n"
  },
  {
    "path": "src/core/tests/validation.test.ts",
    "content": "import * as arbitraries from './arbitraries'\nimport * as fc from 'fast-check'\nimport { Address, Dependent, Information, PrimaryPerson } from '../data'\nimport log from '../log'\nimport * as validators from '../data/validate'\nimport { dateToStringPerson, infoToStringInfo } from 'ustaxes/redux/data'\n\n/* eslint-disable @typescript-eslint/no-empty-function */\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\nbeforeAll(() => {\n  jest.spyOn(console, 'warn').mockImplementation(() => {})\n  jest.spyOn(console, 'error').mockImplementation(() => {})\n  log.setDefaultLevel(log.levels.SILENT)\n})\n\nconst primaryPerson: fc.Arbitrary<PrimaryPerson<string>> =\n  arbitraries.primaryPerson.map((p) => dateToStringPerson(p))\n\nconst information: fc.Arbitrary<Information<string>> = arbitraries\n  .forYear(2020)\n  .information()\n  .map((i) => infoToStringInfo(i))\n\nconst dependent: fc.Arbitrary<Dependent<string>> = arbitraries\n  .forYear(2020)\n  .dependent()\n  .map((p) => ({\n    ...p,\n    dateOfBirth: p.dateOfBirth.toISOString()\n  }))\n\ndescribe('validation', () => {\n  it('should validate some data', () => {\n    fc.assert(\n      fc.property(primaryPerson, (data) => {\n        expect(validators.primaryPerson(data)).toEqual(true)\n      })\n    )\n  })\n\n  it('checktype should throw', () => {\n    fc.assert(\n      fc.property(primaryPerson, (data) => {\n        expect(() =>\n          validators.checkType(\n            {\n              ...data,\n              address: '123 hi street' as unknown as Address\n            },\n            validators.primaryPerson\n          )\n        ).toThrow()\n      })\n    )\n  })\n\n  it('checks dependent', () => {\n    fc.assert(\n      fc.property(dependent, (data) => {\n        expect(validators.checkType(data, validators.dependent)).toEqual(data)\n      })\n    )\n  })\n\n  it('checkType should not modify correct data', () => {\n    fc.assert(\n      fc.property(information, (info) => {\n        expect(validators.checkType(info, validators.information)).toEqual(info)\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/core/util.ts",
    "content": "/**\n * Given a typescript enum, use this to get an array of the keys\n * to the enum\n * @param a Enumerator name\n * @returns tyepsafe array of keys\n */\n\nimport _ from 'lodash'\nimport { DeepMap, DeepPartial } from 'react-hook-form'\n\nexport const enumKeys = <A>(a: A): Array<keyof typeof a> =>\n  Object.keys(a).filter((k) => isNaN(Number(k))) as Array<keyof typeof a>\n\nexport const linear =\n  (m: number, b: number) =>\n  (x: number): number =>\n    b + m * x\n\n// Lower bound, and function to apply above that bound.\ninterface Piece {\n  lowerBound: number\n  f: (x: number) => number\n}\nexport type Piecewise = Piece[]\n\nexport const evaluatePiecewise = (f: Piecewise, x: number): number => {\n  // Select the function segment to evaulate.\n  // The function segment is the one before the segment with the lower bound above x.\n  const selection: number = (() => {\n    const idx = f.findIndex(({ lowerBound }) => lowerBound > x)\n    if (idx < 0) {\n      return f.length - 1\n    }\n    return idx - 1\n  })()\n  return f[selection].f(x)\n}\n\nexport const isLeapYear = (year: number): boolean =>\n  (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\n\nexport const daysInYear = (year: number): number =>\n  isLeapYear(year) ? 366 : 365\n\nexport const ifNegative = <A = number>(\n  n: number,\n  orElse: A | number = 0\n): A | number => (n < 0 ? n : orElse)\n\nexport const ifPositive = <A = number>(\n  n: number,\n  orElse: A | number = 0\n): A | number => (n > 0 ? n : orElse)\n\n// idea from https://github.com/gcanti/fp-ts/blob/3e2af038982cb4090ccc8c2912e4b22f907bdaea/src/Either.ts\nexport interface Left<E> {\n  readonly _tag: 'left'\n  left: E\n}\n\nexport interface Right<A> {\n  readonly _tag: 'right'\n  right: A\n}\n\nexport type Either<E, A> = Left<E> | Right<A>\n\nexport const left = <E = never, A = never>(left: E): Either<E, A> => ({\n  _tag: 'left',\n  left\n})\nexport const right = <E = never, A = never>(right: A): Either<E, A> => ({\n  _tag: 'right',\n  right\n})\n\nexport const isLeft = <E, A>(e: Either<E, A>): e is Left<E> => e._tag === 'left'\nexport const isRight = <E, A>(e: Either<E, A>): e is Right<A> =>\n  e._tag === 'right'\n\n// FP style Either type that also handles promises.\nexport class EitherMethods<E, A> {\n  e: Either<E, A>\n\n  constructor(e: Either<E, A>) {\n    this.e = e\n  }\n\n  map = <B>(f: (a: A) => B): EitherMethods<E, B> =>\n    isLeft(this.e) ? pureLeft(this.e.left) : pure(f(this.e.right))\n\n  ap = <B>(fab: Either<E, (a: A) => B>): EitherMethods<E, B> =>\n    isLeft(fab) ? new EitherMethods(left(fab.left)) : this.map(fab.right)\n\n  chain = <B>(f: (a: A) => Either<E, B>): EitherMethods<E, B> =>\n    new EitherMethods(isLeft(this.e) ? left(this.e.left) : f(this.e.right))\n\n  mapLeft = <E2>(f: (err: E) => E2): EitherMethods<E2, A> =>\n    isLeft(this.e) ? pureLeft(f(this.e.left)) : pure(this.e.right)\n\n  fold = <B, C>(f: (e: E) => B, g: (a: A) => C): B | C =>\n    isLeft(this.e) ? f(this.e.left) : g(this.e.right)\n\n  orThrow = (): A =>\n    this.fold(\n      (e) => {\n        throw e\n      },\n      (a) => a\n    )\n\n  handle = <B>(f: (e: E) => B): B | undefined => this.fold(f, () => undefined)\n\n  mapAsync = async <B>(\n    f: (a: A) => Promise<B>\n  ): Promise<EitherMethods<E, B>> => {\n    if (isLeft(this.e)) {\n      return Promise.resolve(pureLeft(this.e.left))\n    } else {\n      return pure(await f(this.e.right))\n    }\n  }\n\n  value = (): Either<E, A> => this.e\n}\n\nexport const pureLeft = <A, E = unknown>(e: E): EitherMethods<E, A> =>\n  new EitherMethods(left(e))\nexport const pure = <E, A = unknown>(a: A): EitherMethods<E, A> =>\n  new EitherMethods<E, A>(right(a))\nexport const run = <E, A>(e: Either<E, A>): EitherMethods<E, A> =>\n  new EitherMethods(e)\nexport const runAsync = <E, A>(\n  e: Promise<Either<E, A>>\n): Promise<EitherMethods<E, A>> => e.then(run)\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access\nexport const isDesktop = (): boolean => (window as any).__TAURI__ !== undefined\n\nexport const isWeb = (): boolean => !isDesktop()\n\n// Decimal precision\n\nconst fixDecimals =\n  (n: number) =>\n  (x: number): number => {\n    const mul = Math.pow(10, n)\n    return Math.round(x * mul) / mul\n  }\n\nexport const fix2 = fixDecimals(2)\nexport const fix0 = (n: number): number => Math.round(n)\nexport const fix5 = fixDecimals(5)\nexport const fix10 = fixDecimals(10)\n\nexport const parseFormNumber = (x: string | undefined): number | undefined => {\n  if (x !== undefined && x.length > 0) {\n    try {\n      return parseFloat(x)\n    } catch (e) {\n      return undefined\n    }\n  }\n  return undefined\n}\n\nexport const parseFormNumberOrThrow = (x: string | undefined): number => {\n  const res = parseFormNumber(x)\n  if (res === undefined) {\n    throw new Error(`${x ?? 'undefined'} does not parse to number`)\n  }\n  return res\n}\n\nexport const numberOfDaysBetween = (d1: Date, d2: Date): number => {\n  const [start, end] = [d1, d2].map((d) =>\n    // Ignore time part if it exists.\n    new Date(d.toISOString().slice(0, 10)).getTime()\n  )\n  return Math.abs(end - start) / 1000 / 60 / 60 / 24\n}\n\nexport const nextMultipleOf =\n  (mul: number) =>\n  (value: number): number => {\n    const v = Math.round(value)\n    // Just return the highest possible value divisible by mul\n    // if we're above this number (~9E15)\n    // Above that mod cannot be expected to return correct results\n    if (v > Number.MAX_SAFE_INTEGER - mul) {\n      return Number.MAX_SAFE_INTEGER - (Number.MAX_SAFE_INTEGER % mul)\n    }\n\n    return Math.ceil(v / mul) * mul\n  }\n\nexport const nextMultipleOf1000 = nextMultipleOf(1000)\n\n/**\n * https://github.com/typescript-eslint/typescript-eslint/issues/4619#issuecomment-1055653098\n *\n * Mark a promise as intentionally floating, not awaited.\n *\n * In react, we often want to do something asynchronous as a result\n * of a user action, such as when there is an onClick to handle. onClick\n * expects a function that returns void. But in these asynchronous cases\n * we have a promise with no one around to await it. So explicitly mark\n * this use as acceptable by wrapping the handler in this function.\n */\nexport const intentionallyFloat = <A extends unknown[]>(\n  fn: (...args: A) => Promise<unknown>\n): ((...args: A) => void) => {\n  return (...args) => {\n    void fn(...args)\n  }\n}\n\nexport const getNestedValue = <A, E, V>(\n  obj: DeepMap<DeepPartial<A>, E>,\n  path: string,\n  defaultValue: V\n): E | V => _.get(obj, path, defaultValue) as E | V\n"
  },
  {
    "path": "src/customTypes/persistStore.d.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Provides type override for persistStore so that\n * custom state and action types can be easily used.\n * This is taken from a PR that has not been merged,\n * since the redux-persist project appears to be no\n * longer maintained since Sept 2019\n *\n * https://github.com/rt2zz/redux-persist/pull/1085\n */\n\ndeclare module 'redux-persist/es/persistStore' {\n  import { Store, Action, AnyAction } from 'redux'\n  import { PersistorOptions, Persistor } from 'redux-persist/es/types'\n\n  /**\n   * @desc Creates a persistor for a given store.\n   * @param store store to be persisted (or match an existent storage)\n   * @param persistorOptions enhancers of the persistor\n   * @param callback bootstrap callback of sort.\n   */\n  // tslint:disable-next-line: strict-export-declare-modifiers\n  export default function persistStore<\n    S = any,\n    A extends Action<any> = AnyAction\n  >(\n    store: Store<S, A>,\n    persistorOptions?: PersistorOptions | null,\n    callback?: () => any\n  ): Persistor\n}\n\ndeclare module 'redux-persist/lib/persistStore' {\n  //  export * from 'redux-persist/es/persistStore'\n  export { default } from 'redux-persist/es/persistStore'\n}\n"
  },
  {
    "path": "src/data/csvImport.ts",
    "content": "import { parse, ParseError } from 'papaparse'\nimport { Either, left, right, run } from 'ustaxes/core/util'\n\nexport type DateFormat =\n  | 'YYYY-MM-DD'\n  | 'DD-MM-YYYY'\n  | 'MM-DD-YYYY'\n  | 'DD-MM-YY'\n  | 'MM-DD-YY'\n  | 'YY-MM-DD'\n\nexport interface CsvConfig<K> {\n  delimiter: string\n  quote: string\n  escape: string\n  fields: Map<K, number>\n  dateFormat: string\n}\n\nexport type Parsed<Row> = Either<ParseError[], Row[]>\n\nconst parseEither = (contents: string): Parsed<string[]> => {\n  const res = parse<string[]>(contents, {\n    skipEmptyLines: true,\n    delimiter: ','\n  })\n  if (res.errors.length > 0) {\n    return left(res.errors)\n  }\n  return right(res.data)\n}\n\nexport const preflightCsvAll = (contents: string): Parsed<string[]> =>\n  parseEither(contents)\n\nexport const preflightCsvAllOrThrow = (contents: string): string[][] =>\n  run(parseEither(contents)).orThrow()\n\nexport const preflightCsv = (contents: string, sample = 5): Parsed<string[]> =>\n  run(preflightCsvAll(contents))\n    .map((data) => data.slice(0, sample))\n    .value()\n\nexport const preflightCsvOrThrow = (contents: string, sample = 5): string[][] =>\n  run(preflightCsv(contents, sample)).orThrow()\n\nexport const parseCsv = <A>(\n  contents: string,\n  parseRow: (r: string[], rowNum: number) => A[]\n): Parsed<A> =>\n  run(preflightCsvAll(contents))\n    .map((data) => data.flatMap<A>((row, i) => parseRow(row, i)))\n    .value()\n\nexport const parseCsvOrThrow = <A>(\n  contents: string,\n  parseRow: (r: string[], rowNum: number) => A[]\n): A[] => run(parseCsv(contents, parseRow)).orThrow()\n"
  },
  {
    "path": "src/data/transactions.ts",
    "content": "import { Either, left, pure, right } from 'ustaxes/core/util'\n\nexport interface Security {\n  name: string\n}\n\nexport type Side = 'BUY' | 'SELL'\n\n// A transaction represents a single trade in a security.\nexport interface Transaction {\n  security: Security\n  date: string\n  side: Side\n  price: number\n  fee?: number\n  quantity: number\n}\n\n// A position represents a lot of a security. A lot may be split\n// by a transaction into a new lot.\nexport interface Position {\n  security: Security\n  quantity: number\n  price: number\n  openDate: string\n  openFee: number\n  closeFee?: number\n  closeDate?: string\n  closePrice?: number\n}\n\nexport interface Portfolio {\n  positions: Position[]\n}\n\nconst openPosition = (transaction: Transaction): Position => {\n  const { security, date, side, price, quantity, fee } = transaction\n  return {\n    security,\n    quantity: side === 'BUY' ? quantity : 0,\n    price,\n    openDate: date,\n    openFee: fee ?? 0\n  }\n}\n\n// Apply a transaction to a portfolio. In the case of a buy, the portfolio simply gains a\n// new lot. In the case of a sell, lots are consumed in first-in-first-out-order. Any left\n// over quantity in a lot is added to a new position. Note positions are never removed\n// from the portfolio. The closeDate field is set to indicate the position is closed.\n// TODO: Handle wash sales, flag adjustments caused.\nexport const processTransaction = (\n  portfolio: Portfolio,\n  transaction: Transaction\n): Portfolio => {\n  const { positions } = portfolio\n\n  if (transaction.side === 'BUY') {\n    // In the case of a buy, we just open a new position. Simplest case.\n    return {\n      ...portfolio,\n      positions: [...positions, openPosition(transaction)]\n    }\n  } else {\n    // For a sale, we have to handle a few cases.\n    // 1. The security is not in the portfolio. This is a short position. For now, this is an exception\n    // 2. The security is in the portfolio.\n    //    a. We have to consume the quantity from the first matching lot in the portfolio.\n    //    b, If there is a remaining quantity, we have to open a new position.\n    let remainingQuantity = transaction.quantity\n    const newPositions = positions.flatMap((position) => {\n      if (\n        position.closeDate !== undefined ||\n        transaction.security.name !== position.security.name ||\n        remainingQuantity <= 0\n      ) {\n        return [position]\n      }\n\n      if (remainingQuantity >= position.quantity) {\n        // Entire lot is consumed by the sale\n        remainingQuantity -= position.quantity\n        return [\n          {\n            ...position,\n            closePrice: transaction.price,\n            closeDate: transaction.date,\n            closeFee: transaction.fee\n          }\n        ]\n      } else {\n        // Lot is only partially consumed. We have to open a new position\n        const closedQuantity = remainingQuantity\n        const newQuantity = position.quantity - closedQuantity\n        remainingQuantity = 0\n        const closeRatio = closedQuantity / position.quantity\n        return [\n          {\n            ...position,\n\n            // Since we're tracking the fee at opening and closing of\n            // the position, we have to apportion the fee to split lots\n            // so that the cost basis and proceeds for each will calculate\n            // correctly.\n            openFee: position.openFee * closeRatio,\n            closeFee: (position.closeFee ?? 0) * closeRatio,\n            closeDate: transaction.date,\n            closePrice: transaction.price,\n            quantity: closedQuantity\n          },\n          {\n            ...position,\n            openFee: position.openFee * (1 - closeRatio),\n            closeFee: (position.closeFee ?? 0) * (1 - closeRatio),\n            quantity: newQuantity\n          }\n        ]\n      }\n    })\n\n    if (remainingQuantity > 0) {\n      //  This is an error. We hit a sale which tries to consume more\n      // of a security than we have.\n      console.error('Transaction list failed for transaction')\n      console.error(transaction)\n      console.error(newPositions)\n      console.error(\n        `${remainingQuantity} remaining for security ${transaction.security.name}`\n      )\n      throw new Error('Transaction list failed')\n    }\n\n    return {\n      ...portfolio,\n      positions: newPositions\n    }\n  }\n}\n\nexport interface TransactionError {\n  messages: string[]\n  previousPortfolio?: Portfolio\n  errorTransaction?: Transaction\n  errorIndex: number\n}\n\nexport const processTransactions = (\n  initialPortfolio: Portfolio,\n  transactions: Transaction[]\n): Either<TransactionError, Portfolio> =>\n  transactions\n    .reduce(\n      (portfolio, transaction, i) =>\n        portfolio.chain((p: Portfolio) => {\n          try {\n            return right(processTransaction(p, transaction))\n          } catch (e) {\n            return left({\n              messages: [(e as Error).message],\n              previousPortfolio: p,\n              errorTransaction: transaction,\n              errorIndex: i\n            })\n          }\n        }),\n      pure<TransactionError, Portfolio>(initialPortfolio)\n    )\n    .value()\n"
  },
  {
    "path": "src/data/urls.ts",
    "content": "const Urls = {\n  usTaxes: {\n    start: '/start'\n  },\n  taxPayer: {\n    root: '/taxpayer',\n    info: '/info',\n    spouseAndDependent: '/spouseanddependent'\n  },\n  refund: '/refundinfo',\n  questions: '/questions',\n  income: {\n    w2s: '/income/w2jobinfo',\n    f1099s: '/income/f1099s',\n    realEstate: '/income/realestate',\n    otherInvestments: '/income/otherinvestments',\n    stockOptions: '/income/stockoptions',\n    partnershipIncome: '/income/partnershipincome'\n  },\n  payments: {\n    estimatedTaxes: '/payments/estimatedtaxes'\n  },\n  savingsAccounts: {\n    healthSavingsAccounts: '/savingsaccounts/hsa',\n    ira: '/savingsaccounts/ira'\n  },\n  deductions: {\n    f1098es: '/deductions/studentloaninterest',\n    itemized: '/deductions/itemized'\n  },\n  credits: {\n    main: '/credits',\n    eic: '/credits/eic'\n  },\n  createPdf: '/createpdf',\n  settings: '/settings',\n  help: '/help',\n  Y2021: {\n    credits: `/Y2021/credits`\n  },\n  default: ''\n}\n\nUrls.default = Urls.usTaxes.start\n\nexport default Urls\n"
  },
  {
    "path": "src/forms/F1040Base.ts",
    "content": "import {\n  FilingStatus,\n  Income1099B,\n  Income1099Div,\n  Income1099Int,\n  Income1099R,\n  Income1099SSA,\n  Income1099Type,\n  Information,\n  Person,\n  PrimaryPerson,\n  ScheduleK1Form1065,\n  Supported1099,\n  TaxPayer\n} from 'ustaxes/core/data'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { Either, left, right } from 'ustaxes/core/util'\nimport { F1040Error } from './errors'\n\nexport type ValidatedTaxpayer = TaxPayer & {\n  filingStatus: FilingStatus\n  primaryPerson: PrimaryPerson\n}\n\nexport interface ValidatedInformation extends Information {\n  taxPayer: ValidatedTaxpayer\n}\n\nconst isValidTaxpayer = (tp: TaxPayer): tp is ValidatedTaxpayer =>\n  tp.filingStatus !== undefined && tp.primaryPerson !== undefined\n\nexport const isValidInformation = (\n  info: Information\n): info is ValidatedInformation => isValidTaxpayer(info.taxPayer)\n\nexport const validate = (\n  info: Information\n): Either<F1040Error[], ValidatedInformation> => {\n  const result: F1040Error[] = []\n  if (info.taxPayer.filingStatus === undefined) {\n    result.push(F1040Error.filingStatusUndefined)\n  }\n\n  const fs = info.taxPayer.filingStatus\n  const numDependents = info.taxPayer.dependents.length\n  const hasSpouse = info.taxPayer.spouse !== undefined\n  const hasDependents = numDependents > 0\n\n  if (\n    fs === undefined ||\n    ([FilingStatus.S, FilingStatus.HOH].some((x) => x === fs) && hasSpouse) ||\n    (fs === FilingStatus.HOH && !hasDependents)\n  ) {\n    result.push(F1040Error.filingStatusRequirementsNotMet)\n  }\n\n  if (result.length > 0) {\n    return left(result)\n  }\n\n  if (!isValidInformation(info)) {\n    result.push(F1040Error.incompletePrimaryTaxpayer)\n  }\n\n  if (result.length > 0) {\n    return left(result)\n  }\n\n  // Calling this a second time for typechecking.\n  if (isValidInformation(info)) {\n    return right(info)\n  }\n\n  // Should not get here. Above logic should be exhaustive\n  throw new Error('Invalid information.')\n}\n\nexport default abstract class F1040Base extends Form {\n  info: ValidatedInformation\n\n  constructor(info: ValidatedInformation) {\n    super()\n    this.info = info\n  }\n\n  namesString = (): string => {\n    const ps: Person[] = [\n      this.info.taxPayer.primaryPerson,\n      this.info.taxPayer.spouse\n    ]\n      .filter((p: Person | undefined) => p !== undefined)\n      .map((p: Person | undefined) => p as Person)\n\n    return ps.map((p: Person) => `${p.firstName} ${p.lastName}`).join(', ')\n  }\n\n  k1sWithInterest = (): ScheduleK1Form1065[] =>\n    this.info.scheduleK1Form1065s.filter((k1) => k1.interestIncome > 0)\n\n  f1099sByType = (ft: Income1099Type): Supported1099[] =>\n    this.info.f1099s.filter((f1099) => f1099.type === ft)\n\n  f1099Ints = (): Income1099Int[] =>\n    this.f1099sByType(Income1099Type.INT) as Income1099Int[]\n\n  f1099Divs = (): Income1099Div[] =>\n    this.f1099sByType(Income1099Type.DIV) as Income1099Div[]\n\n  f1099Bs = (): Income1099B[] =>\n    this.f1099sByType(Income1099Type.B) as Income1099B[]\n\n  f1099rs = (): Income1099R[] =>\n    this.f1099sByType(Income1099Type.R) as Income1099R[]\n\n  f1099ssas = (): Income1099SSA[] =>\n    this.f1099sByType(Income1099Type.SSA) as Income1099SSA[]\n\n  fullName = (person: Person): string =>\n    `${person.firstName} ${person.lastName}`\n\n  primaryFullName = (): string | undefined =>\n    this.fullName(this.info.taxPayer.primaryPerson)\n\n  spouseFullName = (): string | undefined =>\n    this.info.taxPayer.spouse !== undefined\n      ? this.fullName(this.info.taxPayer.spouse)\n      : undefined\n}\n"
  },
  {
    "path": "src/forms/StateForms.ts",
    "content": "import { State } from 'ustaxes/core/data'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport { Either, left, right } from 'ustaxes/core/util'\nimport F1040Base from './F1040Base'\n\nexport enum StateFormError {\n  unsupportedTaxYear = 'Tax year not supported',\n  NoResidency = 'No residency defined',\n  StateFormsNotAvailable = 'No state forms available',\n  NoFilingRequirement = 'No filing requirement'\n}\n\ntype StateForms<F> = {\n  [K in State]?: (f1040: F) => StateForm\n}\n\nexport const createStateReturn =\n  <F extends F1040Base>(noFilingStates: State[], stateForms: StateForms<F>) =>\n  (f1040: F): Either<StateFormError[], StateForm[]> => {\n    if (f1040.info.stateResidencies.length < 1) {\n      return left([StateFormError.NoResidency])\n    } else if (noFilingStates.includes(f1040.info.stateResidencies[0].state)) {\n      return left([StateFormError.NoFilingRequirement])\n    }\n\n    const residency = f1040.info.stateResidencies[0]\n    const form = stateForms[residency.state]?.call(undefined, f1040)\n    if (form !== undefined) {\n      return right(\n        [form, ...form.attachments()].sort((a, b) => a.formOrder - b.formOrder)\n      )\n    }\n    return left([StateFormError.StateFormsNotAvailable])\n  }\n"
  },
  {
    "path": "src/forms/Y2020/data/federal.ts",
    "content": "import { FilingStatus } from 'ustaxes/core/data'\nimport { linear, Piecewise } from 'ustaxes/core/util'\n\nexport const CURRENT_YEAR = 2020\n\ninterface TaggedAmount {\n  name: string\n  amount: number\n}\n\ninterface Brackets {\n  brackets: number[]\n}\n\ninterface Deductions {\n  deductions: TaggedAmount[]\n  exemptions: TaggedAmount[]\n}\n\ninterface Rates {\n  rates: number[]\n}\n\ninterface FederalBrackets {\n  ordinary: Rates & { status: { [key in FilingStatus]: Brackets & Deductions } }\n  longTermCapGains: Rates & { status: { [key in FilingStatus]: Brackets } }\n}\n\nconst federalBrackets: FederalBrackets = {\n  ordinary: {\n    rates: [10, 12, 22, 24, 32, 35, 37],\n    status: {\n      [FilingStatus.S]: {\n        brackets: [9875, 40125, 85525, 163300, 207350, 510300],\n        deductions: [\n          {\n            name: 'Standard Deduction (Single)',\n            amount: 12400\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.MFJ]: {\n        brackets: [19750, 80250, 171050, 326600, 414700, 622050],\n        deductions: [\n          {\n            name: 'Standard Deduction (Married)',\n            amount: 24800\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.W]: {\n        brackets: [19750, 80250, 171050, 326600, 414700, 622050],\n        deductions: [\n          {\n            name: 'Standard Deduction (Married)',\n            amount: 24800\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.MFS]: {\n        brackets: [9875, 40125, 85525, 163300, 207350, 510300],\n        deductions: [\n          {\n            name: 'Standard Deduction (Married Filing Separately)',\n            amount: 12400\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.HOH]: {\n        brackets: [19750, 80250, 171050, 326600, 414700, 622050],\n        deductions: [\n          {\n            name: 'Standard Deduction (Head of Household)',\n            amount: 18650\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      }\n    }\n  },\n  longTermCapGains: {\n    rates: [0, 15, 20],\n    status: {\n      [FilingStatus.S]: {\n        brackets: [40000, 441450]\n      },\n      [FilingStatus.MFJ]: {\n        brackets: [80000, 496600]\n      },\n      [FilingStatus.W]: {\n        brackets: [80000, 496600]\n      },\n      [FilingStatus.MFS]: {\n        brackets: [40000, 248300]\n      },\n      [FilingStatus.HOH]: {\n        brackets: [53600, 469050]\n      }\n    }\n  }\n}\n\nexport const fica = {\n  maxSSTax: 8537.4,\n  maxIncomeSSTaxApplies: 137700,\n\n  regularMedicareTaxRate: 1.45 / 100,\n  additionalMedicareTaxRate: 0.9 / 100,\n  additionalMedicareTaxThreshold: (filingStatus: FilingStatus): number => {\n    switch (filingStatus) {\n      case FilingStatus.MFJ: {\n        return 250000\n      }\n      case FilingStatus.MFS: {\n        return 125000\n      }\n      default: {\n        return 200000 // Single, Head of Household, Windower\n      }\n    }\n  }\n}\n\n// Net Investment Income Tax calculated on form 8960\nexport const netInvestmentIncomeTax = {\n  taxRate: 0.038, // 3.8%\n  taxThreshold: (filingStatus: FilingStatus): number => {\n    switch (filingStatus) {\n      case FilingStatus.MFJ: {\n        return 250000\n      }\n      case FilingStatus.W: {\n        return 250000\n      }\n      case FilingStatus.MFS: {\n        return 125000\n      }\n      default: {\n        return 200000 // Single, Head of Household\n      }\n    }\n  }\n}\n\nexport const healthSavingsAccounts = {\n  contributionLimit: {\n    'self-only': 3550,\n    family: 7100\n  }\n}\n\n// line 11 caps based on step one in instructions\nconst line11Caps = [15820, 41756, 47440, 50954]\nconst line11MfjCaps = [21710, 47646, 53330, 56844]\n\ntype Point = [number, number]\n\n// Provided a list of points, create a piecewise function\n// that makes linear segments through the list of points.\nconst toPieceWise = (points: Point[]): Piecewise =>\n  points\n    .slice(0, points.length - 1)\n    .map((point, idx) => [point, points[idx + 1]])\n    .map(([[x1, y1], [x2, y2]]) => ({\n      // starting point     slope              intercept\n      lowerBound: x1,\n      f: linear((y2 - y1) / (x2 - x1), y1 - (x1 * (y2 - y1)) / (x2 - x1))\n    }))\n\n// These points are taken directly from IRS publication\n// IRS Rev. Proc. 2019-44 for tax year 2020\n// https://www.irs.gov/pub/irs-drop/rp-19-44.pdf\nconst unmarriedFormulas: Piecewise[] = (() => {\n  const points: Point[][] = [\n    [\n      [0, 0],\n      [7030, 538],\n      [8790, 3584],\n      [15820, 0]\n    ], // 0\n    [\n      [0, 0],\n      [10540, 3584],\n      [19330, 3584],\n      [41756, 0]\n    ], // 1\n    [\n      [0, 0],\n      [14800, 5920],\n      [19330, 5920],\n      [47440, 0]\n    ], // 2\n    [\n      [0, 0],\n      [14800, 6660],\n      [19330, 6660],\n      [50954, 0]\n    ] // 3 or more\n  ]\n  return points.map((ps: Point[]) => toPieceWise(ps))\n})()\n\nconst marriedFormulas: Piecewise[] = (() => {\n  const points: Point[][] = [\n    [\n      [0, 0],\n      [7030, 538],\n      [14680, 3584],\n      [21710, 0]\n    ], // 0\n    [\n      [0, 0],\n      [10540, 3584],\n      [25220, 3584],\n      [47646, 0]\n    ], // 1\n    [\n      [0, 0],\n      [14800, 5920],\n      [25220, 5920],\n      [53330, 0]\n    ], // 2\n    [\n      [0, 0],\n      [14800, 6660],\n      [25220, 6660],\n      [56844, 0]\n    ] // 3 or more\n  ]\n  return points.map((ps) => toPieceWise(ps))\n})()\n\ninterface EICDef {\n  caps: { [k in FilingStatus]: number[] | undefined }\n  maxInvestmentIncome: number\n  formulas: { [k in FilingStatus]: Piecewise[] | undefined }\n}\n\nexport const QualifyingDependents = {\n  childMaxAge: 17,\n  qualifyingDependentMaxAge: 19,\n  qualifyingStudentMaxAge: 24\n}\n\nexport const EIC: EICDef = {\n  // credit caps for number of children (0, 1, 2, 3 or more):\n  // Step 1\n  caps: {\n    [FilingStatus.S]: line11Caps,\n    [FilingStatus.W]: line11Caps,\n    [FilingStatus.HOH]: line11Caps,\n    [FilingStatus.MFS]: undefined,\n    [FilingStatus.MFJ]: line11MfjCaps\n  },\n  maxInvestmentIncome: 3650,\n  formulas: {\n    [FilingStatus.S]: unmarriedFormulas,\n    [FilingStatus.W]: unmarriedFormulas,\n    [FilingStatus.HOH]: unmarriedFormulas,\n    [FilingStatus.MFS]: undefined,\n    [FilingStatus.MFJ]: marriedFormulas\n  }\n}\n\nexport default federalBrackets\n\n// Constants used in the social security benefits worksheet\ninterface SocialSecurityBenefitsDef {\n  caps: { [k in FilingStatus]: { l8: number; l10: number } }\n}\n\nexport const SSBenefits: SocialSecurityBenefitsDef = {\n  caps: {\n    [FilingStatus.S]: { l8: 25000, l10: 9000 },\n    [FilingStatus.W]: { l8: 25000, l10: 9000 },\n    [FilingStatus.HOH]: { l8: 25000, l10: 9000 },\n    [FilingStatus.MFS]: { l8: 25000, l10: 9000 },\n    [FilingStatus.MFJ]: { l8: 32000, l10: 12000 }\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F1040.ts",
    "content": "import {\n  AccountType,\n  Dependent,\n  FilingStatus,\n  IncomeW2,\n  PersonRole,\n  PlanType1099,\n  Asset\n} from 'ustaxes/core/data'\nimport federalBrackets, { CURRENT_YEAR } from '../data/federal'\nimport F1040V from './F1040v'\nimport F2441 from './F2441'\nimport F2555 from './F2555'\nimport F4136 from './F4136'\nimport F4563 from './F4563'\nimport F4797 from './F4797'\nimport F4952 from './F4952'\nimport F4972 from './F4972'\nimport F5695 from './F5695'\nimport F8814 from './F8814'\nimport F8863 from './F8863'\nimport F8888 from './F8888'\nimport F8889 from './F8889'\nimport F8910 from './F8910'\nimport F8936 from './F8936'\nimport F8959 from './F8959'\nimport F8960 from './F8960'\nimport F8962 from './F8962'\nimport F8995 from './F8995'\nimport F8995A from './F8995A'\nimport Schedule1 from './Schedule1'\nimport Schedule2 from './Schedule2'\nimport Schedule3 from './Schedule3'\nimport Schedule8812 from './Schedule8812'\nimport ScheduleA from './ScheduleA'\nimport ScheduleB from './ScheduleB'\nimport ScheduleC from './ScheduleC'\nimport ScheduleD from './ScheduleD'\nimport ScheduleE from './ScheduleE'\nimport ScheduleEIC from './ScheduleEIC'\nimport ScheduleR from './ScheduleR'\nimport Form, { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { computeOrdinaryTax } from './TaxTable'\nimport SDQualifiedAndCapGains from './worksheets/SDQualifiedAndCapGains'\nimport ChildTaxCreditWorksheet from './worksheets/ChildTaxCreditWorksheet'\nimport SocialSecurityBenefitsWorksheet from './worksheets/SocialSecurityBenefits'\nimport StudentLoanInterestWorksheet from './worksheets/StudentLoanInterestWorksheet'\nimport _ from 'lodash'\nimport F8949 from './F8949'\nimport F4137 from './F4137'\nimport F8919 from './F8919'\nimport F8582 from './F8582'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport Form8853 from './F8853'\nimport F1040Base, { ValidatedInformation } from 'ustaxes/forms/F1040Base'\nimport F1040Attachment from './F1040Attachment'\n\nexport default class F1040 extends F1040Base {\n  tag: FormTag = 'f1040'\n  sequenceIndex = 0\n\n  assets: Asset<Date>[]\n\n  schedule1: Schedule1\n  schedule2: Schedule2\n  schedule3: Schedule3\n  scheduleA?: ScheduleA\n  scheduleB: ScheduleB\n  scheduleC?: ScheduleC\n  scheduleD: ScheduleD\n  scheduleE: ScheduleE\n  scheduleEIC: ScheduleEIC\n  scheduleR?: ScheduleR\n  schedule8812: Schedule8812\n  f2441?: F2441\n  f2555?: F2555\n  f4136?: F4136\n\n  f4137?: F4137\n  f4563?: F4563\n  f4797?: F4797\n  f4952?: F4952\n  f4972?: F4972\n  f5695?: F5695\n  f8582?: F8582\n  f8814?: F8814\n  f8853?: Form8853\n  f8863?: F8863\n  f8888?: F8888\n  f8889: F8889\n  f8889Spouse?: F8889\n  f8910?: F8910\n  f8919?: F8919\n  f8936?: F8936\n  f8949: F8949\n  _f8949s?: F8949[]\n  f8959: F8959\n  f8960: F8960\n  f8962?: F8962\n  f8995?: F8995 | F8995A\n  studentLoanInterestWorksheet?: StudentLoanInterestWorksheet\n  socialSecurityBenefitsWorksheet?: SocialSecurityBenefitsWorksheet\n\n  childTaxCreditWorksheet: ChildTaxCreditWorksheet\n\n  constructor(info: ValidatedInformation, assets: Asset<Date>[] = []) {\n    super(info)\n    this.assets = assets\n    this.childTaxCreditWorksheet = new ChildTaxCreditWorksheet(this)\n\n    this.scheduleB = new ScheduleB(this)\n    this.scheduleD = new ScheduleD(this)\n    this.scheduleE = new ScheduleE(this)\n    this.scheduleEIC = new ScheduleEIC(this)\n\n    this.schedule1 = new Schedule1(this)\n    this.schedule2 = new Schedule2(this)\n    this.schedule3 = new Schedule3(this)\n    this.schedule8812 = new Schedule8812(this)\n\n    this.f8889 = new F8889(this, this.info.taxPayer.primaryPerson)\n    if (this.info.taxPayer.spouse !== undefined) {\n      // add in separate form 8889 for the spouse\n      this.f8889Spouse = new F8889(this, this.info.taxPayer.spouse)\n    }\n\n    this.f8949 = new F8949(this)\n    this.f8959 = new F8959(this)\n    this.f8960 = new F8960(this)\n\n    if (this.f1099ssas().length > 0) {\n      const ssws = new SocialSecurityBenefitsWorksheet(this.info, this)\n      this.socialSecurityBenefitsWorksheet = ssws\n    }\n\n    if (this.info.f1098es.length > 0) {\n      this.studentLoanInterestWorksheet = new StudentLoanInterestWorksheet(\n        this,\n        this.info.f1098es\n      )\n    }\n\n    this.childTaxCreditWorksheet = new ChildTaxCreditWorksheet(this)\n  }\n\n  get f8949s(): F8949[] {\n    if (this._f8949s === undefined) {\n      this._f8949s = [this.f8949, ...this.f8949.copies()]\n    }\n    return this._f8949s\n  }\n\n  toString = (): string => `\n    Form 1040 generated from information:\n    Information:\n    ${JSON.stringify(this.info)}\n  `\n\n  schedules = (): Form[] => {\n    const res1: (F1040Attachment | undefined)[] = [\n      this.scheduleA,\n      this.scheduleB,\n      this.scheduleD,\n      this.scheduleE,\n      this.scheduleR,\n      this.scheduleEIC,\n      this.schedule8812,\n      this.f4797,\n      this.f4952,\n      this.f4972,\n      this.f5695,\n      this.f8814,\n      this.f8888,\n      this.f8889,\n      ...(this.f8889Spouse === undefined ? [] : [this.f8889Spouse]),\n      this.f8910,\n      this.f8936,\n      this.f8949,\n      this.f8959,\n      this.f8960,\n      this.f8995,\n      this.schedule1,\n      this.schedule2,\n      this.schedule3\n    ]\n    const res = _.compact(res1)\n      .filter((f) => f.isNeeded())\n      .flatMap((f) => [f, ...f.copies()])\n\n    // Attach payment voucher to front if there is a payment due\n    if (this.l37() > 0) {\n      res.push(new F1040V(this))\n    }\n\n    return [this, ...res].sort((a, b) => a.sequenceIndex - b.sequenceIndex)\n  }\n\n  bornBeforeDate = (): boolean =>\n    this.info.taxPayer.primaryPerson.dateOfBirth <\n    new Date(CURRENT_YEAR - 64, 0, 2)\n\n  blind = (): boolean => this.info.taxPayer.primaryPerson.isBlind\n\n  spouseBeforeDate = (): boolean =>\n    (this.info.taxPayer.spouse?.dateOfBirth ?? new Date()) <\n    new Date(CURRENT_YEAR - 64, 0, 2)\n\n  spouseBlind = (): boolean => this.info.taxPayer.spouse?.isBlind ?? false\n\n  validW2s = (): IncomeW2[] => {\n    if (this.info.taxPayer.filingStatus === FilingStatus.MFS) {\n      return this.info.w2s.filter((w2) => w2.personRole === PersonRole.PRIMARY)\n    }\n    return this.info.w2s\n  }\n\n  wages = (): number => this.validW2s().reduce((res, w2) => res + w2.income, 0)\n  medicareWages = (): number =>\n    this.validW2s().reduce((res, w2) => res + w2.medicareIncome, 0)\n\n  occupation = (r: PersonRole): string | undefined =>\n    this.info.w2s.find((w2) => w2.personRole === r && w2.occupation !== '')\n      ?.occupation\n\n  standardDeduction = (): number | undefined => {\n    const filingStatus = this.info.taxPayer.filingStatus\n    if (\n      this.info.taxPayer.primaryPerson.isTaxpayerDependent ||\n      (this.info.taxPayer.spouse?.isTaxpayerDependent ?? false)\n    ) {\n      return Math.min(\n        federalBrackets.ordinary.status[filingStatus].deductions[0].amount,\n        this.wages() > 750 ? this.wages() + 350 : 1100\n      )\n    }\n    return federalBrackets.ordinary.status[filingStatus].deductions[0].amount\n  }\n\n  totalQualifiedDividends = (): number =>\n    this.f1099Divs().reduce((sum, f) => sum + f.form.qualifiedDividends, 0)\n\n  totalGrossDistributionsFromIra = (): number =>\n    this.info.individualRetirementArrangements.reduce(\n      (res, i) => res + i.grossDistribution,\n      0\n    )\n\n  totalTaxableFromIra = (): number =>\n    this.info.individualRetirementArrangements.reduce(\n      (r, i) => r + i.taxableAmount,\n      0\n    )\n\n  totalGrossDistributionsFrom1099R = (planType: PlanType1099): number =>\n    this.f1099rs()\n      .filter((element) => element.form.planType == planType)\n      .reduce((res, f1099) => res + f1099.form.grossDistribution, 0)\n\n  totalTaxableFrom1099R = (planType: PlanType1099): number =>\n    this.f1099rs()\n      .filter((element) => element.form.planType == planType)\n      .reduce((res, f1099) => res + f1099.form.taxableAmount, 0)\n\n  l1 = (): number => this.wages()\n  l2a = (): number | undefined => this.scheduleB.l3()\n  l2b = (): number | undefined => this.scheduleB.to1040l2b()\n  l3a = (): number | undefined => this.totalQualifiedDividends()\n  l3b = (): number | undefined => this.scheduleB.to1040l3b()\n  // This is the value of box 1 in 1099-R forms coming from IRAs\n  l4a = (): number | undefined => this.totalGrossDistributionsFromIra()\n  // This should be the value of box 2a in 1099-R coming from IRAs\n  l4b = (): number | undefined => this.totalTaxableFromIra()\n  // This is the value of box 1 in 1099-R forms coming from pensions/annuities\n  l5a = (): number | undefined =>\n    this.totalGrossDistributionsFrom1099R(PlanType1099.Pension)\n  // this is the value of box 2a in 1099-R forms coming from pensions/annuities\n  l5b = (): number | undefined =>\n    this.totalTaxableFrom1099R(PlanType1099.Pension)\n  // The sum of box 5 from SSA-1099\n  l6a = (): number | undefined => this.socialSecurityBenefitsWorksheet?.l1()\n  // calculation of the taxable amount of line 6a based on other income\n  l6b = (): number | undefined =>\n    this.socialSecurityBenefitsWorksheet?.taxableAmount()\n  l7 = (): number | undefined => this.scheduleD.to1040()\n  l8 = (): number | undefined => this.schedule1.l9()\n  l9 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2b(),\n      this.l3b(),\n      this.l4b(),\n      this.l5b(),\n      this.l6b(),\n      this.l7(),\n      this.l8()\n    ])\n\n  l10a = (): number | undefined => this.schedule1.l22()\n  l10b = (): number | undefined => undefined\n  l10c = (): number => sumFields([this.l10a(), this.l10b()])\n\n  l11 = (): number => Math.max(0, this.l9() - this.l10c())\n\n  l12 = (): number | undefined => {\n    if (this.scheduleA !== undefined) {\n      return this.scheduleA.deductions()\n    }\n    return this.standardDeduction()\n  }\n\n  l13 = (): number | undefined => this.f8995?.deductions()\n  l14 = (): number => sumFields([this.l12(), this.l13()])\n\n  l15 = (): number => Math.max(0, this.l11() - this.l14())\n\n  computeTax = (): number | undefined => {\n    if (\n      this.scheduleD.computeTaxOnQDWorksheet() ||\n      this.totalQualifiedDividends() > 0\n    ) {\n      const wksht = new SDQualifiedAndCapGains(this)\n      return wksht.tax()\n    }\n\n    return computeOrdinaryTax(this.info.taxPayer.filingStatus, this.l15())\n  }\n\n  l16 = (): number | undefined =>\n    sumFields([this.f8814?.tax(), this.f4972?.tax(), this.computeTax()])\n\n  l17 = (): number | undefined => this.schedule2.l3()\n  l18 = (): number => sumFields([this.l16(), this.l17()])\n\n  // TODO\n  l19 = (): number | undefined => this.childTaxCreditWorksheet.l12()\n  l20 = (): number | undefined => this.schedule3.l7()\n  l21 = (): number => sumFields([this.l19(), this.l20()])\n\n  l22 = (): number => Math.max(0, this.l18() - this.l21())\n\n  l23 = (): number | undefined => this.schedule2.l10()\n  l24 = (): number => sumFields([this.l22(), this.l23()])\n\n  l25a = (): number =>\n    this.validW2s().reduce((res, w2) => res + w2.fedWithholding, 0)\n\n  // tax withheld from 1099s\n  l25b = (): number =>\n    this.f1099rs().reduce(\n      (res, f1099) => res + f1099.form.federalIncomeTaxWithheld,\n      0\n    ) +\n    this.f1099ssas().reduce(\n      (res, f1099) => res + f1099.form.federalIncomeTaxWithheld,\n      0\n    )\n\n  // TODO: form(s) W-2G box 4, schedule K-1, form 1042-S, form 8805, form 8288-A\n  l25c = (): number | undefined => this.f8959.l24()\n\n  l25d = (): number => sumFields([this.l25a(), this.l25b(), this.l25c()])\n\n  l26 = (): number =>\n    this.info.estimatedTaxes.reduce((res, et) => res + et.payment, 0)\n\n  l27 = (): number | undefined => this.scheduleEIC.credit()\n  l28 = (): number | undefined => this.schedule8812.l15()\n\n  l29 = (): number | undefined => this.f8863?.l8()\n\n  // TODO: recovery rebate credit?\n  l30 = (): number | undefined => undefined\n\n  l31 = (): number | undefined => this.schedule3.l13()\n\n  l32 = (): number =>\n    sumFields([this.l27(), this.l28(), this.l29(), this.l30(), this.l31()])\n\n  l33 = (): number => sumFields([this.l25d(), this.l26(), this.l32()])\n\n  l34 = (): number => Math.max(0, this.l33() - this.l24())\n\n  // TODO: assuming user wants amount refunded\n  // rather than applied to estimated tax\n  l35a = (): number => this.l34()\n  l36 = (): number => Math.max(0, this.l34() - this.l35a())\n\n  l37 = (): number => Math.max(0, this.l24() - this.l33())\n\n  // TODO - estimated tax penalty\n  l38 = (): number | undefined => undefined\n\n  _depField = (idx: number): string | boolean => {\n    const deps: Dependent[] = this.info.taxPayer.dependents\n\n    // Based on the PDF row we are on, select correct dependent\n    const depIdx = Math.floor(idx / 5)\n    const depFieldIdx = idx % 5\n\n    let fieldArr = ['', '', '', false, false]\n\n    if (depIdx < deps.length) {\n      const dep = deps[depIdx]\n      // Based on the PDF column, select the correct field\n      fieldArr = [\n        `${dep.firstName} ${dep.lastName}`,\n        dep.ssid,\n        dep.relationship,\n        this.childTaxCreditWorksheet.qualifiesChild(dep),\n        this.childTaxCreditWorksheet.qualifiesOther(dep)\n      ]\n    }\n\n    return fieldArr[depFieldIdx]\n  }\n\n  // 1040 allows 4 dependents listed without a supplemental schedule,\n  // so create field mappings for 4x5 grid of fields\n  _depFieldMappings = (): Array<string | boolean> =>\n    Array.from(Array(20)).map((u, n: number) => this._depField(n))\n\n  fields = (): Field[] =>\n    [\n      this.info.taxPayer.filingStatus === FilingStatus.S,\n      this.info.taxPayer.filingStatus === FilingStatus.MFJ,\n      this.info.taxPayer.filingStatus === FilingStatus.MFS,\n      this.info.taxPayer.filingStatus === FilingStatus.HOH,\n      this.info.taxPayer.filingStatus === FilingStatus.W,\n      // TODO: implement non dependent child for HOH and QW\n      this.info.taxPayer.filingStatus === 'MFS' ? this.spouseFullName() : '',\n      this.info.taxPayer.primaryPerson.firstName,\n      this.info.taxPayer.primaryPerson.lastName,\n      this.info.taxPayer.primaryPerson.ssid,\n      this.info.taxPayer.filingStatus === FilingStatus.MFJ\n        ? this.info.taxPayer.spouse?.firstName\n        : '',\n      this.info.taxPayer.filingStatus === FilingStatus.MFJ\n        ? this.info.taxPayer.spouse?.lastName ?? ''\n        : '',\n      this.info.taxPayer.spouse?.ssid,\n      this.info.taxPayer.primaryPerson.address.address,\n      this.info.taxPayer.primaryPerson.address.aptNo,\n      this.info.taxPayer.primaryPerson.address.city,\n      this.info.taxPayer.primaryPerson.address.state,\n      this.info.taxPayer.primaryPerson.address.zip,\n      this.info.taxPayer.primaryPerson.address.foreignCountry,\n      this.info.taxPayer.primaryPerson.address.province,\n      this.info.taxPayer.primaryPerson.address.postalCode,\n      false, // election campaign boxes\n      false,\n      this.info.questions.CRYPTO ?? false,\n      !(this.info.questions.CRYPTO ?? false),\n      this.info.taxPayer.primaryPerson.isTaxpayerDependent,\n      this.info.taxPayer.spouse?.isTaxpayerDependent ?? false,\n      false, // TODO: spouse itemizes separately,\n      this.bornBeforeDate(),\n      this.blind(),\n      this.spouseBeforeDate(),\n      this.spouseBlind(),\n      this.info.taxPayer.dependents.length > 4,\n      ...this._depFieldMappings(),\n      this.l1(),\n      this.l2a(),\n      this.l2b(),\n      this.l3a(),\n      this.l3b(),\n      this.l4a(),\n      this.l4b(),\n      this.l5a(),\n      this.l5b(),\n      this.l6a(),\n      this.l6b(),\n      !this.scheduleD.isNeeded(),\n      this.l7(),\n      this.l8(),\n      this.l9(),\n      this.l10a(),\n      this.l10b(),\n      this.l10c(),\n      this.l11(),\n      this.l12(),\n      this.l13(),\n      this.l14(),\n      this.l15(),\n      this.f8814 !== undefined,\n      this.f4972 !== undefined,\n      false, // TODO: other tax form\n      '', // TODO: other tax form\n      this.l16(),\n      this.l17(),\n      this.l18(),\n      this.l19(),\n      this.l20(),\n      this.l21(),\n      this.l22(),\n      this.l23(),\n      this.l24(),\n      this.l25a(),\n      this.l25b(),\n      this.l25c(),\n      this.l25d(),\n      this.l26(),\n      this.l27(),\n      this.l28(),\n      this.l29(),\n      this.l30(),\n      this.l31(),\n      this.l32(),\n      this.l33(),\n      this.l34(),\n      this.f8888 !== undefined,\n      this.l35a(),\n      this.info.refund?.routingNumber,\n      this.info.refund?.accountType === AccountType.checking,\n      this.info.refund?.accountType === AccountType.savings,\n      this.info.refund?.accountNumber,\n      this.l36(),\n      this.l37(),\n      this.l38(),\n      // TODO: 3rd party\n      false,\n      false,\n      '',\n      '',\n      '',\n      this.occupation(PersonRole.PRIMARY),\n      // TODO: pin numbers\n      '',\n      this.occupation(PersonRole.SPOUSE),\n      '',\n      this.info.taxPayer.contactPhoneNumber,\n      this.info.taxPayer.contactEmail,\n      // Paid preparer fields:\n      '',\n      '',\n      false,\n      '',\n      '',\n      '',\n      ''\n    ].map((x) => (x === undefined ? '' : x))\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F1040Attachment.ts",
    "content": "import Form from 'ustaxes/core/irsForms/Form'\nimport F1040 from './F1040'\n\nabstract class F1040Attachment extends Form {\n  f1040: F1040\n\n  constructor(f1040: F1040) {\n    super()\n    this.f1040 = f1040\n  }\n\n  isNeeded = (): boolean => true\n  copies = (): F1040Attachment[] => []\n}\n\nexport abstract class Worksheet {\n  f1040: F1040\n\n  constructor(f1040: F1040) {\n    this.f1040 = f1040\n  }\n}\n\nexport default F1040Attachment\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F1040v.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F1040V extends F1040Attachment {\n  tag: FormTag = 'f1040v'\n  sequenceIndex = -1\n\n  fields = (): Field[] => {\n    const tp = this.f1040.info.taxPayer\n    const taxOwed = this.f1040.l37()\n\n    const result = [\n      tp.primaryPerson.ssid,\n      tp.spouse?.ssid,\n      Math.trunc(taxOwed), // dollars\n      Math.round((taxOwed - Math.trunc(taxOwed)) * 100), // cents\n      tp.primaryPerson.firstName,\n      tp.primaryPerson.lastName,\n      tp.spouse?.firstName,\n      tp.spouse?.lastName,\n      tp.primaryPerson.address.address,\n      tp.primaryPerson.address.aptNo,\n      tp.primaryPerson.address.city,\n      tp.primaryPerson.address.state,\n      tp.primaryPerson.address.zip,\n      tp.primaryPerson.address.foreignCountry,\n      tp.primaryPerson.address.province,\n      tp.primaryPerson.address.postalCode\n    ]\n\n    return result\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F2441.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: Credit for child and dependent care expenses\n */\nexport default class F2441 extends F1040Attachment {\n  tag: FormTag = 'f2441'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F2555.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Impacts EIC, 1040 instructions L27 step 1 question 4\n */\nexport default class F2555 extends F1040Attachment {\n  tag: FormTag = 'f2555'\n  sequenceIndex = 34\n\n  // TODO - required from 8812\n  l45 = (): number => 0\n\n  // TODO - required from 8812\n  l50 = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F4136.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: not implemented\n * Credit for federal tax on fuels\n */\nexport default class F4136 extends F1040Attachment {\n  tag: FormTag = 'f4136'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F4137.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n// TODO\nexport default class F4137 extends F1040Attachment {\n  tag = 'f4137'\n  sequenceIndex = 999\n\n  l6 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F4563.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Exclusion of income for residents of American Somoa\n * Impacts 8812,\n */\nexport default class F4563 extends F1040Attachment {\n  sequenceIndex = 563\n  tag: FormTag = 'f4563'\n\n  // TODO - required from 8812\n  l15 = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F4797.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Impacts EIC, 1040 instructions L27 step 2 question 3\n * Not implemented yet\n */\nexport default class F4797 extends F1040Attachment {\n  tag: FormTag = 'f4797'\n  sequenceIndex = 999\n\n  // TODO, required from schedule EIC, PUB 596, worksheet 1\n  l7 = (): number | undefined => undefined\n  l8 = (): number | undefined => undefined\n  l9 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F4952.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Impacts Schedule D, capital gains and taxes worksheet,\n * Not implemented yet\n */\nexport default class F4952 extends F1040Attachment {\n  tag: FormTag = 'f4952'\n  sequenceIndex = 999\n\n  l4e = (): number | undefined => undefined\n  l4g = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F4972.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented yet\n */\nexport default class F4972 extends F1040Attachment {\n  tag: FormTag = 'f4972'\n  sequenceIndex = 999\n\n  tax = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F5695.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented yet\n */\nexport default class F5695 extends F1040Attachment {\n  tag: FormTag = 'f5695'\n  sequenceIndex = 999\n\n  l30 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F6168.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n/**\n * Referenced from line 21 of Schedule E\n */\nexport default class F6168 extends F1040Attachment {\n  tag = 'f6168'\n  sequenceIndex = 999\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8582.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { MatrixRow } from './ScheduleE'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n/**\n * Referenced from line 22 of Schedule E\n */\nexport default class F8582 extends F1040Attachment {\n  tag = 'f8582'\n  sequenceIndex = 999\n\n  // TODO: 'Deducible rental estate loss after limitation, assuming all allowed'\n  deductibleRealEstateLossAfterLimitation = (): MatrixRow =>\n    this.f1040.scheduleE.rentalNet().map((v) => {\n      if (v === undefined || v >= 0) {\n        return undefined\n      }\n      return v\n    }) as MatrixRow\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8814.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F8814 extends F1040Attachment {\n  tag: FormTag = 'f8814'\n  sequenceIndex = 999\n\n  // TODO: required from schedule EIC, pub596, worksheet 1\n  l1b = (): number | undefined => undefined\n\n  tax = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8853.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n// Not yet implemented\nexport default class F8853 extends F1040Attachment {\n  tag: FormTag = 'f8853'\n  sequenceIndex = 999\n\n  l1 = (): number | undefined => undefined\n  l2 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8863.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n// Not yet implemented\nexport default class F8863 extends F1040Attachment {\n  tag: FormTag = 'f8863'\n  sequenceIndex = 999\n\n  l8 = (): number | undefined => undefined\n  l19 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8888.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented yet\n */\nexport default class F8888 extends F1040Attachment {\n  tag: FormTag = 'f8888'\n  sequenceIndex = 999\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8889.ts",
    "content": "import { Person, HealthSavingsAccount } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { CURRENT_YEAR, healthSavingsAccounts } from '../data/federal'\nimport F1040Attachment from './F1040Attachment'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype ContributionType = 'self-only' | 'family'\ntype PerMonthContributionType = {\n  amount: number[]\n  type: ContributionType[]\n}\n\nexport default class F8889 extends F1040Attachment {\n  tag: FormTag = 'f8889'\n  sequenceIndex = 52\n  // these should only be the HSAs that belong to this person\n  // the person can be either the primary person or the spouse\n  hsas: HealthSavingsAccount<Date>[]\n  person: Person\n  calculatedCoverageType: 'self-only' | 'family'\n  perMonthContributions: PerMonthContributionType\n  readonly firstDayOfLastMonth: Date\n\n  constructor(f1040: F1040, person: Person) {\n    super(f1040)\n    this.person = person\n    // The relevant HSAs are the ones either for this person or any that\n    // have family coverage.\n    this.hsas = this.f1040.info.healthSavingsAccounts\n      .filter((h) => {\n        if (h.personRole == person.role || h.coverageType == 'family') {\n          return true\n        }\n        return false\n      })\n      .map((h) => {\n        return {\n          ...h,\n          startDate: new Date(h.startDate),\n          endDate: new Date(h.endDate)\n        }\n      })\n    this.calculatedCoverageType = 'self-only'\n    this.firstDayOfLastMonth = new Date(CURRENT_YEAR, 11, 1)\n    this.perMonthContributions = {\n      amount: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n      type: Array<ContributionType>(12)\n    }\n  }\n\n  isNeeded = (): boolean =>\n    this.f1040.info.healthSavingsAccounts.some(\n      (h) => h.personRole === this.person.role || h.coverageType === 'family'\n    )\n\n  calculatePerMonthLimits = (): void => {\n    for (\n      let index = 0;\n      index < this.perMonthContributions.amount.length;\n      index++\n    ) {\n      // for each month check each HSA to see if we are covered.\n      this.hsas.forEach((h) => {\n        const firstDayOfThisMonth = new Date(CURRENT_YEAR, index, 1)\n        if (\n          h.startDate <= firstDayOfThisMonth &&\n          h.endDate >= firstDayOfThisMonth\n        ) {\n          // the coverage limit for that month is based on the type of coverage of the\n          // HSA. If you have both types of HSA coverage for that month, then the family\n          // coverage limit wins out. Since family coverage limit is higher we can just\n          // take the max of the coverage limit for this month.\n          if (\n            this.perMonthContributions.amount[index] <\n            healthSavingsAccounts.contributionLimit[h.coverageType]\n          ) {\n            this.perMonthContributions.amount[index] =\n              healthSavingsAccounts.contributionLimit[h.coverageType]\n            this.perMonthContributions.type[index] = h.coverageType\n          }\n        }\n      })\n    }\n    // The calculated coverage type is whichever one was in effect for longer\n    let familyMonthCount = 0\n    let singleMonthCount = 0\n    this.perMonthContributions.amount.forEach((m) => {\n      if (m == healthSavingsAccounts.contributionLimit.family) {\n        familyMonthCount += 1\n      } else if (m == healthSavingsAccounts.contributionLimit['self-only']) {\n        singleMonthCount += 1\n      }\n    })\n    if (familyMonthCount >= singleMonthCount) {\n      this.calculatedCoverageType = 'family'\n    } else {\n      this.calculatedCoverageType = 'self-only'\n    }\n  }\n\n  /* If you are an eligible individual on the first day of the last month of your tax year\n   * (December 1 for most taxpayers), you are considered to be an eligible individual\n   * for the entire year.\n   */\n  lastMonthRule = (): boolean => {\n    return this.hsas.some((hsa) => hsa.endDate >= this.firstDayOfLastMonth)\n  }\n\n  /*If, on the first day of the last month of your tax year (December 1 for most taxpayers), \n    you had family coverage, check the \"family\" box.\n  */\n  lastMonthCoverage = (): string | undefined => {\n    let coverage = undefined\n    for (const hsa of this.hsas) {\n      if (hsa.endDate >= this.firstDayOfLastMonth) {\n        if (hsa.coverageType == 'family') {\n          coverage = 'family'\n          break\n        }\n        coverage = 'self-only'\n      }\n    }\n    return coverage\n  }\n\n  fullYearHsa = (): boolean => {\n    return this.hsas.some(\n      (hsa) =>\n        hsa.startDate <= new Date(CURRENT_YEAR, 0, 1) &&\n        hsa.endDate >= this.firstDayOfLastMonth\n    )\n  }\n\n  contributionLimit = (): number => {\n    /*If you were under age 55 at the end of 2020 and, on the first day of every month during 2020, \n    you were, or were considered, an eligible individual with the same coverage, enter $3,550 \n    ($7,100 for family coverage). All others, see the instructions for the amount to enter.\n    */\n    /*If the last-month rule (see Last-month rule, earlier) applies, you are considered an eligible individual \n      for the entire year. You are treated as having the same HDHP coverage for the entire year as you had on \n      the first day of the last month of your tax year.\n      */\n    if (this.lastMonthRule()) {\n      // If, on the first day of the last month of your tax year (December 1 for most taxpayers),\n      // you had family coverage, check the \"family\" box.\n      const lastMonthCoverage = this.lastMonthCoverage()\n      if (lastMonthCoverage !== undefined) {\n        if (lastMonthCoverage === 'family') {\n          this.calculatedCoverageType = 'family'\n          return healthSavingsAccounts.contributionLimit.family\n        } else if (lastMonthCoverage === 'self-only') {\n          this.calculatedCoverageType = 'self-only'\n          return healthSavingsAccounts.contributionLimit['self-only']\n        }\n      }\n    }\n    /* If you don't have coverage in the last month, then you need to figure out\n       your contribution limit. If you don't have coverage for that month then\n       your contribution limit is 0. So let's initialize our per-month contribution\n       limit based on that.\n     */\n    this.calculatePerMonthLimits()\n    return Math.round(\n      this.perMonthContributions.amount.reduce((a, b) => a + b) / 12\n    )\n  }\n\n  splitFamilyContributionLimit = (): number | undefined => {\n    /* if you and your spouse each have separate HSAs and had family coverage under an HDHP at any time during 2020*/\n    /* If you are treated as having family coverage for each month, divide the amount on line 5 equally between you \n       and your spouse, unless you both agree on a different allocation (such as allocating nothing to one spouse).\n       Enter your allocable share on line 6.*/\n    /* Example. In 2020, you are an eligible individual and have self-only HDHP coverage. In March you marry and as\n       of April 1 you have family HDHP coverage. Neither you nor your spouse qualify for the additional contribution\n       amount. Your spouse has a separate HSA and is an eligible individual from April 1 to December 31, 2020. \n       Because you and your spouse are considered to have family coverage on December 1, your contribution limit is\n       $7,100 (the family coverage maximum). You and your spouse can divide this amount in any allocation to which\n      you agree (such as allocating nothing to one spouse).*/\n    if (!this.hsas.some((h) => h.coverageType === 'family')) {\n      return this.l5()\n    }\n\n    if (this.lastMonthCoverage() === 'family') {\n      // TODO: This hard codes the allocation at 50% for each spouse but the\n      // rules say any contribution allowcation is allowed\n      return Math.round(this.l5() / 2)\n    } else {\n      // get the number of months of family coverage\n      const familyMonths: number = this.perMonthContributions.type.filter(\n        (t) => t === 'family'\n      ).length\n\n      // TODO: This hard codes the allocation at 50% for each spouse but the\n      // rules say any contribution allowcation is allowed\n      const familyContribution: number =\n        (familyMonths * healthSavingsAccounts.contributionLimit['family']) /\n        12 /\n        2\n\n      // Add this to the contributions of the self-only portion of the year\n      const selfMonths: number = 12 - familyMonths\n\n      const selfContribution: number =\n        (selfMonths * healthSavingsAccounts.contributionLimit['self-only']) / 12\n\n      return familyContribution + selfContribution\n    }\n  }\n\n  /*Include on line 2 only those amounts you, or others on your behalf, contributed to your HSA in 2020. \n    Also, include those contributions made from January 1, 2021, through April 15, 2021, that were for 2020. \n    Do not include employer contributions (see line 9) or amounts rolled over from another HSA or Archer MSA. \n    See Rollovers, earlier. Also, do not include any qualified HSA funding distributions (see line 10). \n    Contributions to an employee's account through a cafeteria plan are treated as employer contributions \n    and are not included on line 2.\n  */\n  l2 = (): number =>\n    this.hsas.reduce((total, hsa) => hsa.contributions + total, 0)\n\n  l3 = (): number => this.contributionLimit()\n  l4 = (): number => sumFields([this.f1040.f8853?.l1(), this.f1040.f8853?.l2()])\n  l5 = (): number => this.l3() - this.l4()\n  l6 = (): number | undefined => this.splitFamilyContributionLimit()\n  // TODO: Additional contirbution amount. Need to know the age of the user\n  l7 = (): number | undefined => undefined\n  l8 = (): number => sumFields([this.l6(), this.l7()])\n  // Employer contributions are listed in W2 box 12 with code W\n  l9 = (): number =>\n    this.f1040.info.w2s\n      .filter((w2) => w2.personRole == this.person.role)\n      .reduce((res, w2) => res + (w2.box12?.W ?? 0), 0)\n  l10 = (): number | undefined => undefined\n  l11 = (): number => sumFields([this.l9(), this.l10()])\n  l12 = (): number => {\n    const tmp = this.l8() - this.l11()\n    return tmp < 0 ? 0 : tmp\n  }\n  l13 = (): number | undefined =>\n    this.l2() < this.l12() ? this.l2() : this.l12()\n  l14a = (): number =>\n    this.hsas.reduce((total, hsa) => hsa.totalDistributions + total, 0)\n  l14b = (): number | undefined => undefined\n  l14c = (): number => this.l14a() - (this.l14b() ?? 0)\n  l15 = (): number =>\n    this.hsas.reduce((total, hsa) => hsa.qualifiedDistributions + total, 0)\n  l16 = (): number => Math.max(0, this.l14c() - this.l15())\n  l17a = (): boolean => false\n  // TODO: add in logic for when line 17a is true\n  l17b = (): number | undefined => Math.round(this.l16() * 0.2)\n\n  l18 = (): number | undefined => undefined\n  l19 = (): number | undefined => undefined\n  l20 = (): number => sumFields([this.l18(), this.l19()])\n  l21 = (): number => Math.round(this.l20() * 0.1)\n\n  fields = (): Field[] => [\n    `${this.person.firstName} ${this.person.lastName}`,\n    this.person.ssid,\n    this.calculatedCoverageType === 'self-only', // line 1: self-only check box\n    this.calculatedCoverageType === 'family', // line 1: family checkbox\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14a(),\n    this.l14b(),\n    this.l14c(),\n    this.l15(),\n    this.l16(),\n    this.l17a(),\n    this.l17b(),\n    this.l18(),\n    this.l19(),\n    this.l20(),\n    this.l21()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8910.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented\n */\nexport default class F8910 extends F1040Attachment {\n  sequenceIndex = 999\n  tag: FormTag = 'f8910'\n\n  l15 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8919.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n// TODO\nexport default class F8919 extends F1040Attachment {\n  tag = 'f8919'\n  sequenceIndex = 999\n\n  l6 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8936.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\nexport default class F8936 extends F1040Attachment {\n  tag: FormTag = 'f8936'\n  sequenceIndex = 999\n\n  l15 = (): number | undefined => undefined\n  l23 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8949.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Asset, SoldAsset } from 'ustaxes/core/data'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype EmptyLine = [\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined\n]\n\ntype Line =\n  | [string, string, string, number, number, undefined, undefined, number]\n  | EmptyLine\nconst emptyLine: EmptyLine = [\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined\n]\n\nconst showDate = (date: Date): string =>\n  `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`\n\nconst toLine = (position: SoldAsset<Date>): Line => [\n  position.name,\n  showDate(position.openDate),\n  showDate(position.closeDate),\n  position.closePrice * position.quantity,\n  position.openPrice * position.quantity,\n  undefined,\n  undefined,\n  (position.closePrice - position.openPrice) * position.quantity\n]\n\nconst NUM_SHORT_LINES = 14\nconst NUM_LONG_LINES = 14\n\nconst padUntil = <A, B>(xs: A[], v: B, n: number): (A | B)[] => {\n  if (xs.length >= n) {\n    return xs\n  }\n  return [...xs, ...Array.from(Array(n - xs.length)).map(() => v)]\n}\n\nexport default class F8949 extends F1040Attachment {\n  tag: FormTag = 'f8949'\n  sequenceIndex = 12.1\n\n  index = 0\n\n  constructor(f1040: F1040, index = 0) {\n    super(f1040)\n    this.index = index\n  }\n\n  copies = (): F8949[] => {\n    if (this.index === 0) {\n      const extraCopiesNeeded = Math.round(\n        Math.max(\n          this.thisYearShortTermSales().length / NUM_SHORT_LINES,\n          this.thisYearLongTermSales().length / NUM_LONG_LINES\n        )\n      )\n      return Array.from(Array(extraCopiesNeeded)).map(\n        (_, i) => new F8949(this.f1040, i + 1)\n      )\n    }\n    return []\n  }\n\n  isNeeded = (): boolean => this.thisYearSales().length > 0\n\n  // Assuming we're only handling non-reported transactions\n  part1BoxA = (): boolean => false\n  part1BoxB = (): boolean => false\n  part1BoxC = (): boolean => true\n  part2BoxD = (): boolean => false\n  part2BoxE = (): boolean => false\n  part2BoxF = (): boolean => true\n\n  thisYearSales = (): SoldAsset<Date>[] =>\n    this.f1040.assets.filter(\n      (p) => p.closeDate !== undefined && p.closeDate.getFullYear() === 2020\n    ) as SoldAsset<Date>[]\n\n  thisYearLongTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearSales().filter((p) => this.isLongTerm(p))\n\n  thisYearShortTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearSales().filter((p) => !this.isLongTerm(p))\n\n  // in milliseconds\n  oneDay = 1000 * 60 * 60 * 24\n\n  isLongTerm = (p: Asset<Date>): boolean => {\n    if (p.closeDate === undefined) return false\n    const milliInterval = p.closeDate.getTime() - p.openDate.getTime()\n    return milliInterval / this.oneDay > 366\n  }\n\n  /**\n   * Take the short term transactions that fit on this copy of the 8949\n   */\n  shortTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearShortTermSales().slice(\n      this.index * NUM_SHORT_LINES,\n      (this.index + 1) * NUM_SHORT_LINES\n    )\n\n  /**\n   * Take the long term transactions that fit on this copy of the 8949\n   */\n  longTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearLongTermSales().slice(\n      this.index * NUM_LONG_LINES,\n      (this.index + 1) * NUM_LONG_LINES\n    )\n  shortTermLines = (): Line[] =>\n    padUntil(\n      this.shortTermSales().map((p) => toLine(p)),\n      emptyLine,\n      NUM_SHORT_LINES\n    )\n  longTermLines = (): Line[] =>\n    padUntil(\n      this.longTermSales().map((p) => toLine(p)),\n      emptyLine,\n      NUM_LONG_LINES\n    )\n\n  shortTermTotalProceeds = (): number =>\n    this.shortTermSales().reduce(\n      (acc, p) => acc + p.closePrice * p.quantity - (p.closeFee ?? 0),\n      0\n    )\n\n  shortTermTotalCost = (): number =>\n    this.shortTermSales().reduce(\n      (acc, p) => acc + p.openPrice * p.quantity + p.openFee,\n      0\n    )\n\n  shortTermTotalGain = (): number =>\n    this.shortTermTotalProceeds() - this.shortTermTotalCost()\n\n  // TODO: handle adjustments column.\n  shortTermTotalAdjustments = (): number | undefined => undefined\n\n  longTermTotalProceeds = (): number =>\n    this.longTermSales().reduce(\n      (acc, p) => acc + p.closePrice * p.quantity - (p.closeFee ?? 0),\n      0\n    )\n\n  longTermTotalCost = (): number =>\n    this.longTermSales().reduce(\n      (acc, p) => acc + p.openPrice * p.quantity + p.openFee,\n      0\n    )\n\n  longTermTotalGain = (): number =>\n    this.longTermTotalProceeds() - this.longTermTotalCost()\n\n  // TODO: handle adjustments column.\n  longTermTotalAdjustments = (): number | undefined => undefined\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.part1BoxA(),\n    this.part1BoxB(),\n    this.part1BoxC(),\n    ...this.shortTermLines().flat(),\n    this.shortTermTotalProceeds(),\n    this.shortTermTotalCost(),\n    undefined, // greyed out field\n    this.shortTermTotalAdjustments(),\n    this.shortTermTotalGain(),\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.part2BoxD(),\n    this.part2BoxE(),\n    this.part2BoxF(),\n    ...this.longTermLines().flat(),\n    this.longTermTotalProceeds(),\n    this.longTermTotalCost(),\n    undefined, // greyed out field\n    this.longTermTotalAdjustments(),\n    this.longTermTotalGain()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8959.ts",
    "content": "import { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport ScheduleSE from './ScheduleSE'\nimport { fica } from '../data/federal'\nimport F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F8959 extends F1040Attachment {\n  tag: FormTag = 'f8959'\n  sequenceIndex = 71\n  scheduleSE?: ScheduleSE\n\n  isNeeded = (): boolean => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const totalW2Income = this.f1040.info.w2s.reduce(\n      (s, w2) => s + w2.medicareIncome,\n      0\n    )\n    return fica.additionalMedicareTaxThreshold(filingStatus) < totalW2Income\n  }\n\n  thresholdFromFilingStatus = (): number =>\n    fica.additionalMedicareTaxThreshold(this.f1040.info.taxPayer.filingStatus)\n\n  computeAdditionalMedicareTax = (compensation: number): number =>\n    fica.additionalMedicareTaxRate * compensation\n\n  // Part I: Additional Medicare Tax on Medicare Wages\n  l1 = (): number =>\n    this.f1040.info.w2s.reduce((sum, w2) => sum + w2.medicareIncome, 0)\n\n  l2 = (): number | undefined => this.f1040.f4137?.l6()\n  l3 = (): number | undefined => this.f1040.f8919?.l6()\n  l4 = (): number => sumFields([this.l1(), this.l2(), this.l3()])\n\n  l5 = (): number => this.thresholdFromFilingStatus()\n  l6 = (): number => Math.max(0, this.l4() - this.l5())\n\n  l7 = (): number | undefined => this.computeAdditionalMedicareTax(this.l6())\n\n  // Part II: Additional Medicare Tax on Self-Employment Income\n  l8 = (): number | undefined => this.scheduleSE?.l6()\n  l9 = (): number => this.thresholdFromFilingStatus()\n  l10 = (): number => this.l4()\n  l11 = (): number => Math.max(0, this.l9() - this.l10())\n\n  l12 = (): number => Math.max(0, (this.l8() ?? 0) - this.l11())\n\n  l13 = (): number | undefined => this.computeAdditionalMedicareTax(this.l12())\n\n  // Part III: Additional Medicare Tax on Railroad Retirement Tax Act\n  // (RRTA) Compensation\n  l14 = (): number | undefined => undefined // TODO: RRTA in W2\n  l15 = (): number => this.thresholdFromFilingStatus()\n  l16 = (): number => Math.max(0, (this.l14() ?? 0) - this.l15())\n\n  l17 = (): number => this.computeAdditionalMedicareTax(this.l12())\n\n  // Part IV: Total Medicare Tax\n  l18 = (): number => sumFields([this.l7(), this.l3(), this.l17()])\n\n  // Part V: Withholding Reconciliation\n  l19 = (): number =>\n    this.f1040.info.w2s.reduce((sum, w2) => sum + w2.medicareWithholding, 0)\n\n  l20 = (): number => this.l1()\n  l21 = (): number => fica.regularMedicareTaxRate * this.l20()\n\n  l22 = (): number => Math.max(0, this.l19() - this.l21())\n\n  l23 = (): number | undefined => 0 // TODO: RRTA\n  l24 = (): number => sumFields([this.l22(), this.l23()])\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n\n    this.l15(),\n    this.l16(),\n    this.l17(),\n\n    this.l18(),\n\n    this.l19(),\n    this.l20(),\n    this.l21(),\n    this.l22(),\n    this.l23(),\n    this.l24()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8960.ts",
    "content": "import { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { netInvestmentIncomeTax } from '../data/federal'\nimport F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F8960 extends F1040Attachment {\n  tag: FormTag = 'f8960'\n  sequenceIndex = 72\n\n  isNeeded = (): boolean => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const totalW2Income = this.f1040.info.w2s.reduce(\n      (sum, w2) => sum + w2.income,\n      0\n    )\n    return netInvestmentIncomeTax.taxThreshold(filingStatus) < totalW2Income\n  }\n\n  //Taxable Interest\n  l1 = (): number | undefined => this.f1040.l2b()\n\n  // Ordinary Dividends\n  l2 = (): number | undefined => this.f1040.l3b()\n  /* Enter the gross income from all annuities, except annuities paid from the following.\n\n    - Section 401—Qualified pension, profit-sharing, and stock bonus plans.\n    - Section 403(a)—Qualified annuity plans purchased by an employer for an employee.\n    - Section 403(b)—Annuities purchased by public schools or section 501(c)(3) tax-exempt organizations.\n    - Section 408—Individual Retirement Accounts (IRAs) or Annuities.\n    - Section 408A—Roth IRAs.\n    - Section 457(b)—Deferred compensation plans of a state and local government and tax-exempt organization.\n    - Amounts paid in consideration for services (for example, distributions from a foreign retirement plan that \n    are paid in the form of an annuity and include investment income that was earned by the retirement plan).\n\n    How your annuities are reported to you. Net investment income from annuities is reported to a recipient on \n    Form 1099-R, Distributions From Pensions, Annuities, Retirement or Profit-Sharing Plans, IRAs, Insurance \n    Contracts, etc. However, the amount reported on Form 1099-R may also include annuity payments from \n    retirement plans that are exempt from NIIT. Amounts subject to NIIT should be identified with code \"D\" in box 7. \n    If code \"D\" is shown in box 7 of Form 1099-R, include on Form 8960, line 3, the taxable amount reported \n    on Form 1099-R, box 2a. However, if the payor checks box 2b indicating the taxable amount can’t be determined, \n    you may need to calculate the taxable portion of your distribution. See Pub. 939, General Rule for Pensions \n    and Annuities, and Pub. 575, Pension and Annuity Income, for details.\n  */\n  l3 = (): number | undefined => undefined\n  /* Rental Real Estate, Royalties, Partnerships, S Corporations, and Trusts\n      Enter the following amount from your properly completed return.\n\n      - Schedule 1 (Form 1040), line 5.\n      - Form 1041, line 5.\n      - Form 1041-QFT, the portion of line 4 that’s income and loss that properly \n      would be reported by a trust filing Form 1041 on Form 1041, line 5.\n      - Form 1040-NR, the amount properly reported on the attachment to your Form 1040-NR\n      representing the amount that you would properly include on Schedule 1 (Form 1040), line 5, \n      if you were filing Form 1040 or 1040‐SR and including income and loss only for your period of U.S. residency.\n  */\n  l4a = (): number | undefined => this.f1040.schedule1.l5()\n\n  l4b = (): number | undefined => undefined\n\n  l4c = (): number => sumFields([this.l4a(), this.l4b()])\n\n  // Line 5a-5d: Gains and Losses on the Disassets of Property\n  l5a = (): number => sumFields([this.f1040.l7(), this.f1040.schedule1.l4()])\n  // TODO: implement line 5b and 5c from worksheet.\n  l5b = (): number | undefined => undefined\n  l5c = (): number | undefined => undefined\n  l5d = (): number => sumFields([this.l5a(), this.l5b(), this.l5c()])\n\n  // TODO: Line 6: Adjustments to Investment Income for Certain CFCs and PFICs\n  l6 = (): number | undefined => undefined\n\n  // TODO: Line 7: Other Modifications to Investment Income\n  l7 = (): number | undefined => undefined\n\n  l8 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2(),\n      this.l3(),\n      this.l4c(),\n      this.l5d(),\n      this.l6(),\n      this.l7()\n    ])\n  // Todo: Implement Schedule A\n  l9a = (): number | undefined => this.f1040.scheduleA?.l9()\n  l9b = (): number | undefined => undefined\n  l9c = (): number | undefined => undefined\n  l9d = (): number => sumFields([this.l9a(), this.l9b(), this.l9c()])\n  l10 = (): number | undefined => undefined\n  l11 = (): number => sumFields([this.l9d(), this.l10()])\n\n  l12 = (): number => Math.max(0, this.l8() - this.l11())\n\n  // TODO: This should also take into account values on form 2555 and adjustments for Certain CFCs and Certain PFICs\n  l13 = (): number => this.f1040.l11()\n\n  l14 = (): number =>\n    netInvestmentIncomeTax.taxThreshold(this.f1040.info.taxPayer.filingStatus)\n\n  l15 = (): number => Math.max(0, this.l13() - this.l14())\n  l16 = (): number => (this.l12() < this.l15() ? this.l12() : this.l15())\n\n  l17 = (): number => Math.round(this.l16() * netInvestmentIncomeTax.taxRate)\n\n  // TODO: Estates and Trusts\n  // leave all of the following undefined until we support estates and trusts\n  // these lines are to be left blank for individuals\n  l18a = (): number | undefined => undefined\n  l18b = (): number | undefined => undefined\n  l18c = (): number | undefined => undefined\n\n  l19a = (): number | undefined => undefined\n  l19b = (): number | undefined => undefined\n  l19c = (): number | undefined => undefined\n\n  l20 = (): number | undefined => undefined // this.l19c() < this.l18c()? this.l19c() : this.l18c()\n  l21 = (): number | undefined => undefined // Math.round(this.l20() * netInvestmentIncomeTax.taxRate)\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    undefined, // Section 6013(g) election checkbox\n    undefined, // Section 6013(h) election checkbox\n    undefined, // Regulations section 1.1411-10(g) election checkbox\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4a(),\n    this.l4b(),\n    this.l4c(),\n    this.l5a(),\n    this.l5b(),\n    this.l5c(),\n    this.l5d(),\n    this.l6(),\n    this.l7(),\n    this.l8(),\n    this.l9a(),\n    this.l9b(),\n    this.l9c(),\n    this.l9d(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    this.l18a(),\n    this.l18b(),\n    this.l18c(),\n    this.l19a(),\n    this.l19b(),\n    this.l19c(),\n    this.l20(),\n    this.l21()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8962.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: Not yet implemented\n * Net premium tax credit\n */\nexport default class F8962 extends F1040Attachment {\n  tag: FormTag = 'f8962'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8995.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented\n */\nexport default class F8995 extends F1040Attachment {\n  tag: FormTag = 'f8995'\n  sequenceIndex = 999\n\n  deductions = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/F8995A.ts",
    "content": "import F8995 from './F8995'\n\nexport default class F8995A extends F8995 {}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/Main.ts",
    "content": "import { Asset, Information } from 'ustaxes/core/data'\nimport { Either, run } from 'ustaxes/core/util'\nimport F1040 from './F1040'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { F1040Error } from 'ustaxes/forms/errors'\nimport { validate } from 'ustaxes/forms/F1040Base'\n\nexport const create1040 = (\n  info: Information,\n  assets: Asset<Date>[]\n): Either<F1040Error[], [F1040, Form[]]> =>\n  run(validate(info))\n    .map<[F1040, Form[]]>((info) => {\n      const f1040 = new F1040(info, assets)\n      return [f1040, f1040.schedules()]\n    })\n    .value()\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/Schedule1.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport ScheduleE from './ScheduleE'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class Schedule1 extends F1040Attachment {\n  tag: FormTag = 'f1040s1'\n  sequenceIndex = 1\n  scheduleE?: ScheduleE\n  otherIncomeStrings: Set<string>\n\n  constructor(f1040: F1040) {\n    super(f1040)\n    this.otherIncomeStrings = new Set<string>()\n  }\n\n  isNeeded = (): boolean =>\n    this.f1040.studentLoanInterestWorksheet !== undefined &&\n    this.f1040.studentLoanInterestWorksheet.notMFS() &&\n    this.f1040.studentLoanInterestWorksheet.isNotDependent()\n\n  l1 = (): number | undefined => undefined\n  l2a = (): number | undefined => undefined\n  l2b = (): number | undefined => undefined\n  l3 = (): number | undefined => undefined\n  l4 = (): number | undefined => undefined\n  l5 = (): number | undefined => this.scheduleE?.l41()\n  l6 = (): number | undefined => undefined\n  l7 = (): number | undefined => undefined\n  l8 = (): number => {\n    if (\n      this.f1040.f8889.isNeeded() ||\n      (this.f1040.f8889Spouse?.isNeeded() ?? false)\n    ) {\n      this.otherIncomeStrings.add('HSA')\n    }\n    return sumFields([\n      this.f1040.f8889.l16(),\n      this.f1040.f8889.l20(),\n      this.f1040.f8889Spouse?.l16(),\n      this.f1040.f8889Spouse?.l20()\n    ])\n  }\n  l9 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2a(),\n      this.l3(),\n      this.l4(),\n      this.l5(),\n      this.l6(),\n      this.l7(),\n      this.l8()\n    ])\n\n  l10 = (): number | undefined => undefined\n  l11 = (): number | undefined => undefined\n  l12 = (): number | undefined =>\n    sumFields([this.f1040.f8889.l13(), this.f1040.f8889Spouse?.l13()])\n  l13 = (): number | undefined => undefined\n  l14 = (): number | undefined => undefined\n  l15 = (): number | undefined => undefined\n  l16 = (): number | undefined => undefined\n  l17 = (): number | undefined => undefined\n  l18 = (): number | undefined => undefined\n  l19 = (): number | undefined => undefined\n  l20 = (): number | undefined => this.f1040.studentLoanInterestWorksheet?.l9()\n  l21 = (): number | undefined => undefined\n  // TO DO: Write in Deductions\n  l22writeIn = (): number | undefined => undefined\n\n  // TODO: adjustments to income\n  l22 = (): number | undefined =>\n    sumFields([\n      this.l10(),\n      this.l11(),\n      this.l12(),\n      this.l13(),\n      this.l14(),\n      this.l15(),\n      this.l16(),\n      this.l17(),\n      this.l18(),\n      this.l19(),\n      this.l20(),\n      this.l21(),\n      this.l22writeIn()\n    ])\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2a(),\n    this.l2b(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    Array.from(this.otherIncomeStrings).join(' '), // Other income type textbox\n    undefined, // Other income type 2\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    this.l18(),\n    undefined, // Alimony Recipient SSN\n    undefined, // Date of Divorce/Seperation\n    this.l19(),\n    this.l20(),\n    this.l21(),\n    this.l22()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/Schedule2.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class Schedule2 extends F1040Attachment {\n  tag: FormTag = 'f1040s2'\n  sequenceIndex = 2\n  otherIncomeStrings: Set<string>\n\n  constructor(f1040: F1040) {\n    super(f1040)\n    this.otherIncomeStrings = new Set<string>()\n  }\n\n  isNeeded = (): boolean =>\n    this.f1040.f8959.isNeeded() || this.f1040.f8960.isNeeded()\n\n  // Part I: Tax\n  l1 = (): number | undefined => undefined // TODO: Alternative Minimum Tax (form 6251)\n  l2 = (): number | undefined => undefined // TODO: excess advance premium tax credit repayment (form 8962)\n  l3 = (): number => sumFields([this.l1(), this.l2()])\n\n  // Part II: Other Tax\n  l4 = (): number | undefined => undefined // TODO: self-employment tax (schedule SE)\n  l5 = (): number | undefined => undefined // TODO: unreported FICA tax\n  l6 = (): number | undefined => undefined // TODO: additional tax on retirement accounts\n  l7a = (): number | undefined => undefined // TODO: household employment taxes\n  l7b = (): number | undefined => undefined // TODO: repayment of first-time homebuyer credit\n  l8 = (): number | undefined => {\n    if (\n      this.f1040.f8889.l17b() !== undefined ||\n      this.f1040.f8889Spouse?.l17b() !== undefined\n    ) {\n      this.otherIncomeStrings.add('HSA')\n    }\n    if (this.f1040.f8889.l21() > 0) {\n      this.otherIncomeStrings.add('HDHP')\n    }\n\n    if (\n      this.f1040.f8889Spouse?.l21() !== undefined &&\n      this.f1040.f8889Spouse.l21() > 0\n    ) {\n      this.otherIncomeStrings.add('HDHP')\n    }\n\n    return sumFields([\n      this.f1040.f8959.l18(),\n      this.f1040.f8960.l17(),\n      this.f1040.f8889.l17b(),\n      this.f1040.f8889.l21(),\n      this.f1040.f8889Spouse?.l17b(),\n      this.f1040.f8889Spouse?.l21()\n    ])\n  }\n  l9 = (): number | undefined => undefined // TODO: section 965 net tax liability\n  l10 = (): number | undefined =>\n    sumFields([\n      this.l4(),\n      this.l5(),\n      this.l6(),\n      this.l7a(),\n      this.l7b(),\n      this.l8()\n    ])\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n\n    this.l1(),\n    this.l2(),\n    this.l3(),\n\n    this.l4(),\n    undefined,\n    undefined /* checkboxes */,\n    this.l5(),\n    this.l6(),\n    this.l7a(),\n    this.l7b(),\n    this.f1040.f8959.isNeeded(), // Form 8959 checkbox\n    this.f1040.f8960.isNeeded(), // Form 8960 checkbox\n    undefined, //others checkbox\n    Array.from(this.otherIncomeStrings).join(' '), // others textbox\n    this.l8(),\n    this.l9(),\n    this.l10()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/Schedule3.ts",
    "content": "import { IncomeW2, PersonRole } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { fica } from '../data/federal'\nimport F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport const claimableExcessSSTaxWithholding = (w2s: IncomeW2[]): number => {\n  /* Excess FICA taxes are calculated per person. If an individual person\n    has greater than the applicable amount then they are entitled to a refund\n    of that amount\n   */\n  let claimableExcessFica = 0\n  const primaryFica = w2s\n    .filter((w2) => w2.personRole == PersonRole.PRIMARY)\n    .map((w2) => w2.ssWithholding)\n    .reduce((l, r) => l + r, 0)\n  const spouseFica = w2s\n    .filter((w2) => w2.personRole == PersonRole.SPOUSE)\n    .map((w2) => w2.ssWithholding)\n    .reduce((l, r) => l + r, 0)\n\n  if (\n    primaryFica > fica.maxSSTax &&\n    w2s\n      .filter((w2) => w2.personRole == PersonRole.PRIMARY)\n      .every((w2) => w2.ssWithholding <= fica.maxSSTax)\n  ) {\n    claimableExcessFica += primaryFica - fica.maxSSTax\n  }\n\n  if (\n    spouseFica > fica.maxSSTax &&\n    w2s\n      .filter((w2) => w2.personRole == PersonRole.SPOUSE)\n      .every((w2) => w2.ssWithholding <= fica.maxSSTax)\n  ) {\n    claimableExcessFica += spouseFica - fica.maxSSTax\n  }\n\n  return claimableExcessFica\n}\n\nexport default class Schedule3 extends F1040Attachment {\n  tag: FormTag = 'f1040s3'\n  sequenceIndex = 3\n\n  isNeeded = (): boolean =>\n    claimableExcessSSTaxWithholding(this.f1040.info.w2s) > 0\n\n  deductions = (): number => 0\n  // Part I: Nonrefundable credits\n  l1 = (): number | undefined => undefined\n  l2 = (): number | undefined => undefined\n  l3 = (): number | undefined => undefined\n  l4 = (): number | undefined => undefined\n  l5 = (): number | undefined => undefined\n  l6 = (): number | undefined => undefined // TODO: checkboxes\n  l7 = (): number | undefined =>\n    sumFields([this.l1(), this.l2(), this.l3(), this.l4(), this.l5()])\n\n  // Part II: Other payments and refundable credits\n  l8 = (): number | undefined => undefined\n  l9 = (): number | undefined => undefined\n  l10 = (): number =>\n    // TODO: also applies to RRTA tax\n    claimableExcessSSTaxWithholding(this.f1040.validW2s())\n\n  l11 = (): number | undefined => undefined\n\n  l12a = (): number | undefined => undefined\n  l12b = (): number | undefined => undefined\n  l12c = (): number | undefined => undefined\n  l12d = (): number | undefined => undefined // TODO: 'other' box\n  l12e = (): number | undefined => undefined\n  l12f = (): number | undefined =>\n    sumFields([this.l12a(), this.l12b(), this.l12c(), this.l12d(), this.l12e()])\n\n  l13 = (): number | undefined =>\n    sumFields([this.l8(), this.l9(), this.l10(), this.l11(), this.l12f()])\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n\n    ...Array<undefined>(4).fill(undefined), // TODO: checkboxes\n    this.l6(),\n\n    this.l7(),\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n\n    this.l12a(),\n    this.l12b(),\n    this.l12c(),\n    undefined /* TODO: 'other' box */,\n    this.l12d(),\n    this.l12e(),\n\n    this.l12f(),\n    this.l13()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/Schedule8812.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class Schedule8812 extends F1040Attachment {\n  tag: FormTag = 'f1040s8'\n  sequenceIndex = 47\n\n  isNeeded = (): boolean =>\n    this.f1040.info.taxPayer.dependents.some(\n      (dep) =>\n        this.f1040.childTaxCreditWorksheet.qualifiesChild(dep) ||\n        this.f1040.childTaxCreditWorksheet.qualifiesOther(dep)\n    )\n\n  // This can be calculated with either pub 972 or the child tax credit worksheet, but for now we're only supporting the worksheet\n  // TODO: Add pub 972 support\n  l1 = (): number => this.f1040.childTaxCreditWorksheet.l8() ?? 0\n\n  l2 = (): number => this.f1040.l19() ?? 0\n\n  l3 = (): number => Math.max(0, this.l1() - this.l2())\n\n  l4 = (): number | undefined =>\n    this.f1040.childTaxCreditWorksheet.numberQualifyingChildren() * 1400\n\n  l5 = (): number => Math.min(this.l3(), this.l4() ?? 0)\n\n  // This is a horrible, horrible line\n  // have net earnings from self-employment and used optional methods => report pub972 Earned Income Worksheet (even if taking EIC)\n  // Taking EIC => completed worksheet B? => worksheet B line 4b, plus combat pay, minus clergy housing and meals, else EIC step 5 plus combat pay\n  // Not taking EIC? => pub 972 Earned Income Worksheet if self employed, or filing Schedule SE, or filing Schedule C as a \"statutory employee\" ,\n  // else Form 1040 l1, minus fellowships, income as an inmate, deferred compensation, and Medicaid waiver, unless you chose to inclue the Medicaid waivers,\n  // and add combat pay in as well\n  // So for now, it's just line 1 or EIC step 5 (line 9)\n  // TODO: Add other earned income definitions\n  l6 = (): number =>\n    this.f1040.scheduleEIC.isNeeded()\n      ? this.f1040.scheduleEIC.earnedIncome()\n      : this.f1040.l1()\n\n  l7checkBox = (): boolean => this.l6() > 2500\n\n  l7 = (): number | undefined =>\n    this.l7checkBox() ? this.l6() - 2500 : undefined\n\n  l8 = (): number | undefined => (this.l7() ?? 0) * 0.15\n\n  ssWithholding(): number {\n    if (this.f1040.validW2s().length > 0) {\n      return this.f1040\n        .validW2s()\n        .reduce((res, w2) => res + w2.ssWithholding, 0)\n    }\n    return 0\n  }\n\n  medicareWithholding = (): number =>\n    this.f1040.validW2s().reduce((res, w2) => res + w2.medicareWithholding, 0)\n\n  l9checkBox = (): boolean => (this.l4() ?? 0) > 4200\n\n  l9 = (): number | undefined =>\n    this.l9checkBox()\n      ? this.ssWithholding() + this.medicareWithholding()\n      : undefined\n\n  l10 = (): number | undefined =>\n    this.l9checkBox()\n      ? sumFields([\n          this.f1040.schedule1.l14(),\n          this.f1040.schedule2.l5(),\n          this.f1040.schedule2.l8()\n        ])\n      : undefined\n\n  l11 = (): number | undefined =>\n    this.l9checkBox() ? (this.l9() ?? 0) + (this.l10() ?? 0) : undefined\n\n  // TODO: Add 1040-NR\n  l12 = (): number | undefined =>\n    this.l9checkBox()\n      ? sumFields([this.f1040.l27(), this.f1040.schedule3.l10()])\n      : undefined\n\n  l13 = (): number | undefined =>\n    this.l9checkBox()\n      ? Math.max(0, (this.l11() ?? 0) - (this.l12() ?? 0))\n      : undefined\n\n  l14 = (): number | undefined =>\n    this.l9checkBox() ? Math.max(this.l8() ?? 0, this.l13() ?? 0) : undefined\n\n  l15 = (): number | undefined =>\n    this.l9checkBox() ? Math.min(this.l14() ?? 0, this.l5()) : this.l5()\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.f1040.childTaxCreditWorksheet.numberQualifyingChildren(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    undefined, // Nontaxable combat pay not supported,\n    !this.l7checkBox(),\n    this.l7checkBox(),\n    this.l7(),\n    this.l8(),\n    !this.l9checkBox(),\n    this.l9checkBox(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleA.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n// Not yet implemented\nexport default class ScheduleA extends F1040Attachment {\n  tag: FormTag = 'f1040sa'\n  sequenceIndex = 999\n\n  deductions(): number {\n    return 0\n  }\n\n  // Used in Form 8960\n  l9 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleB.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport F1040 from './F1040'\n\ninterface PayerAmount {\n  payer?: string\n  amount?: number\n}\n\nexport default class ScheduleB extends F1040Attachment {\n  tag: FormTag = 'f1040sb'\n  sequenceIndex = 8\n  readonly interestPayersLimit = 14\n  readonly dividendPayersLimit = 16\n\n  index = 0\n\n  constructor(f1040: F1040, index = 0) {\n    super(f1040)\n\n    this.index = index\n  }\n\n  copies = (): ScheduleB[] => {\n    if (this.index === 0) {\n      const numInterestPayers = this.l1Fields().length\n      const numDivPayers = this.l5Fields().length\n\n      const extraCopiesNeeded = Math.floor(\n        Math.max(\n          numInterestPayers / this.interestPayersLimit,\n          numDivPayers / this.dividendPayersLimit\n        )\n      )\n\n      return Array.from(Array(extraCopiesNeeded)).map(\n        (_, i) => new ScheduleB(this.f1040, i + 1)\n      )\n    }\n    return []\n  }\n\n  isNeeded = (): boolean =>\n    this.l1Fields().length > 0 || this.l5Fields().length > 0\n\n  l1Fields = (): PayerAmount[] =>\n    this.f1040.f1099Ints().map((v) => ({\n      payer: v.payer,\n      amount: v.form.income\n    }))\n\n  l1 = (): Array<string | undefined> => {\n    const payerValues = this.l1Fields().slice(\n      this.index * this.interestPayersLimit,\n      (this.index + 1) * this.interestPayersLimit\n    )\n\n    const rightPad = 2 * (this.interestPayersLimit - payerValues.length)\n    // ensure we return an array of length interestPayersLimit * 2.\n    return payerValues\n      .flatMap(({ payer, amount }) => [payer, amount?.toString()])\n      .concat(Array(rightPad).fill(undefined))\n  }\n\n  l2 = (): number => sumFields(this.f1040.f1099Ints().map((f) => f.form.income))\n\n  // TODO: Interest from tax exempt savings bonds\n  l3 = (): number | undefined => undefined\n\n  l4 = (): number => this.l2() - (this.l3() ?? 0)\n\n  /**\n   * Total interest on all schedule Bs.\n   */\n  to1040l2b = (): number =>\n    [this, ...this.copies()].reduce((acc, f) => acc + f.l4(), 0)\n\n  l5Fields = (): PayerAmount[] =>\n    this.f1040.f1099Divs().map((v) => ({\n      payer: v.payer,\n      amount: v.form.dividends\n    }))\n\n  l5 = (): Array<string | undefined | number> => {\n    const payerValues = this.l5Fields().slice(\n      this.index * this.dividendPayersLimit,\n      (this.index + 1) * this.dividendPayersLimit\n    )\n\n    const rightPad = 2 * (this.dividendPayersLimit - payerValues.length)\n    return payerValues\n      .flatMap(({ payer, amount }) => [payer, amount])\n      .concat(Array(rightPad).fill(undefined))\n  }\n\n  l6 = (): number => sumFields(this.l5Fields().map(({ amount }) => amount))\n\n  /**\n   * Total dividends on all schedule Bs.\n   */\n  to1040l3b = (): number =>\n    [this, ...this.copies()].reduce((acc, f) => acc + f.l6(), 0)\n\n  foreignAccount = (): boolean =>\n    this.f1040.info.questions.FOREIGN_ACCOUNT_EXISTS ?? false\n\n  fincenForm = (): boolean => this.f1040.info.questions.FINCEN_114 ?? false\n  fincenCountry = (): string | undefined =>\n    this.f1040.info.questions.FINCEN_114_ACCOUNT_COUNTRY\n  foreignTrust = (): boolean =>\n    this.f1040.info.questions.FOREIGN_TRUST_RELATIONSHIP ?? false\n\n  l7a = (): [boolean, boolean] => [\n    this.foreignAccount(),\n    !this.foreignAccount()\n  ]\n\n  l7a2 = (): [boolean, boolean] => [this.fincenForm(), !this.fincenForm()]\n\n  l7b = (): string | undefined => this.fincenCountry()\n\n  l8 = (): [boolean, boolean] => [this.foreignTrust(), !this.foreignTrust()]\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    ...this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    ...this.l5(),\n    this.l6(),\n    ...this.l7a(),\n    ...this.l7a2(),\n    this.l7b(),\n    ...this.l8()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleC.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented\n */\nexport default class ScheduleC extends F1040Attachment {\n  tag: FormTag = 'f1040sc'\n  sequenceIndex = 999\n\n  // TODO: statutory employee income\n  // shown on Schedule 8812, earned income\n  l1 = (): number | undefined => undefined\n\n  // TODO: net profit or loss\n  // shown on Schedule 8812, earned income\n  l31 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleD.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { F1099BData, FilingStatus } from 'ustaxes/core/data'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport SDRateGainWorksheet from './worksheets/SDRateGainWorksheet'\nimport SDUnrecaptured1250 from './worksheets/SDUnrecaptured1250'\nimport F8949 from './F8949'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class ScheduleD extends F1040Attachment {\n  tag: FormTag = 'f1040sd'\n  sequenceIndex = 12\n  aggregated: F1099BData\n  rateGainWorksheet: SDRateGainWorksheet\n  unrecaptured1250: SDUnrecaptured1250\n\n  readonly l21MinMFS = 1500\n  readonly l21MinDefault = 3000\n\n  constructor(f1040: F1040) {\n    super(f1040)\n\n    const bs: F1099BData[] = f1040.f1099Bs().map((f) => f.form)\n\n    this.aggregated = {\n      shortTermProceeds: bs.reduce((l, r) => l + r.shortTermProceeds, 0),\n      shortTermCostBasis: bs.reduce((l, r) => l + r.shortTermCostBasis, 0),\n      longTermProceeds: bs.reduce((l, r) => l + r.longTermProceeds, 0),\n      longTermCostBasis: bs.reduce((l, r) => l + r.longTermCostBasis, 0)\n    }\n\n    this.rateGainWorksheet = new SDRateGainWorksheet()\n    this.unrecaptured1250 = new SDUnrecaptured1250()\n  }\n\n  isNeeded = (): boolean =>\n    this.f1040.f1099Bs().length > 0 || this.f1040.f8949.isNeeded()\n\n  l21Min = (): number => {\n    if (this.f1040.info.taxPayer.filingStatus === FilingStatus.MFS) {\n      return this.l21MinMFS\n    }\n    return this.l21MinDefault\n  }\n\n  l1ad = (): number | undefined => this.aggregated.shortTermProceeds\n  l1ae = (): number | undefined => this.aggregated.shortTermCostBasis\n  // This field is greyed out, but fillable\n  l1ag = (): number | undefined => undefined\n  l1ah = (): number => sumFields([this.l1ad(), 0 - (this.l1ae() ?? 0)])\n\n  l1f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part1BoxA())\n\n  l1bd = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalProceeds()))\n  l1be = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalCost()))\n\n  l1bg = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalAdjustments()))\n  l1bh = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalGain()))\n\n  l2f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part1BoxB())\n  l2d = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalProceeds()))\n\n  l2e = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalCost()))\n\n  l2g = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalAdjustments()))\n\n  l2h = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalGain()))\n\n  l3f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part1BoxC())\n  l3d = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalProceeds()))\n\n  l3e = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalCost()))\n\n  l3g = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalAdjustments()))\n\n  l3h = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalGain()))\n\n  l4 = (): number | undefined => undefined\n\n  l5 = (): number | undefined => undefined\n\n  l6 = (): number | undefined => undefined\n\n  l7 = (): number =>\n    sumFields([\n      this.l1ah(),\n      this.l1bh(),\n      this.l2h(),\n      this.l3h(),\n      this.l4(),\n      this.l5(),\n      this.l6()\n    ])\n\n  l8ad = (): number | undefined => this.aggregated.longTermProceeds\n  l8ae = (): number | undefined => this.aggregated.longTermCostBasis\n  // This field is greyed out, but fillable\n  l8ag = (): number | undefined => undefined\n  l8ah = (): number | undefined =>\n    sumFields([this.l8ad(), 0 - (this.l8ae() ?? 0)])\n\n  l8f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part2BoxD())\n\n  l8bd = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalProceeds()))\n\n  l8be = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalCost()))\n\n  l8bg = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalAdjustments()))\n\n  l8bh = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalGain()))\n\n  l9f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part2BoxE())\n\n  l9d = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalProceeds()))\n\n  l9e = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalCost()))\n\n  l9g = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalAdjustments()))\n\n  l9h = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalGain()))\n\n  l10f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part2BoxF())\n\n  l10d = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalProceeds()))\n\n  l10e = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalCost()))\n\n  l10g = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalAdjustments()))\n\n  l10h = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalGain()))\n\n  l11 = (): number | undefined => undefined\n\n  l12 = (): number | undefined => undefined\n\n  l13 = (): number | undefined =>\n    this.f1040\n      .f1099Divs()\n      .reduce((s, f) => s + f.form.totalCapitalGainsDistributions, 0)\n\n  l14 = (): number | undefined => undefined\n\n  l15 = (): number =>\n    sumFields([\n      this.l8ah(),\n      this.l8bh(),\n      this.l9h(),\n      this.l10h(),\n      this.l11(),\n      this.l12(),\n      this.l13(),\n      this.l14()\n    ])\n\n  // L7 + L15\n  // If +, enter on L16 of F1040\n  // If -, go to L21\n  // If 0, go to L22\n  l16 = (): number => sumFields([this.l7(), this.l15()])\n\n  // Are L15 and L16 both gains?\n  l17 = (): boolean => this.l15() > 0 && this.l16() > 0\n\n  l18 = (): number | undefined => {\n    if (!this.l17()) {\n      return undefined\n    }\n    return this.rateGainWorksheet.l7()\n  }\n\n  l19 = (): number | undefined => {\n    if (!this.l17()) {\n      return undefined\n    }\n    return this.unrecaptured1250.l18()\n  }\n\n  l20 = (): boolean | undefined => {\n    if (!this.l17()) {\n      return undefined\n    }\n    return (this.l18() ?? 0) === 0 && (this.l19() ?? 0) === 0\n  }\n\n  fillL21 = (): boolean =>\n    !this.l20() && ((this.l16() > 0 && this.l17()) || this.l16() < 0)\n\n  l21 = (): number | undefined => {\n    if (this.fillL21()) {\n      return Math.max(-this.l21Min(), this.l16())\n    }\n  }\n\n  haveQualifiedDividends = (): boolean =>\n    this.f1040.f1099Divs().some((f) => f.form.qualifiedDividends > 0)\n\n  // TODO: Schedule D tax worksheet\n  // neither box should be checked if this question was not required to be answered by l20.\n  l22 = (): boolean | undefined => {\n    if (this.l20() !== false) {\n      return this.haveQualifiedDividends()\n    }\n  }\n\n  lossCarryForward = (): number => {\n    const amount = this.l16() + this.l21Min()\n    if (amount < 0) {\n      return -amount\n    }\n    return 0\n  }\n\n  to1040 = (): number => this.l21() ?? this.l16()\n\n  computeTaxOnQDWorksheet = (): boolean =>\n    (this.l20() ?? false) || (this.l22() ?? false)\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    false,\n    false,\n    this.l1ad(),\n    this.l1ae(),\n    this.l1ag(),\n    this.l1ah(),\n    this.l1bd(),\n    this.l1be(),\n    this.l1bg(),\n    this.l1bh(),\n    this.l2d(),\n    this.l2e(),\n    this.l2g(),\n    this.l2h(),\n    this.l3d(),\n    this.l3e(),\n    this.l3g(),\n    this.l3h(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8ad(),\n    this.l8ae(),\n    this.l8ag(),\n    this.l8ah(),\n    this.l8bd(),\n    this.l8be(),\n    this.l8bg(),\n    this.l8bh(),\n    this.l9d(),\n    this.l9e(),\n    this.l9g(),\n    this.l9h(),\n    this.l10d(),\n    this.l10e(),\n    this.l10g(),\n    this.l10h(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    !this.l17(),\n    this.l18(),\n    this.l19(),\n    this.l20() === true,\n    this.l20() === false,\n    this.l21(),\n    this.l22() === true,\n    this.l22() === false\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleE.ts",
    "content": "import {\n  Address,\n  Property,\n  PropertyType,\n  PropertyExpenseTypeName\n} from 'ustaxes/core/data'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { displayNegPos, sumFields } from 'ustaxes/core/irsForms/util'\nimport _ from 'lodash'\nimport F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype Cell = number | undefined\nexport type MatrixRow = [Cell, Cell, Cell]\n\nconst fill = (values: number[]): MatrixRow => {\n  const realValues = (values as Cell[]).slice(0, 3).map((v) => {\n    if (v === 0) {\n      return undefined\n    }\n    return v\n  })\n  return [\n    ...realValues,\n    ...Array.from(Array(3 - realValues.length)).map(() => undefined)\n  ] as MatrixRow\n}\n\nconst propTypeIndex = {\n  [PropertyType.singleFamily]: 1,\n  [PropertyType.multiFamily]: 2,\n  [PropertyType.vacation]: 3,\n  [PropertyType.commercial]: 4,\n  [PropertyType.land]: 5,\n  [PropertyType.selfRental]: 7,\n  [PropertyType.other]: 8\n}\n\nexport default class ScheduleE extends F1040Attachment {\n  tag: FormTag = 'f1040se'\n  sequenceIndex = 13\n\n  isNeeded = (): boolean => this.f1040.info.realEstate.length > 0\n\n  addressString = (address: Address): string =>\n    [\n      address.address,\n      address.city,\n      address.state ?? address.province ?? '',\n      address.zip ?? address.postalCode ?? ''\n    ].join(', ')\n\n  propForRow = (row: number): Property | undefined => {\n    if (row < this.f1040.info.realEstate.length) {\n      return this.f1040.info.realEstate[row]\n    }\n  }\n\n  /**\n   * Whether or not you can deduct expenses for the unit depends on whether or not you used\n   * the unit as a home in 2020. You used the unit as a home if your personal use of the unit\n   * was more than the greater of:\n   * 14 days, or\n   * 10% of the total days it was rented to others at a fair rental price.\n   * @param p\n   */\n  propertyUseTest = (p: Property): boolean =>\n    p.personalUseDays <= Math.max(14, 0.1 * p.rentalDays)\n\n  l3 = (): MatrixRow => {\n    const properties = this.f1040.info.realEstate\n    return fill(properties.map((a) => a.rentReceived))\n  }\n\n  // TODO: 'Line 4: Royalties\n  l4 = (): MatrixRow => [undefined, undefined, undefined]\n\n  getExpensesRow = (expType: PropertyExpenseTypeName): MatrixRow =>\n    fill(\n      this.f1040.info.realEstate.map((p) => {\n        if (this.propertyUseTest(p)) {\n          return p.expenses[expType] ?? 0\n        }\n        return 0\n      })\n    )\n\n  // Matching order of expenses in rows of form\n  expenses: PropertyExpenseTypeName[] = [\n    'advertising',\n    'auto',\n    'cleaning',\n    'commissions',\n    'insurance',\n    'legal',\n    'management',\n    'mortgage',\n    'otherInterest',\n    'repairs',\n    'supplies',\n    'taxes',\n    'utilities',\n    'depreciation'\n  ]\n\n  l19 = (): [string | undefined, MatrixRow] => {\n    const expenseRow = this.getExpensesRow('other')\n    const otherText = this.f1040.info.realEstate\n      .flatMap((p) =>\n        p.otherExpenseType !== undefined ? [p.otherExpenseType] : []\n      )\n      .join(',')\n    return [otherText, expenseRow]\n  }\n\n  allExpenses = (): MatrixRow[] =>\n    this.expenses.map((e) => this.getExpensesRow(e))\n\n  l12 = (): MatrixRow => this.getExpensesRow('mortgage')\n  l18 = (): MatrixRow => this.getExpensesRow('depreciation')\n\n  // TODO - required from pub 596 worksheet 1\n  royaltyExpenses = (): number | undefined => undefined\n\n  l20 = (): MatrixRow =>\n    fill(_.unzip(this.allExpenses()).map((column) => sumFields(column)))\n\n  l21 = (): MatrixRow =>\n    _.zipWith(\n      this.l3(),\n      this.l4(),\n      this.l20(),\n      (x, y, z) => (x ?? 0) + (y ?? 0) - (z ?? 0)\n    ) as MatrixRow\n\n  // Deductible real estate loss from 8582, as positive number\n  l22 = (): MatrixRow =>\n    this.f1040.f8582?.deductibleRealEstateLossAfterLimitation() ?? [\n      undefined,\n      undefined,\n      undefined\n    ]\n\n  l23a = (): number => sumFields(this.l3())\n  l23b = (): number => sumFields(this.l4())\n  l23c = (): number => sumFields(this.l12())\n  l23d = (): number => sumFields(this.l18())\n  l23e = (): number => sumFields(this.l20())\n\n  rentalNet = (): MatrixRow =>\n    _.zipWith(this.l3(), this.l20(), (x, y) => (x ?? 0) - (y ?? 0)) as MatrixRow\n\n  l24 = (): number =>\n    sumFields(this.l21().filter((x) => x !== undefined && x > 0))\n\n  // TODO: 'Ignoring royalty losses on L25\n  l25 = (): number => {\n    return sumFields(this.l22())\n  }\n\n  l26 = (): number => sumFields([this.l24(), this.l25()])\n\n  // TODO: required from Pub 596\n  l29ah = (): number | undefined => undefined\n  l29ak = (): number | undefined => undefined\n\n  l29bg = (): number | undefined => undefined\n  l29bi = (): number | undefined => undefined\n  l29bj = (): number | undefined => undefined\n\n  // TODO: 'Partnership and S corporation income or loss\n  l32 = (): number | undefined => {\n    return undefined\n  }\n\n  l34ad = (): number | undefined => undefined\n  l34af = (): number | undefined => undefined\n  l34bc = (): number | undefined => undefined\n  l34be = (): number | undefined => undefined\n\n  // TODO: 'Real estate trust income or loss\n  l37 = (): number | undefined => {\n    return undefined\n  }\n\n  // TODO: 'REMICS income or loss\n  l39 = (): number | undefined => {\n    return undefined\n  }\n\n  // TODO: 'Farm rental income or loss\n  l40 = (): number | undefined => {\n    return undefined\n  }\n\n  l41 = (): number =>\n    sumFields([this.l26(), this.l32(), this.l37(), this.l39(), this.l40()])\n\n  fields = (): Field[] => {\n    const [p0, p1, p2] = [0, 1, 2].map((i) => this.propForRow(i))\n\n    return [\n      this.f1040.namesString(),\n      this.f1040.info.taxPayer.primaryPerson.ssid,\n      false,\n      false,\n      false,\n      false,\n      ...[p0, p1, p2].map((p) =>\n        p === undefined ? undefined : this.addressString(p.address)\n      ),\n      p0 === undefined\n        ? undefined\n        : propTypeIndex[PropertyType[p0.propertyType]],\n      p1 === undefined\n        ? undefined\n        : propTypeIndex[PropertyType[p1.propertyType]],\n      p2 === undefined\n        ? undefined\n        : propTypeIndex[PropertyType[p2.propertyType]],\n      p0?.rentalDays,\n      p0?.personalUseDays,\n      p0?.qualifiedJointVenture,\n      p1?.rentalDays,\n      p1?.personalUseDays,\n      p1?.qualifiedJointVenture,\n      p2?.rentalDays,\n      p2?.personalUseDays,\n      p2?.qualifiedJointVenture,\n      [p0, p1, p2].find((p) => p?.propertyType === 'other')\n        ?.otherPropertyType ?? undefined,\n      ...this.l3(),\n      ...this.l4(),\n      ...this.allExpenses().flat(),\n      ...this.l19().flat(),\n      ...this.l20(),\n      ...this.l21(),\n      ...this.l22(),\n      this.l23a(),\n      this.l23b(),\n      this.l23c(),\n      this.l23d(),\n      this.l23e(),\n      this.l24(),\n      Math.abs(this.l25()),\n      displayNegPos(this.l26()),\n      // Page 2 - TODO: completely unimplemented\n      this.f1040.namesString(),\n      this.f1040.info.taxPayer.primaryPerson.ssid,\n      ...[false, false], // l27\n      ...Array<undefined>(6 * 4 + 5 * 4).fill(undefined), // l28\n      undefined, // grey\n      this.l29ah(),\n      undefined, // grey\n      undefined, // grey\n      this.l29ak(),\n      this.l29bg(),\n      undefined, // grey\n      this.l29bi(),\n      this.l29bj(),\n      undefined, // grey\n      undefined, // l30\n      undefined, // l31\n      this.l32(), // l32\n      ...Array<undefined>(2 * 4).fill(undefined), // l33\n      undefined,\n      this.l34ad(),\n      undefined,\n      this.l34af(),\n      ...Array<undefined>(4).fill(undefined),\n      this.l34bc(),\n      undefined, // grey\n      this.l34be(),\n      undefined, // grey\n      // l34b\n      undefined, // l35\n      undefined, // l36\n      this.l37(), // l37\n      ...Array<undefined>(5 + 4).fill(undefined), // l38\n      this.l39(), // l39\n      this.l40(), // l40\n      this.l41(), // l41\n      undefined,\n      undefined\n    ]\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleEIC.ts",
    "content": "import _ from 'lodash'\nimport { Dependent, FilingStatus } from 'ustaxes/core/data'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { evaluatePiecewise, Piecewise } from 'ustaxes/core/util'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport * as federal from '../data/federal'\nimport F1040 from './F1040'\nimport F2555 from './F2555'\nimport F4797 from './F4797'\nimport F8814 from './F8814'\nimport Pub596Worksheet1 from './worksheets/Pub596Worksheet1'\nimport F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype PrecludesEIC<F> = (f: F) => boolean\n\n// TODO: check F2555\nconst checks2555: PrecludesEIC<F2555> = (): boolean => {\n  return false\n}\n\n// TODO: check F4797\nconst checks4797: PrecludesEIC<F4797> = (): boolean => {\n  return false\n}\n\n// TODO: check F8814\nconst checks8814: PrecludesEIC<F8814> = (): boolean => {\n  return false\n}\n\nconst checksPub596: PrecludesEIC<Pub596Worksheet1> = (f): boolean =>\n  f.precludesEIC()\n\nconst precludesEIC =\n  <F>(p: PrecludesEIC<F>) =>\n  (f: F | undefined): boolean => {\n    if (f === undefined) {\n      return false\n    }\n    return p(f)\n  }\n\nexport default class ScheduleEIC extends F1040Attachment {\n  tag: FormTag = 'f1040sei'\n  sequenceIndex = 43\n  f2555?: F2555\n  f4797?: F4797\n  f8814?: F8814\n  pub596Worksheet1: Pub596Worksheet1\n  qualifyingStudentCutoffYear = 1996\n  qualifyingCutoffYear = 2001\n  investmentIncomeLimit = 3650\n\n  constructor(f1040: F1040) {\n    super(f1040)\n    this.pub596Worksheet1 = new Pub596Worksheet1(f1040)\n  }\n\n  isNeeded = (): boolean => this.allowed()\n\n  // instructions step 1.1\n  passIncomeLimit = (): boolean => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const incomeLimits = federal.EIC.caps[filingStatus]\n    if (incomeLimits !== undefined) {\n      const limit =\n        incomeLimits[\n          Math.min(this.qualifyingDependents().length, incomeLimits.length - 1)\n        ]\n      return this.f1040.l11() < limit\n    }\n    return false\n  }\n\n  // Step 1.2, todo, both spouses must have a SSN issued before 2020 due date\n  //\n  // TODO: Step 1.2 (valid SSNs) unchecked and without work restriction and valid for eic purposes\n  validSSNs = (): boolean => {\n    return true\n  }\n\n  // Step 1.3\n  allowedFilingStatus = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFS\n\n  // Step 1.4\n  allowedFilling2555 = (): boolean => !precludesEIC(checks2555)(this.f2555)\n\n  //\n  // TODO: Step 1.5, Not checking non-resident alien Step 1.5 nonResidentAlien\n  allowedNonresidentAlien = (): boolean => {\n    return true\n  }\n\n  // step 2, question 1\n  investmentIncome = (): number =>\n    sumFields([\n      this.f1040.l2a(),\n      this.f1040.l2b(),\n      this.f1040.l3b(),\n      Math.max(this.f1040.l7() ?? 0, 0)\n    ])\n\n  passInvestmentIncomeLimit = (): boolean =>\n    this.investmentIncome() < federal.EIC.maxInvestmentIncome\n\n  // Todo, step 2, question 3\n  f4797AllowsEIC = (): boolean => !precludesEIC(checks4797)(this.f4797)\n\n  // Todo, instruction 2.4.1\n  filingScheduleE = (): boolean => this.f1040.scheduleE.isNeeded()\n\n  //\n  // TODO: Not checking personal property income 2.4.2\n  passIncomeFromPersonalProperty = (): boolean => {\n    return true\n  }\n\n  // 2.4.3\n  passForm8814 = (): boolean => !precludesEIC(checks8814)(this.f8814)\n\n  //\n  // TODO: Not checking passive activity 2.4.4\n  incomeOrLossFromPassiveActivity = (): boolean => {\n    return false\n  }\n\n  // 2.4.5\n  passPub596 = (): boolean => !precludesEIC(checksPub596)(this.pub596Worksheet1)\n\n  // 3.1\n  atLeastOneChild = (): boolean => this.qualifyingDependents().length > 0\n\n  // 3.2, 4.4\n  jointReturn = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ\n\n  //\n  // TODO: 3.3: Not checking qualifying child of another 3.3, 4.5\n  qualifyingChildOfAnother = (): boolean => {\n    return false\n  }\n\n  // 4.1 - covered by income limit check\n  //\n  // TODO: 4.2: Not checking taxpayer age 4.2\n  over25Under65 = (): boolean => {\n    return true\n  }\n\n  //\n  // TODO: 4.3: Not checking residency 4.3\n  mainHomeInsideUsBothPeople = (): boolean => {\n    return true\n  }\n\n  // 4.4 covered above\n  // 4.5 covered above\n  // 4.6 dependent of another\n  dependentOfAnother = (): boolean =>\n    this.f1040.info.taxPayer.primaryPerson.isTaxpayerDependent ||\n    (this.f1040.info.taxPayer.spouse?.isTaxpayerDependent ?? false)\n\n  //\n  // TODO: 5.1: Not checking church self-employment income 5.1 - Filing schedule SE for church\n  filingSEChurchIncome = (): boolean => {\n    return false\n  }\n\n  //\n  // TODO: 5.1.2: Not checking scholarship, grants 5.1.2\n  taxableScholarshipIncome = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: 5.1.3: Not checking prison income 5.1.3\n  prisonIncome = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: 5.1.4: Not checking pension income 5.1.4\n  pensionPlanIncome = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: 5.1.5: Not checking medicaid waiver 5.1.5\n  medicaidWaiverPayment = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: 5.1.8: Not checking nontaxable combat pay 5.1.8\n  nontaxableCombatPay = (): number => {\n    return 0\n  }\n\n  // 5.1 - Earned income\n  earnedIncome = (): number => {\n    const l1 = this.f1040.l1()\n    const l2 = this.taxableScholarshipIncome()\n    const l3 = this.prisonIncome()\n    const l4 = this.pensionPlanIncome()\n    const l5 = this.medicaidWaiverPayment()\n    const l6 = l2 + l3 + l4 + l5\n    const l7 = l1 - l6\n    const l8 = this.nontaxableCombatPay()\n    const l9 = l7 + l8\n    return l9\n  }\n\n  /**\n   * The credit table in Publication 596 provides an\n   * amount for each interval of $50, calculated from the\n   * midpoint of the interval.\n   *\n   * @param income The earned income\n   * @returns the earned income rounded to the nearest 25\n   */\n  roundIncome = (income: number): number => {\n    if (income < 1) {\n      return 0\n    }\n    return Math.round(Math.round(income) / 50) * 50 + 25\n  }\n\n  /**\n   * Based on the earned income and filing status, calculate the\n   * allowed EITC.\n   *\n   * For tax year 2020, IRS Rev. Proc. 2019-44 outlines the required\n   * calculation for the EITC based on number of qualifying children\n   * and filing status.\n   *\n   * https://www.irs.gov/pub/irs-drop/rp-19-44.pdf\n   *\n   * IRS publication 596 provides a table that can be used\n   * to figure the EITC, and is the basis of online calculators published\n   * by IRS. This table uses the formulas outlined in Rev Proc 2019-44\n   * but applies them to incomes lying in $50 intervals, with the midpoint\n   * of those intervals used to calculate the credit for the entire window.\n   * For example, if the taxpayer has an earned income of $5000, the amount\n   * that is found in the table is calculated based on an income of $5025 and\n   * comes out ahead. Conversely, someone with an earned income of $5049 finds\n   * a credit in the table calculated off the same $5,025 and loses out.\n   *\n   * https://www.irs.gov/pub/irs-pdf/p596.pdf\n   *\n   * @param income The earned income\n   * @returns\n   */\n  calculateEICForIncome = (income: number): number => {\n    const f: Piecewise[] | undefined =\n      federal.EIC.formulas[this.f1040.info.taxPayer.filingStatus]\n    if (f === undefined) {\n      return 0\n    }\n\n    return Math.max(\n      0,\n      evaluatePiecewise(\n        f[this.qualifyingDependents().length],\n        this.roundIncome(income)\n      )\n    )\n  }\n\n  //\n  // TODO: 5.2: Not checking selfemployment 5.2\n  selfEmployed = (): boolean => {\n    return false\n  }\n\n  // 5.3 - covered by income check\n\n  // 6.1 - We will figure the credit.\n\n  // EIC worksheet A calculation\n  credit = (): number =>\n    Math.min(\n      this.calculateEICForIncome(this.earnedIncome()),\n      this.calculateEICForIncome(this.f1040.l11())\n    )\n\n  allowed = (): boolean => {\n    return (\n      // Step 1\n      this.passIncomeLimit() &&\n      this.validSSNs() &&\n      this.allowedFilingStatus() &&\n      this.allowedFilling2555() &&\n      this.allowedNonresidentAlien() &&\n      // Step 2\n      (this.passInvestmentIncomeLimit() || this.f4797AllowsEIC()) &&\n      (!(\n        // Step 3\n        (\n          this.filingScheduleE() ||\n          !this.passIncomeFromPersonalProperty() ||\n          !this.passForm8814() ||\n          this.incomeOrLossFromPassiveActivity()\n        )\n      ) ||\n        this.passPub596()) &&\n      !(\n        // Step 4\n        (\n          this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFJ &&\n          this.dependentOfAnother()\n        )\n      ) &&\n      this.credit() > 0\n    )\n  }\n\n  qualifyingDependents = (): Dependent[] =>\n    this.f1040.info.taxPayer.dependents\n      .filter(\n        (d) =>\n          d.dateOfBirth.getFullYear() >= this.qualifyingCutoffYear ||\n          ((d.qualifyingInfo?.isStudent ?? false) &&\n            d.dateOfBirth.getFullYear() >= this.qualifyingStudentCutoffYear)\n      )\n      .sort((d) => d.dateOfBirth.getFullYear())\n      .slice(0, 3)\n\n  qualifyingDependentsFilled = (): Array<Dependent | undefined> => {\n    const res = this.qualifyingDependents()\n    return _.fill([...res], undefined, res.length, 3)\n  }\n\n  // EIC line 1\n  nameFields = (): Array<string | undefined> =>\n    this.qualifyingDependentsFilled().map(\n      (d) => `${d?.firstName ?? ''} ${d?.lastName ?? ''}`\n    )\n\n  // EIC line 2\n  ssnFields = (): Array<string | undefined> =>\n    this.qualifyingDependentsFilled().map((d) => d?.ssid)\n\n  years = (): Array<number | undefined> =>\n    this.qualifyingDependentsFilled().map((d) => d?.dateOfBirth.getFullYear())\n\n  // EIC line 3\n  birthYearFields = (): Array<string | undefined> =>\n    this.years().flatMap((year) => {\n      if (year !== undefined) {\n        return String(year).split('')\n      }\n      return [undefined, undefined, undefined, undefined]\n    })\n\n  // EIC line 4a: Not handling case of child older than taxpayer\n  ageFields = (): Array<boolean | undefined> =>\n    this.years().flatMap((year) => {\n      if (year !== undefined) {\n        const qualifies = year > 1996\n        return [qualifies, !qualifies]\n      }\n      return [undefined, undefined]\n    })\n\n  // TODO: disability\n  disabledFields = (): Array<boolean | undefined> =>\n    this.years().flatMap((year) => {\n      if (year === undefined || year < this.qualifyingCutoffYear) {\n        return [undefined, undefined]\n      }\n      return [undefined, undefined]\n    })\n\n  // Line 5\n  // TODO: Address eic relationships\n  relationships = (): Array<string | undefined> =>\n    this.qualifyingDependentsFilled().map((d) => d?.relationship)\n\n  // Line 6\n  numberMonths = (): Array<number | undefined> =>\n    this.qualifyingDependents().map((d) => d.qualifyingInfo?.numberOfMonths)\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    ...this.nameFields(), // 6\n    ...this.ssnFields(), // 3\n    ...this.birthYearFields(), // 12\n    ...this.ageFields(), // 6\n    ...this.disabledFields(), // 6\n    ...this.relationships(),\n    ...this.numberMonths()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleR.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\nexport default class ScheduleR extends F1040Attachment {\n  tag: FormTag = 'f1040sr'\n  sequenceIndex = 999\n\n  l22 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/ScheduleSE.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n// TODO\nexport default class ScheduleSE extends F1040Attachment {\n  tag = 'f1040se'\n  sequenceIndex = 999\n\n  l6 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/TaxTable.ts",
    "content": "import federalBrackets from '../data/federal'\nimport { FilingStatus } from 'ustaxes/core/data'\nimport _ from 'lodash'\n\nconst computeTax =\n  (brackets: (status: FilingStatus) => number[], rates: number[]) =>\n  (filingStatus: FilingStatus, income: number): number =>\n    _.chain([0, ...brackets(filingStatus)]) // Low end of each bracket\n      .zipWith(\n        [...brackets(filingStatus), undefined], // top end of each bracket\n        rates.map((r) => r / 100), // rate for each bracket\n        (low, high, rate) => {\n          if (income < low) {\n            // this bracket is above income, no tax here\n            return 0\n          } else if (high === undefined) {\n            // This is the top bracket\n            return Math.max(0, income - low) * rate\n          } else if (income > high) {\n            // Taxable income is above the top of this bracket\n            // so add the max tax for this bracket\n            return (high - low) * rate\n          }\n          // Otherwise max income is inside this bracket,\n          // add the tax on the amount falling in this bracket\n          return (income - low) * rate\n        }\n      )\n      .sum()\n      .value()\n\nexport const computeOrdinaryTax = computeTax(\n  (status) => federalBrackets.ordinary.status[status].brackets,\n  federalBrackets.ordinary.rates\n)\n\nexport const computeLongTermCapGainsTax = computeTax(\n  (status) => federalBrackets.longTermCapGains.status[status].brackets,\n  federalBrackets.longTermCapGains.rates\n)\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/index.ts",
    "content": "import { PDFDocument } from 'pdf-lib'\nimport { create1040 } from '../irsForms/Main'\nimport { Either, isLeft, isRight, right } from 'ustaxes/core/util'\nimport log from 'ustaxes/core/log'\nimport { combinePdfs, PDFDownloader } from 'ustaxes/core/pdfFiller/pdfHandler'\nimport { Information, Asset } from 'ustaxes/core/data'\nimport { F1040Error } from 'ustaxes/forms/errors'\nimport { insertFormDataToPdfs } from 'ustaxes/core/irsForms'\n\nexport { create1040 }\n\nexport const create1040PDFs =\n  (state: Information, assets: Asset<Date>[]) =>\n  async (\n    downloader: PDFDownloader\n  ): Promise<Either<F1040Error[], PDFDocument[]>> => {\n    if (state.taxPayer.primaryPerson !== undefined) {\n      const f1040Result = create1040(state, assets)\n      // Get data and pdf links applicable to the model state\n      if (isLeft(f1040Result)) {\n        throw new Error(f1040Result.left.join('\\n'))\n      }\n\n      const [, forms] = f1040Result.right\n\n      const inserted = await insertFormDataToPdfs(forms, downloader)\n\n      return right(inserted)\n    }\n\n    log.error('Attempt to create pdf with no data, will be empty')\n    return right([])\n  }\n\nexport const create1040PDF =\n  (state: Information, assets: Asset<Date>[]) =>\n  async (\n    downloader: PDFDownloader\n  ): Promise<Either<F1040Error[], Uint8Array>> => {\n    const pdfResult = await create1040PDFs(state, assets)(downloader)\n\n    if (isRight(pdfResult)) {\n      const pdf = await combinePdfs(pdfResult.right)\n      const bytes = await pdf.save()\n      return right(bytes)\n    }\n\n    throw new Error(pdfResult.left.join('\\n'))\n  }\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/ChildTaxCreditWorksheet.ts",
    "content": "import F1040 from '../../irsForms/F1040'\nimport { Dependent, FilingStatus } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { QualifyingDependents } from '../../data/federal'\n\nexport default class ChildTaxCreditWorksheet {\n  f1040: F1040\n  year = 2020\n\n  constructor(f1040: F1040) {\n    this.f1040 = f1040\n  }\n\n  qualifiesChild = (d: Dependent): boolean =>\n    this.year - d.dateOfBirth.getFullYear() < QualifyingDependents.childMaxAge\n\n  qualifiesOther = (d: Dependent): boolean =>\n    d.qualifyingInfo !== undefined &&\n    !this.qualifiesChild(d) &&\n    this.year - d.dateOfBirth.getFullYear() <\n      (d.qualifyingInfo.isStudent\n        ? QualifyingDependents.qualifyingDependentMaxAge\n        : QualifyingDependents.qualifyingStudentMaxAge)\n\n  // worksheet line 1\n  numberQualifyingChildren = (): number =>\n    this.f1040.info.taxPayer.dependents.reduce(\n      (total, dependent) =>\n        this.qualifiesChild(dependent) ? total + 1 : total,\n      0\n    )\n\n  l1 = (): number => this.numberQualifyingChildren() * 2000\n\n  // worksheet line 2\n  numberQualifyingOtherDependents = (): number =>\n    this.f1040.info.taxPayer.dependents.reduce(\n      (total, dependent) =>\n        this.qualifiesOther(dependent) ? total : total + 1,\n      0\n    )\n\n  l2 = (): number => this.numberQualifyingOtherDependents() * 500\n\n  // worksheet line 3\n  l3 = (): number => this.l1() + this.l2()\n\n  // worksheet line 4\n  l4 = (): number => this.f1040.l11()\n\n  // worksheet line 5\n  l5 = (): number =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ ? 400000 : 200000\n\n  // worksheet line 6\n  l6 = (): number => Math.max(0, this.l4() - this.l5())\n\n  // worksheet line 7\n  l7 = (): number => this.l6() * 0.05\n\n  // worksheet line 8\n  l8 = (): number | undefined =>\n    this.l3() > this.l7() ? this.l3() - this.l7() : undefined\n\n  // worksheet line 9\n  l9 = (): number => this.f1040.l18()\n\n  // worksheet line 10\n  l10 = (): number =>\n    sumFields([\n      this.f1040.schedule3.l1(),\n      this.f1040.schedule3.l2(),\n      this.f1040.schedule3.l3(),\n      this.f1040.schedule3.l4(),\n      this.f1040.f5695?.l30(),\n      this.f1040.f8910?.l15(),\n      this.f1040.f8936?.l23(),\n      this.f1040.scheduleR?.l22()\n    ])\n\n  // worksheet line 11\n  // This maybe should be >= l9\n  l11 = (): number | undefined =>\n    this.l10() === this.l9() ? undefined : this.l9() - this.l10()\n\n  // worksheet line 13\n  // if l11 is undefined, returns undefined since they can't take the deduction\n  // if l8 > l11, returns l11 following instructions\n  // Otherwise, returns l8, either because l8 is the deduction or because l8 is undefined and they can't take the deduction\n  l12 = (): number | undefined =>\n    this.l11() !== undefined\n      ? Math.min(this.l8() ?? 0, this.l11() ?? 0)\n      : undefined\n\n  // alias\n  credit = (): number | undefined => this.l12()\n\n  isAllowed = (): boolean => this.credit() !== undefined\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/Pub596Worksheet1.ts",
    "content": "import { EIC } from '../../data/federal'\nimport { ifNegative, ifPositive } from 'ustaxes/core/util'\nimport F1040 from '../../irsForms/F1040'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\n\nexport default class Pub596Worksheet1 {\n  f1040: F1040\n\n  constructor(f1040: F1040) {\n    this.f1040 = f1040\n  }\n\n  l1 = (): number | undefined => this.f1040.l2b()\n  l2 = (): number | undefined =>\n    sumFields([this.f1040.l2a(), this.f1040.f8814?.l1b()])\n  l3 = (): number | undefined => this.f1040.l3b()\n\n  // TODO: Unchecked child's Alaska permanent fund dividend\n  l4 = (): number | undefined => this.f1040.schedule1.l8()\n\n  l5 = (): number => ((this.f1040.l7() ?? 0) < 0 ? 0 : this.f1040.l7() ?? 0)\n  l6 = (): number => {\n    const l7 = this.f1040.f4797?.l7()\n    const l9 = this.f1040.f4797?.l9()\n\n    if (l7 !== undefined && l7 < 0) {\n      return l9 ?? 0\n    }\n\n    return l7 ?? 0\n  }\n\n  l7 = (): number => {\n    const diff = this.l5() - this.l6()\n    return diff < 0 ? 0 : diff\n  }\n\n  l8 = (): number | undefined =>\n    sumFields([this.f1040.scheduleE.l23b(), this.f1040.schedule1.l8()])\n\n  l9 = (): number | undefined =>\n    sumFields([\n      this.f1040.scheduleE.royaltyExpenses(),\n      this.f1040.schedule1.l22()\n    ])\n\n  l10 = (): number => {\n    const diff = (this.l9() ?? 0) - (this.l8() ?? 0)\n    return diff < 0 ? 0 : diff\n  }\n\n  l11 = (): number | undefined =>\n    sumFields([\n      ifPositive(this.f1040.scheduleE.l26()),\n      this.f1040.scheduleE.l29ah(),\n      this.f1040.scheduleE.l34ad(),\n      this.f1040.scheduleE.l40()\n      // todo: FPA form 4797 line 10\n    ])\n\n  l12 = (): number | undefined =>\n    sumFields(\n      [\n        this.f1040.scheduleE.l26(),\n        this.f1040.scheduleE.l29bg() ?? 0,\n        this.f1040.scheduleE.l34bc() ?? 0,\n        this.f1040.scheduleE.l40() ?? 0\n        // TODO: PAL Loss form 4797\n      ].map((x) => ifNegative(x))\n    )\n\n  l13 = (): number | undefined =>\n    ifPositive(sumFields([this.l11(), this.l12()]))\n\n  l14 = (): number | undefined =>\n    sumFields([\n      this.l1(),\n      this.l2(),\n      this.l3(),\n      this.l4(),\n      this.l7(),\n      this.l10(),\n      this.l13()\n    ])\n\n  l15 = (): boolean => (this.l14() ?? 0) > EIC.maxInvestmentIncome\n\n  precludesEIC = (): boolean => this.l15()\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/SDQualifiedAndCapGains.ts",
    "content": "// Reference implementation for ltcg and cap gains worksheet\nimport { FilingStatus } from 'ustaxes/core/data'\nimport federalBrackets from '../../data/federal'\nimport { computeOrdinaryTax } from '../../irsForms/TaxTable'\nimport F1040 from '../F1040'\n\nexport interface TestData {\n  qualDiv: number\n  taxableIncome: number\n  f1040l7: number | undefined\n  sdl15: number | undefined\n  sdl16: number | undefined\n  sdl18: number | undefined\n  sdl19: number | undefined\n  filingStatus: FilingStatus\n}\n\ntype Bracket = [number, number]\ntype Cutoffs = { [key in FilingStatus]: Bracket }\nconst cutoffAmounts: Cutoffs = {\n  [FilingStatus.S]: [40000, 441450],\n  [FilingStatus.MFJ]: [80000, 496600],\n  [FilingStatus.MFS]: [40000, 441450],\n  [FilingStatus.W]: [80000, 496600],\n  [FilingStatus.HOH]: [53600, 469050]\n}\n\nexport default class QualDivAndCGWorksheetReference {\n  [k: string]: TestData | (() => number)\n  data: TestData\n\n  constructor(f1040: F1040) {\n    const filingStatus = f1040.info.taxPayer.filingStatus\n    this.data = {\n      qualDiv: f1040.l3a() ?? 0,\n      taxableIncome: f1040.l15(),\n      f1040l7: f1040.l7(),\n      sdl15: f1040.scheduleD.l15(),\n      sdl16: f1040.scheduleD.l16(),\n      sdl18: f1040.scheduleD.l18(),\n      sdl19: f1040.scheduleD.l19(),\n      filingStatus\n    }\n  }\n\n  // 1. Enter the amount from Form 1040 or 1040-SR, line 15. However, if you are filing Form 2555 (relating to foreign earned income), enter the amount from line 3 of the Foreign Earned Income Tax Worksheet\n  l1 = (): number => this.data.taxableIncome\n  // 2. Enter the amount from Form 1040 or 1040-SR, line 3a*\n  l2 = (): number => this.data.qualDiv\n  // 3. Are you filing Schedule D?*\n  // Yes. Enter the smaller of line 15 or 16 of Schedule D. If either line 15 or 16 is blank or a loss, enter -0-. 3.\n  // No. Enter the amount from Form 1040 or 1040-SR, line 7.\n  // Either way, it's the smaller of LTCG or total capital gain.\n  l3 = (): number =>\n    Math.min(\n      Math.max(this.data.sdl15 ?? 0, 0),\n      Math.max(this.data.sdl16 ?? 0, 0)\n    )\n  // 4. Add lines 2 and 3: LTCG + QDIV\n  l4 = (): number => this.l2() + this.l3()\n  // 5. Subtract line 4 from line 1. If zero or less, enter -0-\n  l5 = (): number => Math.max(this.l1() - this.l4(), 0)\n  // 6. Enter:\n  // $40,000 if single or married filing separately,\n  // $80,000 if married filing jointly or qualifying widow(er),$53,600 if head of household.\n  l6 = (): number => cutoffAmounts[this.data.filingStatus][0]\n  // 7. Enter the smaller of line 1 or line 6\n  l7 = (): number => Math.min(this.l1(), this.l6())\n  // 8. Enter the smaller of line 5 or line 7\n  l8 = (): number => Math.min(this.l5(), this.l7())\n  // 9. Subtract line 8 from line 7. This amount is taxed at 0%\n  l9 = (): number => this.l7() - this.l8()\n  // 10. Enter the smaller of line 1 or line 4\n  l10 = (): number => Math.min(this.l1(), this.l4())\n  // 11. Enter the amount from line 9\n  l11 = (): number => this.l9()\n  // 12. Subtract line 11 from line 10\n  l12 = (): number => this.l10() - this.l11()\n  // 13. Enter:\n  // $441,450 if single,$248,300 if married filing separately,$496,600 if married filing jointly or qualifying widow(er),$469,050 if head of household.\n  //\n  l13 = (): number => cutoffAmounts[this.data.filingStatus][1]\n  // 14. Enter the smaller of line 1 or line 13\n  l14 = (): number => Math.min(this.l1(), this.l13())\n  // 15. Add lines 5 and 9\n  l15 = (): number => this.l5() + this.l9()\n  // 16. Subtract line 15 from line 14. If zero or less, enter -0-\n  l16 = (): number => Math.max(this.l14() - this.l15(), 0)\n  // 17. Enter the smaller of line 12 or line 16\n  l17 = (): number => Math.min(this.l12(), this.l16())\n  // 18. Multiply line 17 by 15% (0.15)\n  l18 = (): number =>\n    (this.l17() * federalBrackets.longTermCapGains.rates[1]) / 100\n  // 19. Add lines 9 and 17\n  l19 = (): number => this.l9() + this.l17()\n  // 20. Subtract line 19 from line 10\n  l20 = (): number => this.l10() - this.l19()\n  // 21. Multiply line 20 by 20% (0.20)\n  l21 = (): number =>\n    (this.l20() * federalBrackets.longTermCapGains.rates[2]) / 100\n  // 22. Figure the tax on the amount on line 5. If the amount on line 5 is less than $100,000, use the Tax Table to figure the tax. If the amount on line 5 is $100,000 or more, use the Tax Computation Worksheet\n  l22 = (): number => computeOrdinaryTax(this.data.filingStatus, this.l5())\n  // 23. Add lines 18, 21, and 22\n  l23 = (): number => this.l18() + this.l21() + this.l22()\n  // 24. Figure the tax on the amount on line 1. If the amount on line 1 is less than $100,000, use the Tax Table to figure the tax. If the amount on line 1 is $100,000 or more, use the Tax Computation Worksheet\n  l24 = (): number => computeOrdinaryTax(this.data.filingStatus, this.l1())\n  // 25. Tax on all taxable income. Enter the smaller of line 23 or 24. Also include this amount on the entry space on Form 1040 or 1040-SR, line 16. If you are filing Form 2555, don’t enter this amount on the entry space on Form 1040 or 1040-SR, line 16. Instead, enter it on line 4 of the Foreign Earned Income Tax Worksheet\n  l25 = (): number => Math.min(this.l23(), this.l24())\n\n  tax = (): number => this.l25()\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/SDRateGainWorksheet.ts",
    "content": "export default class SDRateGainWorksheet {\n  l7 = (): number | undefined => undefined\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/SDUnrecaptured1250.ts",
    "content": "export default class SDUnrecaptured1250 {\n  l18 = (): number | undefined => undefined\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/ScheduleDTaxWorksheet.ts",
    "content": "// Reference implementation for Schedule D Tax Worksheet\nimport { FilingStatus } from 'ustaxes/core/data'\nimport { computeOrdinaryTax } from '../../irsForms/TaxTable'\n\nexport interface TestData {\n  qualDiv: number\n  taxableIncome: number\n  f4952l4g: number\n  f4952l4e: number\n  sdl15: number\n  sdl16: number\n  sdl18: number\n  sdl19: number\n  filingStatus: FilingStatus\n}\n\ntype Bracket = [number, number, number]\ntype Cutoffs = { [key in FilingStatus]: Bracket }\nconst cutoffAmounts: Cutoffs = {\n  [FilingStatus.S]: [40000, 163300, 441450],\n  [FilingStatus.MFJ]: [80000, 326600, 496600],\n  [FilingStatus.MFS]: [40000, 163300, 441450],\n  [FilingStatus.W]: [80000, 326600, 496600],\n  [FilingStatus.HOH]: [53600, 163300, 469050]\n}\n\nexport default class LTCGQualDivReference {\n  [k: string]: TestData | (() => number)\n  data: TestData\n\n  constructor(data: TestData) {\n    this.data = data\n  }\n\n  // 1. Enter your taxable income from Form 1040, 1040-SR, or 1040-NR, line 15. (However, if you are filing Form 2555 (relating to foreign earned income), enter instead the amount from line 3 of the Foreign Earned Income Tax Worksheet in the instructions for Forms 1040 and 1040-SR, line 16)\n  l1 = (): number => this.data.taxableIncome\n  // 2. Enter your qualified dividends from Form 1040, 1040-SR, or 1040-NR, line 3a\n  l2 = (): number => this.data.qualDiv\n  // 3. Enter the amount from Form 4952 (used to figure investment interest expense deduction), line 4g\n  l3 = (): number => this.data.f4952l4g\n  // 4. Enter the amount from Form 4952, line 4e*\n  l4 = (): number => this.data.f4952l4e\n  // 5. Subtract line 4 from line 3. If zero or less, enter -0-\n  l5 = (): number => Math.max(0, this.l3() - this.l4())\n  // 6. Subtract line 5 from line 2. If zero or less, enter -0-**\n  l6 = (): number => Math.max(0, this.l2() - this.l5())\n  // 7. Enter the smaller of line 15 or line 16 of Schedule D\n  l7 = (): number => Math.min(this.data.sdl15, this.data.sdl16)\n  // 8. Enter the smaller of line 3 or line 4\n  l8 = (): number => Math.min(this.l3(), this.l4())\n  // 9. Subtract line 8 from line 7. If zero or less, enter -0-**\n  l9 = (): number => Math.max(0, this.l7() - this.l8())\n  // 10. Add lines 6 and 9\n  l10 = (): number => this.l6() + this.l9()\n  // 11. Add lines 18 and 19 of Schedule D**\n  l11 = (): number => this.data.sdl18 + this.data.sdl19\n  // 12. Enter the smaller of line 9 or line 11\n  l12 = (): number => Math.min(this.l9(), this.l11())\n  // 13. Subtract line 12 from line 10\n  l13 = (): number => this.l10() - this.l12()\n  // 14. Subtract line 13 from line 1. If zero or less, enter -0-\n  l14 = (): number => Math.max(0, this.l1() - this.l13())\n  // 15. Enter:\n  l15 = (): number => cutoffAmounts[this.data.filingStatus][0]\n  // 16. Enter the smaller of line 1 or line 15\n  l16 = (): number => Math.min(this.l1(), this.l15())\n  // 17. Enter the smaller of line 14 or line 16\n  l17 = (): number => Math.min(this.l14(), this.l16())\n  // 18. Subtract line 10 from line 1. If zero or less, enter -0-\n  l18 = (): number => Math.max(0, this.l1() - this.l10())\n  // 19. Enter the smaller of line 1 or [ltcg bracket 2]\n  l19 = (): number =>\n    Math.min(this.l1(), cutoffAmounts[this.data.filingStatus][1])\n  // 20. Enter the smaller of line 14 or line 19\n  l20 = (): number => Math.min(this.l14(), this.l19())\n  // 21. Enter the larger of line 18 or line 20\n  l21 = (): number => Math.max(this.l18(), this.l20())\n  // 22. Subtract line 17 from line 16. This amount is taxed at 0%.\n  l22 = (): number => Math.max(0, this.l16() - this.l17())\n  // If lines 1 and 16 are the same, skip lines 23 through 43 and go to line 44. Otherwise, go to line 23.\n  // 23. Enter the smaller of line 1 or line 13\n  l23 = (): number => Math.min(this.l1(), this.l13())\n  // 24. Enter the amount from line 22. (If line 22 is blank, enter -0-.)\n  l24 = (): number => this.l22()\n  // 25. Subtract line 24 from line 23. If zero or less, enter -0-\n  l25 = (): number => Math.max(0, this.l23() - this.l24())\n  // 26. Enter top bracket amount\n  l26 = (): number => cutoffAmounts[this.data.filingStatus][1]\n  // 27. Enter the smaller of line 1 or line 26\n  l27 = (): number => Math.min(this.l1(), this.l26())\n  // 28. Add lines 21 and 22\n  l28 = (): number => this.l21() + this.l22()\n  // 29. Subtract line 28 from line 27. If zero or less, enter -0-\n  l29 = (): number => Math.max(0, this.l27() - this.l28())\n  // 30. Enter the smaller of line 25 or line 29\n  l30 = (): number => Math.min(this.l25(), this.l29())\n  // 31. Multiply line 30 by 15% (0.15)\n  l31 = (): number => this.l30() * 0.15\n  // 32. Add lines 24 and 30\n  l32 = (): number => this.l24() + this.l30()\n  // If lines 1 and 32 are the same, skip lines 33 through 43 and go to line 44. Otherwise, go to line 33.\n  // 33. Subtract line 32 from line 23\n  l33 = (): number => Math.max(0, this.l23() - this.l32())\n  // 34. Multiply line 33 by 20% (0.20)\n  l34 = (): number => this.l33() * 0.2\n  // If Schedule D, line 19, is zero or blank, skip lines 35 through 40 and go to line 41. Otherwise, go to line 35.\n  // 35. Enter the smaller of line 9 above or Schedule D, line 19\n  l35 = (): number => Math.min(this.l9(), this.data.sdl19)\n  // 36. Add lines 10 and 21\n  l36 = (): number => this.l10() + this.l21()\n  // 37. Enter the amount from line 1 above\n  l37 = (): number => this.l1()\n  // 38. Subtract line 37 from line 36. If zero or less, enter -0-\n  l38 = (): number => Math.max(0, this.l36() - this.l37())\n  // 39. Subtract line 38 from line 35. If zero or less, enter -0-\n  l39 = (): number => Math.max(0, this.l35() - this.l38())\n  // 40. Multiply line 39 by 25% (0.25)\n  l40 = (): number => this.l39() * 0.25\n  // If Schedule D, line 18, is zero or blank, skip lines 41 through 43 and go to line 44. Otherwise, go to line 41.\n  // 41. Add lines 21, 22, 30, 33, and 39\n  l41 = (): number =>\n    this.l21() + this.l22() + this.l30() + this.l33() + this.l39()\n  // 42. Subtract line 41 from line 1\n  l42 = (): number => Math.max(0, this.l1() - this.l41())\n  // 43. Multiply line 42 by 28% (0.28)\n  l43 = (): number => this.l42() * 0.28\n  // 44. Figure the tax on the amount on line 21. If the amount on line 21 is less than $100,000, use the Tax Table to\n  l44 = (): number => computeOrdinaryTax(this.data.filingStatus, this.l21())\n  // 45. Add lines 31, 34, 40, 43, and 44\n  l45 = (): number =>\n    this.l31() + this.l34() + this.l40() + this.l43() + this.l44()\n  // 46. Figure the tax on the amount on line 1. If the amount on line 1 is less than $100,000, use the Tax Table to\n  l46 = (): number => computeOrdinaryTax(this.data.filingStatus, this.l1())\n  // figure the tax. If the amount on line 1 is $100,000 or more, use the Tax Computation Worksheet\n  // 47. Tax on all taxable income (including capital gains and qualified dividends). Enter the smaller of line 45\n  // or line 46. Also, include this amount on Form 1040, 1040-SR, or 1040-NR, line 16. (If you are filing Form\n  // 2555, don't enter this amount on Form 1040 or 1040-SR, line 16. Instead, enter it on line 4 of the Foreign\n  // Earned Income Tax Worksheet in the Instructions for Forms 1040 and 1040-SR)\n  l47 = (): number => Math.round(Math.min(this.l45(), this.l46()))\n}\n\nexport const showReference = (r: LTCGQualDivReference): string =>\n  Array.from(Array(47))\n    .map((_, i) => `l${i + 1}`)\n    .map((x) => [x, (r[x] as () => number)()])\n    .map(([l, v]) => `${l}: ${v}`)\n    .join('\\n')\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/SocialSecurityBenefits.ts",
    "content": "import { FilingStatus, TaxPayer, Information } from 'ustaxes/core/data'\nimport F1040 from '../F1040'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { SSBenefits } from '../../data/federal'\n\nexport default class SocialSecurityBenefitsWorksheet {\n  tp: TaxPayer\n  f1040: F1040\n\n  constructor(state: Information, f1040: F1040) {\n    this.f1040 = f1040\n    this.tp = state.taxPayer\n  }\n\n  totalNetBenefits = (): number =>\n    this.f1040.f1099ssas().reduce((sum, f) => sum + f.form.netBenefits, 0)\n\n  /* Enter the total amount from box 5 of all your Forms SSA-1099 and RRB-1099.\n      Also enter this amount on Form 1040 or 1040-SR, line 6a\n   */\n  l1 = (): number => this.totalNetBenefits()\n  // Multiply line 1 by 50% (0.50)\n  l2 = (): number => this.l1() / 2\n  /* If you are not excluding unemployment compensation from income,\n      combine the amounts from Form 1040 or 1040-SR, lines 1, 2b, 3b, 4b, 5b, 7, and 8.\n      If you are excluding unemployment compensation from income,\n      combine the amounts from Form 1040 or 1040-SR , lines 1, 2b, 3b, 4b, 5b, 7,\n      Schedule 1, lines 1 through 7, and line 3 of the Unemployment Compensation Exclusion Worksheet\n   */\n  l3 = (): number =>\n    sumFields([\n      this.f1040.l1(),\n      this.f1040.l2b(),\n      this.f1040.l3b(),\n      this.f1040.l4b(),\n      this.f1040.l5b(),\n      this.f1040.l7(),\n      this.f1040.l8()\n    ])\n  // Enter the amount, if any, from Form 1040 or 1040-SR, line 2a\n  l4 = (): number | undefined => this.f1040.l2a()\n  // Combine lines 2, 3, and 4\n  l5 = (): number => sumFields([this.l2(), this.l3(), this.l4()])\n  /* Enter the total of the amounts from Form 1040 or 1040-SR, line 10b, \n      Schedule 1, lines 10 through 19, \n      plus any write-in adjustments you entered on the dotted line next to Schedule 1, line 22\n   */\n  l6 = (): number =>\n    sumFields([\n      this.f1040.l10b(),\n      this.f1040.schedule1.l10(),\n      this.f1040.schedule1.l11(),\n      this.f1040.schedule1.l12(),\n      this.f1040.schedule1.l13(),\n      this.f1040.schedule1.l14(),\n      this.f1040.schedule1.l15(),\n      this.f1040.schedule1.l16(),\n      this.f1040.schedule1.l17(),\n      this.f1040.schedule1.l18(),\n      this.f1040.schedule1.l19(),\n      this.f1040.schedule1.l22writeIn()\n    ])\n\n  /* Line 7: Is the amount on line 6 less than the amount on line 5?\n    If No, None of your social security benefits are taxable. Enter -0- on Form 1040 or 1040-SR, line 6b.\n    If Yes, Subtract line 6 from line 5\n  */\n\n  l7 = (): number => {\n    if (this.l6() < this.l5()) {\n      return this.l5() - this.l6()\n    } else {\n      return 0\n    }\n  }\n  /*\n    If you are:\n    Married filing jointly, enter $32,000\n    Single, head of household, qualifying widow(er), or married filing\n    separately and you lived apart from your spouse for all of the year,\n    enter $25,000\n    Married filing separately and you lived with your spouse at any time\n    in the year, skip lines 8 through 15; multiply line 7 by 85% (0.85) and\n    enter the result on line 16. Then, go to line 17\n  */\n  l8 = (): number => {\n    if (this.tp.filingStatus == undefined) {\n      return 0\n    } else if (this.tp.filingStatus == FilingStatus.MFS) {\n      // treat Married filing separately specially due to the extra question below\n      // and resulting logic in the worksheet\n      if (this.f1040.info.questions.LIVE_APART_FROM_SPOUSE) {\n        return SSBenefits.caps[this.tp.filingStatus].l8\n      } else {\n        // Note that this value won't be taken into account. Instead,\n        // the line 16 function will also check for this and perform\n        // the right math.\n        return 0\n      }\n    } else {\n      return SSBenefits.caps[this.tp.filingStatus].l8\n    }\n  }\n  /*\n  Is the amount on line 8 less than the amount on line 7?\n  \n  If No, None of your social security benefits are taxable. \n  Enter -0- on Form 1040 or 1040-SR, line 6b. \n  If you are married filing separately and you lived apart from your spouse for all of 2020, \n  be sure you entered \"D\" to the right of the word \"benefits\" on line 6a.\n\n  If Yes, Subtract line 8 from line 7.\n  */\n  l9 = (): number => {\n    if (this.l8() < this.l7()) {\n      return this.l7() - this.l8()\n    } else {\n      return 0\n    }\n  }\n\n  /*\n  Enter: $12,000 if married filing jointly; \n  $9,000 if single, head of household, qualifying widow(er), or married filing separately \n  and you lived apart from your spouse for all of 2020\n  */\n  l10 = (): number => {\n    if (this.tp.filingStatus == undefined) {\n      return 0\n    }\n    return SSBenefits.caps[this.tp.filingStatus].l10\n  }\n\n  // Subtract line 10 from line 9. If zero or less, enter -0-\n  l11 = (): number => {\n    const tmp = this.l9() - this.l10()\n    if (tmp < 0) {\n      return 0\n    } else {\n      return tmp\n    }\n  }\n\n  // Enter the smaller of line 9 or line 10\n  l12 = (): number => Math.min(this.l9(), this.l10())\n\n  // Enter one-half of line 12\n  l13 = (): number => this.l12() / 2\n\n  // Enter the smaller of line 2 or line 13\n  l14 = (): number => Math.min(this.l13(), this.l2())\n\n  // Multiply line 11 by 85% (0.85). If line 11 is zero, enter -0-\n  l15 = (): number => {\n    if (this.l11() == 0) {\n      return 0\n    } else {\n      return this.l11() * 0.85\n    }\n  }\n\n  // Add lines 14 and 15\n  l16 = (): number => {\n    // From line 7 instructions:\n    // Married filing separately and you lived with your spouse at any time\n    // in 2020, skip lines 8 through 15; multiply line 7 by 85% (0.85) and\n    // enter the result on line 16. Then, go to line 17\n    if (\n      this.tp.filingStatus == FilingStatus.MFS &&\n      !this.f1040.info.questions.LIVE_APART_FROM_SPOUSE\n    ) {\n      return this.l7() * 0.85\n    } else {\n      return sumFields([this.l14(), this.l15()])\n    }\n  }\n\n  // Multiply line 1 by 85% (0.85)\n  l17 = (): number => this.l1() * 0.85\n\n  // Taxable social security benefits. Enter the smaller of line 16 or line 17.\n  // Also enter this amount on Form 1040 or 1040-SR, line 6b\n  l18 = (): number => Math.min(this.l16(), this.l17())\n\n  // This is the function used to return the taxable amount of the social security\n  // benefits to be entered in line 6b of 1040. It takes into account the various\n  // stopping points in the worksheet.\n  taxableAmount = (): number => {\n    const line7 = this.l7()\n    if (line7 == 0) {\n      return line7\n    }\n\n    const line9 = this.l9()\n    if (line9 == 0) {\n      return line9\n    }\n\n    return this.l18()\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2020/irsForms/worksheets/StudentLoanInterestWorksheet.ts",
    "content": "import { F1098e, FilingStatus } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport F1040 from '../../irsForms/F1040'\n\nexport default class StudentLoanInterestWorksheet {\n  f1040: F1040\n  f1098es: F1098e[]\n\n  constructor(f1040: F1040, f1098es: F1098e[]) {\n    this.f1040 = f1040\n    this.f1098es = f1098es\n  }\n\n  // Can't take deduction if filling Married Filling Seperate\n  notMFS = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFS\n\n  // Can't take deduction if MFJ and spouse is a dependent\n  isNotDependentSpouse = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFJ ||\n    this.f1040.info.taxPayer.spouse === undefined ||\n    !this.f1040.info.taxPayer.spouse.isTaxpayerDependent\n\n  // Can't take deduction if someone else claims you as a dependent\n  isNotDependentSelf = (): boolean =>\n    !this.f1040.info.taxPayer.primaryPerson.isTaxpayerDependent\n\n  isNotDependent = (): boolean =>\n    this.isNotDependentSpouse() && this.isNotDependentSelf()\n\n  // Sum interest, but maximum of 2500 can be deducted\n  l1 = (): number =>\n    Math.min(\n      this.f1098es.reduce((sum, f) => sum + f.interest, 0),\n      2500\n    )\n\n  // Currently do not support unemployment compensation exclusion\n  // TO DO: add unemployment compensation exclusion\n  l2 = (): number => this.f1040.l9()\n\n  // Schedule 1 deductions\n  l3 = (): number =>\n    sumFields([\n      this.f1040.schedule1.l10(),\n      this.f1040.schedule1.l11(),\n      this.f1040.schedule1.l12(),\n      this.f1040.schedule1.l13(),\n      this.f1040.schedule1.l14(),\n      this.f1040.schedule1.l15(),\n      this.f1040.schedule1.l16(),\n      this.f1040.schedule1.l17(),\n      this.f1040.schedule1.l18(),\n      this.f1040.schedule1.l19(),\n      this.f1040.schedule1.l22writeIn()\n    ])\n\n  l4 = (): number => Math.max(0, this.l2() - this.l3())\n\n  l5 = (): number =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ ? 140000 : 70000\n\n  l6 = (): number => Math.max(0, this.l4() - this.l5())\n\n  l7 = (): number => Math.min(this.l6() / 15000, 1)\n\n  l8 = (): number => this.l1() * this.l7()\n\n  l9 = (): number | undefined =>\n    this.notMFS() && this.isNotDependent()\n      ? Math.max(0, this.l1() - this.l8())\n      : undefined\n}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/AK/Form.ts",
    "content": "export default class AKForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/AL/Form.ts",
    "content": "export default class ALForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/AR/Form.ts",
    "content": "export default class ARForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/AZ/Form.ts",
    "content": "export default class AZForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/CA/Form.ts",
    "content": "export default class CAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/CO/Form.ts",
    "content": "export default class COForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/CT/Form.ts",
    "content": "export default class CTForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/DC/Form.ts",
    "content": "export default class DCForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/DE/Form.ts",
    "content": "export default class DEForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/FL/Form.ts",
    "content": "export default class FLForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/GA/Form.ts",
    "content": "export default class GAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/HI/Form.ts",
    "content": "export default class HIForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IA/Form.ts",
    "content": "export default class IAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/ID/Form.ts",
    "content": "export default class IDForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IL/IL1040.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field, RadioSelect } from 'ustaxes/core/pdfFiller'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { AccountType, FilingStatus, State } from 'ustaxes/core/data'\nimport parameters from './Parameters'\nimport { IL1040scheduleileeic } from './IL1040ScheduleILEIC'\nimport IL1040V from './IL1040V'\nimport { ILWIT } from './ILWit'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class IL1040 extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  scheduleEIC: IL1040scheduleileeic\n  il1040V: IL1040V\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'IL-1040'\n    this.state = 'IL'\n    this.scheduleEIC = new IL1040scheduleileeic(this.info, f1040)\n    this.il1040V = new IL1040V(this.info, f1040, this)\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    const pmt = this.payment()\n    const result: Form[] = []\n    if ((pmt ?? 0) > 0) {\n      result.push(this.il1040V)\n    }\n    if (this.scheduleEIC.isRequired()) {\n      result.push(this.scheduleEIC)\n    }\n    if (this.methods.stateWithholding() > 0) {\n      const ilwit = new ILWIT(this.f1040)\n      result.push(ilwit)\n      ilwit.attachments().forEach((f) => result.push(f))\n    }\n\n    return result\n  }\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: month\n   */\n  month = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.month()\n\n  /**\n   * Index 2: year\n   */\n  year = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.year()\n\n  /**\n   * Index 3: name1\n   */\n  name1 = (): string | undefined => this.info.taxPayer.primaryPerson.firstName\n\n  f3 = (): string | undefined => this.name1()\n\n  /**\n   * Index 4: name2\n   */\n  name2 = (): string | undefined => this.info.taxPayer.primaryPerson.lastName\n\n  f4 = (): string | undefined => this.name2()\n\n  /**\n   * Index 5: YoB\n   * TODO - year of birth\n   */\n  YoB = (): string | undefined => undefined\n\n  f5 = (): string | undefined => this.YoB()\n\n  /**\n   * Index 6: ssn1\n   */\n  ssn1 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f6 = (): string | undefined => this.ssn1()\n\n  /**\n   * Index 7: ssn2\n   */\n  ssn2 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f7 = (): string | undefined => this.ssn2()\n\n  /**\n   * Index 8: ssn3\n   */\n  ssn3 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f8 = (): string | undefined => this.ssn3()\n\n  /**\n   * Index 9: name3\n   */\n  name3 = (): string | undefined => this.info.taxPayer.spouse?.firstName\n\n  f9 = (): string | undefined => this.name3()\n\n  /**\n   * Index 10: name4\n   */\n  name4 = (): string | undefined => this.info.taxPayer.spouse?.lastName\n\n  f10 = (): string | undefined => this.name4()\n\n  /**\n   * Index 11: SpYoB\n   * TODO: spouse birth year\n   */\n  SpYoB = (): string | undefined => undefined\n\n  f11 = (): string | undefined => this.SpYoB()\n\n  /**\n   * Index 12: ssn4\n   */\n  ssn4 = (): string | undefined => this.info.taxPayer.spouse?.ssid.slice(0, 3)\n\n  f12 = (): string | undefined => this.ssn4()\n\n  /**\n   * Index 13: ssn5\n   */\n  ssn5 = (): string | undefined => this.info.taxPayer.spouse?.ssid.slice(3, 5)\n\n  f13 = (): string | undefined => this.ssn5()\n\n  /**\n   * Index 14: ssn6\n   */\n  ssn6 = (): string | undefined => this.info.taxPayer.spouse?.ssid.slice(5)\n\n  f14 = (): string | undefined => this.ssn6()\n\n  /**\n   * Index 15: address\n   */\n  address = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.address\n\n  f15 = (): string | undefined => this.address()\n\n  /**\n   * Index 16: apt\n   */\n  apt = (): string | undefined => this.info.taxPayer.primaryPerson.address.aptNo\n\n  f16 = (): string | undefined => this.apt()\n\n  /**\n   * Index 17: County\n   * TODO - county\n   */\n  County = (): string | undefined => undefined\n\n  f17 = (): string | undefined => this.County()\n\n  /**\n   * Index 18: city\n   */\n  city = (): string | undefined => this.info.taxPayer.primaryPerson.address.city\n\n  f18 = (): string | undefined => this.city()\n\n  /**\n   * Index 19: st\n   */\n  st = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.state ??\n    this.info.taxPayer.primaryPerson.address.province\n\n  f19 = (): string | undefined => this.st()\n\n  /**\n   * Index 20: zip\n   */\n  zip = (): string | undefined => this.info.taxPayer.primaryPerson.address.zip\n\n  f20 = (): string | undefined => this.zip()\n\n  /**\n   * Index 21: foreign\n   */\n  foreign = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.foreignCountry\n\n  f21 = (): string | undefined => this.foreign()\n\n  /**\n   * Index 22: Check Box1\n   * This is actually a radio group, so indicate the correct selection\n   * by index.\n   */\n  CheckBox1 = (): RadioSelect | undefined => ({\n    select: [\n      FilingStatus.S,\n      FilingStatus.MFJ,\n      FilingStatus.MFS,\n      FilingStatus.W,\n      FilingStatus.HOH\n    ].findIndex((x) => x === this.info.taxPayer.filingStatus)\n  })\n\n  f22 = (): RadioSelect | undefined => this.CheckBox1()\n\n  /**\n   * Index 23: Check Box1c\n   */\n  CheckBox1c = (): boolean | undefined =>\n    this.info.taxPayer.primaryPerson.isTaxpayerDependent\n\n  f23 = (): boolean | undefined => this.CheckBox1c()\n\n  /**\n   * Index 24: Check Box1cc\n   */\n  CheckBox1cc = (): boolean | undefined =>\n    this.info.taxPayer.spouse?.isTaxpayerDependent\n\n  f24 = (): boolean | undefined => this.CheckBox1cc()\n\n  /**\n   * Index 25: Check Box7\n   * TODO - nonresident, part year\n   */\n  CheckBox7 = (): boolean | undefined => undefined\n\n  f25 = (): boolean | undefined => this.CheckBox7()\n\n  /**\n   * Index 26: 1\n   */\n  l1 = (): number | undefined => this.f1040.l11()\n\n  /**\n   * Index 27: 2\n   */\n  l2 = (): number | undefined => this.f1040.l2a()\n\n  /**\n   * Index 28: 3\n   * TODO: Schedule M, other additions\n   */\n  l3 = (): number | undefined => undefined\n\n  /**\n   * Index 29: 4\n   */\n  l4 = (): number => sumFields([this.l1(), this.l2(), this.l3()])\n\n  /**\n   * Index 30: 5\n   * TODO - ss benefits and certain retirement plan income received if included in line 1, attach p1 of federal return\n   */\n  l5 = (): number | undefined => undefined\n\n  /**\n   * Index 31: 6\n   * TODO IL income tax overpayment included in federal form 1040 S1 L1\n   */\n  l6 = (): number | undefined => undefined\n\n  /**\n   * Index 32: 7\n   * TODO: other subtractions, attach Schedule M\n   */\n  l7 = (): number | undefined => undefined\n\n  /**\n   * Index 33: Check Box2\n   * Check if L7 includes any amount from Schedule 1299-C\n   */\n  CheckBox2 = (): boolean | undefined => undefined\n\n  f33 = (): boolean | undefined => this.CheckBox2()\n\n  /**\n   * Index 34: 8\n   */\n  l8 = (): number => sumFields([this.l5(), this.l6(), this.l7()])\n\n  /**\n   * Index 35: 9\n   * IL base income\n   */\n  l9 = (): number => Math.max(0, this.l4() - this.l8())\n\n  /**\n   * Index 36: 10a\n   */\n  l10a = (): number => {\n    if (this.info.taxPayer.filingStatus === FilingStatus.MFJ)\n      return parameters.exemptions.MFJ.exemptionAmount\n    return parameters.exemptions.S.exemptionAmount\n  }\n\n  /**\n   * Index 37: Check Box3\n   * Check if TP senior\n   */\n  primarySenior = (): boolean | undefined => undefined\n\n  f37 = (): boolean | undefined => this.primarySenior()\n\n  /**\n   * Index 38: Check Box4\n   * Check if spouse senior\n   */\n  spouseSenior = (): boolean | undefined => undefined\n\n  f38 = (): boolean | undefined => this.spouseSenior()\n\n  /**\n   * Index 39: 10b\n   */\n  l10b = (): number =>\n    [this.primarySenior() ?? false, this.spouseSenior() ?? false].filter(\n      (x) => x\n    ).length * parameters.seniorExemption\n\n  /**\n   * Index 40: Check Box5\n   * TODO: TP blind\n   */\n  CheckBox5 = (): boolean | undefined => undefined\n\n  f40 = (): boolean | undefined => this.CheckBox5()\n\n  /**\n   * Index 41: Check Box6\n   * TODO: Spouse blind\n   */\n  CheckBox6 = (): boolean | undefined => undefined\n\n  f41 = (): boolean | undefined => this.CheckBox6()\n\n  /**\n   * Index 42: 10c\n   */\n  l10c = (): number | undefined =>\n    [this.CheckBox5(), this.CheckBox6()].filter((x) => x).length *\n    parameters.blindExemption\n\n  /**\n   * Index 43: 10d\n   * TODO: Schedule EC step 2, line 1\n   */\n  l10d = (): number | undefined => undefined\n\n  /**\n   * Index 44: 10\n   * Net income\n   */\n  l10 = (): number =>\n    sumFields([this.l10a(), this.l10b(), this.l10c(), this.l10d()])\n\n  /**\n   * Index 45: 11\n   * TODO: handle non-residents, part year residents\n   */\n  l11 = (): number => Math.max(0, this.l9() - this.l10())\n\n  /**\n   * Index 46: 12\n   */\n  l12 = (): number => this.l11() * parameters.taxRate\n\n  /**\n   * Index 47: 13\n   * TODO: recapture investment tax credits, schedule 4255\n   */\n  l13 = (): number | undefined => undefined\n\n  /**\n   * Index 48: 14\n   * Income tax\n   */\n  l14 = (): number => sumFields([this.l12(), this.l13()])\n\n  /**\n   * Index 49: 15\n   * TODO: income tax paid to another state while IL resident\n   */\n  l15 = (): number | undefined => undefined\n\n  /**\n   * Index 50: 16\n   * Property tax and K12 education expense credit amount from Schedule ICR\n   */\n  l16 = (): number | undefined => undefined\n\n  /**\n   * Index 51: 17\n   * TODO: Credit amount from Schedule 1299-C Attach 1299-C\n   */\n  l17 = (): number | undefined => undefined\n\n  /**\n   * Index 52: 18\n   * Total credits\n   */\n  l18 = (): number => sumFields([this.l15(), this.l16(), this.l17()])\n\n  /**\n   * Index 53: 19\n   * Total non-refundable credits\n   */\n  l19 = (): number => Math.max(0, this.l14() - this.l18())\n\n  /**\n   * Index 54: 20\n   * TODO: Household employment tax\n   */\n  l20 = (): number | undefined => undefined\n\n  /**\n   * Index 55: 21\n   * TODO: Use tax on internet, mail order, or other out-of-state purchases\n   */\n  l21 = (): number | undefined => undefined\n\n  /**\n   * Index 56: 22\n   * TODO: Compassionate use of medical cannabis program act and sale of assets by gaming licensee\n   */\n  l22 = (): number | undefined => undefined\n\n  /**\n   * Index 57: 23\n   * Total tax\n   */\n  l23 = (): number =>\n    sumFields([this.l19(), this.l20(), this.l21(), this.l22()])\n\n  /**\n   * Index 58: 24\n   */\n  l24 = (): number => this.l23()\n\n  /**\n   * Index 59: 25\n   * IL Income tax withheld\n   */\n  l25 = (): number | undefined => this.methods.witholdingForState('IL')\n\n  /**\n   * Index 60: 26\n   * TODO: Estimated tax payments\n   */\n  l26 = (): number | undefined => undefined\n\n  /**\n   * Index 61: 27\n   * Pass-through withholding\n   */\n  l27 = (): number | undefined => undefined\n\n  /**\n   * Index 62: 28\n   * Earned income credit from Schedule IL-E/EIC, Step 4, line 8\n   */\n  l28 = (): number | undefined => this.scheduleEIC.earnedIncomeCredit()\n\n  /**\n   * Index 63: 29\n   * Total payments and refundable credits\n   */\n  l29 = (): number =>\n    sumFields([this.l25(), this.l26(), this.l27(), this.l28()])\n\n  /**\n   * Index 64: 30\n   */\n  l30 = (): number => Math.max(0, this.l29() - this.l24())\n\n  /**\n   * Index 65: 31\n   */\n  l31 = (): number => Math.max(0, this.l24() - this.l29())\n\n  /**\n   * Index 66: 32\n   * TODO: late payment penalty for underpayment of estimated tax\n   */\n  l32 = (): number | undefined => undefined\n\n  /**\n   * Index 67: Check Box8a\n   * TODO: 2/3 of income from farming\n   */\n  CheckBox8a = (): boolean | undefined => undefined\n\n  f67 = (): boolean | undefined => this.CheckBox8a()\n\n  /**\n   * Index 68: Check Box8b\n   * TODO: You or spouse is 65 or older and permanently in nursing home\n   */\n  CheckBox8b = (): boolean | undefined => undefined\n\n  f68 = (): boolean | undefined => this.CheckBox8b()\n\n  /**\n   * Index 69: Check Box8c\n   * TODO: Income not received evenly during the year and you annualized your income on IL-2210\n   */\n  CheckBox8c = (): boolean | undefined => undefined\n\n  f69 = (): boolean | undefined => this.CheckBox8c()\n\n  /**\n   * Index 70: Check Box8d\n   * TODO: Check if you were not required to file an IL individual tax return in the previous tax year.\n   */\n  CheckBox8d = (): boolean | undefined => undefined\n\n  f70 = (): boolean | undefined => this.CheckBox8d()\n\n  /**\n   * Index 71: 33\n   * TODO: Voluntary charitable contributions\n   */\n  l33 = (): number | undefined => undefined\n\n  /**\n   * Index 72: 34\n   */\n  l34 = (): number => sumFields([this.l32(), this.l33()])\n\n  /**\n   * Index 73: 35\n   * If you have an amount on L30 and this amount is greater than L34, this is your overpayment\n   */\n  l35 = (): number => Math.max(0, this.l30() - this.l34())\n\n  /**\n   * Index 74: 36\n   * Amount you want refunded to you\n   * TODO: assuming payer wants all refunded.\n   */\n  l36 = (): number => this.l35()\n\n  /**\n   * Index 75: rn1\n   */\n  rn1 = (): string | undefined => this.info.refund?.routingNumber\n\n  f75 = (): string | undefined => this.rn1()\n\n  /**\n   * Index 76: Check Box11\n   * TODO: support savings account checkbox - radio field issue\n   */\n  CheckBox11 = (): boolean | undefined =>\n    this.info.refund?.accountType === AccountType.checking\n\n  f76 = (): boolean | undefined => this.CheckBox11()\n\n  /**\n   * Index 77: ac1\n   */\n  ac1 = (): string | undefined => this.info.refund?.accountNumber\n\n  f77 = (): string | undefined => this.ac1()\n\n  /**\n   * Index 78: Refund Method\n   * TODO: radio issue, only handling direct deposit.\n   */\n  RefundMethod = (): boolean | undefined => true\n\n  f78 = (): boolean | undefined => this.RefundMethod()\n\n  /**\n   * Index 79: 38\n   * TODO: not supporting credit forward\n   */\n  l38 = (): number | undefined => undefined\n\n  /**\n   * Index 80: 39\n   */\n  l39 = (): number | undefined => {\n    const l31 = this.l31()\n    const l34 = this.l34()\n    const l30 = this.l30()\n    if (l31 > 0) return l31 + l34\n    if (l30 > 0 && l30 < l34) return l34 - l30\n  }\n  payment = (): number | undefined => this.l39()\n\n  // Signature block fields omitted\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.f33(),\n    this.l8(),\n    this.l9(),\n    this.l10a(),\n    this.f37(),\n    this.f38(),\n    this.l10b(),\n    this.f40(),\n    this.f41(),\n    this.l10c(),\n    this.l10d(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    this.l18(),\n    this.l19(),\n    this.l20(),\n    this.l21(),\n    this.l22(),\n    this.l23(),\n    this.l24(),\n    this.l25(),\n    this.l26(),\n    this.l27(),\n    this.l28(),\n    this.l29(),\n    this.l30(),\n    this.l31(),\n    this.l32(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.l33(),\n    this.l34(),\n    this.l35(),\n    this.l36(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.l38(),\n    this.l39()\n  ]\n}\n\nconst makeIL1040 = (f1040: F1040): IL1040 => new IL1040(f1040)\n\nexport default makeIL1040\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IL/IL1040ScheduleILEIC.ts",
    "content": "import Form from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { Dependent, PrimaryPerson, State } from 'ustaxes/core/data'\nimport parameters from './Parameters'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class IL1040scheduleileeic extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  formOrder = 1\n  attachments: () => Form[] = () => []\n  qualifyingDependents: Dependent[]\n\n  constructor(info: ValidatedInformation, f1040: F1040) {\n    super()\n    this.info = info\n    this.f1040 = f1040\n    this.formName = 'il-1040-schedule-il-e-eic'\n    this.state = 'IL'\n    this.qualifyingDependents = this.f1040.scheduleEIC.qualifyingDependents()\n  }\n\n  get primary(): PrimaryPerson | undefined {\n    return this.info.taxPayer.primaryPerson\n  }\n\n  isRequired = (): boolean => (this.earnedIncomeCredit() ?? 0) > 0\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: X  2325\n   */\n  X2325 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.X2325()\n\n  /**\n   * Index 2: Reset\n   */\n  Reset = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.Reset()\n\n  /**\n   * Index 3: Print\n   */\n  Print = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.Print()\n\n  /**\n   * Index 4: Your name\n   */\n  Yourname = (): string | undefined =>\n    [this.primary?.firstName, this.primary?.lastName].flat().join(' ')\n\n  f4 = (): string | undefined => this.Yourname()\n\n  /**\n   * Index 5: Dependents first name - 2\n   */\n  Dependentsfirstname2 = (): string | undefined =>\n    this.info.taxPayer.dependents[1]?.firstName\n\n  f5 = (): string | undefined => this.Dependentsfirstname2()\n\n  /**\n   * Index 6: Dependent's first name - 1\n   */\n  Dependentsfirstname1 = (): string | undefined =>\n    this.info.taxPayer.dependents[0]?.firstName\n\n  f6 = (): string | undefined => this.Dependentsfirstname1()\n\n  /**\n   * Index 7: Dependent's first name - 3\n   */\n  Dependentsfirstname3 = (): string | undefined =>\n    this.info.taxPayer.dependents[2]?.firstName\n\n  f7 = (): string | undefined => this.Dependentsfirstname3()\n\n  /**\n   * Index 8: Dependent's first name - 4\n   */\n  Dependentsfirstname4 = (): string | undefined =>\n    this.info.taxPayer.dependents[3]?.firstName\n\n  f8 = (): string | undefined => this.Dependentsfirstname4()\n\n  /**\n   * Index 9: Dependent's first name - 5\n   */\n  Dependentsfirstname5 = (): string | undefined =>\n    this.info.taxPayer.dependents[4]?.firstName\n\n  f9 = (): string | undefined => this.Dependentsfirstname5()\n\n  /**\n   * Index 10: Dependent's first name - 6\n   */\n  Dependentsfirstname6 = (): string | undefined =>\n    this.info.taxPayer.dependents[5]?.firstName\n\n  f10 = (): string | undefined => this.Dependentsfirstname6()\n\n  /**\n   * Index 11: Dependent's first name - 7\n   */\n  Dependentsfirstname7 = (): string | undefined =>\n    this.info.taxPayer.dependents[6]?.firstName\n\n  f11 = (): string | undefined => this.Dependentsfirstname7()\n\n  /**\n   * Index 12: Dependent's first name - 8\n   */\n  Dependentsfirstname8 = (): string | undefined =>\n    this.info.taxPayer.dependents[7]?.firstName\n\n  f12 = (): string | undefined => this.Dependentsfirstname8()\n\n  /**\n   * Index 13: Dependent's first name - 9\n   */\n  Dependentsfirstname9 = (): string | undefined =>\n    this.info.taxPayer.dependents[8]?.firstName\n\n  f13 = (): string | undefined => this.Dependentsfirstname9()\n\n  /**\n   * Index 14: Dependent's first name - 10\n   */\n  Dependentsfirstname10 = (): string | undefined =>\n    this.info.taxPayer.dependents[9]?.firstName\n\n  f14 = (): string | undefined => this.Dependentsfirstname10()\n\n  /**\n   * Index 15: Dependent's last name - 2\n   */\n  Dependentslastname2 = (): string | undefined =>\n    this.info.taxPayer.dependents[1]?.lastName\n\n  f15 = (): string | undefined => this.Dependentslastname2()\n\n  /**\n   * Index 16: Dependent's last name - 1\n   */\n  Dependentslastname1 = (): string | undefined =>\n    this.info.taxPayer.dependents[0]?.lastName\n\n  f16 = (): string | undefined => this.Dependentslastname1()\n\n  /**\n   * Index 17: Dependent's last name - 3\n   */\n  Dependentslastname3 = (): string | undefined =>\n    this.info.taxPayer.dependents[2]?.lastName\n\n  f17 = (): string | undefined => this.Dependentslastname3()\n\n  /**\n   * Index 18: Dependent's last name - 4\n   */\n  Dependentslastname4 = (): string | undefined =>\n    this.info.taxPayer.dependents[3]?.lastName\n\n  f18 = (): string | undefined => this.Dependentslastname4()\n\n  /**\n   * Index 19: Dependent's last name - 5\n   */\n  Dependentslastname5 = (): string | undefined =>\n    this.info.taxPayer.dependents[4]?.lastName\n\n  f19 = (): string | undefined => this.Dependentslastname5()\n\n  /**\n   * Index 20: Dependent's last name - 6\n   */\n  Dependentslastname6 = (): string | undefined =>\n    this.info.taxPayer.dependents[5]?.lastName\n\n  f20 = (): string | undefined => this.Dependentslastname6()\n\n  /**\n   * Index 21: Dependent's last name - 7\n   */\n  Dependentslastname7 = (): string | undefined =>\n    this.info.taxPayer.dependents[6]?.lastName\n\n  f21 = (): string | undefined => this.Dependentslastname7()\n\n  /**\n   * Index 22: Dependent's last name - 8\n   */\n  Dependentslastname8 = (): string | undefined =>\n    this.info.taxPayer.dependents[7]?.lastName\n\n  f22 = (): string | undefined => this.Dependentslastname8()\n\n  /**\n   * Index 23: Dependent's last name - 9\n   */\n  Dependentslastname9 = (): string | undefined =>\n    this.info.taxPayer.dependents[8]?.lastName\n\n  f23 = (): string | undefined => this.Dependentslastname9()\n\n  /**\n   * Index 24: Dependent's last name - 10\n   */\n  Dependentslastname10 = (): string | undefined =>\n    this.info.taxPayer.dependents[9]?.lastName\n\n  f24 = (): string | undefined => this.Dependentslastname10()\n\n  /**\n   * Index 25: Social Security number - 2\n   */\n  SocialSecuritynumber2 = (): string | undefined =>\n    this.info.taxPayer.dependents[1]?.ssid\n\n  f25 = (): string | undefined => this.SocialSecuritynumber2()\n\n  /**\n   * Index 26: Social Security number - 3\n   */\n  SocialSecuritynumber3 = (): string | undefined =>\n    this.info.taxPayer.dependents[2]?.ssid\n\n  f26 = (): string | undefined => this.SocialSecuritynumber3()\n\n  /**\n   * Index 27: Social Security number - 4\n   */\n  SocialSecuritynumber4 = (): string | undefined =>\n    this.info.taxPayer.dependents[3]?.ssid\n\n  f27 = (): string | undefined => this.SocialSecuritynumber4()\n\n  /**\n   * Index 28: Social Security number - 5\n   */\n  SocialSecuritynumber5 = (): string | undefined =>\n    this.info.taxPayer.dependents[4]?.ssid\n\n  f28 = (): string | undefined => this.SocialSecuritynumber5()\n\n  /**\n   * Index 29: Social Security number - 6\n   */\n  SocialSecuritynumber6 = (): string | undefined =>\n    this.info.taxPayer.dependents[5]?.ssid\n\n  f29 = (): string | undefined => this.SocialSecuritynumber6()\n\n  /**\n   * Index 30: Social Security number - 7\n   */\n  SocialSecuritynumber7 = (): string | undefined =>\n    this.info.taxPayer.dependents[6]?.ssid\n\n  f30 = (): string | undefined => this.SocialSecuritynumber7()\n\n  /**\n   * Index 31: Social Security number - 8\n   */\n  SocialSecuritynumber8 = (): string | undefined =>\n    this.info.taxPayer.dependents[7]?.ssid\n\n  f31 = (): string | undefined => this.SocialSecuritynumber8()\n\n  /**\n   * Index 32: Social Security number - 9\n   */\n  SocialSecuritynumber9 = (): string | undefined =>\n    this.info.taxPayer.dependents[8]?.ssid\n\n  f32 = (): string | undefined => this.SocialSecuritynumber9()\n\n  /**\n   * Index 33: Social Security number - 10\n   */\n  SocialSecuritynumber10 = (): string | undefined =>\n    this.info.taxPayer.dependents[9]?.ssid\n\n  f33 = (): string | undefined => this.SocialSecuritynumber10()\n\n  /**\n   * Index 34: Dependent's relationship to you - 1\n   */\n  Dependentsrelationshiptoyou1 = (): string | undefined => {\n    return undefined\n  }\n\n  f34 = (): string | undefined => this.Dependentsrelationshiptoyou1()\n\n  /**\n   * Index 35: Dependent's relationship to you - 2\n   */\n  Dependentsrelationshiptoyou2 = (): string | undefined => {\n    return undefined\n  }\n\n  f35 = (): string | undefined => this.Dependentsrelationshiptoyou2()\n\n  /**\n   * Index 36: Dependent's relationship to you - 3\n   */\n  Dependentsrelationshiptoyou3 = (): string | undefined => {\n    return undefined\n  }\n\n  f36 = (): string | undefined => this.Dependentsrelationshiptoyou3()\n\n  /**\n   * Index 37: Dependent's relationship to you - 4\n   */\n  Dependentsrelationshiptoyou4 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.Dependentsrelationshiptoyou4()\n\n  /**\n   * Index 38: Dependent's relationship to you - 5\n   */\n  Dependentsrelationshiptoyou5 = (): string | undefined => {\n    return undefined\n  }\n\n  f38 = (): string | undefined => this.Dependentsrelationshiptoyou5()\n\n  /**\n   * Index 39: Dependent's relationship to you - 6\n   */\n  Dependentsrelationshiptoyou6 = (): string | undefined => {\n    return undefined\n  }\n\n  f39 = (): string | undefined => this.Dependentsrelationshiptoyou6()\n\n  /**\n   * Index 40: Dependent's relationship to you - 7\n   */\n  Dependentsrelationshiptoyou7 = (): string | undefined => {\n    return undefined\n  }\n\n  f40 = (): string | undefined => this.Dependentsrelationshiptoyou7()\n\n  /**\n   * Index 41: Dependent's relationship to you - 8\n   */\n  Dependentsrelationshiptoyou8 = (): string | undefined => {\n    return undefined\n  }\n\n  f41 = (): string | undefined => this.Dependentsrelationshiptoyou8()\n\n  /**\n   * Index 42: Dependent's relationship to you - 9\n   */\n  Dependentsrelationshiptoyou9 = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.Dependentsrelationshiptoyou9()\n\n  /**\n   * Index 43: Dependent's relationship to you - 10\n   */\n  Dependentsrelationshiptoyou10 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.Dependentsrelationshiptoyou10()\n\n  /**\n   * Index 44: Dependent's date of birth (mm/dd/yyyy) - 1\n   */\n  Dependentsdateofbirthmmddyyyy1 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy1()\n\n  /**\n   * Index 45: Dependent's date of birth (mm/dd/yyyy) - 2\n   */\n  Dependentsdateofbirthmmddyyyy2 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy2()\n\n  /**\n   * Index 46: Dependent's date of birth (mm/dd/yyyy) - 3\n   */\n  Dependentsdateofbirthmmddyyyy3 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy3()\n\n  /**\n   * Index 47: Dependent's date of birth (mm/dd/yyyy) - 4\n   */\n  Dependentsdateofbirthmmddyyyy4 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy4()\n\n  /**\n   * Index 48: Dependent's date of birth (mm/dd/yyyy) - 5\n   */\n  Dependentsdateofbirthmmddyyyy5 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy5()\n\n  /**\n   * Index 49: Dependent's date of birth (mm/dd/yyyy) - 6\n   */\n  Dependentsdateofbirthmmddyyyy6 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy6()\n\n  /**\n   * Index 50: Dependent's date of birth (mm/dd/yyyy) - 7\n   */\n  Dependentsdateofbirthmmddyyyy7 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy7()\n\n  /**\n   * Index 51: Dependent's date of birth (mm/dd/yyyy) - 8\n   */\n  Dependentsdateofbirthmmddyyyy8 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy8()\n\n  /**\n   * Index 52: Dependent's date of birth (mm/dd/yyyy) - 9\n   */\n  Dependentsdateofbirthmmddyyyy9 = (): string | undefined => {\n    return undefined\n  }\n\n  f52 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy9()\n\n  /**\n   * Index 53: Dependent's date of birth (mm/dd/yyyy) - 10\n   */\n  Dependentsdateofbirthmmddyyyy10 = (): string | undefined => {\n    return undefined\n  }\n\n  f53 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy10()\n\n  /**\n   * Index 54: Full Time Student - 1\n   */\n  FullTimeStudent1 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[0]?.qualifyingInfo?.isStudent\n\n  f54 = (): boolean | undefined => this.FullTimeStudent1()\n\n  /**\n   * Index 55: Full Time Student - 2\n   */\n  FullTimeStudent2 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[1]?.qualifyingInfo?.isStudent\n\n  f55 = (): boolean | undefined => this.FullTimeStudent2()\n\n  /**\n   * Index 56: Full Time Student - 3\n   */\n  FullTimeStudent3 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[2]?.qualifyingInfo?.isStudent\n\n  f56 = (): boolean | undefined => this.FullTimeStudent3()\n\n  /**\n   * Index 57: Full Time Student - 4\n   */\n  FullTimeStudent4 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[3]?.qualifyingInfo?.isStudent\n\n  f57 = (): boolean | undefined => this.FullTimeStudent4()\n\n  /**\n   * Index 58: Full Time Student - 5\n   */\n  FullTimeStudent5 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[4]?.qualifyingInfo?.isStudent\n\n  f58 = (): boolean | undefined => this.FullTimeStudent5()\n\n  /**\n   * Index 59: Full Time Student - 6\n   */\n  FullTimeStudent6 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[5]?.qualifyingInfo?.isStudent\n\n  f59 = (): boolean | undefined => this.FullTimeStudent6()\n\n  /**\n   * Index 60: Full Time Student - 7\n   */\n  FullTimeStudent7 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[6]?.qualifyingInfo?.isStudent\n\n  f60 = (): boolean | undefined => this.FullTimeStudent7()\n\n  /**\n   * Index 61: Full Time Student - 8\n   */\n  FullTimeStudent8 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[7]?.qualifyingInfo?.isStudent\n\n  f61 = (): boolean | undefined => this.FullTimeStudent8()\n\n  /**\n   * Index 62: Full Time Student - 9\n   */\n  FullTimeStudent9 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[8]?.qualifyingInfo?.isStudent\n\n  f62 = (): boolean | undefined => this.FullTimeStudent9()\n\n  /**\n   * Index 63: Full Time Student - 10\n   */\n  FullTimeStudent10 = (): boolean | undefined =>\n    this.info.taxPayer.dependents[9]?.qualifyingInfo?.isStudent\n\n  f63 = (): boolean | undefined => this.FullTimeStudent10()\n\n  /**\n   * Index 64: Person with disability - 1\n   * TODO: Handle disabilities\n   */\n  Personwithdisability1 = (): boolean | undefined => undefined\n\n  f64 = (): boolean | undefined => this.Personwithdisability1()\n\n  /**\n   * Index 65: Person with disability - 2\n   * TODO: Handle disabilities\n   */\n  Personwithdisability2 = (): boolean | undefined => undefined\n\n  f65 = (): boolean | undefined => this.Personwithdisability2()\n\n  /**\n   * Index 66: Person with disability - 3\n   * TODO: Handle disabilities\n   */\n  Personwithdisability3 = (): boolean | undefined => undefined\n\n  f66 = (): boolean | undefined => this.Personwithdisability3()\n\n  /**\n   * Index 67: Person with disability - 4\n   * TODO: Handle disabilities\n   */\n  Personwithdisability4 = (): boolean | undefined => undefined\n\n  f67 = (): boolean | undefined => this.Personwithdisability4()\n\n  /**\n   * Index 68: Person with disability - 5\n   * TODO: Handle disabilities\n   */\n  Personwithdisability5 = (): boolean | undefined => undefined\n\n  f68 = (): boolean | undefined => this.Personwithdisability5()\n\n  /**\n   * Index 69: Person with disability - 6\n   * TODO: Handle disabilities\n   */\n  Personwithdisability6 = (): boolean | undefined => undefined\n\n  f69 = (): boolean | undefined => this.Personwithdisability6()\n\n  /**\n   * Index 70: Person with disability - 7\n   * TODO: Handle disabilities\n   */\n  Personwithdisability7 = (): boolean | undefined => undefined\n\n  f70 = (): boolean | undefined => this.Personwithdisability7()\n\n  /**\n   * Index 71: Person with disability - 8\n   * TODO: Handle disabilities\n   */\n  Personwithdisability8 = (): boolean | undefined => undefined\n\n  f71 = (): boolean | undefined => this.Personwithdisability8()\n\n  /**\n   * Index 72: Person with disability - 9\n   * TODO: Handle disabilities\n   */\n  Personwithdisability9 = (): boolean | undefined => undefined\n\n  f72 = (): boolean | undefined => this.Personwithdisability9()\n\n  /**\n   * Index 73: Person with disability - 10\n   * TODO: Handle disabilities\n   */\n  Personwithdisability10 = (): boolean | undefined => undefined\n\n  f73 = (): boolean | undefined => this.Personwithdisability10()\n\n  /**\n   * Index 74: Number of months living with you - 1\n   */\n  Numberofmonthslivingwithyou1 = (): number | undefined =>\n    this.info.taxPayer.dependents[0]?.qualifyingInfo?.numberOfMonths\n\n  f74 = (): number | undefined => this.Numberofmonthslivingwithyou1()\n\n  /**\n   * Index 75: Number of months living with you - 2\n   */\n  Numberofmonthslivingwithyou2 = (): number | undefined =>\n    this.info.taxPayer.dependents[1]?.qualifyingInfo?.numberOfMonths\n\n  f75 = (): number | undefined => this.Numberofmonthslivingwithyou2()\n\n  /**\n   * Index 76: Number of months living with you - 3\n   */\n  Numberofmonthslivingwithyou3 = (): number | undefined =>\n    this.info.taxPayer.dependents[2]?.qualifyingInfo?.numberOfMonths\n\n  f76 = (): number | undefined => this.Numberofmonthslivingwithyou3()\n\n  /**\n   * Index 77: Number of months living with you - 4\n   */\n  Numberofmonthslivingwithyou4 = (): number | undefined =>\n    this.info.taxPayer.dependents[3]?.qualifyingInfo?.numberOfMonths\n\n  f77 = (): number | undefined => this.Numberofmonthslivingwithyou4()\n\n  /**\n   * Index 78: Number of months living with you - 5\n   */\n  Numberofmonthslivingwithyou5 = (): number | undefined =>\n    this.info.taxPayer.dependents[4]?.qualifyingInfo?.numberOfMonths\n\n  f78 = (): number | undefined => this.Numberofmonthslivingwithyou5()\n\n  /**\n   * Index 79: Number of months living with you - 6\n   */\n  Numberofmonthslivingwithyou6 = (): number | undefined =>\n    this.info.taxPayer.dependents[5]?.qualifyingInfo?.numberOfMonths\n\n  f79 = (): number | undefined => this.Numberofmonthslivingwithyou6()\n\n  /**\n   * Index 80: Number of months living with you - 7\n   */\n  Numberofmonthslivingwithyou7 = (): number | undefined =>\n    this.info.taxPayer.dependents[6]?.qualifyingInfo?.numberOfMonths\n\n  f80 = (): number | undefined => this.Numberofmonthslivingwithyou7()\n\n  /**\n   * Index 81: Number of months living with you - 8\n   */\n  Numberofmonthslivingwithyou8 = (): number | undefined =>\n    this.info.taxPayer.dependents[7]?.qualifyingInfo?.numberOfMonths\n\n  f81 = (): number | undefined => this.Numberofmonthslivingwithyou8()\n\n  /**\n   * Index 82: Number of months living with you - 9\n   */\n  Numberofmonthslivingwithyou9 = (): number | undefined =>\n    this.info.taxPayer.dependents[8]?.qualifyingInfo?.numberOfMonths\n\n  f82 = (): number | undefined => this.Numberofmonthslivingwithyou9()\n\n  /**\n   * Index 83: Number of months living with you - 10\n   */\n  Numberofmonthslivingwithyou10 = (): number | undefined =>\n    this.info.taxPayer.dependents[9]?.qualifyingInfo?.numberOfMonths\n\n  f83 = (): number | undefined => this.Numberofmonthslivingwithyou10()\n\n  /**\n   * Index 84: Eligible for Earned Income Credit - 1\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit1 = (): boolean =>\n    this.info.taxPayer.dependents.length > 0\n\n  f84 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit1()\n\n  /**\n   * Index 85: Eligible for Earned Income Credit - 2\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit2 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 1\n\n  f85 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit2()\n\n  /**\n   * Index 86: Eligible for Earned Income Credit - 3\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit3 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 2\n\n  f86 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit3()\n\n  /**\n   * Index 87: Eligible for Earned Income Credit - 4\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit4 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 3\n\n  f87 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit4()\n\n  /**\n   * Index 88: Eligible for Earned Income Credit - 5\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit5 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 4\n\n  f88 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit5()\n\n  /**\n   * Index 89: Eligible for Earned Income Credit - 6\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit6 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 5\n\n  f89 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit6()\n\n  /**\n   * Index 90: Eligible for Earned Income Credit - 7\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit7 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 6\n\n  f90 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit7()\n\n  /**\n   * Index 91: Eligible for Earned Income Credit - 8\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit8 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 7\n\n  f91 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit8()\n\n  /**\n   * Index 92: Eligible for Earned Income Credit - 9\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit9 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 8\n\n  f92 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit9()\n\n  /**\n   * Index 93: Eligible for Earned Income Credit - 10\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit10 = (): boolean | undefined =>\n    this.info.taxPayer.dependents.length > 9\n\n  f93 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit10()\n\n  /**\n   * Index 94: Mutiplied total number of dependents\n   */\n  Mutipliedtotalnumberofdependents = (): number | undefined =>\n    this.qualifyingDependents.length * parameters.eicDependentCredit\n\n  f94 = (): number | undefined => this.Mutipliedtotalnumberofdependents()\n\n  /**\n   * Index 95: Child's first name -1\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname1 = (): string | undefined => {\n    return undefined\n  }\n\n  f95 = (): string | undefined => this.Childsfirstname1()\n\n  /**\n   * Index 96: Child's first name -2\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname2 = (): string | undefined => {\n    return undefined\n  }\n\n  f96 = (): string | undefined => this.Childsfirstname2()\n\n  /**\n   * Index 97: Child's first name -3\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname3 = (): string | undefined => {\n    return undefined\n  }\n\n  f97 = (): string | undefined => this.Childsfirstname3()\n\n  /**\n   * Index 98: Child's first name - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname4 = (): string | undefined => {\n    return undefined\n  }\n\n  f98 = (): string | undefined => this.Childsfirstname4()\n\n  /**\n   * Index 99: Child's first name - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname5 = (): string | undefined => {\n    return undefined\n  }\n\n  f99 = (): string | undefined => this.Childsfirstname5()\n\n  /**\n   * Index 100: Child's first name - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname6 = (): string | undefined => {\n    return undefined\n  }\n\n  f100 = (): string | undefined => this.Childsfirstname6()\n\n  /**\n   * Index 101: Child's first name - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname7 = (): string | undefined => {\n    return undefined\n  }\n\n  f101 = (): string | undefined => this.Childsfirstname7()\n\n  /**\n   * Index 102: Child's first name - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname8 = (): string | undefined => {\n    return undefined\n  }\n\n  f102 = (): string | undefined => this.Childsfirstname8()\n\n  /**\n   * Index 103: Child's last name - 1\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname1 = (): string | undefined => {\n    return undefined\n  }\n\n  f103 = (): string | undefined => this.Childslastname1()\n\n  /**\n   * Index 104: Child's last name - 2\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname2 = (): string | undefined => {\n    return undefined\n  }\n\n  f104 = (): string | undefined => this.Childslastname2()\n\n  /**\n   * Index 105: Child's last name - 3\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname3 = (): string | undefined => {\n    return undefined\n  }\n\n  f105 = (): string | undefined => this.Childslastname3()\n\n  /**\n   * Index 106: Child's last name - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname4 = (): string | undefined => {\n    return undefined\n  }\n\n  f106 = (): string | undefined => this.Childslastname4()\n\n  /**\n   * Index 107: Child's last name - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname5 = (): string | undefined => {\n    return undefined\n  }\n\n  f107 = (): string | undefined => this.Childslastname5()\n\n  /**\n   * Index 108: Child's last name - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname6 = (): string | undefined => {\n    return undefined\n  }\n\n  f108 = (): string | undefined => this.Childslastname6()\n\n  /**\n   * Index 109: Child's last name - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname7 = (): string | undefined => {\n    return undefined\n  }\n\n  f109 = (): string | undefined => this.Childslastname7()\n\n  /**\n   * Index 110: Child's last name - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname8 = (): string | undefined => {\n    return undefined\n  }\n\n  f110 = (): string | undefined => this.Childslastname8()\n\n  /**\n   * Index 111: Social Security number - 1\n   */\n  SocialSecuritynumber1 = (): string | undefined =>\n    this.info.taxPayer.dependents[0]?.ssid\n\n  f111 = (): string | undefined => this.SocialSecuritynumber1()\n\n  /**\n   * Index 112: Child's Social Security number - 1\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber1 = (): string | undefined => {\n    return undefined\n  }\n\n  f112 = (): string | undefined => this.ChildsSocialSecuritynumber1()\n\n  /**\n   * Index 113: Child's Social Security number - 2\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber2 = (): string | undefined => {\n    return undefined\n  }\n\n  f113 = (): string | undefined => this.ChildsSocialSecuritynumber2()\n\n  /**\n   * Index 114: Child's Social Security number - 3\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber3 = (): string | undefined => {\n    return undefined\n  }\n\n  f114 = (): string | undefined => this.ChildsSocialSecuritynumber3()\n\n  /**\n   * Index 115: Child's Social Security number - 4\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber4 = (): string | undefined => {\n    return undefined\n  }\n\n  f115 = (): string | undefined => this.ChildsSocialSecuritynumber4()\n\n  /**\n   * Index 116: Child's Social Security number - 5\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber5 = (): string | undefined => {\n    return undefined\n  }\n\n  f116 = (): string | undefined => this.ChildsSocialSecuritynumber5()\n\n  /**\n   * Index 117: Child's Social Security number - 6\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber6 = (): string | undefined => {\n    return undefined\n  }\n\n  f117 = (): string | undefined => this.ChildsSocialSecuritynumber6()\n\n  /**\n   * Index 118: Child's Social Security number - 7\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber7 = (): string | undefined => {\n    return undefined\n  }\n\n  f118 = (): string | undefined => this.ChildsSocialSecuritynumber7()\n\n  /**\n   * Index 119: Child's Social Security number - 8\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber8 = (): string | undefined => {\n    return undefined\n  }\n\n  f119 = (): string | undefined => this.ChildsSocialSecuritynumber8()\n\n  /**\n   * Index 120: Child's relationship to you - 1\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou1 = (): string | undefined => {\n    return undefined\n  }\n\n  f120 = (): string | undefined => this.Childsrelationshiptoyou1()\n\n  /**\n   * Index 121: Child's relationship to you - 2\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou2 = (): string | undefined => {\n    return undefined\n  }\n\n  f121 = (): string | undefined => this.Childsrelationshiptoyou2()\n\n  /**\n   * Index 122: Child's relationship to you - 3\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou3 = (): string | undefined => {\n    return undefined\n  }\n\n  f122 = (): string | undefined => this.Childsrelationshiptoyou3()\n\n  /**\n   * Index 123: Child's relationship to you - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou4 = (): string | undefined => {\n    return undefined\n  }\n\n  f123 = (): string | undefined => this.Childsrelationshiptoyou4()\n\n  /**\n   * Index 124: Child's relationship to you - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou5 = (): string | undefined => {\n    return undefined\n  }\n\n  f124 = (): string | undefined => this.Childsrelationshiptoyou5()\n\n  /**\n   * Index 125: Child's relationship to you - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou6 = (): string | undefined => {\n    return undefined\n  }\n\n  f125 = (): string | undefined => this.Childsrelationshiptoyou6()\n\n  /**\n   * Index 126: Child's relationship to you - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou7 = (): string | undefined => {\n    return undefined\n  }\n\n  f126 = (): string | undefined => this.Childsrelationshiptoyou7()\n\n  /**\n   * Index 127: Child's relationship to you - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou8 = (): string | undefined => {\n    return undefined\n  }\n\n  f127 = (): string | undefined => this.Childsrelationshiptoyou8()\n\n  /**\n   * Index 128: Child's date of birth (mm/dd/yyyy) - 1\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy1 = (): string | undefined => {\n    return undefined\n  }\n\n  f128 = (): string | undefined => this.Childsdateofbirthmmddyyyy1()\n\n  /**\n   * Index 129: Child's date of birth (mm/dd/yyyy) - 2\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy2 = (): string | undefined => {\n    return undefined\n  }\n\n  f129 = (): string | undefined => this.Childsdateofbirthmmddyyyy2()\n\n  /**\n   * Index 130: Child's date of birth (mm/dd/yyyy) - 3\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy3 = (): string | undefined => {\n    return undefined\n  }\n\n  f130 = (): string | undefined => this.Childsdateofbirthmmddyyyy3()\n\n  /**\n   * Index 131: Child's date of birth (mm/dd/yyyy) - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy4 = (): string | undefined => {\n    return undefined\n  }\n\n  f131 = (): string | undefined => this.Childsdateofbirthmmddyyyy4()\n\n  /**\n   * Index 132: Child's date of birth (mm/dd/yyyy) - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy5 = (): string | undefined => {\n    return undefined\n  }\n\n  f132 = (): string | undefined => this.Childsdateofbirthmmddyyyy5()\n\n  /**\n   * Index 133: Child's date of birth (mm/dd/yyyy) - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy6 = (): string | undefined => {\n    return undefined\n  }\n\n  f133 = (): string | undefined => this.Childsdateofbirthmmddyyyy6()\n\n  /**\n   * Index 134: Child's date of birth (mm/dd/yyyy) - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy7 = (): string | undefined => {\n    return undefined\n  }\n\n  f134 = (): string | undefined => this.Childsdateofbirthmmddyyyy7()\n\n  /**\n   * Index 135: Child's date of birth (mm/dd/yyyy) - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy8 = (): string | undefined => {\n    return undefined\n  }\n\n  f135 = (): string | undefined => this.Childsdateofbirthmmddyyyy8()\n\n  /**\n   * Index 136: Child - Full Time Student - 1\n   */\n  ChildFullTimeStudent1 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f136 = (): boolean | undefined => this.ChildFullTimeStudent1()\n\n  /**\n   * Index 137: Child - Full Time Student - 2\n   */\n  ChildFullTimeStudent2 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f137 = (): boolean | undefined => this.ChildFullTimeStudent2()\n\n  /**\n   * Index 138: Child - Full Time Student - 3\n   */\n  ChildFullTimeStudent3 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f138 = (): boolean | undefined => this.ChildFullTimeStudent3()\n\n  /**\n   * Index 139: Child - Full Time Student - 4\n   */\n  ChildFullTimeStudent4 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f139 = (): boolean | undefined => this.ChildFullTimeStudent4()\n\n  /**\n   * Index 140: Child - Full Time Student - 5\n   */\n  ChildFullTimeStudent5 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f140 = (): boolean | undefined => this.ChildFullTimeStudent5()\n\n  /**\n   * Index 141: Child - Full Time Student - 6\n   */\n  ChildFullTimeStudent6 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f141 = (): boolean | undefined => this.ChildFullTimeStudent6()\n\n  /**\n   * Index 142: Child - Full Time Student - 7\n   */\n  ChildFullTimeStudent7 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f142 = (): boolean | undefined => this.ChildFullTimeStudent7()\n\n  /**\n   * Index 143: Child - Full Time Student - 8\n   */\n  ChildFullTimeStudent8 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f143 = (): boolean | undefined => this.ChildFullTimeStudent8()\n\n  /**\n   * Index 144: Child - Person with disability - 2\n   */\n  ChildPersonwithdisability2 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f144 = (): boolean | undefined => this.ChildPersonwithdisability2()\n\n  /**\n   * Index 145: Child - Person with disability - 1\n   */\n  ChildPersonwithdisability1 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f145 = (): boolean | undefined => this.ChildPersonwithdisability1()\n\n  /**\n   * Index 146: Child - Person with disability - 3\n   */\n  ChildPersonwithdisability3 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f146 = (): boolean | undefined => this.ChildPersonwithdisability3()\n\n  /**\n   * Index 147: Child - Person with disability - 4\n   */\n  ChildPersonwithdisability4 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f147 = (): boolean | undefined => this.ChildPersonwithdisability4()\n\n  /**\n   * Index 148: Child - Person with disability - 5\n   */\n  ChildPersonwithdisability5 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f148 = (): boolean | undefined => this.ChildPersonwithdisability5()\n\n  /**\n   * Index 149: Child - Person with disability - 6\n   */\n  ChildPersonwithdisability6 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f149 = (): boolean | undefined => this.ChildPersonwithdisability6()\n\n  /**\n   * Index 150: Child - Person with disability - 7\n   */\n  ChildPersonwithdisability7 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f150 = (): boolean | undefined => this.ChildPersonwithdisability7()\n\n  /**\n   * Index 151: Child - Person with disability - 8\n   */\n  ChildPersonwithdisability8 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f151 = (): boolean | undefined => this.ChildPersonwithdisability8()\n\n  /**\n   * Index 152: Child - Number of months living with you - 1\n   */\n  ChildNumberofmonthslivingwithyou1 = (): string | undefined => {\n    return undefined\n  }\n\n  f152 = (): string | undefined => this.ChildNumberofmonthslivingwithyou1()\n\n  /**\n   * Index 153: Child - Number of months living with you - 2\n   */\n  ChildNumberofmonthslivingwithyou2 = (): string | undefined => {\n    return undefined\n  }\n\n  f153 = (): string | undefined => this.ChildNumberofmonthslivingwithyou2()\n\n  /**\n   * Index 154: Child - Number of months living with you - 3\n   */\n  ChildNumberofmonthslivingwithyou3 = (): string | undefined => {\n    return undefined\n  }\n\n  f154 = (): string | undefined => this.ChildNumberofmonthslivingwithyou3()\n\n  /**\n   * Index 155: Child - Number of months living with you - 4\n   */\n  ChildNumberofmonthslivingwithyou4 = (): string | undefined => {\n    return undefined\n  }\n\n  f155 = (): string | undefined => this.ChildNumberofmonthslivingwithyou4()\n\n  /**\n   * Index 156: Child - Number of months living with you - 5\n   */\n  ChildNumberofmonthslivingwithyou5 = (): string | undefined => {\n    return undefined\n  }\n\n  f156 = (): string | undefined => this.ChildNumberofmonthslivingwithyou5()\n\n  /**\n   * Index 157: Child - Number of months living with you - 6\n   */\n  ChildNumberofmonthslivingwithyou6 = (): string | undefined => {\n    return undefined\n  }\n\n  f157 = (): string | undefined => this.ChildNumberofmonthslivingwithyou6()\n\n  /**\n   * Index 158: Child - Number of months living with you - 7\n   */\n  ChildNumberofmonthslivingwithyou7 = (): string | undefined => {\n    return undefined\n  }\n\n  f158 = (): string | undefined => this.ChildNumberofmonthslivingwithyou7()\n\n  /**\n   * Index 159: Child - Number of months living with you - 8\n   */\n  ChildNumberofmonthslivingwithyou8 = (): string | undefined => {\n    return undefined\n  }\n\n  f159 = (): string | undefined => this.ChildNumberofmonthslivingwithyou8()\n\n  /**\n   * Index 160: Wages - Salaries - Tips\n   */\n  WagesSalariesTips = (): number | undefined => this.f1040.l1()\n\n  f160 = (): number | undefined => this.WagesSalariesTips()\n\n  /**\n   * Index 161: Business income/loss\n   */\n  Businessincomeloss = (): number | undefined => this.f1040.schedule1.l3()\n\n  f161 = (): number | undefined => this.Businessincomeloss()\n\n  /**\n   * Index 162: Occupation requirement\n   * TODO: jurisdictional license question\n   */\n  Occupationrequirement = (): boolean | undefined => undefined\n\n  f162 = (): boolean | undefined => this.Occupationrequirement()\n\n  /**\n   * Index 163: Issuing agency - 1\n   */\n  Issuingagency1 = (): string | undefined => undefined\n\n  f163 = (): string | undefined => this.Issuingagency1()\n\n  /**\n   * Index 164: Issuing agency - 2\n   */\n  Issuingagency2 = (): string | undefined => undefined\n\n  f164 = (): string | undefined => this.Issuingagency2()\n\n  /**\n   * Index 165: Issuing agency - 3\n   */\n  Issuingagency3 = (): string | undefined => undefined\n\n  f165 = (): string | undefined => this.Issuingagency3()\n\n  /**\n   * Index 166: Issuing agency - 5\n   */\n  Issuingagency5 = (): string | undefined => undefined\n\n  f166 = (): string | undefined => this.Issuingagency5()\n\n  /**\n   * Index 167: Issuing agency - 4\n   */\n  Issuingagency4 = (): string | undefined => undefined\n\n  f167 = (): string | undefined => this.Issuingagency4()\n\n  /**\n   * Index 168: License/Registration/Certification - 1\n   */\n  LicenseRegistrationCertification1 = (): string | undefined => undefined\n\n  f168 = (): string | undefined => this.LicenseRegistrationCertification1()\n\n  /**\n   * Index 169: License/Registration/Certification - 2\n   */\n  LicenseRegistrationCertification2 = (): string | undefined => undefined\n\n  f169 = (): string | undefined => this.LicenseRegistrationCertification2()\n\n  /**\n   * Index 170: License/Registration/Certification - 3\n   */\n  LicenseRegistrationCertification3 = (): string | undefined => undefined\n\n  f170 = (): string | undefined => this.LicenseRegistrationCertification3()\n\n  /**\n   * Index 171: License/Registration/Certification - 4\n   */\n  LicenseRegistrationCertification4 = (): string | undefined => undefined\n\n  f171 = (): string | undefined => this.LicenseRegistrationCertification4()\n\n  /**\n   * Index 172: License/Registration/Certification - 5\n   */\n  LicenseRegistrationCertification5 = (): string | undefined => undefined\n\n  f172 = (): string | undefined => this.LicenseRegistrationCertification5()\n\n  /**\n   * Index 173: Filing - married filing jointly\n   * TODO: Handle MFJ federal / MFS state issue.\n   */\n  Filingmarriedfilingjointly = (): string | undefined => {\n    return undefined\n  }\n\n  f173 = (): string | undefined => this.Filingmarriedfilingjointly()\n\n  /**\n   * Index 174: Spouse' s SSN3-2\n   * TODO - only applicable for MFS state and MFJ federal return\n   */\n  SpousesSSN32 = (): string | undefined => undefined\n\n  f174 = (): string | undefined => this.SpousesSSN32()\n\n  /**\n   * Index 175: Spouse's SSN2-2\n   */\n  SpousesSSN22 = (): string | undefined => undefined\n\n  f175 = (): string | undefined => this.SpousesSSN22()\n\n  /**\n   * Index 176: Spouse's SSN4-2\n   */\n  SpousesSSN42 = (): string | undefined => undefined\n\n  f176 = (): string | undefined => this.SpousesSSN42()\n\n  /**\n   * Index 177: Statutory employee box marked\n   */\n  Statutoryemployeeboxmarked = (): boolean | undefined => {\n    return undefined\n  }\n\n  f177 = (): boolean | undefined => this.Statutoryemployeeboxmarked()\n\n  /**\n   * Index 178: Federal Earned Income Credit amount\n   */\n  FederalEarnedIncomeCreditamount = (): number | undefined => this.f1040.l27()\n\n  f178 = (): number | undefined => this.FederalEarnedIncomeCreditamount()\n\n  /**\n   * Index 179: Multiply L5\n   */\n  MultiplyL5 = (): number =>\n    (this.FederalEarnedIncomeCreditamount() ?? 0) *\n    parameters.earnedIncomeCreditFactor\n\n  f179 = (): number => Math.round(this.MultiplyL5())\n\n  /**\n   * Index 180: Residents / Non-Residents rate - 1\n   * TODO: Handle non-residents rate\n   */\n  ResidentsNonResidentsrate1 = (): number => 1\n\n  f180 = (): number => this.ResidentsNonResidentsrate1()\n\n  /**\n   * Index 181: Residents / Non-Residents rate - 2\n   * TODO: Handle non-residents rate and Schedule NR\n   */\n  ResidentsNonResidentsrate2 = (): number => 0\n\n  f181 = (): number => this.ResidentsNonResidentsrate2()\n\n  /**\n   * Index 182: Multiply L6 - L7\n   */\n  MultiplyL6L7 = (): number | undefined =>\n    this.MultiplyL5() *\n    (this.ResidentsNonResidentsrate1() +\n      this.ResidentsNonResidentsrate2() / 100)\n\n  earnedIncomeCredit = (): number | undefined => this.MultiplyL6L7()\n\n  f182 = (): number => Math.round(this.MultiplyL6L7() ?? 0)\n\n  /**\n   * Index 183: Your SSN3\n   */\n  YourSSN3 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f183 = (): string | undefined => this.YourSSN3()\n\n  /**\n   * Index 184: Your SSN2\n   */\n  YourSSN2 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f184 = (): string | undefined => this.YourSSN2()\n\n  /**\n   * Index 185: Your SSN4\n   */\n  YourSSN4 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f185 = (): string | undefined => this.YourSSN4()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.f85(),\n    this.f86(),\n    this.f87(),\n    this.f88(),\n    this.f89(),\n    this.f90(),\n    this.f91(),\n    this.f92(),\n    this.f93(),\n    this.f94(),\n    this.f95(),\n    this.f96(),\n    this.f97(),\n    this.f98(),\n    this.f99(),\n    this.f100(),\n    this.f101(),\n    this.f102(),\n    this.f103(),\n    this.f104(),\n    this.f105(),\n    this.f106(),\n    this.f107(),\n    this.f108(),\n    this.f109(),\n    this.f110(),\n    this.f111(),\n    this.f112(),\n    this.f113(),\n    this.f114(),\n    this.f115(),\n    this.f116(),\n    this.f117(),\n    this.f118(),\n    this.f119(),\n    this.f120(),\n    this.f121(),\n    this.f122(),\n    this.f123(),\n    this.f124(),\n    this.f125(),\n    this.f126(),\n    this.f127(),\n    this.f128(),\n    this.f129(),\n    this.f130(),\n    this.f131(),\n    this.f132(),\n    this.f133(),\n    this.f134(),\n    this.f135(),\n    this.f136(),\n    this.f137(),\n    this.f138(),\n    this.f139(),\n    this.f140(),\n    this.f141(),\n    this.f142(),\n    this.f143(),\n    this.f144(),\n    this.f145(),\n    this.f146(),\n    this.f147(),\n    this.f148(),\n    this.f149(),\n    this.f150(),\n    this.f151(),\n    this.f152(),\n    this.f153(),\n    this.f154(),\n    this.f155(),\n    this.f156(),\n    this.f157(),\n    this.f158(),\n    this.f159(),\n    this.f160(),\n    this.f161(),\n    this.f162(),\n    this.f163(),\n    this.f164(),\n    this.f165(),\n    this.f166(),\n    this.f167(),\n    this.f168(),\n    this.f169(),\n    this.f170(),\n    this.f171(),\n    this.f172(),\n    this.f173(),\n    this.f174(),\n    this.f175(),\n    this.f176(),\n    this.f177(),\n    this.f178(),\n    this.f179(),\n    this.f180(),\n    this.f181(),\n    this.f182(),\n    this.f183(),\n    this.f184(),\n    this.f185()\n  ]\n}\n\nconst makeil1040scheduleileeic = (\n  info: ValidatedInformation,\n  f1040: F1040\n): IL1040scheduleileeic => new IL1040scheduleileeic(info, f1040)\n\nexport default makeil1040scheduleileeic\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IL/IL1040V.ts",
    "content": "import Form from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { IL1040 } from './IL1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport default class IL1040V extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  il1040: IL1040\n  formOrder = -1\n  attachments: () => Form[] = () => []\n\n  constructor(info: ValidatedInformation, f1040: F1040, il1040: IL1040) {\n    super()\n    this.info = info\n    this.f1040 = f1040\n    this.formName = 'IL-1040-V'\n    this.state = 'IL'\n    this.il1040 = il1040\n  }\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: PrimarySSN1\n   */\n  PrimarySSN1 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f1 = (): string | undefined => this.PrimarySSN1()\n\n  /**\n   * Index 2: PrimarySSN2\n   */\n  PrimarySSN2 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f2 = (): string | undefined => this.PrimarySSN2()\n\n  /**\n   * Index 3: PrimarySSN3\n   */\n  PrimarySSN3 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f3 = (): string | undefined => this.PrimarySSN3()\n\n  /**\n   * Index 4: SpouseSSN1\n   */\n  SpouseSSN1 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(0, 3)\n\n  f4 = (): string | undefined => this.SpouseSSN1()\n\n  /**\n   * Index 5: SpouseSSN2\n   */\n  SpouseSSN2 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(3, 5)\n\n  f5 = (): string | undefined => this.SpouseSSN2()\n\n  /**\n   * Index 6: SpouseSSN3\n   */\n  SpouseSSN3 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(5)\n\n  f6 = (): string | undefined => this.SpouseSSN3()\n\n  /**\n   * Index 7: FirstName\n   */\n  FirstName = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.firstName\n\n  f7 = (): string | undefined => this.FirstName()\n\n  /**\n   * Index 8: SpouseFirstName\n   */\n  SpouseFirstName = (): string | undefined =>\n    this.info.taxPayer.spouse?.firstName\n\n  f8 = (): string | undefined => this.SpouseFirstName()\n\n  /**\n   * Index 9: LastName\n   */\n  LastName = (): string | undefined => this.info.taxPayer.primaryPerson.lastName\n\n  f9 = (): string | undefined => this.LastName()\n\n  /**\n   * Index 10: Address\n   */\n  Address = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.address\n\n  f10 = (): string | undefined => this.Address()\n\n  /**\n   * Index 11: City\n   */\n  City = (): string | undefined => this.info.taxPayer.primaryPerson.address.city\n\n  f11 = (): string | undefined => this.City()\n\n  /**\n   * Index 12: State\n   */\n  State = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.state\n\n  f12 = (): string | undefined => this.State()\n\n  /**\n   * Index 13: ZIP\n   */\n  ZIP = (): string | undefined => this.info.taxPayer.primaryPerson.address.zip\n\n  f13 = (): string | undefined => this.ZIP()\n\n  /**\n   * Index 14: PaymentAmount\n   */\n  PaymentAmount = (): number | undefined => {\n    const amount = this.il1040.payment()\n    if (amount !== undefined) {\n      return Math.trunc(amount)\n    }\n  }\n\n  f14 = (): number | undefined => this.PaymentAmount()\n\n  /**\n   * Index 15: PaymentAmountCents\n   */\n  PaymentAmountCents = (): number | undefined => {\n    const amount = this.il1040.payment()\n    if (amount !== undefined) {\n      return Math.round((amount - Math.trunc(amount)) * 100)\n    }\n  }\n\n  f15 = (): number | undefined => this.PaymentAmountCents()\n\n  /**\n   * Index 16: Reset\n   */\n  Reset = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.Reset()\n\n  /**\n   * Index 17: Print\n   */\n  Print = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.Print()\n\n  /**\n   * Index 18: scanline\n   */\n  scanline = (): string | undefined => {\n    return undefined\n  }\n\n  f18 = (): string | undefined => this.scanline()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IL/ILWit.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { IncomeW2, PersonRole, PrimaryPerson, State } from 'ustaxes/core/data'\nimport _ from 'lodash'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\ntype FormType =\n  | 'W' // W-2\n  | 'WG' // W2-G\n  | 'R' // 1099-R\n  | 'G' // 1099-G\n  | 'M' // 1099-MISC\n  | 'O' // 1099-OID\n  | 'D' // 1099-DIV\n  | 'I' // 1099-INT\n  | 'S' // 1042-S\n  | 'B' // 1099-B\n  | 'K' // 1099-K\n  | 'N' // 1099-NEC\n\ninterface WithholdingForm {\n  formType: FormType\n  role: PersonRole\n  ein: string\n  federalWages: number\n  ilWages: number\n  ilTax: number\n}\n\nconst toWithholdingForm = (w2: IncomeW2): WithholdingForm | undefined => {\n  if (\n    w2.stateWages !== undefined &&\n    w2.stateWithholding !== undefined &&\n    w2.employer?.EIN !== undefined\n  ) {\n    return {\n      formType: 'W',\n      ein: w2.employer.EIN,\n      federalWages: w2.income,\n      ilWages: w2.stateWages,\n      ilTax: w2.stateWithholding,\n      role: w2.personRole\n    }\n  }\n}\n\n/**\n * Each ILWIT form supports 5 withholding forms for\n * primary taxpayer and 5 for spouse\n * TODO: support more than 5 for each\n */\nexport class ILWIT extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName = 'IL-WIT'\n  state: State = 'IL'\n  formOrder = 31\n  methods: FormMethods\n  formIndex: number\n\n  static WITHHOLDING_FORMS_PER_PAGE = 5\n\n  constructor(f1040: F1040, subFormIndex = 0) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.methods = new FormMethods(this)\n    this.formIndex = subFormIndex\n  }\n\n  get primary(): PrimaryPerson | undefined {\n    return this.info.taxPayer.primaryPerson\n  }\n\n  attachments = (): Form[] => {\n    // If this is the head form, see if we need\n    // more copies. For example if the SSIDs have 4 and 11 forms,\n    // we will need 2 extra copies. this one will have 4 + 5,\n    // next will have 0 + 5, last will have 0 + 1\n    if (this.formIndex === 0) {\n      const copiesNeeded =\n        Math.ceil(\n          Math.max(\n            ...[PersonRole.PRIMARY, PersonRole.SPOUSE].map(\n              (r) =>\n                this.methods\n                  .stateW2s()\n                  .filter((w2) => (w2.stateWithholding ?? 0) > 0)\n                  .filter((w2) => w2.personRole === r).length\n            )\n          ) / ILWIT.WITHHOLDING_FORMS_PER_PAGE\n        ) - 1\n\n      return Array(copiesNeeded)\n        .fill(undefined)\n        .map((x, i) => new ILWIT(this.f1040, i + 1))\n    }\n\n    return []\n  }\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: Reset\n   */\n  Reset = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.Reset()\n\n  /**\n   * Index 2: Print\n   */\n  Print = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.Print()\n\n  /**\n   * Index 3: Your name\n   */\n  Yourname = (): string | undefined =>\n    [this.primary?.firstName, this.primary?.lastName].flat().join(' ')\n\n  f3 = (): string | undefined => this.Yourname()\n\n  /**\n   * Index 4: Your SSN-3\n   */\n  YourSSN3 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f4 = (): string | undefined => this.YourSSN3()\n\n  /**\n   * Index 5: Your SSN-2\n   */\n  YourSSN2 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f5 = (): string | undefined => this.YourSSN2()\n\n  /**\n   * Index 6: Your SSN-4\n   */\n  YourSSN4 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f6 = (): string | undefined => this.YourSSN4()\n\n  allWithholdingForms = (): WithholdingForm[] =>\n    this.methods\n      .stateW2s()\n      .map((w2) => toWithholdingForm(w2))\n      .filter((x) => x !== undefined) as WithholdingForm[]\n\n  formsByRole = (role: PersonRole): WithholdingForm[] =>\n    this.allWithholdingForms().filter((w2) => w2.role === role)\n\n  primaryForms = (): WithholdingForm[] =>\n    _.chain(this.formsByRole(PersonRole.PRIMARY))\n      .drop(this.formIndex * 5)\n      .take(5)\n      .value()\n\n  spouseForms = (): WithholdingForm[] =>\n    _.chain(this.formsByRole(PersonRole.SPOUSE))\n      .drop(this.formIndex * 5)\n      .take(5)\n      .value()\n\n  /**\n   * 4 x 5 grid for primary taxpayer, columnwise\n   * Note the form type column is indexed after all this.\n   */\n  formGrid = (forms: WithholdingForm[]): (string | number | undefined)[] =>\n    [\n      forms.map((form) => form.ein),\n      forms.map((form) => form.federalWages),\n      forms.map((form) => form.ilWages),\n      forms.map((form) => form.ilTax)\n    ].flatMap((column) => [\n      ...column,\n      ...Array<undefined>(5 - column.length).fill(undefined)\n    ])\n\n  /**\n   * Primary ssid withholding, Column B -> Column E\n   */\n  f7Tof26 = (): (string | number | undefined)[] =>\n    this.formGrid(this.primaryForms())\n\n  /**\n   * Index 27: Spouse's name\n   */\n  Spousesname = (): string | undefined => {\n    const spouse = this.info.taxPayer.spouse\n    if (spouse !== undefined) {\n      return `${spouse.firstName} ${spouse.lastName}`\n    }\n  }\n\n  f27 = (): string | undefined => this.Spousesname()\n\n  /**\n   * Index 28: Spouse's SSN-3\n   */\n  SpousesSSN3 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(0, 3)\n\n  f28 = (): string | undefined => this.SpousesSSN3()\n\n  /**\n   * Index 29: Spouse's SSN-2\n   */\n  SpousesSSN2 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(3, 5)\n\n  f29 = (): string | undefined => this.SpousesSSN2()\n\n  /**\n   * Index 30: Spouse's SSN-4\n   */\n  SpousesSSN4 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(5)\n\n  f30 = (): string | undefined => this.SpousesSSN4()\n\n  /**\n   * Spouse ssid forms, Column B -> Column E\n   */\n  f31tof50 = (): (string | number | undefined)[] =>\n    this.formGrid(this.spouseForms())\n\n  /**\n   * Index 51: Total amount\n   */\n  Totalamount = (): number | undefined => {\n    if (this.formIndex === 0) {\n      return this.allWithholdingForms().reduce((s, f) => s + f.ilTax, 0)\n    }\n  }\n\n  f51 = (): number | undefined => this.Totalamount()\n\n  /**\n   * Index 52 -> 56\n   * Spouse form types\n   */\n\n  formTypesColumn = (forms: WithholdingForm[]): (string | undefined)[] => [\n    ...forms.map((f) => f.formType),\n    ...Array<undefined>(5 - forms.length).fill(undefined)\n  ]\n\n  f52to56 = (): (string | undefined)[] =>\n    this.formTypesColumn(this.spouseForms())\n\n  /**\n   * Index 57 -> 61\n   * Primary form types\n   */\n  f57to61 = (): (string | undefined)[] =>\n    this.formTypesColumn(this.primaryForms())\n\n  /**\n   * There's a second field in the Column A column,\n   * purpose not clear.\n   */\n  f62to71 = (): undefined[] => Array<undefined>(10).fill(undefined)\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    ...this.f7Tof26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    ...this.f31tof50(),\n    this.f51(),\n    ...this.f52to56(),\n    ...this.f57to61(),\n    ...this.f62to71()\n  ]\n}\n\nconst makeILWIT = (f1040: F1040): ILWIT => new ILWIT(f1040)\n\nexport default makeILWIT\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IL/Parameters.ts",
    "content": "import { FilingStatus } from 'ustaxes/core/data'\n\nconst parameters = {\n  exemptions: {\n    [FilingStatus.S]: {\n      incomeLowerLimit: 2325,\n      incomeUpperLimit: 250000,\n      exemptionAmount: 2325\n    },\n    [FilingStatus.MFJ]: {\n      incomeLowerLimit: 4650,\n      incomeUpperLimit: 500000,\n      exemptionAmount: 4650\n    }\n  },\n  taxRate: 0.0495,\n  seniorExemption: 1000,\n  blindExemption: 1000,\n  earnedIncomeCreditFactor: 0.18,\n  eicDependentCredit: 2325\n}\n\nexport default parameters\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/IN/Form.ts",
    "content": "export default class INForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/KS/Form.ts",
    "content": "export default class KSForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/KY/Form.ts",
    "content": "export default class KYForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/LA/Form.ts",
    "content": "export default class LAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MA/Form.ts",
    "content": "export default class MAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MD/Form.ts",
    "content": "export default class MDForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/ME/Form.ts",
    "content": "export default class MEForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MI/Form.ts",
    "content": "export default class MIForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MN/Form.ts",
    "content": "export default class MNForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MO/Form.ts",
    "content": "export default class MOForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MS/Form.ts",
    "content": "export default class MSForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/MT/Form.ts",
    "content": "export default class MTForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NC/Form.ts",
    "content": "export default class NCForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/ND/Form.ts",
    "content": "export default class NDForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NE/Form.ts",
    "content": "export default class NEForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NH/Form.ts",
    "content": "export default class NHForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NJ/Form.ts",
    "content": "export default class NJForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NM/Form.ts",
    "content": "export default class NMForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NV/Form.ts",
    "content": "export default class NVForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/NY/Form.ts",
    "content": "export default class NYForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/OH/Form.ts",
    "content": "export default class OHForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/OK/Form.ts",
    "content": "export default class OKForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/OR/Form.ts",
    "content": "export default class ORForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/PA/Form.ts",
    "content": "export default class PAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/RI/Form.ts",
    "content": "export default class RIForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/SC/Form.ts",
    "content": "export default class SCForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/SD/Form.ts",
    "content": "export default class SDForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/TN/Form.ts",
    "content": "export default class TNForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/TX/Form.ts",
    "content": "export default class TXForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/UT/Form.ts",
    "content": "export default class UTForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/VA/Form.ts",
    "content": "export default class VAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/VT/Form.ts",
    "content": "export default class VTForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/WA/Form.ts",
    "content": "export default class WAForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/WI/Form.ts",
    "content": "export default class WIForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/WV/Form.ts",
    "content": "export default class WVForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/WY/Form.ts",
    "content": "export default class WYForm {}\n"
  },
  {
    "path": "src/forms/Y2020/stateForms/index.ts",
    "content": "import F1040 from '../irsForms/F1040'\nimport { State } from 'ustaxes/core/data'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport il1040 from './IL/IL1040'\nimport { Either } from 'ustaxes/core/util'\nimport { createStateReturn as createStateReturnF } from '../../StateForms'\nimport { StateFormError } from '../../StateForms'\n\nexport const noFilingRequirementStates: State[] = [\n  'AK',\n  'TN',\n  'WY',\n  'FL',\n  'NH',\n  'SD',\n  'TX',\n  'WA',\n  'NV'\n]\n\nexport const stateForms: {\n  [K in State]?: (f1040: F1040) => StateForm\n} = {\n  IL: il1040\n}\n\nexport const createStateReturn = (\n  f1040: F1040\n): Either<StateFormError[], StateForm[]> =>\n  createStateReturnF<F1040>(noFilingRequirementStates, stateForms)(f1040)\n"
  },
  {
    "path": "src/forms/Y2020/tests/ScheduleD.test.ts",
    "content": "import * as fc from 'fast-check'\nimport { testKit, commonTests } from '.'\n\ndescribe('ScheduleD', () => {\n  it('should never pass through more than allowed losses', async () => {\n    await fc.assert(\n      testKit.with1040Property(async (forms): Promise<void> => {\n        const f1040 = commonTests.findF1040OrFail(forms)\n        if (f1040.scheduleD.isNeeded()) {\n          expect(Math.round(f1040.l7() ?? 0)).toBeGreaterThanOrEqual(\n            -f1040.scheduleD.l21Min()\n          )\n        }\n        return Promise.resolve()\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2020/tests/ScheduleEIC.test.ts",
    "content": "/* eslint @typescript-eslint/no-empty-function: \"off\" */\n\nimport * as federal from '../data/federal'\nimport { testKit, commonTests } from '.'\n\nbeforeAll(() => jest.spyOn(console, 'warn').mockImplementation(() => {}))\n\ndescribe('ScheduleEIC', () => {\n  it('should disallow EIC for income below threshold', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      const formula = federal.EIC.formulas[f1040.info.taxPayer.filingStatus]\n      if (formula !== undefined && f1040.wages() < formula[0][1].lowerBound) {\n        expect(f1040.scheduleEIC.allowed()).toBe(false)\n        expect(f1040.scheduleEIC.credit()).toBe(0)\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2020/tests/f1040.test.ts",
    "content": "import { displayRound } from 'ustaxes/core/irsForms/util'\nimport { commonTests, testKit } from '.'\n\njest.setTimeout(40000)\n\nbeforeAll(() => {\n  jest.spyOn(console, 'warn').mockImplementation((x: string) => {\n    if (!x.includes('Removing XFA form data as pdf-lib')) {\n      console.warn(x)\n    }\n  })\n})\n\ndescribe('f1040', () => {\n  commonTests.run()\n  it('should never have higher AGI than total income', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040(forms)\n      expect(f1040).not.toBeUndefined()\n      if (f1040 !== undefined) {\n        expect(displayRound(f1040.l11()) ?? 0).toBeLessThanOrEqual(\n          // It is possible for losses to create negative income.\n          displayRound(Math.max(0, f1040.l9())) ?? 0\n        )\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should never produce higher tax than total income', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040(forms)\n      expect(f1040).not.toBeUndefined()\n      if (f1040 !== undefined) {\n        expect(displayRound(f1040.l24()) ?? 0).toBeLessThanOrEqual(\n          displayRound(Math.max(0, f1040.l9())) ?? 0\n        )\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should never produce tax on taxable income higher than income', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040(forms)\n      expect(f1040).not.toBeUndefined()\n      if (f1040 !== undefined) {\n        // tax on taxable income should be less than taxable income\n        if (f1040.l15() > 0) {\n          expect(f1040.l16() ?? 0).toBeLessThan(f1040.l15())\n        } else {\n          expect(f1040.l16() ?? 0).toEqual(0)\n        }\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2020/tests/f8889.test.ts",
    "content": "/* eslint @typescript-eslint/no-empty-function: \"off\" */\n\nimport { FilingStatus, Income1099Type, PersonRole } from 'ustaxes/core/data'\nimport { CURRENT_YEAR, healthSavingsAccounts } from '../data/federal'\nimport F8889 from '../irsForms/F8889'\nimport { cloneDeep } from 'lodash'\nimport F1040 from '../irsForms/F1040'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\nimport { yearFormBuilder } from 'ustaxes/forms/YearForms'\nimport { run } from 'ustaxes/core/util'\nimport { commonTests } from '.'\n\nconst baseInformation: ValidatedInformation = {\n  ...blankState,\n  f1099s: [\n    {\n      payer: 'payer-name',\n      type: Income1099Type.INT,\n      form: { income: 1111111 },\n      personRole: PersonRole.PRIMARY\n    }\n  ],\n  w2s: [\n    {\n      employer: { EIN: '111111111', employerName: 'w2s employer name' },\n      personRole: PersonRole.SPOUSE,\n      occupation: 'w2s-occupation',\n      state: 'AL',\n      income: 111,\n      medicareIncome: 222,\n      fedWithholding: 333,\n      ssWages: 111,\n      ssWithholding: 444,\n      medicareWithholding: 555,\n      stateWages: 666,\n      stateWithholding: 777\n    }\n  ],\n  estimatedTaxes: [],\n  realEstate: [],\n  taxPayer: {\n    primaryPerson: {\n      address: {\n        address: '0001',\n        aptNo: '',\n        city: 'AR city',\n        state: 'AR',\n        zip: '1234567'\n      },\n      firstName: 'payer-first-name',\n      lastName: 'payer-last-name',\n      isTaxpayerDependent: false,\n      role: PersonRole.PRIMARY,\n      ssid: '111111111'\n    },\n    spouse: {\n      firstName: 'spouse-first-name',\n      isTaxpayerDependent: false,\n      lastName: 'spouse-last-name',\n      role: PersonRole.SPOUSE,\n      ssid: '222222222'\n    },\n    dependents: [],\n    filingStatus: FilingStatus.MFS\n  },\n  questions: {},\n  f1098es: [],\n  stateResidencies: [{ state: 'AL' }],\n  healthSavingsAccounts: []\n}\n\ndescribe('Health Savings Accounts', () => {\n  it('should not need form 8889 if there are no health savings accounts', () => {\n    const builder = yearFormBuilder('Y2020').build(baseInformation, [])\n    const fs = run(builder.f1040()).orThrow()\n    expect(commonTests.findF1040OrFail(fs).f8889.isNeeded()).toEqual(false)\n  })\n\n  it('should have a max contribution limit when covered for all months', () => {\n    const information = cloneDeep(baseInformation)\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'self-only',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(),\n        endDate: new Date(CURRENT_YEAR, 11, 31).toISOString(),\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.fullYearHsa()).toEqual(true)\n    expect(f8889.lastMonthCoverage()).toEqual('self-only')\n    expect(f8889.contributionLimit()).toEqual(\n      healthSavingsAccounts.contributionLimit['self-only']\n    )\n    expect(f8889.calculatedCoverageType).toEqual('self-only')\n  })\n\n  it('should select family coverage when both are options', () => {\n    const information = cloneDeep(baseInformation)\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'self-only',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(),\n        endDate: new Date(CURRENT_YEAR, 11, 31).toISOString(),\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      },\n      {\n        coverageType: 'family',\n        contributions: 7100,\n        personRole: PersonRole.SPOUSE,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(),\n        endDate: new Date(CURRENT_YEAR, 11, 31).toISOString(),\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.fullYearHsa()).toEqual(true)\n    expect(f8889.lastMonthCoverage()).toEqual('family')\n    expect(f8889.contributionLimit()).toEqual(\n      healthSavingsAccounts.contributionLimit['family']\n    )\n    expect(f8889.calculatedCoverageType).toEqual('family')\n  })\n\n  it('should calculate a partial contribution limit correctly with a single HSA', () => {\n    const information = cloneDeep(baseInformation)\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'family',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(), // Jan 1st\n        endDate: new Date(CURRENT_YEAR, 5, 30).toISOString(), // Jun 30th\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.fullYearHsa()).toEqual(false)\n    expect(f8889.contributionLimit()).toEqual(\n      Math.round((healthSavingsAccounts.contributionLimit['family'] * 6) / 12)\n    )\n    expect(f8889.calculatedCoverageType).toEqual('family')\n  })\n\n  it('should calculate a partial contribution limit correctly with a multiple HSA', () => {\n    const information = cloneDeep(baseInformation)\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'family',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(), // Jan 1st\n        endDate: new Date(CURRENT_YEAR, 5, 30).toISOString(), // Jun 30th\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      },\n      {\n        coverageType: 'self-only',\n        contributions: 1750,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 6, 1).toISOString(), // Jul 1st\n        endDate: new Date(CURRENT_YEAR, 10, 30).toISOString(), // Nov 30st\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.fullYearHsa()).toEqual(false)\n    expect(f8889.contributionLimit()).toEqual(\n      Math.round(\n        (healthSavingsAccounts.contributionLimit['family'] * 6) / 12 +\n          (healthSavingsAccounts.contributionLimit['self-only'] * 5) / 12\n      )\n    )\n    expect(f8889.calculatedCoverageType).toEqual('family')\n  })\n\n  it('should calculate a partial contribution limit correctly with a multiple overlapping HSA', () => {\n    const information = cloneDeep(baseInformation)\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'family',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(), // Jan 1st\n        endDate: new Date(CURRENT_YEAR, 5, 30).toISOString(), // Jun 30th\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      },\n      {\n        coverageType: 'self-only',\n        contributions: 1750,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 3, 1).toISOString(), // Apr 1st\n        endDate: new Date(CURRENT_YEAR, 10, 30).toISOString(), // Nov 30st\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.fullYearHsa()).toEqual(false)\n    expect(f8889.contributionLimit()).toEqual(\n      Math.round(\n        (healthSavingsAccounts.contributionLimit['family'] * 6) / 12 +\n          (healthSavingsAccounts.contributionLimit['self-only'] * 5) / 12\n      )\n    )\n    expect(f8889.calculatedCoverageType).toEqual('family')\n  })\n\n  it('should split the family contribution correctly', () => {\n    const information = cloneDeep(baseInformation)\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'family',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(), // Jan 1st\n        endDate: new Date(CURRENT_YEAR, 4, 31).toISOString(), // May 31st\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      },\n      {\n        coverageType: 'self-only',\n        contributions: 1750,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 5, 1).toISOString(), // Jun 1st\n        endDate: new Date(CURRENT_YEAR, 11, 31).toISOString(), // Dec 31st\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.splitFamilyContributionLimit()).toEqual(3550)\n    expect(f8889.calculatedCoverageType).toEqual('self-only')\n  })\n\n  it('Should apply employer contributions to only the form belonging to the right person', () => {\n    const information = cloneDeep(baseInformation)\n    information.w2s[0].box12 = { W: 4000 } // The w2 belongs to the spouse\n    information.healthSavingsAccounts = [\n      {\n        coverageType: 'self-only',\n        contributions: 3550,\n        personRole: PersonRole.PRIMARY,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(),\n        endDate: new Date(CURRENT_YEAR, 11, 31).toISOString(),\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      },\n      {\n        coverageType: 'self-only',\n        contributions: 3550,\n        personRole: PersonRole.SPOUSE,\n        startDate: new Date(CURRENT_YEAR, 0, 1).toISOString(),\n        endDate: new Date(CURRENT_YEAR, 11, 31).toISOString(),\n        label: 'test',\n        totalDistributions: 500,\n        qualifiedDistributions: 500\n      }\n    ]\n    const f1040 = new F1040(information)\n\n    const f8889 = new F8889(f1040, information.taxPayer.primaryPerson)\n    expect(f8889.l9()).toEqual(0)\n\n    if (information.taxPayer.spouse !== undefined) {\n      const f8889spouse = new F8889(f1040, information.taxPayer.spouse)\n      expect(f8889spouse.l9()).toEqual(4000)\n    }\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2020/tests/f8949.test.ts",
    "content": "import { testKit } from '.'\n\ndescribe('f8949', () => {\n  it('should attach 8949 if there are sales this year', async () => {\n    await testKit.with1040Assert((forms, info, assets): Promise<void> => {\n      if (\n        assets.filter((p) => p.closeDate?.getFullYear() === 2020).length > 0\n      ) {\n        expect(forms.filter((s) => s.tag === 'f8949').length).toBeGreaterThan(0)\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2020/tests/fica.test.ts",
    "content": "import { fica } from '../data/federal'\nimport F1040 from '../irsForms/F1040'\nimport F8959 from '../irsForms/F8959'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { displayRound } from 'ustaxes/core/irsForms/util'\nimport Schedule2 from '../irsForms/Schedule2'\nimport Schedule3 from '../irsForms/Schedule3'\nimport { claimableExcessSSTaxWithholding } from 'ustaxes/forms/Y2020/irsForms/Schedule3'\nimport { testKit, commonTests } from '.'\nimport { PersonRole } from 'ustaxes/core/data'\n\nbeforeAll(() => {\n  jest.spyOn(console, 'warn').mockImplementation(() => {\n    // do nothing\n  })\n})\n\njest.setTimeout(10000)\n\nconst hasSSRefund = (f1040: F1040): boolean => f1040.schedule3.l10() > 0\n\nconst hasAdditionalMedicareTax = (f1040: F1040): boolean =>\n  f1040.f8959.l18() > 0\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype Constructor<T> = new (...args: any[]) => T\nfunction hasAttachment<FormType>(\n  attachments: Form[],\n  formType: Constructor<FormType>\n): boolean {\n  return (\n    attachments.find((f) => {\n      return f instanceof formType\n    }) !== undefined\n  )\n}\n\ndescribe('fica', () => {\n  it('should give refund SS tax overpayment only in some conditions', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      if (f1040.validW2s().length <= 1) {\n        // Should never give SS refund with 1 or fewer W2s\n        expect(hasSSRefund(f1040)).toEqual(false)\n      } else {\n        const ssWithheld = f1040\n          .validW2s()\n          .reduce((sum, w2) => sum + w2.ssWithholding, 0)\n        if (\n          f1040.wages() <= fica.maxIncomeSSTaxApplies ||\n          f1040.validW2s().some((w2) => w2.ssWithholding > fica.maxSSTax) ||\n          ssWithheld < fica.maxSSTax\n        ) {\n          // Should never give SS refund if W2 income below max threshold, some W2 has\n          // withheld over the max, or there is no SS withholding to refund.\n          expect(hasSSRefund(f1040)).toEqual(false)\n        } else {\n          // Otherwise, should always give SS refund, and attach schedule 3\n          expect(hasSSRefund(f1040)).toEqual(true)\n          expect(hasAttachment(forms, Schedule3)).toEqual(true)\n        }\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should give SS refund based on filing status', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      if (hasSSRefund(f1040)) {\n        const s3l10 = f1040.schedule3.l10()\n        expect(displayRound(s3l10)).not.toBeUndefined()\n        expect(s3l10).toBeGreaterThan(0)\n\n        const ssWithheld = f1040\n          .validW2s()\n          .reduce((sum, w2) => sum + w2.ssWithholding, 0)\n        expect(s3l10).toEqual(ssWithheld - fica.maxSSTax)\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should not give a refund if each person has less than the max', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      f1040.info.w2s = [\n        {\n          employer: { EIN: '111111111', employerName: 'w2s employer name' },\n          personRole: PersonRole.SPOUSE,\n          occupation: 'w2s-occupation',\n          state: 'AL',\n          income: 111,\n          medicareIncome: 222,\n          fedWithholding: 333,\n          ssWages: 111,\n          ssWithholding: fica.maxSSTax,\n          medicareWithholding: 555,\n          stateWages: 666,\n          stateWithholding: 777\n        },\n        {\n          employer: { EIN: '111111111', employerName: 'w2s employer name' },\n          personRole: PersonRole.PRIMARY,\n          occupation: 'w2s-occupation',\n          state: 'AL',\n          income: 111,\n          medicareIncome: 222,\n          fedWithholding: 333,\n          ssWages: 111,\n          ssWithholding: fica.maxSSTax,\n          medicareWithholding: 555,\n          stateWages: 666,\n          stateWithholding: 777\n        }\n      ]\n      expect(claimableExcessSSTaxWithholding(f1040.info.w2s)).toEqual(0)\n      return Promise.resolve()\n    })\n  })\n\n  it('should give a refund if a person has more than the max if they have two w2s', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      f1040.info.w2s = [\n        {\n          employer: { EIN: '111111111', employerName: 'w2s employer name' },\n          personRole: PersonRole.SPOUSE,\n          occupation: 'w2s-occupation',\n          state: 'AL',\n          income: 111,\n          medicareIncome: 222,\n          fedWithholding: 333,\n          ssWages: 111,\n          ssWithholding: fica.maxSSTax,\n          medicareWithholding: 555,\n          stateWages: 666,\n          stateWithholding: 777\n        },\n        {\n          employer: { EIN: '111111111', employerName: 'w2s employer name' },\n          personRole: PersonRole.SPOUSE,\n          occupation: 'w2s-occupation',\n          state: 'AL',\n          income: 111,\n          medicareIncome: 222,\n          fedWithholding: 333,\n          ssWages: 111,\n          // This person has already contributed to the max for their other w2 so the refund should equal this amount\n          ssWithholding: 1000,\n          medicareWithholding: 555,\n          stateWages: 666,\n          stateWithholding: 777\n        },\n        {\n          employer: { EIN: '111111111', employerName: 'w2s employer name' },\n          personRole: PersonRole.PRIMARY,\n          occupation: 'w2s-occupation',\n          state: 'AL',\n          income: 111,\n          medicareIncome: 222,\n          fedWithholding: 333,\n          ssWages: 111,\n          ssWithholding: fica.maxSSTax,\n          medicareWithholding: 555,\n          stateWages: 666,\n          stateWithholding: 777\n        }\n      ]\n      expect(claimableExcessSSTaxWithholding(f1040.info.w2s)).toEqual(1000)\n      return Promise.resolve()\n    })\n  })\n\n  it('should add Additional Medicare Tax form 8959', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      const filingStatus = f1040.info.taxPayer.filingStatus\n      // Should add Additional Medicare Tax if medicare wages over threshold\n      if (\n        f1040.medicareWages() >\n        fica.additionalMedicareTaxThreshold(filingStatus)\n      ) {\n        expect(hasAdditionalMedicareTax(f1040)).toEqual(true)\n\n        // Should attach both S2 and F8959 to return\n        expect(hasAttachment(forms, Schedule2)).toEqual(true)\n        expect(hasAttachment(forms, F8959)).toEqual(true)\n      } else {\n        expect(hasAdditionalMedicareTax(f1040)).toEqual(false)\n        expect(hasAttachment(forms, F8959)).toEqual(false)\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should add Additional Medicare Tax based on filing status', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      if (hasAdditionalMedicareTax(f1040)) {\n        const filingStatus = f1040.info.taxPayer.filingStatus\n        const incomeOverThreshold =\n          f1040.medicareWages() -\n          fica.additionalMedicareTaxThreshold(filingStatus)\n        expect(incomeOverThreshold).toBeGreaterThan(0)\n\n        // Adds the right amount of additional tax\n        const s2l8 = f1040.f8959.l18()\n        expect(s2l8).not.toBeUndefined()\n        expect(displayRound(s2l8)).toEqual(\n          displayRound(incomeOverThreshold * fica.additionalMedicareTaxRate)\n        )\n\n        // Also adds in the extra Medicare tax withheld to 1040 taxes already paid\n        const medicareWithheld = f1040\n          .validW2s()\n          .reduce((sum, w2) => sum + w2.medicareWithholding, 0)\n        const regularWithholding = Math.round(\n          fica.regularMedicareTaxRate * f1040.medicareWages()\n        )\n        if (medicareWithheld > regularWithholding) {\n          const f1040l25c = f1040.l25c()\n          expect(f1040l25c).not.toBeUndefined()\n          const additionalWithheld = medicareWithheld - regularWithholding\n          expect(displayRound(f1040l25c)).toEqual(\n            displayRound(additionalWithheld)\n          )\n        } else {\n          expect(displayRound(f1040.l25c())).toBeUndefined()\n        }\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2020/tests/index.ts",
    "content": "import CommonTests, { FormTestInfo } from 'ustaxes/forms/tests/CommonTests'\nimport TestKit from 'ustaxes/forms/tests/TestKit'\nimport F1040 from '../irsForms/F1040'\n\nexport const testKit = new TestKit('Y2020')\n\nclass FormTestInfo2020 extends FormTestInfo<F1040> {\n  getAssets = (f1040: F1040) => f1040.assets\n  getInfo = (f1040: F1040) => f1040.info\n}\n\nexport const commonTests = new CommonTests<F1040>(\n  testKit,\n  new FormTestInfo2020()\n)\n"
  },
  {
    "path": "src/forms/Y2020/tests/states/il.test.ts",
    "content": "import * as fc from 'fast-check'\nimport F1040 from '../../irsForms/F1040'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { create1040 } from '../../irsForms/Main'\nimport { Information, PersonRole } from 'ustaxes/core/data'\nimport { createStateReturn } from '../../stateForms'\nimport { ILWIT } from '../../stateForms/IL/ILWit'\nimport { isLeft } from 'ustaxes/core/util'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport { fail } from 'assert'\n\nconst withStateReturn = (\n  info: Information,\n  logContext: fc.ContextValue,\n  test: (f1040Forms: [F1040, Form[]], stateForms: StateForm[]) => void\n): void => {\n  const f1040Result = create1040(info, [])\n\n  if (isLeft(f1040Result)) {\n    // ignore error infos with no 1040\n    logContext.log(f1040Result.left.join(';'))\n    return\n  }\n\n  const [f1040] = f1040Result.right\n  const stateReturn = createStateReturn(f1040)\n  if (isLeft(stateReturn)) {\n    fail(stateReturn.left.join(';'))\n  }\n\n  test(f1040Result.right, stateReturn.right)\n}\n\nconst A = new arbitraries.Arbitraries(2020)\n\ndescribe('il year 2020', () => {\n  it('should produce correct withholding attachments in', () => {\n    fc.assert(\n      fc.property(A.information(), fc.context(), (info, ctx) => {\n        info.stateResidencies = [{ state: 'IL' }]\n        info.w2s.forEach((w2) => {\n          w2.state = 'IL'\n        })\n        withStateReturn(info, ctx, (_, stateForms) => {\n          ctx.log(stateForms.map((f) => f.formName).join(';'))\n          expect(stateForms.filter((f) => f.formName === 'IL-WIT').length).toBe(\n            Math.ceil(\n              Math.max(\n                ...[PersonRole.PRIMARY, PersonRole.SPOUSE].map(\n                  (r) =>\n                    info.w2s.filter(\n                      (w2) =>\n                        w2.personRole === r && (w2.stateWithholding ?? 0) > 0\n                    ).length\n                )\n              ) / ILWIT.WITHHOLDING_FORMS_PER_PAGE\n            )\n          )\n        })\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/data/federal.ts",
    "content": "import { FilingStatus } from 'ustaxes/core/data'\nimport { linear, Piecewise } from 'ustaxes/core/util'\n\nexport const CURRENT_YEAR = 2021\n\ninterface TaggedAmount {\n  name: string\n  amount: number\n}\n\ninterface Brackets {\n  brackets: number[]\n}\n\ninterface Deductions {\n  deductions: TaggedAmount[]\n  exemptions: TaggedAmount[]\n}\n\ninterface Rates {\n  rates: number[]\n}\n\ninterface FederalBrackets {\n  ordinary: Rates & { status: { [key in FilingStatus]: Brackets & Deductions } }\n  longTermCapGains: Rates & { status: { [key in FilingStatus]: Brackets } }\n}\n\nconst federalBrackets: FederalBrackets = {\n  ordinary: {\n    rates: [10, 12, 22, 24, 32, 35, 37],\n    status: {\n      [FilingStatus.S]: {\n        brackets: [9950, 40525, 86375, 164925, 209425, 523600],\n        deductions: [\n          {\n            name: 'Standard Deduction (Single)',\n            amount: 12550\n          },\n          {\n            name: 'Standard Deduction (Single) with 1 age or blindness allowance',\n            amount: 14250\n          },\n          {\n            name: 'Standard Deduction (Single) with 2 age or blindness allowances',\n            amount: 15950\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.MFJ]: {\n        brackets: [19900, 81050, 172750, 329850, 418850, 628300],\n        deductions: [\n          {\n            name: 'Standard Deduction (Married)',\n            amount: 25100\n          },\n          {\n            name: 'Standard Deduction (Married) with 1 age or blindness allowance',\n            amount: 26450\n          },\n          {\n            name: 'Standard Deduction (Married) with 2 age or blindness allowances',\n            amount: 27800\n          },\n          {\n            name: 'Standard Deduction (Married) with 3 age or blindness allowances',\n            amount: 29150\n          },\n          {\n            name: 'Standard Deduction (Married) with 4 age or blindness allowances',\n            amount: 30500\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.W]: {\n        brackets: [19900, 81050, 172750, 329850, 418850, 628300],\n        deductions: [\n          {\n            name: 'Standard Deduction (Widowed)',\n            amount: 24800\n          },\n          {\n            name: 'Standard Deduction (Widowed) with 1 age or blindness allowance',\n            amount: 26450\n          },\n          {\n            name: 'Standard Deduction (Widowed) with 2 age or blindness allowances',\n            amount: 27800\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Widowed)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.MFS]: {\n        brackets: [9950, 40525, 86375, 164925, 209425, 314150],\n        deductions: [\n          {\n            name: 'Standard Deduction (Married Filing Separately)',\n            amount: 12550\n          },\n          {\n            name: 'Standard Deduction (Married Filing Separately) with 1 age or blindness allowance',\n            amount: 13900\n          },\n          {\n            name: 'Standard Deduction (Married Filing Separately) with 2 age or blindness allowances',\n            amount: 15250\n          },\n          {\n            name: 'Standard Deduction (Married Filing Separately) with 3 age or blindness allowances',\n            amount: 16600\n          },\n          {\n            name: 'Standard Deduction (Married Filing Separately) with 4 age or blindness allowances',\n            amount: 17950\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      },\n      [FilingStatus.HOH]: {\n        brackets: [14200, 54200, 86350, 164900, 209400, 523600],\n        deductions: [\n          {\n            name: 'Standard Deduction (Head of Household)',\n            amount: 18800\n          },\n          {\n            name: 'Standard Deduction (Head of Household) with 1 age or blindness allowance',\n            amount: 20500\n          },\n          {\n            name: 'Standard Deduction (Head of Household) with 2 age or blindness allowances',\n            amount: 22200\n          }\n        ],\n        exemptions: [\n          {\n            name: 'Standard Exemption (Single)',\n            amount: 0\n          }\n        ]\n      }\n    }\n  },\n  longTermCapGains: {\n    rates: [0, 15, 20],\n    status: {\n      [FilingStatus.S]: {\n        brackets: [40400, 445850]\n      },\n      [FilingStatus.MFJ]: {\n        brackets: [80800, 501600]\n      },\n      [FilingStatus.W]: {\n        brackets: [80800, 501600]\n      },\n      [FilingStatus.MFS]: {\n        brackets: [40400, 250800]\n      },\n      [FilingStatus.HOH]: {\n        brackets: [54100, 473750]\n      }\n    }\n  }\n}\n\nexport const fica = {\n  maxSSTax: 8853.6,\n  maxIncomeSSTaxApplies: 142800,\n\n  regularMedicareTaxRate: 1.45 / 100,\n  additionalMedicareTaxRate: 0.9 / 100,\n  additionalMedicareTaxThreshold: (filingStatus: FilingStatus): number => {\n    switch (filingStatus) {\n      case FilingStatus.MFJ: {\n        return 250000\n      }\n      case FilingStatus.MFS: {\n        return 125000\n      }\n      default: {\n        return 200000 // Single, Head of Household, Windower\n      }\n    }\n  }\n}\n\n// Net Investment Income Tax calculated on form 8960\nexport const netInvestmentIncomeTax = {\n  taxRate: 0.038, // 3.8%\n  taxThreshold: (filingStatus: FilingStatus): number => {\n    switch (filingStatus) {\n      case FilingStatus.MFJ: {\n        return 250000\n      }\n      case FilingStatus.W: {\n        return 250000\n      }\n      case FilingStatus.MFS: {\n        return 125000\n      }\n      default: {\n        return 200000 // Single, Head of Household\n      }\n    }\n  }\n}\n\nexport const healthSavingsAccounts = {\n  contributionLimit: {\n    'self-only': 3600,\n    family: 7200\n  }\n}\n\n// line 11 caps based on step one in instructions\nconst line11Caps = [21430, 42158, 47915, 51464]\nconst line11MfjCaps = [27830, 48108, 53865, 57414]\n\ntype Point = [number, number]\n\n// Provided a list of points, create a piecewise function\n// that makes linear segments through the list of points.\nconst toPieceWise = (points: Point[]): Piecewise =>\n  points\n    .slice(0, points.length - 1)\n    .map((point, idx) => [point, points[idx + 1]])\n    .map(([[x1, y1], [x2, y2]]) => ({\n      // starting point     slope              intercept\n      lowerBound: x1,\n      f: linear((y2 - y1) / (x2 - x1), y1 - (x1 * (y2 - y1)) / (x2 - x1))\n    }))\n\n// These points are taken directly from IRS publication\n// IRS Rev. Proc. 2019-44 for tax year 2020\n// https://www.irs.gov/pub/irs-drop/rp-19-44.pdf\nconst unmarriedFormulas: Piecewise[] = (() => {\n  const points: Point[][] = [\n    [\n      [0, 0],\n      [7030, 538],\n      [8790, 3584],\n      [15820, 0]\n    ], // 0\n    [\n      [0, 0],\n      [10540, 3584],\n      [19330, 3584],\n      [41756, 0]\n    ], // 1\n    [\n      [0, 0],\n      [14800, 5920],\n      [19330, 5920],\n      [47440, 0]\n    ], // 2\n    [\n      [0, 0],\n      [14800, 6660],\n      [19330, 6660],\n      [50954, 0]\n    ] // 3 or more\n  ]\n  return points.map((ps: Point[]) => toPieceWise(ps))\n})()\n\nconst marriedFormulas: Piecewise[] = (() => {\n  const points: Point[][] = [\n    [\n      [0, 0],\n      [7030, 538],\n      [14680, 3584],\n      [21710, 0]\n    ], // 0\n    [\n      [0, 0],\n      [10540, 3584],\n      [25220, 3584],\n      [47646, 0]\n    ], // 1\n    [\n      [0, 0],\n      [14800, 5920],\n      [25220, 5920],\n      [53330, 0]\n    ], // 2\n    [\n      [0, 0],\n      [14800, 6660],\n      [25220, 6660],\n      [56844, 0]\n    ] // 3 or more\n  ]\n  return points.map((ps) => toPieceWise(ps))\n})()\n\ninterface EICDef {\n  caps: { [k in FilingStatus]: number[] | undefined }\n  maxInvestmentIncome: number\n  formulas: { [k in FilingStatus]: Piecewise[] | undefined }\n}\n\nexport const QualifyingDependents = {\n  childMaxAge: 17,\n  qualifyingDependentMaxAge: 19,\n  qualifyingStudentMaxAge: 24\n}\n\nexport const EIC: EICDef = {\n  // credit caps for number of children (0, 1, 2, 3 or more):\n  // Step 1\n  caps: {\n    [FilingStatus.S]: line11Caps,\n    [FilingStatus.W]: line11Caps,\n    [FilingStatus.HOH]: line11Caps,\n    [FilingStatus.MFS]: undefined,\n    [FilingStatus.MFJ]: line11MfjCaps\n  },\n  maxInvestmentIncome: 10000,\n  formulas: {\n    [FilingStatus.S]: unmarriedFormulas,\n    [FilingStatus.W]: unmarriedFormulas,\n    [FilingStatus.HOH]: unmarriedFormulas,\n    [FilingStatus.MFS]: undefined,\n    [FilingStatus.MFJ]: marriedFormulas\n  }\n}\n\nexport default federalBrackets\n\n// Constants used in the social security benefits worksheet\ninterface SocialSecurityBenefitsDef {\n  caps: { [k in FilingStatus]: { l8: number; l10: number } }\n}\n\nexport const SSBenefits: SocialSecurityBenefitsDef = {\n  caps: {\n    [FilingStatus.S]: { l8: 25000, l10: 9000 },\n    [FilingStatus.W]: { l8: 25000, l10: 9000 },\n    [FilingStatus.HOH]: { l8: 25000, l10: 9000 },\n    [FilingStatus.MFS]: { l8: 25000, l10: 9000 },\n    [FilingStatus.MFJ]: { l8: 32000, l10: 12000 }\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F1040.ts",
    "content": "import {\n  AccountType,\n  Dependent,\n  FilingStatus,\n  IncomeW2,\n  PersonRole,\n  PlanType1099,\n  Asset\n} from 'ustaxes/core/data'\nimport federalBrackets, { CURRENT_YEAR } from '../data/federal'\nimport F4972 from './F4972'\nimport F5695 from './F5695'\nimport F8814 from './F8814'\nimport F8888 from './F8888'\nimport F8889 from './F8889'\nimport F8910 from './F8910'\nimport F8936 from './F8936'\nimport F8959 from './F8959'\nimport F8995, { getF8995PhaseOutIncome } from './F8995'\nimport F8995A from './F8995A'\nimport Schedule1 from './Schedule1'\nimport Schedule2 from './Schedule2'\nimport Schedule3 from './Schedule3'\nimport Schedule8812 from './Schedule8812'\nimport ScheduleA from './ScheduleA'\nimport ScheduleD from './ScheduleD'\nimport ScheduleE from './ScheduleE'\nimport ScheduleSE from './ScheduleSE'\nimport ScheduleEIC from './ScheduleEIC'\nimport ScheduleR from './ScheduleR'\nimport Form, { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport ScheduleB from './ScheduleB'\nimport { computeOrdinaryTax } from './TaxTable'\nimport SDQualifiedAndCapGains from './worksheets/SDQualifiedAndCapGains'\nimport QualifyingDependents from './worksheets/QualifyingDependents'\nimport SocialSecurityBenefitsWorksheet from './worksheets/SocialSecurityBenefits'\nimport F4797 from './F4797'\nimport StudentLoanInterestWorksheet from './worksheets/StudentLoanInterestWorksheet'\nimport F1040V from './F1040v'\nimport _ from 'lodash'\nimport F8960 from './F8960'\nimport F4952 from './F4952'\nimport F2555 from './F2555'\nimport F4563 from './F4563'\nimport F8863 from './F8863'\nimport F8962 from './F8962'\nimport F4136 from './F4136'\nimport F2439 from './F2439'\nimport F2441 from './F2441'\nimport ScheduleC from './ScheduleC'\nimport F8949 from './F8949'\nimport F6251 from './F6251'\nimport F4137 from './F4137'\nimport F8919 from './F8919'\nimport F8853 from './F8853'\nimport F8582 from './F8582'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport F1040Base, { ValidatedInformation } from 'ustaxes/forms/F1040Base'\nimport F1040Attachment from './F1040Attachment'\n\nexport default class F1040 extends F1040Base {\n  tag: FormTag = 'f1040'\n  sequenceIndex = 0\n\n  assets: Asset<Date>[]\n\n  schedule1: Schedule1\n  schedule2: Schedule2\n  schedule3: Schedule3\n  scheduleA: ScheduleA\n  scheduleB: ScheduleB\n  scheduleC?: ScheduleC\n  scheduleD: ScheduleD\n  scheduleE: ScheduleE\n  scheduleSE: ScheduleSE\n  scheduleEIC: ScheduleEIC\n  scheduleR?: ScheduleR\n  schedule8812: Schedule8812\n  f2439?: F2439\n  f2441?: F2441\n  f2555?: F2555\n  f4136?: F4136\n  f4137?: F4137\n  f4563?: F4563\n  f4797?: F4797\n  f4952?: F4952\n  f4972?: F4972\n  f5695?: F5695\n  f6251: F6251\n  f8814?: F8814\n  f8582?: F8582\n  f8853?: F8853\n  f8863?: F8863\n  f8888?: F8888\n  f8889: F8889\n  f8889Spouse?: F8889\n  f8910?: F8910\n  f8919?: F8919\n  f8936?: F8936\n  f8949: F8949\n  _f8949s?: F8949[]\n  f8959: F8959\n  f8960: F8960\n  f8962?: F8962\n  f8995?: F8995 | F8995A\n  qualifiedAndCapGainsWorksheet?: SDQualifiedAndCapGains\n  studentLoanInterestWorksheet?: StudentLoanInterestWorksheet\n  socialSecurityBenefitsWorksheet?: SocialSecurityBenefitsWorksheet\n\n  qualifyingDependents: QualifyingDependents\n\n  constructor(info: ValidatedInformation, assets: Asset<Date>[]) {\n    super(info)\n    this.assets = assets\n    this.qualifyingDependents = new QualifyingDependents(this)\n\n    this.scheduleA = new ScheduleA(this)\n    this.scheduleB = new ScheduleB(this)\n    this.scheduleD = new ScheduleD(this)\n    this.scheduleE = new ScheduleE(this)\n    this.scheduleEIC = new ScheduleEIC(this)\n    this.scheduleSE = new ScheduleSE(this)\n\n    this.schedule1 = new Schedule1(this)\n    this.schedule2 = new Schedule2(this)\n    this.schedule3 = new Schedule3(this)\n    this.schedule8812 = new Schedule8812(this)\n\n    this.f6251 = new F6251(this)\n    this.f8949 = new F8949(this)\n    this.f8889 = new F8889(this, this.info.taxPayer.primaryPerson)\n\n    // add in separate form 8889 for the spouse\n    if (this.info.taxPayer.spouse) {\n      this.f8889Spouse = new F8889(this, this.info.taxPayer.spouse)\n    }\n\n    this.f8959 = new F8959(this)\n    this.f8960 = new F8960(this)\n\n    if (this.f1099ssas().length > 0) {\n      const ssws = new SocialSecurityBenefitsWorksheet(this)\n      this.socialSecurityBenefitsWorksheet = ssws\n    }\n\n    if (this.info.f1098es.length > 0) {\n      this.studentLoanInterestWorksheet = new StudentLoanInterestWorksheet(\n        this,\n        this.info.f1098es\n      )\n    }\n\n    if (this.totalQbi() > 0) {\n      const formAMinAmount = getF8995PhaseOutIncome(\n        this.info.taxPayer.filingStatus\n      )\n      if (this.l11() - this.l12c() >= formAMinAmount) {\n        this.f8995 = new F8995A(this)\n      } else {\n        this.f8995 = new F8995(this)\n      }\n    }\n  }\n\n  get f8949s(): F8949[] {\n    if (this._f8949s === undefined) {\n      this._f8949s = [this.f8949, ...this.f8949.copies()]\n    }\n    return this._f8949s\n  }\n\n  totalQbi = () =>\n    this.info.scheduleK1Form1065s\n      .map((k1) => k1.section199AQBI)\n      .reduce((c, a) => c + a, 0)\n\n  toString = (): string => `\n    Form 1040 generated from information:\n    Information:\n    ${JSON.stringify(this.info)}\n  `\n\n  // TODO - get from W2 box 12, code Q\n  nonTaxableCombatPay = (): number | undefined => undefined\n\n  schedules = (): Form[] => {\n    const res1: (F1040Attachment | undefined)[] = [\n      this.scheduleA,\n      this.scheduleB,\n      this.scheduleD,\n      this.scheduleE,\n      this.scheduleSE,\n      this.scheduleR,\n      this.scheduleEIC,\n      this.schedule8812,\n      this.f4797,\n      this.f4952,\n      this.f4972,\n      this.f5695,\n      this.f6251,\n      this.f8814,\n      this.f8888,\n      this.f8889,\n      this.f8889Spouse,\n      this.f8910,\n      this.f8936,\n      this.f8949,\n      this.f8959,\n      this.f8960,\n      this.f8995,\n      this.schedule1,\n      this.schedule2,\n      this.schedule3\n    ]\n    const res = _.compact(res1)\n      .filter((f) => f.isNeeded())\n      .flatMap((f) => [f, ...f.copies()])\n\n    // Attach payment voucher to front if there is a payment due\n    if (this.l37() > 0) {\n      res.push(new F1040V(this))\n    }\n\n    return [this, ...res].sort((a, b) => a.sequenceIndex - b.sequenceIndex)\n  }\n\n  // born before 1957/01/02\n  bornBeforeDate = (): boolean =>\n    this.info.taxPayer.primaryPerson.dateOfBirth <\n    new Date(CURRENT_YEAR - 64, 0, 2)\n\n  blind = (): boolean => this.info.taxPayer.primaryPerson.isBlind\n\n  spouseBeforeDate = (): boolean =>\n    (this.info.taxPayer.spouse?.dateOfBirth ?? new Date()) <\n    new Date(CURRENT_YEAR - 64, 0, 2)\n\n  spouseBlind = (): boolean => this.info.taxPayer.spouse?.isBlind ?? false\n\n  validW2s = (): IncomeW2[] => {\n    if (this.info.taxPayer.filingStatus === FilingStatus.MFS) {\n      return this.info.w2s.filter((w2) => w2.personRole === PersonRole.PRIMARY)\n    }\n    return this.info.w2s\n  }\n\n  wages = (): number => this.validW2s().reduce((res, w2) => res + w2.income, 0)\n  medicareWages = (): number =>\n    this.validW2s().reduce((res, w2) => res + w2.medicareIncome, 0)\n\n  occupation = (r: PersonRole): string | undefined =>\n    this.info.w2s.find((w2) => w2.personRole === r && w2.occupation !== '')\n      ?.occupation\n\n  standardDeduction = (): number | undefined => {\n    const filingStatus = this.info.taxPayer.filingStatus\n\n    const allowances = [\n      this.bornBeforeDate(),\n      this.blind(),\n      this.spouseBeforeDate(),\n      this.spouseBlind()\n    ].reduce((res, e) => res + +!!e, 0)\n\n    if (\n      this.info.taxPayer.primaryPerson.isTaxpayerDependent ||\n      (this.info.taxPayer.spouse?.isTaxpayerDependent ?? false)\n    ) {\n      const l4a = Math.min(\n        federalBrackets.ordinary.status[filingStatus].deductions[0].amount,\n        this.wages() > 750 ? this.wages() + 350 : 1100\n      )\n      if (allowances > 0) {\n        if (\n          filingStatus === FilingStatus.HOH ||\n          filingStatus === FilingStatus.S\n        ) {\n          return l4a + allowances * 1700\n        } else {\n          return l4a + allowances * 1350\n        }\n      } else {\n        return l4a\n      }\n    }\n\n    return federalBrackets.ordinary.status[filingStatus].deductions[allowances]\n      .amount\n  }\n\n  totalQualifiedDividends = (): number =>\n    this.f1099Divs()\n      .map((f) => f.form.qualifiedDividends)\n      .reduce((l, r) => l + r, 0)\n\n  totalGrossDistributionsFromIra = (): number =>\n    this.info.individualRetirementArrangements.reduce(\n      (res, i) => res + i.grossDistribution,\n      0\n    )\n\n  totalTaxableFromIra = (): number =>\n    this.info.individualRetirementArrangements.reduce(\n      (r, i) => r + i.taxableAmount,\n      0\n    )\n\n  totalGrossDistributionsFrom1099R = (planType: PlanType1099): number =>\n    this.f1099rs()\n      .filter((element) => element.form.planType === planType)\n      .reduce((res, f1099) => res + f1099.form.grossDistribution, 0)\n\n  totalTaxableFrom1099R = (planType: PlanType1099): number =>\n    this.f1099rs()\n      .filter((element) => element.form.planType === planType)\n      .reduce((res, f1099) => res + f1099.form.taxableAmount, 0)\n\n  l1 = (): number => this.wages()\n  l2a = (): number | undefined => this.scheduleB.l3()\n  l2b = (): number | undefined => this.scheduleB.to1040l2b()\n  l3a = (): number | undefined => this.totalQualifiedDividends()\n  l3b = (): number | undefined => this.scheduleB.to1040l3b()\n  // This is the value of box 1 in 1099-R forms coming from IRAs\n  l4a = (): number | undefined => this.totalGrossDistributionsFromIra()\n  // This should be the value of box 2a in 1099-R coming from IRAs\n  l4b = (): number | undefined => this.totalTaxableFromIra()\n  // This is the value of box 1 in 1099-R forms coming from pensions/annuities\n  l5a = (): number | undefined =>\n    this.totalGrossDistributionsFrom1099R(PlanType1099.Pension)\n  // this is the value of box 2a in 1099-R forms coming from pensions/annuities\n  l5b = (): number | undefined =>\n    this.totalTaxableFrom1099R(PlanType1099.Pension)\n  // The sum of box 5 from SSA-1099\n  l6a = (): number | undefined => this.socialSecurityBenefitsWorksheet?.l1()\n  // calculation of the taxable amount of line 6a based on other income\n  l6b = (): number | undefined =>\n    this.socialSecurityBenefitsWorksheet?.taxableAmount()\n  l7Box = (): boolean => !this.scheduleD.isNeeded()\n  l7 = (): number | undefined => this.scheduleD.to1040()\n  l8 = (): number | undefined => this.schedule1.l10()\n  l9 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2b(),\n      this.l3b(),\n      this.l4b(),\n      this.l5b(),\n      this.l6b(),\n      this.l7(),\n      this.l8()\n    ])\n\n  l10 = (): number | undefined => this.schedule1.to1040Line10()\n\n  l11 = (): number => Math.max(0, this.l9() - (this.l10() ?? 0))\n\n  l12a = (): number | undefined => {\n    if (this.scheduleA.isNeeded()) {\n      return this.scheduleA.deductions()\n    }\n    return this.standardDeduction()\n  }\n\n  // TODO: Charitable contributions with standard deduction\n  l12b = (): number | undefined => undefined\n  l12c = (): number => sumFields([this.l12a(), this.l12b()])\n\n  l13 = (): number | undefined => this.f8995?.deductions()\n  l14 = (): number => sumFields([this.l12c(), this.l13()])\n\n  l15 = (): number => Math.max(0, this.l11() - this.l14())\n\n  f8814Box = (): boolean | undefined => this.f8814 !== undefined\n  f4972Box = (): boolean | undefined => this.f4972 !== undefined\n  // TODO: tax from other form?\n  otherFormBox = (): boolean => false\n  otherFormName = (): string | undefined => undefined\n\n  computeTax = (): number | undefined => {\n    if (\n      this.scheduleD.computeTaxOnQDWorksheet() ||\n      this.totalQualifiedDividends() > 0\n    ) {\n      this.qualifiedAndCapGainsWorksheet = new SDQualifiedAndCapGains(this)\n      return this.qualifiedAndCapGainsWorksheet.tax()\n    }\n\n    return computeOrdinaryTax(this.info.taxPayer.filingStatus, this.l15())\n  }\n\n  l16 = (): number | undefined =>\n    sumFields([this.f8814?.tax(), this.f4972?.tax(), this.computeTax()])\n\n  l17 = (): number | undefined => this.schedule2.l3()\n  l18 = (): number => sumFields([this.l16(), this.l17()])\n\n  l19 = (): number | undefined => this.schedule8812.to1040Line19()\n  l20 = (): number | undefined =>\n    this.schedule3.isNeeded() ? this.schedule3.l7() : undefined\n\n  l21 = (): number => sumFields([this.l19(), this.l20()])\n\n  l22 = (): number => Math.max(0, this.l18() - this.l21())\n\n  l23 = (): number | undefined => this.schedule2.l21()\n\n  l24 = (): number => sumFields([this.l22(), this.l23()])\n\n  l25a = (): number =>\n    this.validW2s().reduce((res, w2) => res + w2.fedWithholding, 0)\n\n  // tax withheld from 1099s\n  l25b = (): number =>\n    this.f1099rs().reduce(\n      (res, f1099) => res + f1099.form.federalIncomeTaxWithheld,\n      0\n    ) +\n    this.f1099ssas().reduce(\n      (res, f1099) => res + f1099.form.federalIncomeTaxWithheld,\n      0\n    )\n\n  // TODO: form(s) W-2G box 4, schedule K-1, form 1042-S, form 8805, form 8288-A\n  l25c = (): number | undefined => this.f8959.l24()\n\n  l25d = (): number => sumFields([this.l25a(), this.l25b(), this.l25c()])\n\n  l26 = (): number =>\n    this.info.estimatedTaxes.reduce((res, et) => res + et.payment, 0)\n\n  l27a = (): number =>\n    this.scheduleEIC.isNeeded() ? this.scheduleEIC.credit() : 0\n\n  // TODO: handle taxpayers between 1998 and 2004 that\n  // can claim themselves for eic.\n  l27acheckBox = (): boolean => false\n\n  // TODO: nontaxable combat pay\n  l27b = (): number | undefined => undefined\n\n  // TODO: prior year earned income\n  l27c = (): number | undefined => undefined\n\n  l28 = (): number | undefined => this.schedule8812.to1040Line28()\n\n  l29 = (): number | undefined => this.f8863?.l8()\n\n  // TODO: recovery rebate credit?\n  l30 = (): number | undefined => undefined\n\n  l31 = (): number | undefined =>\n    this.schedule3.isNeeded() ? this.schedule3.l15() : undefined\n\n  l32 = (): number =>\n    sumFields([this.l27a(), this.l28(), this.l29(), this.l30(), this.l31()])\n\n  l33 = (): number => sumFields([this.l25d(), this.l26(), this.l32()])\n\n  l34 = (): number => Math.max(0, this.l33() - this.l24())\n\n  // TODO: assuming user wants amount refunded\n  // rather than applied to estimated tax\n  l35a = (): number => this.l34()\n  l36 = (): number => Math.max(0, this.l34() - this.l35a())\n\n  l37 = (): number => Math.max(0, this.l24() - this.l33())\n\n  // TODO - estimated tax penalty\n  l38 = (): number | undefined => undefined\n\n  _depField = (idx: number): string | boolean => {\n    const deps: Dependent[] = this.info.taxPayer.dependents\n\n    // Based on the PDF row we are on, select correct dependent\n    const depIdx = Math.floor(idx / 5)\n    const depFieldIdx = idx % 5\n\n    let fieldArr = ['', '', '', false, false]\n\n    if (depIdx < deps.length) {\n      const dep = deps[depIdx]\n      // Based on the PDF column, select the correct field\n      fieldArr = [\n        `${dep.firstName} ${dep.lastName}`,\n        dep.ssid,\n        dep.relationship,\n        this.qualifyingDependents.qualifiesChild(dep),\n        this.qualifyingDependents.qualifiesOther(dep)\n      ]\n    }\n\n    return fieldArr[depFieldIdx]\n  }\n\n  // 1040 allows 4 dependents listed without a supplemental schedule,\n  // so create field mappings for 4x5 grid of fields\n  _depFieldMappings = (): Array<string | boolean> =>\n    Array.from(Array(20)).map((u, n: number) => this._depField(n))\n\n  fields = (): Field[] =>\n    [\n      this.info.taxPayer.filingStatus === FilingStatus.S,\n      this.info.taxPayer.filingStatus === FilingStatus.MFJ,\n      this.info.taxPayer.filingStatus === FilingStatus.MFS,\n      this.info.taxPayer.filingStatus === FilingStatus.HOH,\n      this.info.taxPayer.filingStatus === FilingStatus.W,\n      // TODO: implement non dependent child for HOH and QW\n      this.info.taxPayer.filingStatus === 'MFS' ? this.spouseFullName() : '',\n      this.info.taxPayer.primaryPerson.firstName,\n      this.info.taxPayer.primaryPerson.lastName,\n      this.info.taxPayer.primaryPerson.ssid,\n      this.info.taxPayer.filingStatus === FilingStatus.MFJ\n        ? this.info.taxPayer.spouse?.firstName\n        : '',\n      this.info.taxPayer.filingStatus === FilingStatus.MFJ\n        ? this.info.taxPayer.spouse?.lastName ?? ''\n        : '',\n      this.info.taxPayer.spouse?.ssid,\n      this.info.taxPayer.primaryPerson.address.address,\n      this.info.taxPayer.primaryPerson.address.aptNo,\n      this.info.taxPayer.primaryPerson.address.city,\n      this.info.taxPayer.primaryPerson.address.state,\n      this.info.taxPayer.primaryPerson.address.zip,\n      this.info.taxPayer.primaryPerson.address.foreignCountry,\n      this.info.taxPayer.primaryPerson.address.province,\n      this.info.taxPayer.primaryPerson.address.postalCode,\n      false, // election campaign boxes\n      false,\n      this.info.questions.CRYPTO ?? false,\n      !(this.info.questions.CRYPTO ?? false),\n      this.info.taxPayer.primaryPerson.isTaxpayerDependent,\n      this.info.taxPayer.spouse?.isTaxpayerDependent ?? false,\n      false, // TODO: spouse itemizes separately,\n      this.bornBeforeDate(),\n      this.blind(),\n      this.spouseBeforeDate(),\n      this.spouseBlind(),\n      this.info.taxPayer.dependents.length > 4,\n      ...this._depFieldMappings(),\n      this.l1(),\n      this.l2a(),\n      this.l2b(),\n      this.l3a(),\n      this.l3b(),\n      this.l4a(),\n      this.l4b(),\n      this.l5a(),\n      this.l5b(),\n      this.l6a(),\n      this.l6b(),\n      this.l7Box(),\n      this.l7(),\n      this.l8(),\n      this.l9(),\n      this.l10(),\n      this.l11(),\n      this.l12a(),\n      this.l12b(),\n      this.l12c(),\n      this.l13(),\n      this.l14(),\n      this.l15(),\n      this.f8814Box(),\n      this.f4972Box(),\n      this.otherFormBox(),\n      this.otherFormName(),\n      this.l16(),\n      this.l17(),\n      this.l18(),\n      this.l19(),\n      this.l20(),\n      this.l21(),\n      this.l22(),\n      this.l23(),\n      this.l24(),\n      this.l25a(),\n      this.l25b(),\n      this.l25c(),\n      this.l25d(),\n      this.l26(),\n      this.l27a(),\n      this.l27acheckBox(),\n      this.l27b(),\n      this.l27c(),\n      this.l28(),\n      this.l29(),\n      this.l30(),\n      this.l31(),\n      this.l32(),\n      this.l33(),\n      this.l34(),\n      this.f8888 !== undefined,\n      this.l35a(),\n      this.info.refund?.routingNumber,\n      this.info.refund?.accountType === AccountType.checking,\n      this.info.refund?.accountType === AccountType.savings,\n      this.info.refund?.accountNumber,\n      this.l36(),\n      this.l37(),\n      this.l38(),\n      // TODO: 3rd party\n      false,\n      false,\n      '',\n      '',\n      '',\n      this.occupation(PersonRole.PRIMARY),\n      // TODO: pin numbers\n      '',\n      this.occupation(PersonRole.SPOUSE),\n      '',\n      this.info.taxPayer.contactPhoneNumber,\n      this.info.taxPayer.contactEmail,\n      // Paid preparer fields:\n      '',\n      '',\n      false,\n      '',\n      '',\n      '',\n      ''\n    ].map((x) => (x === undefined ? '' : x))\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F1040Attachment.ts",
    "content": "import Form from 'ustaxes/core/irsForms/Form'\nimport F1040 from './F1040'\n\nabstract class F1040Attachment extends Form {\n  f1040: F1040\n\n  constructor(f1040: F1040) {\n    super()\n    this.f1040 = f1040\n  }\n\n  isNeeded = (): boolean => true\n  copies = (): F1040Attachment[] => []\n}\n\nexport abstract class Worksheet {\n  f1040: F1040\n\n  constructor(f1040: F1040) {\n    this.f1040 = f1040\n  }\n}\n\nexport default F1040Attachment\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F1040v.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F1040V extends F1040Attachment {\n  tag: FormTag = 'f1040v'\n  sequenceIndex = -1\n\n  fields = (): Field[] => {\n    const tp = this.f1040.info.taxPayer\n\n    const taxOwed = this.f1040.l37()\n\n    const result = [\n      tp.primaryPerson.ssid,\n      tp.spouse?.ssid,\n      taxOwed.toFixed(2), // dollars\n      tp.primaryPerson.firstName,\n      tp.primaryPerson.lastName,\n      tp.spouse?.firstName,\n      tp.spouse?.lastName,\n      tp.primaryPerson.address.address,\n      tp.primaryPerson.address.aptNo,\n      tp.primaryPerson.address.city,\n      tp.primaryPerson.address.state,\n      tp.primaryPerson.address.zip,\n      tp.primaryPerson.address.foreignCountry,\n      tp.primaryPerson.address.province,\n      tp.primaryPerson.address.postalCode\n    ]\n\n    return result\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F2439.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: not implemented\n * Referenced Schedule 3 line 13a\n */\nexport default class F2439 extends F1040Attachment {\n  tag: FormTag = 'f2439'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F2441.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: Credit for child and dependent care expenses\n */\nexport default class F2441 extends F1040Attachment {\n  tag: FormTag = 'f2441'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F2555.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Impacts EIC, 1040 instructions L27 step 1 squestion 4\n */\nexport default class F2555 extends F1040Attachment {\n  tag: FormTag = 'f2555'\n  sequenceIndex = 34\n\n  // TODO - Required from SDCapitalGainWorksheet\n  l3 = (): number | undefined => undefined\n\n  // TODO - required from 6251\n  l36 = (): number => 0\n\n  // TODO - required from 6251\n  l42 = (): number => 0\n\n  // TODO - required from 8812\n  l45 = (): number => 0\n\n  // TODO - required from 6251 & 8812\n  l50 = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F4136.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: not implemented\n * Credit for federal tax on fuels\n */\nexport default class F4136 extends F1040Attachment {\n  tag: FormTag = 'f4136'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F4137.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n// TODO\nexport default class F4137 extends F1040Attachment {\n  tag = 'f4137'\n  sequenceIndex = 999\n\n  l6 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F4563.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Exclusion of income for residents of American Somoa\n * Impacts 8812,\n */\nexport default class F4563 extends F1040Attachment {\n  sequenceIndex = 563\n  tag: FormTag = 'f4563'\n\n  // TODO - required from 8812\n  l15 = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F4797.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Impacts EIC, 1040 instructions L27 step 2 question 3\n * Not implemented yet\n */\nexport default class F4797 extends F1040Attachment {\n  tag: FormTag = 'f4797'\n  sequenceIndex = 999\n\n  // TODO, required from schedule EIC, PUB 596, worksheet 1\n  l7 = (): number | undefined => undefined\n  l8 = (): number | undefined => undefined\n  l9 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F4952.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Impacts Schedule D, capital gains and taxes worksheet,\n * TODO: Not implemented yet\n */\nexport default class F4952 extends F1040Attachment {\n  tag: FormTag = 'f4952'\n  sequenceIndex = 999\n\n  l4e = (): number | undefined => undefined\n  l4g = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F4972.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: Not implemented yet\n */\nexport default class F4972 extends F1040Attachment {\n  tag: FormTag = 'f4972'\n  sequenceIndex = 999\n\n  tax = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F5695.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented yet\n */\nexport default class F5695 extends F1040Attachment {\n  tag: FormTag = 'f5695'\n  sequenceIndex = 999\n\n  l30 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F6168.ts",
    "content": "import { Field } from 'ustaxes/core/pdfFiller'\nimport F1040Attachment from './F1040Attachment'\n\n/**\n * Referenced from line 21 of Schedule E\n * TODO: Not implemented\n */\nexport default class F6168 extends F1040Attachment {\n  sequenceIndex = 999\n  tag = 'f6168'\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F6251.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FilingStatus, PersonRole } from 'ustaxes/core/data'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype Part3 = Partial<{\n  l12: number\n  l13: number\n  l14: number\n  l15: number\n  l16: number\n  l17: number\n  l18: number\n  l19: number\n  l20: number\n  l21: number\n  l22: number\n  l23: number\n  l24: number\n  l25: number\n  l26: number\n  l27: number\n  l28: number\n  l29: number\n  l30: number\n  l31: number\n  l32: number\n  l33: number\n  l34: number\n  l35: number\n  l36: number\n  l37: number\n  l38: number\n  l39: number\n  l40: number\n}>\n\nexport default class F6251 extends F1040Attachment {\n  tag: FormTag = 'f6251'\n  sequenceIndex = 32\n\n  isNeeded = (): boolean => {\n    // See https://www.irs.gov/instructions/i6251\n\n    // 1. Form 6251, line 7, is greater than line 10.\n    if ((this.l7() ?? 0) > this.l10()) {\n      return true\n    }\n\n    // TODO: 2. You claim any general business credit, and either line 6 (in Part I) of Form 3800 or line 25 of Form 3800 is more than zero.\n\n    // TODO: 3. You claim the qualified electric vehicle credit (Form 8834), the personal use part of the alternative fuel vehicle refueling property credit (Form 8911), or the credit for prior year minimum tax (Form 8801).\n\n    // 4. The total of Form 6251, lines 2c through 3, is negative and line 7 would be greater than line 10 if you didn’t take into account lines 2c through 3.\n    const l2cTo3Total =\n      (this.l2c() ?? 0) +\n      (this.l2d() ?? 0) +\n      (this.l2e() ?? 0) +\n      (this.l2f() ?? 0) +\n      (this.l2g() ?? 0) +\n      (this.l2h() ?? 0) +\n      (this.l2i() ?? 0) +\n      (this.l2j() ?? 0) +\n      (this.l2k() ?? 0) +\n      (this.l2l() ?? 0) +\n      (this.l2m() ?? 0) +\n      (this.l2n() ?? 0) +\n      (this.l2o() ?? 0) +\n      (this.l2p() ?? 0) +\n      (this.l2q() ?? 0) +\n      (this.l2r() ?? 0) +\n      (this.l2s() ?? 0) +\n      (this.l2t() ?? 0) +\n      (this.l3() ?? 0)\n    if (l2cTo3Total < 0 && (this.l7(-l2cTo3Total) ?? 0) > this.l10())\n      return true\n\n    return false\n  }\n\n  l1 = (): number | undefined => {\n    const l15 = this.f1040.l15()\n    if (l15 !== 0) {\n      return l15\n    }\n    return this.f1040.l11() - this.f1040.l14()\n  }\n\n  l2a = (): number | undefined => {\n    if (this.f1040.scheduleA.isNeeded()) {\n      return this.f1040.scheduleA.l7()\n    }\n    return this.f1040.l12a()\n  }\n\n  l2b = (): number | undefined => {\n    return (this.f1040.schedule1.l1() ?? 0) + this.f1040.schedule1.l8z()\n  }\n\n  // TODO: Investment interest expense (difference between regular tax and AMT)\n  l2c = (): number | undefined => undefined\n\n  // TODO: Depletion (difference between regular tax and AMT)\n  l2d = (): number | undefined => undefined\n\n  l2e = (): number | undefined => {\n    return Math.abs(this.f1040.schedule1.l8a() ?? 0)\n  }\n\n  // TODO: Alternative tax net operating loss deduction\n  l2f = (): number | undefined => undefined\n  // TODO: Interest from specified private activity bonds exempt from the regular tax\n  l2g = (): number | undefined => undefined\n  // TODO: Qualified small business stock, see instructions\n  l2h = (): number | undefined => undefined\n\n  // Exercise of incentive stock options (excess of AMT income over regular tax income)\n  l2i = (): number | undefined => {\n    let f3921s = this.f1040.info.f3921s\n    if (this.f1040.info.taxPayer.filingStatus === FilingStatus.MFS) {\n      f3921s = f3921s.filter((w2) => w2.personRole === PersonRole.PRIMARY)\n    }\n    return f3921s.reduce(\n      (amount, f) => (f.fmv - f.exercisePricePerShare) * f.numShares + amount,\n      0\n    )\n  }\n\n  // TODO: Estates and trusts (amount from Schedule K-1 (Form 1041), box 12, code A)\n  l2j = (): number | undefined => undefined\n  // TODO: Disposition of property (difference between AMT and regular tax gain or loss)\n  l2k = (): number | undefined => undefined\n  // TODO: Depreciation on assets placed in service after 1986 (difference between regular tax and AMT)\n  l2l = (): number | undefined => undefined\n  // TODO: Passive activities (difference between AMT and regular tax income or loss)\n  l2m = (): number | undefined => undefined\n  // TODO: Loss limitations (difference between AMT and regular tax income or loss)\n  l2n = (): number | undefined => undefined\n  // TODO: Circulation costs (difference between regular tax and AMT)\n  l2o = (): number | undefined => undefined\n  // TODO: Long-term contracts (difference between AMT and regular tax income)\n  l2p = (): number | undefined => undefined\n  // TODO: Mining costs (difference between regular tax and AMT)\n  l2q = (): number | undefined => undefined\n  // TODO: Research and experimental costs (difference between regular tax and AMT)\n  l2r = (): number | undefined => undefined\n  // TODO: Income from certain installment sales before January 1, 1987\n  l2s = (): number | undefined => undefined\n  // TODO: Intangible drilling costs preference\n  l2t = (): number | undefined => undefined\n\n  // TODO: Other adjustments, including income-based related adjustments\n  l3 = (): number | undefined => undefined\n\n  l4 = (additionalAmount = 0): number | undefined =>\n    additionalAmount +\n    (this.l1() ?? 0) +\n    (this.l2a() ?? 0) -\n    (this.l2b() ?? 0) +\n    (this.l2c() ?? 0) +\n    (this.l2d() ?? 0) +\n    (this.l2e() ?? 0) -\n    (this.l2f() ?? 0) +\n    (this.l2g() ?? 0) +\n    (this.l2h() ?? 0) +\n    (this.l2i() ?? 0) +\n    (this.l2j() ?? 0) +\n    (this.l2k() ?? 0) +\n    (this.l2l() ?? 0) +\n    (this.l2m() ?? 0) +\n    (this.l2n() ?? 0) +\n    (this.l2o() ?? 0) +\n    (this.l2p() ?? 0) +\n    (this.l2q() ?? 0) +\n    (this.l2r() ?? 0) -\n    (this.l2s() ?? 0) +\n    (this.l2t() ?? 0) +\n    (this.l3() ?? 0)\n\n  l5 = (additionalAmount = 0): number | undefined => {\n    const l4 = this.l4(additionalAmount) ?? 0\n    switch (this.f1040.info.taxPayer.filingStatus) {\n      case FilingStatus.S:\n        if (l4 <= 523600) {\n          return 73600\n        }\n        break\n      case FilingStatus.MFJ:\n        if (l4 <= 1047200) {\n          return 114600\n        }\n        break\n      case FilingStatus.MFS:\n        if (l4 <= 523600) {\n          return 57300\n        } else {\n          return 57300\n        }\n        break\n    }\n    // TODO: Handle \"Exemption Worksheet\"\n    return undefined\n  }\n\n  l6 = (additionalAmount = 0): number =>\n    Math.max(\n      0,\n      (this.l4(additionalAmount) ?? 0) - (this.l5(additionalAmount) ?? 0)\n    )\n\n  requiresPartIII = (): boolean => {\n    // If you reported capital gain distributions directly on Form 1040 or 1040-SR, line 7;\n    // you reported qualified dividends on Form 1040 or 1040-SR, line 3a;\n    // or you had a gain on both lines 15 and 16 of Schedule D (Form 1040) (as refigured for the AMT, if necessary),\n    // complete Part III on the back and enter the amount from line 40 here.\n    return (\n      this.f1040.l7() !== undefined ||\n      this.f1040.l3a() !== undefined ||\n      (this.f1040.scheduleD.l15() > 0 && this.f1040.scheduleD.l16() > 0)\n    )\n  }\n\n  l7 = (additionalAmount = 0): number | undefined => {\n    const l6 = this.l6(additionalAmount)\n    if (l6 === 0) {\n      return 0\n    }\n\n    // TODO: Handle Form 2555\n    const f2555 = this.f1040.f2555\n    if (\n      f2555 !== undefined &&\n      (f2555.l36() > 0 || f2555.l42() > 0 || f2555.l50() > 0)\n    ) {\n      // TODO: Foreign Earned Income Tax Worksheet—Line 7\n    }\n\n    // Use line 40 if Part III is required\n    if (this.requiresPartIII()) {\n      return this.part3().l40\n    }\n\n    const cap =\n      this.f1040.info.taxPayer.filingStatus === FilingStatus.MFS\n        ? 99950\n        : 199900\n    if (l6 <= cap) {\n      return l6 * 0.26\n    }\n    return l6 * 0.28\n  }\n\n  // TODO: Alternative minimum tax foreign tax credit\n  l8 = (): number | undefined => undefined\n\n  l9 = (additionalAmount = 0): number => {\n    const l6 = this.l6(additionalAmount)\n    if (l6 === 0) {\n      return 0\n    }\n    return (this.l7(additionalAmount) ?? 0) - (this.l8() ?? 0)\n  }\n\n  // Add Form 1040 or 1040-SR, line 16 (minus any tax from Form 4972),\n  // and Schedule 2 (Form 1040), line 2.\n  // Subtract from the result Schedule 3 (Form 1040), line 1\n  // and any negative amount reported on Form 8978, line 14 (treated as a positive number).\n  // If zero or less, enter -0-.\n  // TODO: If you used Schedule J to figure your tax on Form 1040 or 1040-SR, line 16, refigure that tax without using Schedule J before completing this line. See instructions\n  l10 = (): number => {\n    const f1040L16 = this.f1040.l16() ?? 0\n    const f4972 = this.f1040.f4972?.tax() ?? 0\n    const sch2L2 = this.f1040.schedule2.l2() ?? 0\n    const sch3L1 = this.f1040.schedule3.l1() ?? 0\n    const f8978L14 = Math.abs(0) // TODO: Form 8978\n    return Math.max(0, f1040L16 - f4972 + sch2L2 - sch3L1 - f8978L14)\n  }\n\n  l11 = (): number => {\n    const l6 = this.l6()\n    if (l6 === 0) {\n      return 0\n    }\n    return Math.max(0, this.l9() - this.l10())\n  }\n\n  part3 = (): Part3 => {\n    if (!this.requiresPartIII()) {\n      return {}\n    }\n    const fs = this.f1040.info.taxPayer.filingStatus\n    const qdivWorksheet = this.f1040.qualifiedAndCapGainsWorksheet\n    const schDWksht = this.f1040.scheduleD.taxWorksheet\n    const usingTaxWorksheet = schDWksht.isNeeded()\n\n    const l18Consts: [number, number] = (() => {\n      if (this.f1040.info.taxPayer.filingStatus === FilingStatus.MFS) {\n        return [99950, 1999]\n      }\n      return [199900, 3998]\n    })()\n\n    const l19Value: { [k in FilingStatus]: number } = {\n      [FilingStatus.MFJ]: 80800,\n      [FilingStatus.W]: 80800,\n      [FilingStatus.S]: 40400,\n      [FilingStatus.MFS]: 40400,\n      [FilingStatus.HOH]: 54100\n    }\n\n    const l25Value: { [k in FilingStatus]: number } = {\n      [FilingStatus.MFJ]: 501600,\n      [FilingStatus.W]: 501600,\n      [FilingStatus.S]: 445860,\n      [FilingStatus.MFS]: 250800,\n      [FilingStatus.HOH]: 473750\n    }\n\n    const l12 = this.l6()\n\n    // TODO - for F2555, see the instructions for amount\n    const l13: number = (() => {\n      if (usingTaxWorksheet) {\n        return schDWksht.l13() ?? 0\n      }\n\n      return qdivWorksheet?.l4() ?? 0\n    })()\n\n    const l14 = this.f1040.scheduleD.l19() ?? 0\n\n    const l15 = (() => {\n      if (!usingTaxWorksheet) {\n        return l13\n      }\n      return Math.min(l13 + l14, schDWksht.l10() ?? 0)\n    })()\n\n    const l16 = Math.min(l12, l15)\n\n    const l17 = l12 - l16\n\n    const l18 = (() => {\n      const [c1, c2] = l18Consts\n\n      if (l17 <= c1) {\n        return l17 * 0.26\n      }\n      return l17 * 0.28 - c2\n    })()\n\n    const l19 = l19Value[fs]\n\n    const l20 = (() => {\n      if (usingTaxWorksheet) {\n        return schDWksht.l14() ?? 0\n      }\n\n      if (qdivWorksheet !== undefined) {\n        return qdivWorksheet.l5()\n      }\n\n      return Math.max(0, this.f1040.l15())\n    })()\n\n    const l21 = Math.max(0, l19 - l20)\n\n    const l22 = Math.min(l12, l13)\n\n    const l23 = Math.min(l21, l22)\n\n    const l24 = Math.max(0, l22 - l23)\n\n    const l25 = l25Value[fs]\n\n    const l26 = l21\n\n    // TODO - see instructions for F2555\n    const l27 = (() => {\n      if (usingTaxWorksheet) {\n        return schDWksht.l21() ?? 0\n      }\n\n      if (qdivWorksheet !== undefined) {\n        return qdivWorksheet.l5()\n      }\n\n      return Math.max(0, this.f1040.l15())\n    })()\n\n    const l28 = l26 + l27\n\n    const l29 = Math.max(0, l25 - l28)\n\n    const l30 = Math.min(l24, l29)\n\n    const l31 = l30 * 0.15\n\n    const l32 = l23 + l30\n\n    const l33 = l22 - l32\n\n    const l34 = l33 * 0.2\n\n    const l35 = l17 + l32 + l33\n\n    const l36 = l12 - l35\n\n    const l37 = l36 * 0.25\n\n    const l38 = l18 + l31 + l34 + l37\n\n    const l39 = (() => {\n      // numbers referenced here are the same as l18.\n      const [c1, c2] = l18Consts\n      if (l12 <= c1) {\n        return l12 * 0.26\n      }\n      return l12 * 0.28 - c2\n    })()\n\n    const l40 = Math.min(l38, l39)\n\n    return {\n      l12,\n      l13,\n      l14,\n      l15,\n      l16,\n      l17,\n      l18,\n      l19,\n      l20,\n      l21,\n      l22,\n      l23,\n      l24,\n      l25,\n      l26,\n      l27,\n      l28,\n      l29,\n      l30,\n      l31,\n      l32,\n      l33,\n      l34,\n      l35,\n      l36,\n      l37,\n      l38,\n      l39,\n      l40\n    }\n  }\n\n  fields = (): Field[] => {\n    const p3 = this.part3()\n    return [\n      this.f1040.namesString(),\n      this.f1040.info.taxPayer.primaryPerson.ssid,\n      // Part I\n      this.l1(),\n      this.l2a(),\n      this.l2b(),\n      this.l2c(),\n      this.l2d(),\n      this.l2e(),\n      this.l2f(),\n      this.l2g(),\n      this.l2h(),\n      this.l2i(),\n      this.l2j(),\n      this.l2k(),\n      this.l2l(),\n      this.l2m(),\n      this.l2n(),\n      this.l2o(),\n      this.l2p(),\n      this.l2q(),\n      this.l2r(),\n      this.l2s(),\n      this.l2t(),\n      this.l3(),\n      this.l4(),\n      // Part II\n      this.l5(),\n      this.l6(),\n      this.l7(),\n      this.l8(),\n      this.l9(),\n      this.l10(),\n      this.l11(),\n      // Part III\n      p3.l12,\n      p3.l13,\n      p3.l14,\n      p3.l15,\n      p3.l16,\n      p3.l17,\n      p3.l18,\n      p3.l19,\n      p3.l20,\n      p3.l21,\n      p3.l22,\n      p3.l23,\n      p3.l24,\n      p3.l25,\n      p3.l26,\n      p3.l27,\n      p3.l28,\n      p3.l29,\n      p3.l30,\n      p3.l31,\n      p3.l32,\n      p3.l33,\n      p3.l34,\n      p3.l35,\n      p3.l36,\n      p3.l37,\n      p3.l38,\n      p3.l39,\n      p3.l40\n    ]\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8582.ts",
    "content": "import { MatrixRow } from './ScheduleE'\nimport F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n/**\n * Referenced from line 22 of Schedule E\n * TODO: Not implemented\n */\nexport default class F8582 extends F1040Attachment {\n  tag = 'f8562'\n  sequenceIndex = 999\n\n  // TODO: 'Deducible rental estate loss after limitation, assuming all allowed'\n  deductibleRealEstateLossAfterLimitation = (): MatrixRow =>\n    this.f1040.scheduleE.rentalNet().map((v) => {\n      if (v === undefined || v >= 0) {\n        return undefined\n      }\n      return v\n    }) as MatrixRow\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8814.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F8814 extends F1040Attachment {\n  tag: FormTag = 'f8814'\n  sequenceIndex = 999\n\n  // TODO: required from schedule EIC, pub596, worksheet 1\n  l1b = (): number | undefined => undefined\n\n  tax = (): number => 0\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8853.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n// Not yet implemented\nexport default class F8853 extends F1040Attachment {\n  tag: FormTag = 'f8853'\n  sequenceIndex = 999\n\n  l1 = (): number | undefined => undefined\n  l2 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8863.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n// Not yet implemented\nexport default class F8863 extends F1040Attachment {\n  tag: FormTag = 'f8863'\n  sequenceIndex = 999\n\n  l8 = (): number | undefined => undefined\n  l19 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8888.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented yet\n */\nexport default class F8888 extends F1040Attachment {\n  tag: FormTag = 'f8888'\n  sequenceIndex = 999\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8889.ts",
    "content": "import { Information, Person, HealthSavingsAccount } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport F8853 from './F8853'\nimport { CURRENT_YEAR, healthSavingsAccounts } from '../data/federal'\nimport F1040Attachment from './F1040Attachment'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype ContributionType = 'self-only' | 'family'\ntype PerMonthContributionType = {\n  amount: number[]\n  type: ContributionType[]\n}\n\nexport default class F8889 extends F1040Attachment {\n  tag: FormTag = 'f8889'\n  sequenceIndex = 52\n  // these should only be the HSAs that belong to this person\n  // the person can be either the primary person or the spouse\n  hsas: HealthSavingsAccount<Date>[]\n  f8853?: F8853\n  person: Person\n  state: Information\n  calculatedCoverageType: 'self-only' | 'family'\n  perMonthContributions: PerMonthContributionType\n  readonly firstDayOfLastMonth: Date\n\n  isNeeded = (): boolean => {\n    return this.f1040.info.healthSavingsAccounts.some(\n      (h) => h.personRole === this.person.role || h.coverageType === 'family'\n    )\n  }\n\n  constructor(f1040: F1040, person: Person) {\n    super(f1040)\n    this.f8853 = f1040.f8853\n    this.person = person\n    this.state = f1040.info\n    // The relevant HSAs are the ones either for this person or any that\n    // have family coverage.\n    this.hsas = this.state.healthSavingsAccounts\n      .filter((h) => {\n        if (h.personRole == person.role || h.coverageType == 'family') {\n          return true\n        }\n        return false\n      })\n      .map((h) => {\n        return {\n          ...h,\n          startDate: new Date(h.startDate),\n          endDate: new Date(h.endDate)\n        }\n      })\n    this.calculatedCoverageType = 'self-only'\n    this.firstDayOfLastMonth = new Date(CURRENT_YEAR, 11, 1)\n    this.perMonthContributions = {\n      amount: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n      type: new Array<ContributionType>(12)\n    }\n  }\n\n  calculatePerMonthLimits = (): void => {\n    for (\n      let index = 0;\n      index < this.perMonthContributions.amount.length;\n      index++\n    ) {\n      // for each month check each HSA to see if we are covered.\n      this.hsas.forEach((h) => {\n        const firstDayOfThisMonth = new Date(CURRENT_YEAR, index, 1)\n        if (\n          h.startDate <= firstDayOfThisMonth &&\n          h.endDate >= firstDayOfThisMonth\n        ) {\n          // the coverage limit for that month is based on the type of coverage of the\n          // HSA. If you have both types of HSA coverage for that month, then the family\n          // coverage limit wins out. Since family coverage limit is higher we can just\n          // take the max of the coverage limit for this month.\n          if (\n            this.perMonthContributions.amount[index] <\n            healthSavingsAccounts.contributionLimit[h.coverageType]\n          ) {\n            this.perMonthContributions.amount[index] =\n              healthSavingsAccounts.contributionLimit[h.coverageType]\n            this.perMonthContributions.type[index] = h.coverageType\n          }\n        }\n      })\n    }\n    // The calculated coverage type is whichever one was in effect for longer\n    let familyMonthCount = 0\n    let singleMonthCount = 0\n    this.perMonthContributions.amount.forEach((m) => {\n      if (m == healthSavingsAccounts.contributionLimit.family) {\n        familyMonthCount += 1\n      } else if (m == healthSavingsAccounts.contributionLimit['self-only']) {\n        singleMonthCount += 1\n      }\n    })\n    if (familyMonthCount >= singleMonthCount) {\n      this.calculatedCoverageType = 'family'\n    } else {\n      this.calculatedCoverageType = 'self-only'\n    }\n  }\n\n  /* If you are an eligible individual on the first day of the last month of your tax year \n     (December 1 for most taxpayers), you are considered to be an eligible individual \n     for the entire year.\n    */\n  lastMonthRule = (): boolean => {\n    return this.hsas.some((hsa) => hsa.endDate >= this.firstDayOfLastMonth)\n  }\n\n  /*If, on the first day of the last month of your tax year (December 1 for most taxpayers), \n    you had family coverage, check the \"family\" box.\n  */\n  lastMonthCoverage = (): string | undefined => {\n    let coverage = undefined\n    for (const hsa of this.hsas) {\n      if (hsa.endDate >= this.firstDayOfLastMonth) {\n        if (hsa.coverageType == 'family') {\n          coverage = 'family'\n          break\n        }\n        coverage = 'self-only'\n      }\n    }\n    return coverage\n  }\n\n  fullYearHsa = (): boolean => {\n    return this.hsas.some(\n      (hsa) =>\n        hsa.startDate <= new Date(CURRENT_YEAR, 0, 1) &&\n        hsa.endDate >= this.firstDayOfLastMonth\n    )\n  }\n\n  contributionLimit = (): number => {\n    /*If you were under age 55 at the end of 2020 and, on the first day of every month during 2020, \n    you were, or were considered, an eligible individual with the same coverage, enter $3,550 \n    ($7,100 for family coverage). All others, see the instructions for the amount to enter.\n    */\n    /*If the last-month rule (see Last-month rule, earlier) applies, you are considered an eligible individual \n      for the entire year. You are treated as having the same HDHP coverage for the entire year as you had on \n      the first day of the last month of your tax year.\n      */\n    if (this.lastMonthRule()) {\n      // If, on the first day of the last month of your tax year (December 1 for most taxpayers),\n      // you had family coverage, check the \"family\" box.\n      const lastMonthCoverage = this.lastMonthCoverage()\n      if (lastMonthCoverage !== undefined) {\n        if (lastMonthCoverage === 'family') {\n          this.calculatedCoverageType = 'family'\n          return healthSavingsAccounts.contributionLimit.family\n        } else if (lastMonthCoverage === 'self-only') {\n          this.calculatedCoverageType = 'self-only'\n          return healthSavingsAccounts.contributionLimit['self-only']\n        }\n      }\n    }\n    /* If you don't have coverage in the last month, then you need to figure out\n       your contribution limit. If you don't have coverage for that month then\n       your contribution limit is 0. So let's initialize our per-month contribution\n       limit based on that.\n     */\n    this.calculatePerMonthLimits()\n    return Math.round(\n      this.perMonthContributions.amount.reduce((a, b) => a + b) / 12\n    )\n  }\n\n  splitFamilyContributionLimit = (): number | undefined => {\n    /* if you and your spouse each have separate HSAs and had family coverage under an HDHP at any time during 2020*/\n    /* If you are treated as having family coverage for each month, divide the amount on line 5 equally between you \n       and your spouse, unless you both agree on a different allocation (such as allocating nothing to one spouse).\n       Enter your allocable share on line 6.*/\n    /* Example. In 2020, you are an eligible individual and have self-only HDHP coverage. In March you marry and as\n       of April 1 you have family HDHP coverage. Neither you nor your spouse qualify for the additional contribution\n       amount. Your spouse has a separate HSA and is an eligible individual from April 1 to December 31, 2020. \n       Because you and your spouse are considered to have family coverage on December 1, your contribution limit is\n       $7,100 (the family coverage maximum). You and your spouse can divide this amount in any allocation to which\n      you agree (such as allocating nothing to one spouse).*/\n    if (!this.hsas.some((h) => h.coverageType === 'family')) {\n      return this.l5()\n    }\n\n    if (this.lastMonthCoverage() === 'family') {\n      // TODO: This hard codes the allocation at 50% for each spouse but the\n      // rules say any contribution allowcation is allowed\n      return Math.round(this.l5() / 2)\n    } else {\n      // get the number of months of family coverage\n      const familyMonths: number = this.perMonthContributions.type.filter(\n        (t) => t === 'family'\n      ).length\n\n      // TODO: This hard codes the allocation at 50% for each spouse but the\n      // rules say any contribution allowcation is allowed\n      const familyContribution: number =\n        (familyMonths * healthSavingsAccounts.contributionLimit['family']) /\n        12 /\n        2\n\n      // Add this to the contributions of the self-only portion of the year\n      const selfMonths: number = 12 - familyMonths\n\n      const selfContribution: number =\n        (selfMonths * healthSavingsAccounts.contributionLimit['self-only']) / 12\n\n      return familyContribution + selfContribution\n    }\n  }\n\n  /*Include on line 2 only those amounts you, or others on your behalf, contributed to your HSA in 2020. \n    Also, include those contributions made from January 1, 2021, through April 15, 2021, that were for 2020. \n    Do not include employer contributions (see line 9) or amounts rolled over from another HSA or Archer MSA. \n    See Rollovers, earlier. Also, do not include any qualified HSA funding distributions (see line 10). \n    Contributions to an employee's account through a cafeteria plan are treated as employer contributions \n    and are not included on line 2.\n  */\n  l2 = (): number =>\n    this.hsas.reduce((total, hsa) => hsa.contributions + total, 0)\n\n  l3 = (): number => this.contributionLimit()\n  l4 = (): number => sumFields([this.f8853?.l1(), this.f8853?.l2()])\n  l5 = (): number => this.l3() - this.l4()\n  l6 = (): number | undefined => this.splitFamilyContributionLimit()\n  // TODO: Additional contirbution amount. Need to know the age of the user\n  l7 = (): number | undefined => undefined\n  l8 = (): number => sumFields([this.l6(), this.l7()])\n  // Employer contributions are listed in W2 box 12 with code W\n  l9 = (): number =>\n    this.state.w2s\n      .filter((w2) => w2.personRole == this.person.role)\n      .reduce((res, w2) => res + (w2.box12?.W ?? 0), 0)\n  l10 = (): number | undefined => undefined\n  l11 = (): number => sumFields([this.l9(), this.l10()])\n  l12 = (): number => {\n    const tmp = this.l8() - this.l11()\n    return tmp < 0 ? 0 : tmp\n  }\n  l13 = (): number | undefined =>\n    this.l2() < this.l12() ? this.l2() : this.l12()\n  l14a = (): number =>\n    this.hsas.reduce((total, hsa) => hsa.totalDistributions + total, 0)\n  l14b = (): number | undefined => undefined\n  l14c = (): number => Math.max(0, this.l14a() - (this.l14b() ?? 0))\n  l15 = (): number =>\n    this.hsas.reduce((total, hsa) => hsa.qualifiedDistributions + total, 0)\n  l16 = (): number => Math.max(0, this.l14c() - this.l15())\n  l17a = (): boolean => false\n  // TODO: add in logic for when line 17a is true\n  l17b = (): number | undefined => Math.round(this.l16() * 0.2)\n\n  l18 = (): number | undefined => undefined\n  l19 = (): number | undefined => undefined\n  l20 = (): number => sumFields([this.l18(), this.l19()])\n  l21 = (): number => Math.round(this.l20() * 0.1)\n\n  fields = (): Field[] => [\n    `${this.person.firstName} ${this.person.lastName}`,\n    this.person.ssid,\n    this.calculatedCoverageType === 'self-only', // line 1: self-only check box\n    this.calculatedCoverageType === 'family', // line 1: family checkbox\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14a(),\n    this.l14b(),\n    this.l14c(),\n    this.l15(),\n    this.l16(),\n    this.l17a(),\n    this.l17b(),\n    this.l18(),\n    this.l19(),\n    this.l20(),\n    this.l21()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8910.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented\n */\nexport default class F8910 extends F1040Attachment {\n  sequenceIndex = 999\n  tag: FormTag = 'f8910'\n\n  l15 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8919.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\n// TODO: Not implemented yet\nexport default class F8919 extends F1040Attachment {\n  tag = 'f8919'\n  sequenceIndex = 999\n\n  l6 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8936.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\nexport default class F8936 extends F1040Attachment {\n  tag: FormTag = 'f8936'\n  sequenceIndex = 999\n\n  l15 = (): number | undefined => undefined\n  l23 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8949.ts",
    "content": "import { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Asset, isSold, SoldAsset } from 'ustaxes/core/data'\nimport F1040Attachment from './F1040Attachment'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype EmptyLine = [\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined\n]\n\ntype Line =\n  | [string, string, string, number, number, undefined, undefined, number]\n  | EmptyLine\nconst emptyLine: EmptyLine = [\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined,\n  undefined\n]\n\nconst showDate = (date: Date): string =>\n  `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`\n\nconst toLine = (position: SoldAsset<Date>): Line => [\n  position.name,\n  showDate(position.openDate),\n  showDate(position.closeDate),\n  position.closePrice * position.quantity,\n  position.openPrice * position.quantity,\n  undefined,\n  undefined,\n  (position.closePrice - position.openPrice) * position.quantity\n]\n\nconst NUM_SHORT_LINES = 14\nconst NUM_LONG_LINES = 14\n\nconst padUntil = <A, B>(xs: A[], v: B, n: number): (A | B)[] => {\n  if (xs.length >= n) {\n    return xs\n  }\n  return [...xs, ...Array.from(Array(n - xs.length)).map(() => v)]\n}\n\nexport default class F8949 extends F1040Attachment {\n  tag: FormTag = 'f8949'\n  sequenceIndex = 12.1\n\n  index = 0\n\n  constructor(f1040: F1040, index = 0) {\n    super(f1040)\n    this.index = index\n  }\n\n  isNeeded = (): boolean => this.thisYearSales().length > 0\n\n  copies = (): F8949[] => {\n    if (this.index === 0) {\n      const extraCopiesNeeded = Math.round(\n        Math.max(\n          this.thisYearShortTermSales().length / NUM_SHORT_LINES,\n          this.thisYearLongTermSales().length / NUM_LONG_LINES\n        )\n      )\n      return Array.from(Array(extraCopiesNeeded)).map(\n        (_, i) => new F8949(this.f1040, i + 1)\n      )\n    }\n    return []\n  }\n\n  // Assuming we're only handling non-reported transactions\n  part1BoxA = (): boolean => false\n  part1BoxB = (): boolean => false\n  part1BoxC = (): boolean => true\n  part2BoxD = (): boolean => false\n  part2BoxE = (): boolean => false\n  part2BoxF = (): boolean => true\n\n  thisYearSales = (): SoldAsset<Date>[] =>\n    this.f1040.assets.filter(\n      (p) => isSold(p) && p.closeDate.getFullYear() === 2021\n    ) as SoldAsset<Date>[]\n\n  thisYearLongTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearSales().filter((p) => this.isLongTerm(p))\n\n  thisYearShortTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearSales().filter((p) => !this.isLongTerm(p))\n\n  // in milliseconds\n  oneDay = 1000 * 60 * 60 * 24\n\n  isLongTerm = (p: Asset<Date>): boolean => {\n    if (p.closeDate === undefined || p.closePrice === undefined) return false\n    const milliInterval = p.closeDate.getTime() - p.openDate.getTime()\n    return milliInterval / this.oneDay > 366\n  }\n\n  /**\n   * Take the short term transactions that fit on this copy of the 8949\n   */\n  shortTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearShortTermSales().slice(\n      this.index * NUM_SHORT_LINES,\n      (this.index + 1) * NUM_SHORT_LINES\n    )\n\n  /**\n   * Take the long term transactions that fit on this copy of the 8949\n   */\n  longTermSales = (): SoldAsset<Date>[] =>\n    this.thisYearLongTermSales().slice(\n      this.index * NUM_LONG_LINES,\n      (this.index + 1) * NUM_LONG_LINES\n    )\n\n  shortTermLines = (): Line[] =>\n    padUntil(\n      this.shortTermSales().map((p) => toLine(p)),\n      emptyLine,\n      NUM_SHORT_LINES\n    )\n  longTermLines = (): Line[] =>\n    padUntil(\n      this.longTermSales().map((p) => toLine(p)),\n      emptyLine,\n      NUM_LONG_LINES\n    )\n\n  shortTermTotalProceeds = (): number =>\n    this.shortTermSales().reduce(\n      (acc, p) => acc + p.closePrice * p.quantity - (p.closeFee ?? 0),\n      0\n    )\n\n  shortTermTotalCost = (): number =>\n    this.shortTermSales().reduce(\n      (acc, p) => acc + p.openPrice * p.quantity + p.openFee,\n      0\n    )\n\n  shortTermTotalGain = (): number =>\n    this.shortTermTotalProceeds() - this.shortTermTotalCost()\n\n  // TODO: handle adjustments column.\n  shortTermTotalAdjustments = (): number | undefined => undefined\n\n  longTermTotalProceeds = (): number =>\n    this.longTermSales().reduce(\n      (acc, p) => acc + p.closePrice * p.quantity - (p.closeFee ?? 0),\n      0\n    )\n\n  longTermTotalCost = (): number =>\n    this.longTermSales().reduce(\n      (acc, p) => acc + p.openPrice * p.quantity + p.openFee,\n      0\n    )\n\n  longTermTotalGain = (): number =>\n    this.longTermTotalProceeds() - this.longTermTotalCost()\n\n  // TODO: handle adjustments column.\n  longTermTotalAdjustments = (): number | undefined => undefined\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.part1BoxA(),\n    this.part1BoxB(),\n    this.part1BoxC(),\n    ...this.shortTermLines().flat(),\n    this.shortTermTotalProceeds(),\n    this.shortTermTotalCost(),\n    undefined, // greyed out field\n    this.shortTermTotalAdjustments(),\n    this.shortTermTotalGain(),\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.part2BoxD(),\n    this.part2BoxE(),\n    this.part2BoxF(),\n    ...this.longTermLines().flat(),\n    this.longTermTotalProceeds(),\n    this.longTermTotalCost(),\n    undefined, // greyed out field\n    this.longTermTotalAdjustments(),\n    this.longTermTotalGain()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8959.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { fica } from '../data/federal'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F8959 extends F1040Attachment {\n  tag: FormTag = 'f8959'\n  sequenceIndex = 71\n\n  isNeeded = (): boolean => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const totalW2Income = this.f1040.info.w2s\n      .map((w2) => w2.medicareIncome)\n      .reduce((l, r) => l + r, 0)\n    return (\n      fica.additionalMedicareTaxThreshold(filingStatus) <\n      totalW2Income + (this.f1040.scheduleSE.l6() ?? 0)\n    )\n  }\n\n  thresholdFromFilingStatus = (): number =>\n    fica.additionalMedicareTaxThreshold(this.f1040.info.taxPayer.filingStatus)\n\n  computeAdditionalMedicareTax = (compensation: number): number =>\n    fica.additionalMedicareTaxRate * compensation\n\n  // Part I: Additional Medicare Tax on Medicare Wages\n  l1 = (): number => this.f1040.medicareWages()\n\n  l2 = (): number | undefined => this.f1040.f4137?.l6()\n  l3 = (): number | undefined => this.f1040.f8919?.l6()\n  l4 = (): number => sumFields([this.l1(), this.l2(), this.l3()])\n\n  l5 = (): number => this.thresholdFromFilingStatus()\n  l6 = (): number => Math.max(0, this.l4() - this.l5())\n\n  l7 = (): number | undefined => this.computeAdditionalMedicareTax(this.l6())\n\n  // Part II: Additional Medicare Tax on Self-Employment Income\n  l8 = (): number | undefined => this.f1040.scheduleSE.l6()\n  l9 = (): number => this.thresholdFromFilingStatus()\n  l10 = (): number => this.l4()\n  l11 = (): number => Math.max(0, this.l9() - this.l10())\n\n  l12 = (): number => Math.max(0, (this.l8() ?? 0) - this.l11())\n\n  l13 = (): number | undefined => this.computeAdditionalMedicareTax(this.l12())\n\n  // Part III: Additional Medicare Tax on Railroad Retirement Tax Act\n  // (RRTA) Compensation\n  l14 = (): number | undefined => undefined // TODO: RRTA in W2\n  l15 = (): number => this.thresholdFromFilingStatus()\n  l16 = (): number => Math.max(0, (this.l14() ?? 0) - this.l15())\n\n  l17 = (): number => this.computeAdditionalMedicareTax(this.l16())\n\n  // Part IV: Total Medicare Tax\n  l18 = (): number => sumFields([this.l7(), this.l13(), this.l17()])\n\n  // Part V: Withholding Reconciliation\n  l19 = (): number =>\n    this.f1040\n      .validW2s()\n      .map((w2) => w2.medicareWithholding)\n      .reduce((l, r) => l + r, 0)\n\n  l20 = (): number => this.l1()\n  l21 = (): number => fica.regularMedicareTaxRate * this.l20()\n\n  l22 = (): number => Math.max(0, this.l19() - this.l21())\n\n  l23 = (): number | undefined => 0 // TODO: RRTA\n  l24 = (): number => sumFields([this.l22(), this.l23()])\n\n  toSchedule2l11 = (): number => this.l18()\n  to1040l25c = (): number => this.l24()\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n\n    this.l15(),\n    this.l16(),\n    this.l17(),\n\n    this.l18(),\n\n    this.l19(),\n    this.l20(),\n    this.l21(),\n    this.l22(),\n    this.l23(),\n    this.l24()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8960.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { netInvestmentIncomeTax } from '../data/federal'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class F8960 extends F1040Attachment {\n  tag: FormTag = 'f8960'\n  sequenceIndex = 72\n\n  isNeeded = (): boolean => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const totalW2Income = this.f1040.info.w2s\n      .map((w2) => w2.income)\n      .reduce((l, r) => l + r, 0)\n    return netInvestmentIncomeTax.taxThreshold(filingStatus) < totalW2Income\n  }\n\n  //Taxable Interest\n  l1 = (): number | undefined => this.f1040.l2b()\n\n  // Ordinary Dividends\n  l2 = (): number | undefined => this.f1040.l3b()\n  /* Enter the gross income from all annuities, except annuities paid from the following.\n\n    - Section 401—Qualified pension, profit-sharing, and stock bonus plans.\n    - Section 403(a)—Qualified annuity plans purchased by an employer for an employee.\n    - Section 403(b)—Annuities purchased by public schools or section 501(c)(3) tax-exempt organizations.\n    - Section 408—Individual Retirement Accounts (IRAs) or Annuities.\n    - Section 408A—Roth IRAs.\n    - Section 457(b)—Deferred compensation plans of a state and local government and tax-exempt organization.\n    - Amounts paid in consideration for services (for example, distributions from a foreign retirement plan that \n    are paid in the form of an annuity and include investment income that was earned by the retirement plan).\n\n    How your annuities are reported to you. Net investment income from annuities is reported to a recipient on \n    Form 1099-R, Distributions From Pensions, Annuities, Retirement or Profit-Sharing Plans, IRAs, Insurance \n    Contracts, etc. However, the amount reported on Form 1099-R may also include annuity payments from \n    retirement plans that are exempt from NIIT. Amounts subject to NIIT should be identified with code \"D\" in box 7. \n    If code \"D\" is shown in box 7 of Form 1099-R, include on Form 8960, line 3, the taxable amount reported \n    on Form 1099-R, box 2a. However, if the payor checks box 2b indicating the taxable amount can’t be determined, \n    you may need to calculate the taxable portion of your distribution. See Pub. 939, General Rule for Pensions \n    and Annuities, and Pub. 575, Pension and Annuity Income, for details.\n  */\n  l3 = (): number | undefined => undefined\n  /* Rental Real Estate, Royalties, Partnerships, S Corporations, and Trusts\n      Enter the following amount from your properly completed return.\n\n      - Schedule 1 (Form 1040), line 5.\n      - Form 1041, line 5.\n      - Form 1041-QFT, the portion of line 4 that’s income and loss that properly \n      would be reported by a trust filing Form 1041 on Form 1041, line 5.\n      - Form 1040-NR, the amount properly reported on the attachment to your Form 1040-NR\n      representing the amount that you would properly include on Schedule 1 (Form 1040), line 5, \n      if you were filing Form 1040 or 1040‐SR and including income and loss only for your period of U.S. residency.\n  */\n  l4a = (): number | undefined => this.f1040.schedule1.l5()\n\n  l4b = (): number | undefined => undefined\n\n  l4c = (): number => sumFields([this.l4a(), this.l4b()])\n\n  // Line 5a-5d: Gains and Losses on the Disassets of Property\n  l5a = (): number => sumFields([this.f1040.l7(), this.f1040.schedule1.l4()])\n  // TODO: implement line 5b and 5c from worksheet.\n  l5b = (): number | undefined => undefined\n  l5c = (): number | undefined => undefined\n  l5d = (): number => sumFields([this.l5a(), this.l5b(), this.l5c()])\n\n  // TODO: Line 6: Adjustments to Investment Income for Certain CFCs and PFICs\n  l6 = (): number | undefined => undefined\n\n  // TODO: Line 7: Other Modifications to Investment Income\n  l7 = (): number | undefined => undefined\n\n  l8 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2(),\n      this.l3(),\n      this.l4c(),\n      this.l5d(),\n      this.l6(),\n      this.l7()\n    ])\n  // Todo: Implement Schedule A\n  l9a = (): number | undefined =>\n    this.f1040.scheduleA.isNeeded() ? this.f1040.scheduleA.l9() : undefined\n  // Line 9b Reasonable method: Total state tax from W2 * Form 8960 Line 8 / 1040 Line 11, Adjusted gross income\n  l9b = (): number | undefined => {\n    const totalStateWithholding = this.f1040\n      .validW2s()\n      .map((w2) => w2.stateWithholding ?? 0)\n      .reduce((l, r) => l + r, 0)\n    const f1040L11 = this.f1040.l11()\n    if (f1040L11 === 0) {\n      return 0\n    }\n    return (totalStateWithholding * this.l8()) / f1040L11\n  }\n  l9c = (): number | undefined => undefined\n  l9d = (): number => sumFields([this.l9a(), this.l9b(), this.l9c()])\n  l10 = (): number | undefined => undefined\n  l11 = (): number => sumFields([this.l9d(), this.l10()])\n\n  l12 = (): number => Math.max(0, this.l8() - this.l11())\n\n  // TODO: This should also take into account values on form 2555 and adjustments for Certain CFCs and Certain PFICs\n  l13 = (): number => this.f1040.l11()\n\n  l14 = (): number =>\n    netInvestmentIncomeTax.taxThreshold(this.f1040.info.taxPayer.filingStatus)\n\n  l15 = (): number => Math.max(0, this.l13() - this.l14())\n  l16 = (): number => (this.l12() < this.l15() ? this.l12() : this.l15())\n\n  l17 = (): number => Math.round(this.l16() * netInvestmentIncomeTax.taxRate)\n\n  // TODO: Estates and Trusts\n  // leave all of the following undefined until we support estates and trusts\n  // these lines are to be left blank for individuals\n  l18a = (): number | undefined => undefined\n  l18b = (): number | undefined => undefined\n  l18c = (): number | undefined => undefined\n\n  l19a = (): number | undefined => undefined\n  l19b = (): number | undefined => undefined\n  l19c = (): number | undefined => undefined\n\n  l20 = (): number | undefined => undefined // this.l19c() < this.l18c()? this.l19c() : this.l18c()\n  l21 = (): number | undefined => undefined // Math.round(this.l20() * netInvestmentIncomeTax.taxRate)\n\n  toSchedule2l12 = (): number | undefined => this.l17()\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    undefined, // Section 6013(g) election checkbox\n    undefined, // Section 6013(h) election checkbox\n    undefined, // Regulations section 1.1411-10(g) election checkbox\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4a(),\n    this.l4b(),\n    this.l4c(),\n    this.l5a(),\n    this.l5b(),\n    this.l5c(),\n    this.l5d(),\n    this.l6(),\n    this.l7(),\n    this.l8(),\n    this.l9a(),\n    this.l9b(),\n    this.l9c(),\n    this.l9d(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    this.l18a(),\n    this.l18b(),\n    this.l18c(),\n    this.l19a(),\n    this.l19b(),\n    this.l19c(),\n    this.l20(),\n    this.l21()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8962.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * TODO: Not yet implemented\n * Net premium tax credit\n */\nexport default class F8962 extends F1040Attachment {\n  tag: FormTag = 'f8962'\n  sequenceIndex = 999\n\n  credit = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8995.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { FilingStatus } from 'ustaxes/core/data'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport function getF8995PhaseOutIncome(filingStatus: FilingStatus): number {\n  let formAMinAmount = 164900\n  if (filingStatus === FilingStatus.MFS) {\n    formAMinAmount = 164925\n  } else if (filingStatus === FilingStatus.MFJ) {\n    formAMinAmount = 329800\n  }\n  return formAMinAmount\n}\n\nfunction ifNumber(\n  num: number | undefined,\n  f: (num: number) => number | undefined\n) {\n  return num !== undefined ? f(num) : undefined\n}\n\nexport default class F8995 extends F1040Attachment {\n  tag: FormTag = 'f8995'\n  sequenceIndex = 999\n\n  applicableK1s = () =>\n    this.f1040.info.scheduleK1Form1065s.filter((k1) => k1.section199AQBI > 0)\n\n  netCapitalGains = (): number => {\n    let rtn = this.f1040.l3a() ?? 0\n    if (this.f1040.scheduleD.isNeeded()) {\n      const l15 = this.f1040.scheduleD.l15()\n      const l16 = this.f1040.scheduleD.l16()\n      const min = Math.min(l15, l16)\n      if (min > 0) rtn += min\n    } else {\n      rtn += this.f1040.l7() ?? 0\n    }\n    return rtn\n  }\n\n  l2 = (): number | undefined =>\n    this.applicableK1s()\n      .map((k1) => k1.section199AQBI)\n      .reduce((c, a) => c + a, 0)\n  l3 = (): number | undefined => undefined\n  l4 = (): number | undefined =>\n    ifNumber(this.l2(), (num) => num + (this.l3() ?? 0))\n  l5 = (): number | undefined => ifNumber(this.l4(), (num) => num * 0.2)\n\n  // TODO: REIT\n  l6 = (): number => 0\n  l7 = (): number => 0\n  l8 = (): number | undefined => ifNumber(this.l6(), (num) => num + this.l7())\n  l9 = (): number | undefined => ifNumber(this.l8(), (num) => num * 0.2)\n\n  l10 = (): number | undefined =>\n    ifNumber(this.l5(), (num) => num + (this.l9() ?? 0))\n  l11 = (): number => this.f1040.l11() - this.f1040.l12c()\n  l12 = (): number => this.netCapitalGains()\n  l13 = (): number => Math.max(0, this.l11() - this.l12())\n  l14 = (): number => this.l13() * 0.2\n  l15 = (): number => Math.min(this.l10() ?? 0, this.l14())\n  l16 = (): number => Math.min(0, (this.l2() ?? 0) + (this.l3() ?? 0))\n  l17 = (): number => Math.min(0, this.l6() + this.l7())\n\n  deductions = (): number => this.l15()\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.applicableK1s()[0]?.partnershipName,\n    this.applicableK1s()[0]?.partnershipEin,\n    this.applicableK1s()[0]?.section199AQBI,\n    this.applicableK1s()[1]?.partnershipName,\n    this.applicableK1s()[1]?.partnershipEin,\n    this.applicableK1s()[1]?.section199AQBI,\n    this.applicableK1s()[2]?.partnershipName,\n    this.applicableK1s()[2]?.partnershipEin,\n    this.applicableK1s()[2]?.section199AQBI,\n    this.applicableK1s()[3]?.partnershipName,\n    this.applicableK1s()[3]?.partnershipEin,\n    this.applicableK1s()[3]?.section199AQBI,\n    this.applicableK1s()[4]?.partnershipName,\n    this.applicableK1s()[4]?.partnershipEin,\n    this.applicableK1s()[4]?.section199AQBI,\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/F8995A.ts",
    "content": "import F8995, { getF8995PhaseOutIncome } from './F8995'\n\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { FilingStatus } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nfunction ifNumber(\n  num: number | undefined,\n  f: (num: number) => number | undefined\n) {\n  return num !== undefined ? f(num) : undefined\n}\n\nexport default class F8995A extends F8995 {\n  tag: FormTag = 'f8995a'\n\n  l2a = (): number | undefined => this.applicableK1s()[0]?.section199AQBI\n  l2b = (): number | undefined => this.applicableK1s()[1]?.section199AQBI\n  l2c = (): number | undefined => this.applicableK1s()[2]?.section199AQBI\n\n  l3a = (): number | undefined => ifNumber(this.l2a(), (num) => num * 0.2)\n  l3b = (): number | undefined => ifNumber(this.l2b(), (num) => num * 0.2)\n  l3c = (): number | undefined => ifNumber(this.l2c(), (num) => num * 0.2)\n\n  // TODO: Allow W2 income with QBI\n  l4a = (): number | undefined => ifNumber(this.l2a(), () => 0)\n  l4b = (): number | undefined => ifNumber(this.l2a(), () => 0)\n  l4c = (): number | undefined => ifNumber(this.l2a(), () => 0)\n\n  l5a = (): number | undefined => ifNumber(this.l4a(), (num) => num * 0.5)\n  l5b = (): number | undefined => ifNumber(this.l4a(), (num) => num * 0.5)\n  l5c = (): number | undefined => ifNumber(this.l4a(), (num) => num * 0.5)\n\n  l6a = (): number | undefined => ifNumber(this.l4a(), (num) => num * 0.25)\n  l6b = (): number | undefined => ifNumber(this.l4a(), (num) => num * 0.25)\n  l6c = (): number | undefined => ifNumber(this.l4a(), (num) => num * 0.25)\n\n  // TODO: Allow UBIA\n  l7a = (): number | undefined => ifNumber(this.l2a(), () => 0)\n  l7b = (): number | undefined => ifNumber(this.l2a(), () => 0)\n  l7c = (): number | undefined => ifNumber(this.l2a(), () => 0)\n\n  l8a = (): number | undefined => ifNumber(this.l7a(), (num) => num * 0.25)\n  l8b = (): number | undefined => ifNumber(this.l7a(), (num) => num * 0.25)\n  l8c = (): number | undefined => ifNumber(this.l7a(), (num) => num * 0.25)\n\n  l9a = (): number | undefined =>\n    ifNumber(this.l6a(), (num) => num + (this.l8a() ?? 0))\n  l9b = (): number | undefined =>\n    ifNumber(this.l6a(), (num) => num + (this.l8b() ?? 0))\n  l9c = (): number | undefined =>\n    ifNumber(this.l6a(), (num) => num + (this.l8c() ?? 0))\n\n  l10a = (): number | undefined =>\n    ifNumber(this.l5a(), (num) => Math.max(num, this.l9a() ?? 0))\n  l10b = (): number | undefined =>\n    ifNumber(this.l5b(), (num) => Math.max(num, this.l9b() ?? 0))\n  l10c = (): number | undefined =>\n    ifNumber(this.l5c(), (num) => Math.max(num, this.l9c() ?? 0))\n\n  l11a = (): number | undefined =>\n    ifNumber(this.l3a(), (num) => Math.min(num, this.l10a() ?? 0))\n  l11b = (): number | undefined =>\n    ifNumber(this.l3b(), (num) => Math.min(num, this.l10b() ?? 0))\n  l11c = (): number | undefined =>\n    ifNumber(this.l3c(), (num) => Math.min(num, this.l10c() ?? 0))\n\n  l12a = (): number | undefined => ifNumber(this.l26a(), (num) => num)\n  l12b = (): number | undefined => ifNumber(this.l26b(), (num) => num)\n  l12c = (): number | undefined => ifNumber(this.l26c(), (num) => num)\n\n  l13a = (): number | undefined =>\n    ifNumber(this.l12a(), (num) => Math.max(num, this.l11a() ?? 0))\n  l13b = (): number | undefined =>\n    ifNumber(this.l12b(), (num) => Math.max(num, this.l11b() ?? 0))\n  l13c = (): number | undefined =>\n    ifNumber(this.l12c(), (num) => Math.max(num, this.l11c() ?? 0))\n\n  // TODO: Patron reduction\n  l14a = (): number | undefined => ifNumber(this.l2a(), () => 0)\n  l14b = (): number | undefined => ifNumber(this.l2a(), () => 0)\n  l14c = (): number | undefined => ifNumber(this.l2a(), () => 0)\n\n  l15a = (): number | undefined =>\n    ifNumber(this.l13a(), (num) => num - (this.l14a() ?? 0))\n  l15b = (): number | undefined =>\n    ifNumber(this.l13b(), (num) => num - (this.l14b() ?? 0))\n  l15c = (): number | undefined =>\n    ifNumber(this.l13c(), (num) => num - (this.l14c() ?? 0))\n\n  l16 = (): number => sumFields([this.l15a(), this.l15b(), this.l15c()])\n\n  l17a = (): number | undefined => ifNumber(this.l3a(), (num) => num)\n  l17b = (): number | undefined => ifNumber(this.l3b(), (num) => num)\n  l17c = (): number | undefined => ifNumber(this.l3c(), (num) => num)\n\n  l18a = (): number | undefined => ifNumber(this.l10a(), (num) => num)\n  l18b = (): number | undefined => ifNumber(this.l10b(), (num) => num)\n  l18c = (): number | undefined => ifNumber(this.l10c(), (num) => num)\n\n  l19a = (): number | undefined =>\n    ifNumber(this.l17a(), (num) => num - (this.l18a() ?? 0))\n  l19b = (): number | undefined =>\n    ifNumber(this.l17b(), (num) => num - (this.l18b() ?? 0))\n  l19c = (): number | undefined =>\n    ifNumber(this.l17c(), (num) => num - (this.l18c() ?? 0))\n\n  l20 = (): number => this.f1040.l11() - this.f1040.l12c()\n  l21 = (): number =>\n    getF8995PhaseOutIncome(this.f1040.info.taxPayer.filingStatus)\n  l22 = (): number => this.l20() - this.l21()\n  l23 = (): number =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ ? 100000 : 50000\n  l24 = (): number => Math.round((this.l22() / this.l23()) * 10000) / 10000 // We want xx.xx%\n\n  l25a = (): number | undefined =>\n    ifNumber(this.l19a(), (num) => num * this.l24())\n  l25b = (): number | undefined =>\n    ifNumber(this.l19b(), (num) => num * this.l24())\n  l25c = (): number | undefined =>\n    ifNumber(this.l19c(), (num) => num * this.l24())\n\n  l26a = (): number | undefined =>\n    ifNumber(this.l17a(), (num) => num - (this.l25a() ?? 0))\n  l26b = (): number | undefined =>\n    ifNumber(this.l17b(), (num) => num - (this.l25b() ?? 0))\n  l26c = (): number | undefined =>\n    ifNumber(this.l17c(), (num) => num - (this.l25c() ?? 0))\n\n  l27 = (): number => this.l16()\n\n  // TODO: REIT\n  l28 = (): number => 0\n  l29 = (): number => 0\n\n  l30 = (): number => Math.max(0, this.l28() + this.l29())\n  l31 = (): number => this.l30() * 0.2\n\n  l32 = (): number => this.l27() + this.l31()\n  l33 = (): number => this.l20()\n  l34 = (): number => this.netCapitalGains()\n  l35 = (): number => this.l33() - this.l34()\n  l36 = (): number => this.l35() * 0.2\n  l37 = (): number => Math.min(this.l32(), this.l36())\n\n  // TODO: DPAD\n  l38 = (): number => 0\n\n  l39 = (): number => this.l37() - this.l38()\n  deductions = (): number => this.l39()\n  l40 = (): number => Math.min(0, this.l28() + this.l29())\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.applicableK1s()[0]?.partnershipName,\n    false, // 1Ab\n    false, // 1Ac\n    this.applicableK1s()[0]?.partnershipEin,\n    false, // 1Ae\n    this.applicableK1s()[1]?.partnershipName,\n    false, // 1Bb\n    false, // 1Bc\n    this.applicableK1s()[1]?.partnershipEin,\n    false, // 1Be\n    this.applicableK1s()[2]?.partnershipName,\n    false, // 1Cb\n    false, // 1Cc\n    this.applicableK1s()[2]?.partnershipEin,\n    false, // 1Ce\n    this.l2a(),\n    this.l2b(),\n    this.l2c(),\n    this.l3a(),\n    this.l3b(),\n    this.l3c(),\n    this.l4a(),\n    this.l4b(),\n    this.l4c(),\n    this.l5a(),\n    this.l5b(),\n    this.l5c(),\n    this.l6a(),\n    this.l6b(),\n    this.l6c(),\n    this.l7a(),\n    this.l7b(),\n    this.l7c(),\n    this.l8a(),\n    this.l8b(),\n    this.l8c(),\n    this.l9a(),\n    this.l9b(),\n    this.l9c(),\n    this.l10a(),\n    this.l10b(),\n    this.l10c(),\n    this.l11a(),\n    this.l11b(),\n    this.l11c(),\n    this.l12a(),\n    this.l12b(),\n    this.l12c(),\n    this.l13a(),\n    this.l13b(),\n    this.l13c(),\n    this.l14a(),\n    this.l14b(),\n    this.l14c(),\n    this.l15a(),\n    this.l15b(),\n    this.l15c(),\n    this.l16(),\n    undefined, // Gray\n    undefined, // Gray\n    this.l17a(),\n    this.l17b(),\n    this.l17c(),\n    this.l18a(),\n    this.l18b(),\n    this.l18c(),\n    this.l19a(),\n    this.l19b(),\n    this.l19c(),\n    this.l20(),\n    undefined, // Gray\n    undefined, // Gray\n    undefined, // Gray\n    this.l21(),\n    undefined, // Gray\n    undefined, // Gray\n    undefined, // Gray\n    this.l22(),\n    undefined, // Gray\n    undefined, // Gray\n    undefined, // Gray\n    this.l23(),\n    undefined, // Gray\n    undefined, // Gray\n    undefined, // Gray\n    (this.l24() * 100).toFixed(2) + '%', // TODO: Percent sign is duplicated, but it prevents Fill.ts from rounding this\n    undefined, // Gray\n    undefined, // Gray\n    undefined, // Gray\n    this.l25a(),\n    this.l25b(),\n    this.l25c(),\n    this.l26a(),\n    this.l26b(),\n    this.l26c(),\n    this.l27(),\n    this.l28(),\n    this.l29(),\n    this.l30(),\n    this.l31(),\n    this.l32(),\n    this.l33(),\n    this.l34(),\n    this.l35(),\n    this.l36(),\n    this.l37(),\n    this.l38(),\n    this.l39(),\n    this.l40()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/Main.ts",
    "content": "import { Asset, Information } from 'ustaxes/core/data'\nimport { Either, run } from 'ustaxes/core/util'\nimport F1040 from './F1040'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { F1040Error } from 'ustaxes/forms/errors'\nimport { validate } from 'ustaxes/forms/F1040Base'\n\nexport const create1040 = (\n  info: Information,\n  assets: Asset<Date>[]\n): Either<F1040Error[], [F1040, Form[]]> =>\n  run(validate(info))\n    .map<[F1040, Form[]]>((info) => {\n      const f1040 = new F1040(info, assets)\n      return [f1040, f1040.schedules()]\n    })\n    .value()\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/Schedule1.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class Schedule1 extends F1040Attachment {\n  tag: FormTag = 'f1040s1'\n  sequenceIndex = 1\n  otherIncomeStrings: Set<string>\n\n  constructor(f1040: F1040) {\n    super(f1040)\n    this.otherIncomeStrings = new Set<string>()\n  }\n\n  isNeeded = (): boolean =>\n    this.f1040.scheduleE.isNeeded() ||\n    (this.f1040.studentLoanInterestWorksheet !== undefined &&\n      this.f1040.studentLoanInterestWorksheet.notMFS() &&\n      this.f1040.studentLoanInterestWorksheet.isNotDependent()) ||\n    this.f1040.f8889.isNeeded() ||\n    (this.f1040.f8889Spouse?.isNeeded() ?? false)\n\n  l1 = (): number | undefined => undefined\n  l2a = (): number | undefined => undefined\n  l2b = (): number | undefined => undefined\n  l3 = (): number | undefined => undefined\n  l4 = (): number | undefined => undefined\n  l5 = (): number | undefined => this.f1040.scheduleE.l41()\n  l6 = (): number | undefined => undefined\n  l7 = (): number | undefined => undefined\n  l8a = (): number | undefined => undefined\n  l8b = (): number | undefined => undefined\n  l8c = (): number | undefined => undefined\n  l8d = (): number | undefined => undefined\n  l8e = (): number | undefined =>\n    sumFields([this.f1040.f8889.l16(), this.f1040.f8889Spouse?.l16()])\n  l8f = (): number | undefined => undefined\n  l8g = (): number | undefined => undefined\n  l8h = (): number | undefined => undefined\n  l8i = (): number | undefined => undefined\n  l8j = (): number | undefined => undefined\n  l8k = (): number | undefined => undefined\n  l8l = (): number | undefined => undefined\n  l8m = (): number | undefined => undefined\n  l8n = (): number | undefined => undefined\n  l8o = (): number | undefined => undefined\n  l8p = (): number | undefined => undefined\n  l8q = (): number | undefined => undefined\n  l8z = (): number => {\n    if (\n      (this.f1040.f8889.isNeeded() && this.f1040.f8889.l20() > 0) ||\n      ((this.f1040.f8889Spouse?.isNeeded() ?? false) &&\n        this.f1040.f8889Spouse?.l20() !== undefined &&\n        this.f1040.f8889Spouse.l20() > 0)\n    ) {\n      this.otherIncomeStrings.add('HSA')\n    }\n\n    return sumFields([this.f1040.f8889.l20(), this.f1040.f8889Spouse?.l20()])\n  }\n\n  l9 = (): number =>\n    sumFields([\n      this.l8a(),\n      this.l8b(),\n      this.l8c(),\n      this.l8d(),\n      this.l8e(),\n      this.l8f(),\n      this.l8g(),\n      this.l8h(),\n      this.l8i(),\n      this.l8j(),\n      this.l8k(),\n      this.l8l(),\n      this.l8m(),\n      this.l8n(),\n      this.l8o(),\n      this.l8p(),\n      this.l8q(),\n      this.l8z()\n    ])\n\n  l10 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2a(),\n      this.l3(),\n      this.l4(),\n      this.l5(),\n      this.l6(),\n      this.l7(),\n      this.l9()\n    ])\n\n  to1040Line8 = (): number => this.l10()\n\n  l11 = (): number | undefined => undefined\n  l12 = (): number | undefined => undefined\n  l13 = (): number | undefined =>\n    sumFields([this.f1040.f8889.l13(), this.f1040.f8889Spouse?.l13()])\n  l14 = (): number | undefined => undefined\n  l15 = (): number | undefined => this.f1040.scheduleSE.l13()\n  l16 = (): number | undefined => undefined\n  l17 = (): number | undefined => undefined\n  l18 = (): number | undefined => undefined\n  l19a = (): number | undefined => undefined\n  l19b = (): string | undefined => undefined\n  l19c = (): string | undefined => undefined\n  l20 = (): number | undefined => undefined\n  l21 = (): number | undefined => this.f1040.studentLoanInterestWorksheet?.l9()\n  // Reserved for future use\n  l22 = (): string | undefined => undefined\n  l23 = (): number | undefined => undefined\n  l24a = (): number | undefined => undefined\n  l24b = (): number | undefined => undefined\n  l24c = (): number | undefined => undefined\n  l24d = (): number | undefined => undefined\n  l24e = (): number | undefined => undefined\n  l24f = (): number | undefined => undefined\n  l24g = (): number | undefined => undefined\n  l24h = (): number | undefined => undefined\n  l24i = (): number | undefined => undefined\n  l24j = (): number | undefined => undefined\n  l24k = (): number | undefined => undefined\n  l24zDesc = (): string | undefined => undefined\n  l24zDesc2 = (): string | undefined => undefined\n  l24z = (): number | undefined => undefined\n\n  l25 = (): number =>\n    sumFields([\n      this.l24a(),\n      this.l24b(),\n      this.l24c(),\n      this.l24d(),\n      this.l24e(),\n      this.l24f(),\n      this.l24g(),\n      this.l24h(),\n      this.l24i(),\n      this.l24j(),\n      this.l24k(),\n      this.l24z()\n    ])\n\n  l26 = (): number =>\n    sumFields([\n      this.l11(),\n      this.l12(),\n      this.l13(),\n      this.l14(),\n      this.l15(),\n      this.l16(),\n      this.l17(),\n      this.l18(),\n      this.l19a(),\n      this.l20(),\n      this.l21(),\n      this.l23(),\n      this.l25()\n    ])\n\n  to1040Line10 = (): number => this.l26()\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2a(),\n    this.l2b(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8a(),\n    this.l8b(),\n    this.l8c(),\n    this.l8d(),\n    this.l8e(),\n    this.l8f(),\n    this.l8g(),\n    this.l8h(),\n    this.l8i(),\n    this.l8j(),\n    this.l8k(),\n    this.l8l(),\n    this.l8m(),\n    this.l8n(),\n    this.l8o(),\n    this.l8p(),\n    Array.from(this.otherIncomeStrings).join(' '),\n    undefined,\n    this.l8z(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    this.l18(),\n    this.l19a(),\n    this.l19b(),\n    this.l19c(),\n    this.l20(),\n    this.l21(),\n    this.l22(),\n    this.l23(),\n    this.l24a(),\n    this.l24b(),\n    this.l24c(),\n    this.l24d(),\n    this.l24e(),\n    this.l24f(),\n    this.l24g(),\n    this.l24h(),\n    this.l24i(),\n    this.l24j(),\n    this.l24k(),\n    this.l24zDesc(),\n    this.l24zDesc2(),\n    this.l24z(),\n    this.l25(),\n    this.l26()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/Schedule2.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class Schedule2 extends F1040Attachment {\n  tag: FormTag = 'f1040s2'\n  sequenceIndex = 2\n\n  // Part I: Tax\n  l1 = (): number | undefined => this.f1040.f6251.l11()\n  l2 = (): number | undefined => undefined // TODO: excess advance premium tax credit repayment (form 8962)\n  l3 = (): number => sumFields([this.l1(), this.l2()])\n\n  // Part II: Other Tax\n  l4 = (): number | undefined => this.f1040.scheduleSE.l12() // self-employment tax (schedule SE)\n  l5 = (): number | undefined => undefined // TODO: unreported FICA tax\n  l6 = (): number | undefined => undefined // TODO: additional tax on retirement accounts\n  l7 = (): number | undefined => undefined // TODO: total additional ss and medicare tax\n  l8 = (): number | undefined => undefined // TODO: additional tax on IRAs or other tax favored accoutns, form 5329\n  l9 = (): number | undefined => undefined // TODO: household employment taxes, schedule H\n  l10 = (): number | undefined => undefined // repayment of firsttime homebuyer credit, form 5405\n  l11 = (): number | undefined => this.f1040.f8959.toSchedule2l11()\n  l12 = (): number | undefined => this.f1040.f8960.toSchedule2l12()\n  l13 = (): number | undefined => undefined // TODO: uncollected ss and medicare or rrta tax on tips or group-term life insurance, w-2, box 12\n  l14 = (): number | undefined => undefined // TODO - interest on tax due on installment income from the sale of residential lots and timeshares\n  l15 = (): number | undefined => undefined //interest on the deferred tax on gain from certain installment sales with a sales price over 150000.\n  l16 = (): number | undefined => undefined // recapture of low-income housing credit, form 8611\n\n  // Other additional taxes:\n  // TODO: Recapture of other credits. List type, form number, and\n  // amount ▶\n  l17aDesc = (): string | undefined => undefined\n  l17a = (): number | undefined => undefined\n  // TODO: Recapture of federal mortgage subsidy. If you sold your home in\n  // 2021, see instructions\n  l17b = (): number | undefined => undefined\n\n  l17c = (): number | undefined =>\n    sumFields([this.f1040.f8889.l17b(), this.f1040.f8889Spouse?.l17b()])\n\n  l17d = (): number | undefined =>\n    sumFields([this.f1040.f8889.l21(), this.f1040.f8889Spouse?.l21()])\n  // TODO: Additional tax on Archer MSA distributions. Attach Form 8853\n  l17e = (): number | undefined => undefined\n  // TODO: Additional tax on Medicare Advantage MSA distributions. Attach\n  // Form 8853\n  l17f = (): number | undefined => undefined\n  // TODO: Recapture of a charitable contribution deduction related to a\n  // fractional interest in tangible personal property...17g\n  l17g = (): number | undefined => undefined\n  // TODO: Income you received from a nonqualified deferred compensation\n  // plan that fails to meet the requirements of section 409A.17h\n  l17h = (): number | undefined => undefined\n  // TODO Compensation you received from a nonqualified deferred\n  // compensation plan described in section 457A\n  l17i = (): number | undefined => undefined\n  // Section 72(m)(5) excess benefits tax\n  l17j = (): number | undefined => undefined\n  // TODO: Golden parachute payments\n  l17k = (): number | undefined => undefined\n  // Tax on accumulation distribution of trusts\n  l17l = (): number | undefined => undefined\n  // m Excise tax on insider stock compensation from an expatriated\n  // corporation\n  l17m = (): number | undefined => undefined\n  // n Look-back interest under section 167(g) or 460(b) from Form\n  // 8697 or 8866\n  l17n = (): number | undefined => undefined\n  // o Tax on non-effectively connected income for any part of the\n  // year you were a nonresident alien from Form 1040-NR\n  l17o = (): number | undefined => undefined\n  // p Any interest from Form 8621, line 16f, relating to distributions\n  // from, and disassets of, stock of a section 1291 fund.. 17p\n  l17p = (): number | undefined => undefined\n  // q Any interest from Form 8621, line 24\n  l17q = (): number | undefined => undefined\n  // z Any other taxes. List type and amount ▶\n  l17zDesc = (): string | undefined => undefined\n  l17z = (): number | undefined => undefined\n  // 18Total additional taxes. Add lines 17a through 17z.......18\n  l18 = (): number =>\n    sumFields([\n      this.l17a(),\n      this.l17b(),\n      this.l17c(),\n      this.l17d(),\n      this.l17e(),\n      this.l17f(),\n      this.l17g(),\n      this.l17h(),\n      this.l17i(),\n      this.l17j(),\n      this.l17k(),\n      this.l17l(),\n      this.l17m(),\n      this.l17n(),\n      this.l17o(),\n      this.l17p(),\n      this.l17q(),\n      this.l17z()\n    ])\n\n  // 19 Additional tax from Schedule 8812\n  l19 = (): number | undefined => this.f1040.schedule8812.toSchedule2Line19()\n\n  // TODO: Section 965 net tax liability installment from Form 965-A. .\n  l20 = (): number | undefined => undefined\n\n  // Add lines 4, 7 through 16, 18, and 19. These are your total other taxes. Enter here\n  l21 = (): number =>\n    sumFields([\n      this.l4(),\n      this.l7(),\n      this.l8(),\n      this.l9(),\n      this.l10(),\n      this.l11(),\n      this.l12(),\n      this.l13(),\n      this.l14(),\n      this.l15(),\n      this.l16(),\n      this.l18(),\n      this.l19()\n    ])\n\n  to1040l23 = (): number => this.l21()\n  // and on Form 1040 or 1040-SR, line 23, or Form 1040-NR, line 23b\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n\n    this.l1(),\n    this.l2(),\n    this.l3(),\n\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17aDesc(),\n    this.l17a(),\n    this.l17b(),\n    this.l17c(),\n    this.l17d(),\n    this.l17e(),\n    this.l17f(),\n    this.l17g(),\n    this.l17h(),\n    this.l17i(),\n    this.l17j(),\n    this.l17k(),\n    this.l17l(),\n    this.l17m(),\n    this.l17n(),\n    this.l17o(),\n    this.l17p(),\n    this.l17q(),\n    this.l17zDesc(),\n    undefined,\n    this.l17z(),\n    this.l18(),\n    this.l19(),\n    this.l20(),\n    this.l21()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/Schedule3.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { PersonRole } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { fica } from '../data/federal'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class Schedule3 extends F1040Attachment {\n  tag: FormTag = 'f1040s3'\n  sequenceIndex = 3\n\n  claimableExcessSSTaxWithholding = (): number => {\n    const w2s = this.f1040.validW2s()\n\n    // Excess FICA taxes are calculated per person. If an individual person\n    //    has greater than the applicable amount then they are entitled to a refund\n    //    of that amount\n\n    let claimableExcessFica = 0\n    const primaryFica = w2s\n      .filter((w2) => w2.personRole == PersonRole.PRIMARY)\n      .map((w2) => w2.ssWithholding)\n      .reduce((l, r) => l + r, 0)\n    const spouseFica = w2s\n      .filter((w2) => w2.personRole == PersonRole.SPOUSE)\n      .map((w2) => w2.ssWithholding)\n      .reduce((l, r) => l + r, 0)\n\n    if (\n      primaryFica > fica.maxSSTax &&\n      w2s\n        .filter((w2) => w2.personRole == PersonRole.PRIMARY)\n        .every((w2) => w2.ssWithholding <= fica.maxSSTax)\n    ) {\n      claimableExcessFica += primaryFica - fica.maxSSTax\n    }\n\n    if (\n      spouseFica > fica.maxSSTax &&\n      w2s\n        .filter((w2) => w2.personRole == PersonRole.SPOUSE)\n        .every((w2) => w2.ssWithholding <= fica.maxSSTax)\n    ) {\n      claimableExcessFica += spouseFica - fica.maxSSTax\n    }\n\n    return claimableExcessFica\n  }\n\n  isNeeded = (): boolean => this.claimableExcessSSTaxWithholding() > 0\n\n  deductions = (): number => 0\n  // Part I: Nonrefundable credits\n  l1 = (): number | undefined => undefined\n  l2 = (): number | undefined => undefined\n  l3 = (): number | undefined => this.f1040.f8863?.l19()\n  l4 = (): number | undefined => undefined\n  l5 = (): number | undefined => undefined\n  l6a = (): number | undefined => undefined // TODO: other credits\n  l6b = (): number | undefined => undefined // TODO: other credits\n  l6c = (): number | undefined => undefined // TODO: other credits\n  l6d = (): number | undefined => undefined // TODO: other credits\n  l6e = (): number | undefined => undefined // TODO: other credits\n  l6f = (): number | undefined => undefined // TODO: other credits\n  l6g = (): number | undefined => undefined // TODO: other credits\n  l6h = (): number | undefined => undefined // TODO: other credits\n  l6i = (): number | undefined => undefined // TODO: other credits\n  l6j = (): number | undefined => undefined // TODO: other credits\n  l6k = (): number | undefined => undefined // TODO: other credits\n  l6l = (): number | undefined => undefined // TODO: other credits\n  l6zDesc1 = (): string | undefined => undefined\n  l6zDesc2 = (): string | undefined => undefined\n  l6z = (): number | undefined => undefined // TODO: other credits\n\n  l7 = (): number =>\n    sumFields([\n      this.l6a(),\n      this.l6b(),\n      this.l6c(),\n      this.l6d(),\n      this.l6e(),\n      this.l6f(),\n      this.l6g(),\n      this.l6h(),\n      this.l6i(),\n      this.l6j(),\n      this.l6k(),\n      this.l6l(),\n      this.l6z()\n    ])\n\n  l8 = (): number =>\n    sumFields([\n      this.l1(),\n      this.l2(),\n      this.l3(),\n      this.l4(),\n      this.l5(),\n      this.l7()\n    ])\n\n  // Part II: Other payments and refundable credits\n  l9 = (): number | undefined => this.f1040.f8962?.credit()\n\n  // TODO: Amount paid with extension for time to file\n  l10 = (): number | undefined => undefined\n\n  l11 = (): number =>\n    // TODO: also applies to RRTA tax\n    this.claimableExcessSSTaxWithholding()\n\n  l12 = (): number | undefined => this.f1040.f4136?.credit()\n\n  l13a = (): number | undefined => this.f1040.f2439?.credit()\n  // TODO: qualified sick and family leave credits\n  // Schedule H and form 7202 pre 4/1/21\n  l13b = (): number | undefined => undefined\n\n  // Health coverage tax credit from 8885\n  l13c = (): number | undefined => undefined\n\n  // TODO: Credit for repayment of amounts included in income from earlier years\n  l13d = (): number | undefined => undefined // TODO: 'other' box\n\n  // reserved!\n  l13e = (): number | undefined => undefined\n\n  // deferred amount of net 965 tax liability\n  l13f = (): number | undefined => undefined\n\n  l13g = (): number | undefined => this.f1040.f2441?.credit()\n\n  // TODO: qualified sick and family leave credits\n  // Schedule H and form 7202 post 3/31/21\n  l13h = (): number | undefined => undefined\n\n  l13zDesc1 = (): string | undefined => undefined\n  l13zDesc2 = (): string | undefined => undefined\n  l13z = (): number | undefined => undefined\n\n  l14 = (): number =>\n    sumFields([\n      this.l13a(),\n      this.l13b(),\n      this.l13c(),\n      this.l13d(),\n      this.l13e(),\n      this.l13f(),\n      this.l13g(),\n      this.l13h(),\n      this.l13z()\n    ])\n\n  l15 = (): number =>\n    sumFields([this.l9(), this.l10(), this.l11(), this.l12(), this.l14()])\n\n  // Credit for child and dependent care expenses form 2441, line 10\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6a(),\n    this.l6b(),\n    this.l6c(),\n    this.l6d(),\n    this.l6e(),\n    this.l6f(),\n    this.l6g(),\n    this.l6h(),\n    this.l6i(),\n    this.l6j(),\n    this.l6k(),\n    this.l6l(),\n    this.l6zDesc1(),\n    this.l6zDesc2(),\n    this.l6z(),\n    this.l7(),\n    this.l8(),\n\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n\n    this.l13a(),\n    this.l13b(),\n    this.l13c(),\n    this.l13d(),\n    //this.l13e(),  // this field is left for future use and is not fillable\n    this.l13f(),\n    this.l13g(),\n    this.l13h(),\n    this.l13zDesc1(),\n    this.l13zDesc2(),\n    this.l13z(),\n    this.l14(),\n    this.l15()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/Schedule8812.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { CreditType, Dependent, FilingStatus } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { CURRENT_YEAR } from '../data/federal'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { nextMultipleOf1000 } from 'ustaxes/core/util'\n\ntype Part1b = { allowed: boolean } & Partial<{\n  l14a: number\n  l14b: number\n  l14c: number\n  l14d: number\n  l14e: number\n  l14f: number\n  l14g: number\n  l14h: number\n  l14i: number\n}>\n\ntype Part1c = { allowed: boolean } & Partial<{\n  l15a: number\n  l15b: number\n  l15c: number\n  l15d: number\n  l15e: number\n  l15f: number\n  l15g: number\n  l15h: number\n}>\n\ntype Part2a = { allowed: boolean } & Partial<{\n  l16a: number\n  l16bdeps: number\n  l16b: number\n  l17: number\n  l18a: number\n  l18b: number\n  l19No: boolean\n  l19Yes: boolean\n  l19: number\n  l20: number\n  l20No: boolean\n  l20Yes: boolean\n  toLine27: number\n}>\n\ntype Part2b = { allowed: boolean } & Partial<{\n  l21: number\n  l22: number\n  l23: number\n  l24: number\n  l25: number\n  l26: number\n  toLine27: number\n}>\n\ntype Part3 = { allowed: boolean } & Partial<{\n  l28a: number\n  l28b: number\n  l29: number\n  l30: number\n  l31: number\n  l32: number\n  l33: number\n  l34: number\n  l35: number\n  l36: string\n  l37: number\n  l38: number\n  l39: number\n  l40: number\n}>\n\nexport default class Schedule8812 extends F1040Attachment {\n  tag: FormTag = 'f1040s8'\n  sequenceIndex = 47\n\n  isNeeded = (): boolean =>\n    this.f1040.info.taxPayer.dependents.some(\n      (dep) =>\n        this.f1040.qualifyingDependents.qualifiesChild(dep) ||\n        this.f1040.qualifyingDependents.qualifiesOther(dep)\n    )\n\n  l1 = (): number => this.f1040.l11()\n\n  // TODO: Puerto Rico income\n  l2a = (): number => 0\n\n  l2b = (): number =>\n    sumFields([this.f1040.f2555?.l45(), this.f1040.f2555?.l50()])\n\n  l2c = (): number => this.f1040.f4563?.l15() ?? 0\n\n  l2d = (): number => sumFields([this.l2a(), this.l2b(), this.l2c()])\n\n  l3 = (): number => sumFields([this.l1(), this.l2d()])\n\n  creditDependents = (): Dependent[] =>\n    this.f1040.qualifyingDependents.qualifyingChildren()\n\n  l4a = (): number => this.creditDependents().length\n\n  // Number of qualifying children under age 6 at EOY\n  l4b = (): number =>\n    this.creditDependents().filter(\n      (d) =>\n        d.qualifyingInfo !== undefined &&\n        d.dateOfBirth.getFullYear() > CURRENT_YEAR - 6\n    ).length\n\n  l4c = (): number => Math.max(0, this.l4a() - this.l4b())\n\n  /**\n   * Computed using the line 5 worksheet, Schedule 8812 instructions\n   */\n  l5 = (): number => {\n    const fs = this.f1040.info.taxPayer.filingStatus\n\n    const wsl1 = this.l4b() * 3600\n    const wsl2 = this.l4c() * 3000\n    const wsl3 = wsl1 + wsl2\n    const wsl4 = this.l4a() * 2000\n    // Note wsl3 >= wsl4\n    const wsl5 = wsl3 - wsl4\n    const wsl6values: Partial<{ [key in FilingStatus]: number }> = {\n      [FilingStatus.MFJ]: 12500,\n      [FilingStatus.W]: 2500,\n      [FilingStatus.HOH]: 4375\n    }\n    const wsl6 = wsl6values[fs] ?? 6250\n    const wsl7 = Math.min(wsl5, wsl6)\n    const wsl8values: Partial<{ [key in FilingStatus]: number }> = {\n      [FilingStatus.MFJ]: 150000,\n      [FilingStatus.W]: 150000,\n      [FilingStatus.HOH]: 112500\n    }\n    const wsl8 = wsl8values[fs] ?? 75000\n\n    const wsl9 = nextMultipleOf1000(Math.max(0, this.l3() - wsl8))\n    const wsl10 = wsl9 * 0.05\n    const wsl11 = Math.min(wsl7, wsl10)\n    return Math.max(0, wsl3 - wsl11)\n  }\n\n  // TODO: Verify:\n  // Number of other dependents, including any qualifying children, who are not under age 18 or who do not have the required SSN. Do not include yourself, your spouse,\n  // or anyone who is not a US citizen/national/resident alien,\n  // or do not have the required SSN.\n  l6 = (): number => this.f1040.info.taxPayer.dependents.length - this.l4a()\n\n  l7 = (): number => this.l6() * 500\n\n  l8 = (): number => sumFields([this.l5(), this.l7()])\n\n  l9 = (): number =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ ? 400000 : 200000\n\n  l10 = (): number => nextMultipleOf1000(Math.max(0, this.l3() - this.l9()))\n\n  l11 = (): number => this.l10() * 0.05\n\n  l12 = (): number => Math.max(0, this.l8() - this.l11())\n\n  // you and spouse have residence in US for more than half of year.\n  // TODO: Assuming true\n  l13a = (): boolean => true\n\n  // Resident of puerto rico for 2021\n  // TODO: assuming false\n  l13b = (): boolean => false\n\n  // Part 1 B - requires a box on line 13\n  req =\n    <A>(pred: boolean) =>\n    (f: () => A) =>\n    (): A | undefined => {\n      if (pred) {\n        return f()\n      } else {\n        return undefined\n      }\n    }\n\n  req13 = this.req<number>(this.l13a() || this.l13b())\n\n  creditLimitWorksheetB = (): number | undefined => undefined\n\n  creditLimitWorksheetA = (): number => {\n    const wsl1 = this.f1040.l18()\n    const schedule3Fields = this.f1040.schedule3.isNeeded()\n      ? [\n          this.f1040.schedule3.l1(),\n          this.f1040.schedule3.l2(),\n          this.f1040.schedule3.l3(),\n          this.f1040.schedule3.l4(),\n          this.f1040.schedule3.l6l()\n        ]\n      : []\n\n    const wsl2 = sumFields([\n      ...schedule3Fields,\n      this.f1040.f5695?.l30(),\n      this.f1040.f8936?.l15(),\n      this.f1040.f8936?.l23(),\n      this.f1040.scheduleR?.l22()\n    ])\n    const wsl3 = Math.max(0, wsl1 - wsl2)\n    const wsl4 = this.creditLimitWorksheetB() ?? 0\n    const wsl5 = Math.max(0, wsl3 - wsl4)\n    return wsl5\n  }\n\n  // TODO: Letter 6419 advance child tax credit payments\n  letter6419Payments = (): number | undefined =>\n    this.f1040.info.credits\n      .filter((c) => c.type === CreditType.AdvanceChildTaxCredit)\n      .reduce((sum, c) => sum + c.amount, 0)\n\n  part1b = (): Part1b => {\n    const allowed = this.l13a() || this.l13b()\n    if (!allowed) return { allowed: false }\n\n    const l14a = Math.min(this.l7(), this.l12())\n    const l14b = Math.max(this.l12() - l14a)\n    const l14c = l14a === 0 ? 0 : this.creditLimitWorksheetA()\n    const l14d = Math.min(l14a, l14c)\n    const l14e = sumFields([l14b, l14d])\n    // TODO:\n    // IMPORTANT: Letter 6419 advance child tax credit payments\n    const l14f = this.letter6419Payments() ?? 0\n    const l14g = Math.max(0, l14e - l14f)\n\n    // Credit for other dependents\n    const l14h = Math.min(l14d, l14g)\n\n    // Refundable child tax credit\n    const l14i = Math.max(0, l14g - l14h)\n\n    return {\n      allowed,\n      l14a,\n      l14b,\n      l14c,\n      l14d,\n      l14e,\n      l14f,\n      l14g,\n      l14h,\n      l14i\n    }\n  }\n\n  part1c = (): Part1c => {\n    const allowed = !(this.l13a() || this.l13b())\n    if (!allowed) return { allowed: false }\n\n    const l15a = this.creditLimitWorksheetA()\n    const l15b = Math.min(this.l12(), l15a)\n\n    //TODO - implement after 2a through 2c\n    const l15c = this.l27() ?? 0\n    const l15d = sumFields([l15b, l15c])\n    const l15e = this.letter6419Payments() ?? 0\n    const l15f = Math.max(0, l15d - l15e)\n    const l15g = Math.min(l15b, l15f)\n    const l15h = Math.max(0, l15f - l15g)\n\n    return {\n      allowed,\n      l15a,\n      l15b,\n      l15c,\n      l15d,\n      l15e,\n      l15f,\n      l15g,\n      l15h\n    }\n  }\n\n  // from Part 1-C, Line 15b 1 - 3\n  part2AllowedBy1C = (): boolean => {\n    const part1c = this.part1c()\n    return (\n      !part1c.allowed ||\n      (this.f1040.f2555 === undefined &&\n        this.l4a() > 0 &&\n        this.l12() > (part1c.l15a ?? 0))\n    )\n  }\n\n  to1040Line19 = (): number | undefined =>\n    this.part1b().l14h ?? this.part1c().l15g\n\n  to1040Line28 = (): number | undefined =>\n    this.part1b().l14i ?? this.part1c().l15h\n\n  earnedIncomeWorksheet = (): number => {\n    const l1a = this.f1040.l1()\n    const l1b = this.f1040.nonTaxableCombatPay()\n    const l2a = this.f1040.scheduleC?.l1() ?? 0\n    // Todo: 1065 Schedule K-1, box 14, code A, and other\n    // data also belong here.\n    const l2b = this.f1040.scheduleC?.l31() ?? 0\n    // TODO: Net farm profit...\n    // const l2c = undefined\n    // TODO: Farm optional method for self-employment net earnings\n    const l2d = 0\n\n    // TODO: min(l2c, l2d)\n    // Allowed to be a loss:\n    const l2e = Math.min(0, l2d)\n\n    const l3 = sumFields([l1a, l1b, l2a, l2b, l2e])\n\n    const allowed = l3 > 0\n\n    // TODO: Scholarship or grant not reported on w-2\n    const l4a = !allowed ? undefined : 0\n\n    // TODO: Penal income\n    const l4b = !allowed ? undefined : 0\n\n    // TODO: nonqualified deferred comp plan or 457 plan\n    const l4c = !allowed ? undefined : 0\n\n    // TODO: Amount included on 1040 that is a medicaid\n    // waiver payment excluded from income, schedule 1, line 8z\n    // or choose to include in earned income, then enter 0.\n    const l4d = !allowed ? undefined : 0\n\n    const l5 = this.f1040.schedule1.l15() ?? 0\n\n    const l6 = sumFields([l4a, l4b, l4c, l4d, l5])\n\n    const l7 = Math.max(0, l3 - l6)\n\n    return l7\n  }\n\n  part2a = (): Part2a => {\n    const l16a = Math.max(0, this.l12() - (this.part1c().l15b ?? 0))\n    const l16bdeps = this.l4a()\n\n    const allowed =\n      this.part2AllowedBy1C() &&\n      this.f1040.f2555 === undefined &&\n      !(this.l13a() || this.l13b()) &&\n      l16a > 0 &&\n      l16bdeps > 0\n\n    if (!allowed) return { allowed: false }\n\n    const l16b = l16bdeps * 1400\n\n    const l17 = Math.min(l16a, l16b)\n    const l18a = this.earnedIncomeWorksheet()\n    const l18b = this.f1040.nonTaxableCombatPay() ?? 0\n    const l19No = l18a > 2500\n    const l19Yes = l18a <= 2500\n    const l19 = Math.max(0, l18a - 2500)\n    const l20 = l19 * 0.15\n    const l20No = l16b >= 4200\n    const l20Yes = l16b < 4200\n\n    const toLine27 = (() => {\n      if (l20No && l20 > 0) {\n        return Math.min(l17, l20)\n      } else if (l20Yes && l20 >= l17) {\n        return l17\n      }\n    })()\n\n    return {\n      allowed: true,\n      l16a,\n      l16bdeps,\n      l16b,\n      l17,\n      l18a,\n      l18b,\n      l19No,\n      l19Yes,\n      l19,\n      l20,\n      l20No,\n      l20Yes,\n      toLine27\n    }\n  }\n\n  part2b = (): Part2b => {\n    const part2a = this.part2a()\n    // three or more qualifying children.\n    const allowed = part2a.allowed\n\n    if (!allowed) return { allowed: false }\n\n    const ssWithholding = this.f1040\n      .validW2s()\n      .reduce((res, w2) => res + w2.ssWithholding, 0)\n\n    const medicareWithholding = this.f1040\n      .validW2s()\n      .reduce((res, w2) => res + w2.medicareWithholding, 0)\n\n    const l21 = ssWithholding + medicareWithholding\n\n    const l22 = sumFields([\n      this.f1040.schedule1.l15(),\n      this.f1040.schedule2.l5(),\n      this.f1040.schedule2.l6(),\n      this.f1040.schedule2.l13()\n    ])\n\n    const l23 = sumFields([l21, l22])\n\n    const l24 = sumFields([this.f1040.l27a(), this.f1040.schedule3.l11()])\n\n    const l25 = Math.max(0, l23 - l24)\n\n    const l26 = Math.max(part2a.l20 ?? 0, l25)\n\n    const toLine27 = Math.min(part2a.l17 ?? 0, l26)\n\n    return {\n      allowed: true,\n      l21,\n      l22,\n      l23,\n      l24,\n      l25,\n      l26,\n      toLine27\n    }\n  }\n\n  l27 = (): number | undefined =>\n    this.part2a().toLine27 ?? this.part2b().toLine27\n\n  part3 = (): Part3 => {\n    const fs = this.f1040.info.taxPayer.filingStatus\n    const part1b = this.part1b()\n    const part1c = this.part1c()\n\n    const allowed =\n      (part1b.allowed && part1b.l14g === 0) ||\n      (part1c.allowed && part1c.l15f === 0)\n\n    if (!allowed) return { allowed: false }\n\n    const l28a = this.part1b().l14f ?? this.part1c().l15e\n\n    const l28b = part1b.l14e ?? part1c.l15d\n\n    const l29 = Math.max(0, (l28a ?? 0) - (l28b ?? 0))\n\n    // Enter the number of qualifying children taken into account in determining the annual advance amount you\n    // received for 2021. See your Letter 6419 for this number. If you are missing your Letter 6419, you are filing a joint\n    // return, or you received more than one Letter 6419, see the instructions before entering a number on this line\n    const l30 = this.l4a()\n\n    const l31 = Math.min(this.l4a(), l30)\n\n    const l32 = Math.max(0, l30 - l31)\n\n    const l33Values: { [key in FilingStatus]: number } = {\n      [FilingStatus.MFJ]: 60000,\n      [FilingStatus.W]: 60000,\n      [FilingStatus.HOH]: 50000,\n      [FilingStatus.S]: 40000,\n      [FilingStatus.MFS]: 40000\n    }\n\n    const l33 = l33Values[fs]\n\n    const l34 = Math.max(0, this.l3() - l33)\n\n    const l35 = l33\n\n    const l36 = Math.min(1, l34 / l35).toFixed(3)\n\n    const l37 = l32 * 2000\n\n    const l38 = l37 * parseFloat(l36)\n\n    const l39 = Math.max(0, l37 - l38)\n\n    const l40 = Math.max(0, l29 - l39)\n\n    return {\n      allowed: true,\n      l28a,\n      l28b,\n      l29,\n      l30,\n      l31,\n      l32,\n      l33,\n      l34,\n      l35,\n      l36,\n      l37,\n      l38,\n      l39,\n      l40\n    }\n  }\n\n  l40 = (): number => this.part3().l40 ?? 0\n\n  // This is your additional tax.\n  toSchedule2Line19: () => number = this.l40\n\n  fields = (): Field[] => {\n    const part1b = this.part1b()\n    const part1c = this.part1c()\n    const part2a = this.part2a()\n    const part2b = this.part2b()\n    const part3 = this.part3()\n\n    return [\n      this.f1040.namesString(),\n      this.f1040.info.taxPayer.primaryPerson.ssid,\n      this.l1(),\n      this.l2a(),\n      this.l2b(),\n      this.l2c(),\n      this.l2d(),\n      this.l3(),\n      this.l4a(),\n      this.l4b(),\n      this.l4c(),\n      this.l5(),\n      this.l6(),\n      this.l7(),\n      this.l8(),\n      this.l9(),\n      this.l10(),\n      this.l11(),\n      this.l12(),\n      this.l13a(),\n      this.l13b(),\n      part1b.l14a,\n      part1b.l14b,\n      part1b.l14c,\n      part1b.l14d,\n      part1b.l14e,\n      part1b.l14f,\n      part1b.l14g,\n      part1b.l14h,\n      part1b.l14i,\n      part1c.l15a,\n      part1c.l15b,\n      part1c.l15c,\n      part1c.l15d,\n      part1c.l15e,\n      part1c.l15f,\n      part1c.l15g,\n      part1c.l15h,\n      part2a.l16a,\n      part2a.l16bdeps,\n      part2a.l16b,\n      part2a.l17,\n      part2a.l18a,\n      part2a.l18b,\n      part2a.l19No,\n      part2a.l19Yes,\n      part2a.l19,\n      part2a.l20,\n      part2a.l20No,\n      part2a.l20Yes,\n      part2b.l21,\n      part2b.l22,\n      part2b.l23,\n      part2b.l24,\n      part2b.l25,\n      part2b.l26,\n      this.l27(),\n      part3.l28a,\n      part3.l28b,\n      part3.l29,\n      part3.l30,\n      part3.l31,\n      part3.l32,\n      part3.l33,\n      part3.l34,\n      part3.l35,\n      part3.l36,\n      part3.l37,\n      part3.l38,\n      part3.l39,\n      this.l40()\n    ]\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleA.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FilingStatus, ItemizedDeductions } from 'ustaxes/core/data'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport F1040 from './F1040'\n\nconst blankItemizedDeductions = {\n  medicalAndDental: 0,\n  stateAndLocalTaxes: 0,\n  isSalesTax: false,\n  stateAndLocalRealEstateTaxes: 0,\n  stateAndLocalPropertyTaxes: 0,\n  interest8a: 0,\n  interest8b: 0,\n  interest8c: 0,\n  interest8d: 0,\n  investmentInterest: 0,\n  charityCashCheck: 0,\n  charityOther: 0\n}\n\nexport default class ScheduleA extends F1040Attachment {\n  tag: FormTag = 'f1040sa'\n  itemizedDeductions: ItemizedDeductions\n  sequenceIndex = 7\n\n  constructor(f1040: F1040) {\n    super(f1040)\n    this.itemizedDeductions = {\n      ...blankItemizedDeductions,\n      ...(f1040.info.itemizedDeductions ?? {})\n    }\n  }\n\n  isNeeded = (): boolean => {\n    if (this.f1040.info.itemizedDeductions !== undefined) {\n      const standardDeduction = this.f1040.standardDeduction()\n      const itemizedAmount = this.deductions()\n      return (\n        standardDeduction === undefined || itemizedAmount > standardDeduction\n      )\n    }\n    return false\n  }\n\n  deductions(): number {\n    return (\n      this.l4() + this.l7() + this.l10() + this.l14() + this.l15() + this.l16()\n    )\n  }\n\n  l1 = (): number => Number(this.itemizedDeductions.medicalAndDental)\n\n  l2 = (): number => this.f1040.l11()\n\n  l3 = (): number => this.l2() * 0.075\n\n  l4 = (): number => Math.max(0, this.l1() - this.l3())\n\n  l5aSalesTax = (): boolean => this.itemizedDeductions.isSalesTax\n\n  l5a = (): number => Number(this.itemizedDeductions.stateAndLocalTaxes)\n  l5b = (): number =>\n    Number(this.itemizedDeductions.stateAndLocalRealEstateTaxes)\n  l5c = (): number => Number(this.itemizedDeductions.stateAndLocalPropertyTaxes)\n  l5d = (): number => this.l5a() + this.l5b() + this.l5c()\n  l5e = (): number => {\n    const max =\n      this.f1040.info.taxPayer.filingStatus === FilingStatus.MFS ? 5000 : 10000\n    return Math.min(max, this.l5d())\n  }\n\n  // TODO\n  l6OtherTaxesTypeAndAmount1 = (): string | undefined => undefined\n  l6OtherTaxesTypeAndAmount2 = (): string | undefined => undefined\n\n  // TODO\n  l6 = (): number | undefined => undefined\n\n  l7 = (): number => this.l5e() + (this.l6() ?? 0)\n\n  // TODO\n  l8AllMortgageLoan = (): boolean => false\n  l8a = (): number => Number(this.itemizedDeductions.interest8a)\n\n  // TODO\n  l8bUnreportedInterest1 = (): string | undefined => undefined\n  // TODO\n  l8bUnreportedInterest2 = (): string | undefined => undefined\n  l8b = (): number => Number(this.itemizedDeductions.interest8b)\n  l8c = (): number => Number(this.itemizedDeductions.interest8c)\n  l8d = (): number => Number(this.itemizedDeductions.interest8d)\n  l8e = (): number => this.l8a() + this.l8b() + this.l8c() + this.l8d()\n\n  // Used in Form 8960\n  l9 = (): number | undefined =>\n    Number(this.itemizedDeductions.investmentInterest)\n\n  l10 = (): number => this.l8e() + (this.l9() ?? 0)\n\n  l11 = (): number => Number(this.itemizedDeductions.charityCashCheck)\n\n  // TODO: form 8283\n  l12 = (): number => Number(this.itemizedDeductions.charityOther)\n  l13 = (): number => 0\n  l14 = (): number => this.l11() + this.l12() + this.l13()\n\n  l15 = (): number => 0\n\n  // TODO\n  l16Other1 = (): string | undefined => undefined\n  l16Other2 = (): string | undefined => undefined\n  l16Other3 = (): string | undefined => undefined\n  l16 = (): number => 0\n\n  l17 = (): number =>\n    this.l4() + this.l7() + this.l10() + this.l14() + this.l15() + this.l16()\n\n  l18 = (): boolean => false\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5aSalesTax(),\n    this.l5a(),\n    this.l5b(),\n    this.l5c(),\n    this.l5d(),\n    this.l5e(),\n    this.l6OtherTaxesTypeAndAmount1(),\n    this.l6OtherTaxesTypeAndAmount2(),\n    this.l6(),\n    this.l7(),\n    this.l8AllMortgageLoan(),\n    this.l8a(),\n    this.l8bUnreportedInterest1(),\n    this.l8bUnreportedInterest2(),\n    this.l8b(),\n    this.l8c(),\n    this.l8d(),\n    this.l8e(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16Other1(),\n    this.l16Other2(),\n    this.l16Other3(),\n    this.l16(),\n    this.l17(),\n    this.l18()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleB.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport F1040 from './F1040'\n\ninterface PayerAmount {\n  payer?: string\n  amount?: number\n}\n\nexport default class ScheduleB extends F1040Attachment {\n  tag: FormTag = 'f1040sb'\n  sequenceIndex = 8\n  readonly interestPayersLimit = 14\n  readonly dividendPayersLimit = 16\n\n  index = 0\n\n  constructor(f1040: F1040, index = 0) {\n    super(f1040)\n    this.index = index\n  }\n\n  copies = (): ScheduleB[] => {\n    if (this.index === 0) {\n      const numInterestPayers = this.l1Fields().length\n      const numDivPayers = this.l5Fields().length\n\n      const extraCopiesNeeded = Math.floor(\n        Math.max(\n          numInterestPayers / this.interestPayersLimit,\n          numDivPayers / this.dividendPayersLimit\n        )\n      )\n\n      return Array.from(Array(extraCopiesNeeded)).map(\n        (_, i) => new ScheduleB(this.f1040, i + 1)\n      )\n    } else {\n      return []\n    }\n  }\n\n  isNeeded = (): boolean =>\n    this.l1Fields().length > 0 || this.l5Fields().length > 0\n\n  l1Fields = (): PayerAmount[] =>\n    this.f1040\n      .f1099Ints()\n      .map((v) => ({\n        payer: v.payer,\n        amount: v.form.income\n      }))\n      .concat(\n        this.f1040.k1sWithInterest().map((v) => ({\n          payer: v.partnershipName,\n          amount: v.interestIncome\n        }))\n      )\n\n  l1 = (): Array<string | undefined> => {\n    const payerValues = this.l1Fields().slice(\n      this.index * this.interestPayersLimit,\n      (this.index + 1) * this.interestPayersLimit\n    )\n    const rightPad = 2 * (this.interestPayersLimit - payerValues.length)\n    // ensure we return an array of length interestPayersLimit * 2.\n    // This form may have multiple copies, only display the copies for this form\n    return payerValues\n      .flatMap(({ payer, amount }) => [payer, amount?.toString()])\n      .concat(Array(rightPad).fill(undefined))\n  }\n\n  l2 = (): number => sumFields(this.f1040.f1099Ints().map((f) => f.form.income))\n\n  // TODO: Interest from tax exempt savings bonds\n  l3 = (): number | undefined => undefined\n\n  l4 = (): number => this.l2() - (this.l3() ?? 0)\n\n  /**\n   * Total interest on all schedule Bs.\n   */\n  to1040l2b = (): number =>\n    [this, ...this.copies()].reduce((acc, f) => acc + f.l4(), 0)\n\n  l5Fields = (): PayerAmount[] =>\n    this.f1040.f1099Divs().map((v) => ({\n      payer: v.payer,\n      amount: v.form.dividends\n    }))\n\n  l5 = (): Array<string | undefined | number> => {\n    const payerValues = this.l5Fields().slice(\n      this.index * this.dividendPayersLimit,\n      (this.index + 1) * this.dividendPayersLimit\n    )\n\n    const rightPad = 2 * (this.dividendPayersLimit - payerValues.length)\n    return payerValues\n      .flatMap(({ payer, amount }) => [payer, amount])\n      .concat(Array(rightPad).fill(undefined))\n  }\n\n  l6 = (): number => sumFields(this.l5Fields().map(({ amount }) => amount))\n\n  /**\n   * Total dividends on all schedule Bs.\n   */\n  to1040l3b = (): number =>\n    [this, ...this.copies()].reduce((acc, f) => acc + f.l6(), 0)\n\n  foreignAccount = (): boolean =>\n    this.f1040.info.questions.FOREIGN_ACCOUNT_EXISTS ?? false\n  fincenForm = (): boolean => this.f1040.info.questions.FINCEN_114 ?? false\n  fincenCountry = (): string | undefined =>\n    this.f1040.info.questions.FINCEN_114_ACCOUNT_COUNTRY\n  foreignTrust = (): boolean =>\n    this.f1040.info.questions.FOREIGN_TRUST_RELATIONSHIP ?? false\n\n  l7a = (): [boolean, boolean] => [\n    this.foreignAccount(),\n    !this.foreignAccount()\n  ]\n\n  l7a2 = (): [boolean, boolean] => [this.fincenForm(), !this.fincenForm()]\n\n  l7b = (): string | undefined => this.fincenCountry()\n\n  l8 = (): [boolean, boolean] => [this.foreignTrust(), !this.foreignTrust()]\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    ...this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    ...this.l5(),\n    this.l6(),\n    ...this.l7a(),\n    ...this.l7a2(),\n    this.l7b(),\n    ...this.l8()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleC.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\n/**\n * Not implemented\n */\nexport default class ScheduleC extends F1040Attachment {\n  tag: FormTag = 'f1040sc'\n  sequenceIndex = 9\n\n  // TODO: statutory employee income\n  // shown on Schedule 8812, earned income\n  l1 = (): number | undefined => undefined\n\n  // TODO: net profit or loss\n  // shown on Schedule 8812, earned income\n  l31 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleD.ts",
    "content": "import { F1099BData, FilingStatus } from 'ustaxes/core/data'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport SDRateGainWorksheet from './worksheets/SDRateGainWorksheet'\nimport SDUnrecaptured1250 from './worksheets/SDUnrecaptured1250'\nimport F8949 from './F8949'\nimport F1040Attachment from './F1040Attachment'\nimport F1040 from './F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport SDTaxWorksheet from './worksheets/SDTaxWorksheet'\nimport QualDivAndCGWorksheet from './worksheets/SDQualifiedAndCapGains'\nexport default class ScheduleD extends F1040Attachment {\n  tag: FormTag = 'f1040sd'\n  sequenceIndex = 12\n  _aggregated?: F1099BData\n  qualifiedDivAndCGWorksheet: QualDivAndCGWorksheet\n  taxWorksheet: SDTaxWorksheet\n  rateGainWorksheet: SDRateGainWorksheet\n  unrecaptured1250: SDUnrecaptured1250\n  _f8949s?: F8949[]\n\n  readonly l21MinMFS = 1500\n  readonly l21MinDefault = 3000\n\n  constructor(f1040: F1040) {\n    super(f1040)\n\n    this.rateGainWorksheet = new SDRateGainWorksheet()\n    this.taxWorksheet = new SDTaxWorksheet(f1040)\n    this.qualifiedDivAndCGWorksheet = new QualDivAndCGWorksheet(f1040)\n    this.unrecaptured1250 = new SDUnrecaptured1250()\n  }\n\n  get aggregated(): F1099BData {\n    if (this._aggregated === undefined) {\n      const bs: F1099BData[] = this.f1040.f1099Bs().map((f) => f.form)\n\n      this._aggregated = {\n        shortTermProceeds: bs.reduce((l, r) => l + r.shortTermProceeds, 0),\n        shortTermCostBasis: bs.reduce((l, r) => l + r.shortTermCostBasis, 0),\n        longTermProceeds: bs.reduce((l, r) => l + r.longTermProceeds, 0),\n        longTermCostBasis: bs.reduce((l, r) => l + r.longTermCostBasis, 0)\n      }\n    }\n\n    return this._aggregated\n  }\n\n  isNeeded = (): boolean =>\n    this.f1040.f1099Bs().length > 0 || this.f1040.f8949.isNeeded()\n\n  l21Min = (): number => {\n    if (this.f1040.info.taxPayer.filingStatus === FilingStatus.MFS) {\n      return this.l21MinMFS\n    }\n    return this.l21MinDefault\n  }\n\n  l1ad = (): number | undefined => this.aggregated.shortTermProceeds\n  l1ae = (): number | undefined => this.aggregated.shortTermCostBasis\n  // This field is greyed out, but fillable\n  l1ag = (): number | undefined => undefined\n  l1ah = (): number => sumFields([this.l1ad(), 0 - (this.l1ae() ?? 0)])\n\n  l1f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part1BoxA())\n\n  l1bd = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalProceeds()))\n  l1be = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalCost()))\n\n  l1bg = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalAdjustments()))\n  l1bh = (): number =>\n    sumFields(this.l1f8949s().map((f) => f.shortTermTotalGain()))\n\n  l2f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part1BoxB())\n\n  l2d = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalProceeds()))\n\n  l2e = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalCost()))\n\n  l2g = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalAdjustments()))\n\n  l2h = (): number =>\n    sumFields(this.l2f8949s().map((f) => f.shortTermTotalGain()))\n\n  l3f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part1BoxC())\n\n  l3d = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalProceeds()))\n\n  l3e = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalCost()))\n\n  l3g = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalAdjustments()))\n\n  l3h = (): number =>\n    sumFields(this.l3f8949s().map((f) => f.shortTermTotalGain()))\n\n  l4 = (): number | undefined => undefined\n\n  l5 = (): number | undefined => undefined\n\n  l6 = (): number | undefined => undefined\n\n  l7 = (): number =>\n    sumFields([\n      this.l1ah(),\n      this.l1bh(),\n      this.l2h(),\n      this.l3h(),\n      this.l4(),\n      this.l5(),\n      this.l6()\n    ])\n\n  l8ad = (): number | undefined => this.aggregated.longTermProceeds\n  l8ae = (): number | undefined => this.aggregated.longTermCostBasis\n  // This field is greyed out, but fillable\n  l8ag = (): number | undefined => undefined\n  l8ah = (): number | undefined =>\n    sumFields([this.l8ad(), 0 - (this.l8ae() ?? 0)])\n\n  l8f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part2BoxD())\n\n  l8bd = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalProceeds()))\n\n  l8be = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalCost()))\n\n  l8bg = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalAdjustments()))\n\n  l8bh = (): number =>\n    sumFields(this.l8f8949s().map((f) => f.longTermTotalGain()))\n\n  l9f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part2BoxE())\n\n  l9d = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalProceeds()))\n\n  l9e = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalCost()))\n\n  l9g = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalAdjustments()))\n\n  l9h = (): number =>\n    sumFields(this.l9f8949s().map((f) => f.longTermTotalGain()))\n\n  l10f8949s = (): F8949[] => this.f1040.f8949s.filter((f) => f.part2BoxF())\n\n  l10d = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalProceeds()))\n\n  l10e = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalCost()))\n\n  l10g = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalAdjustments()))\n\n  l10h = (): number =>\n    sumFields(this.l10f8949s().map((f) => f.longTermTotalGain()))\n\n  l11 = (): number | undefined => undefined\n\n  l12 = (): number | undefined => undefined\n\n  l13 = (): number | undefined =>\n    this.f1040\n      .f1099Divs()\n      .reduce((s, f) => s + f.form.totalCapitalGainsDistributions, 0)\n\n  l14 = (): number | undefined => undefined\n\n  l15 = (): number =>\n    sumFields([\n      this.l8ah(),\n      this.l8bh(),\n      this.l9h(),\n      this.l10h(),\n      this.l11(),\n      this.l12(),\n      this.l13(),\n      this.l14()\n    ])\n\n  // L7 + L15\n  // If +, enter on L16 of F1040\n  // If -, go to L21\n  // If 0, go to L22\n  l16 = (): number => sumFields([this.l7(), this.l15()])\n\n  // Are L15 and L16 both gains?\n  l17 = (): boolean => this.l15() > 0 && this.l16() > 0\n\n  l18 = (): number | undefined => {\n    if (!this.l17()) {\n      return undefined\n    }\n    return this.rateGainWorksheet.l7()\n  }\n\n  l19 = (): number | undefined => {\n    if (!this.l17()) {\n      return undefined\n    }\n    return this.unrecaptured1250.l18()\n  }\n\n  l20 = (): boolean | undefined => {\n    if (!this.l17()) {\n      return undefined\n    }\n    return (this.l18() ?? 0) === 0 && (this.l19() ?? 0) === 0\n  }\n\n  fillL21 = (): boolean =>\n    !this.l20() && ((this.l16() > 0 && this.l17()) || this.l16() < 0)\n\n  l21 = (): number | undefined => {\n    if (this.fillL21()) {\n      return Math.max(-this.l21Min(), this.l16())\n    }\n  }\n\n  haveQualifiedDividends = (): boolean =>\n    this.f1040.f1099Divs().some((f) => f.form.qualifiedDividends > 0)\n\n  // TODO: Schedule D tax worksheet\n  // neither box should be checked if this question was not required to be answered by l20.\n  l22 = (): boolean | undefined => {\n    if (this.l20() !== false) {\n      return this.haveQualifiedDividends()\n    }\n  }\n\n  lossCarryForward = (): number => {\n    const amount = this.l16() + this.l21Min()\n    if (amount < 0) {\n      return -amount\n    }\n    return 0\n  }\n\n  to1040 = (): number => this.l21() ?? this.l16()\n\n  computeTaxOnQDWorksheet = (): boolean =>\n    (this.l20() ?? false) || (this.l22() ?? false)\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    false,\n    false,\n    this.l1ad(),\n    this.l1ae(),\n    this.l1ag(),\n    this.l1ah(),\n    this.l1bd(),\n    this.l1be(),\n    this.l1bg(),\n    this.l1bh(),\n    this.l2d(),\n    this.l2e(),\n    this.l2g(),\n    this.l2h(),\n    this.l3d(),\n    this.l3e(),\n    this.l3g(),\n    this.l3h(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.l8ad(),\n    this.l8ae(),\n    this.l8ag(),\n    this.l8ah(),\n    this.l8bd(),\n    this.l8be(),\n    this.l8bg(),\n    this.l8bh(),\n    this.l9d(),\n    this.l9e(),\n    this.l9g(),\n    this.l9h(),\n    this.l10d(),\n    this.l10e(),\n    this.l10g(),\n    this.l10h(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    !this.l17(),\n    this.l18(),\n    this.l19(),\n    this.l20() === true,\n    this.l20() === false,\n    this.l21(),\n    this.l22() === true,\n    this.l22() === false\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleE.ts",
    "content": "import {\n  Address,\n  Property,\n  PropertyType,\n  PropertyExpenseTypeName\n} from 'ustaxes/core/data'\nimport { displayNegPos, sumFields } from 'ustaxes/core/irsForms/util'\nimport _ from 'lodash'\nimport F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype Cell = number | undefined\nexport type MatrixRow = [Cell, Cell, Cell]\n\nconst fill = (values: number[]): MatrixRow => {\n  const realValues = (values as Cell[]).slice(0, 3).map((v) => {\n    if (v === 0) {\n      return undefined\n    }\n    return v\n  })\n  return [\n    ...realValues,\n    ...Array.from(Array(3 - realValues.length)).map(() => undefined)\n  ] as MatrixRow\n}\n\nconst propTypeIndex = {\n  [PropertyType.singleFamily]: 1,\n  [PropertyType.multiFamily]: 2,\n  [PropertyType.vacation]: 3,\n  [PropertyType.commercial]: 4,\n  [PropertyType.land]: 5,\n  [PropertyType.selfRental]: 7,\n  [PropertyType.other]: 8\n}\n\nexport default class ScheduleE extends F1040Attachment {\n  tag: FormTag = 'f1040se'\n  sequenceIndex = 13\n\n  isNeeded = (): boolean =>\n    this.f1040.info.realEstate.length > 0 ||\n    this.f1040.info.scheduleK1Form1065s.length > 0\n\n  addressString = (address: Address): string =>\n    [\n      address.address,\n      address.city,\n      address.state ?? address.province ?? '',\n      address.zip ?? address.postalCode ?? ''\n    ].join(', ')\n\n  propForRow = (row: number): Property | undefined => {\n    if (row < this.f1040.info.realEstate.length) {\n      return this.f1040.info.realEstate[row]\n    }\n  }\n\n  /**\n   * Whether or not you can deduct expenses for the unit depends on whether or not you used\n   * the unit as a home in 2020. You used the unit as a home if your personal use of the unit\n   * was more than the greater of:\n   * 14 days, or\n   * 10% of the total days it was rented to others at a fair rental price.\n   * @param p\n   */\n  propertyUseTest = (p: Property): boolean =>\n    p.personalUseDays <= Math.max(14, 0.1 * p.rentalDays)\n\n  l3 = (): MatrixRow => {\n    const properties = this.f1040.info.realEstate\n    return fill(properties.map((a) => a.rentReceived))\n  }\n\n  // TODO: not implemented\n  l4 = (): MatrixRow => {\n    return [undefined, undefined, undefined]\n  }\n\n  getExpensesRow = (expType: PropertyExpenseTypeName): MatrixRow =>\n    fill(\n      this.f1040.info.realEstate.map((p) => {\n        if (this.propertyUseTest(p)) {\n          return p.expenses[expType] ?? 0\n        }\n        return 0\n      })\n    )\n\n  // Matching order of expenses in rows of form\n  expenses: PropertyExpenseTypeName[] = [\n    'advertising',\n    'auto',\n    'cleaning',\n    'commissions',\n    'insurance',\n    'legal',\n    'management',\n    'mortgage',\n    'otherInterest',\n    'repairs',\n    'supplies',\n    'taxes',\n    'utilities',\n    'depreciation'\n  ]\n\n  l19 = (): [string | undefined, MatrixRow] => {\n    const expenseRow = this.getExpensesRow('other')\n    const otherText = this.f1040.info.realEstate\n      .flatMap((p) =>\n        p.otherExpenseType !== undefined ? [p.otherExpenseType] : []\n      )\n      .join(',')\n    return [otherText, expenseRow]\n  }\n\n  allExpenses = (): MatrixRow[] =>\n    this.expenses.map((e) => this.getExpensesRow(e))\n\n  l12 = (): MatrixRow => this.getExpensesRow('mortgage')\n  l18 = (): MatrixRow => this.getExpensesRow('depreciation')\n\n  // TODO - required from pub 596 worksheet 1\n  royaltyExpenses = (): number | undefined => undefined\n\n  l20 = (): MatrixRow =>\n    fill(_.unzip(this.allExpenses()).map((column) => sumFields(column)))\n\n  l21 = (): MatrixRow =>\n    _.zipWith(\n      this.l3(),\n      this.l4(),\n      this.l20(),\n      (x, y, z) => (x ?? 0) + (y ?? 0) - (z ?? 0)\n    ) as MatrixRow\n\n  // Deductible real estate loss from 8582, as positive number\n  l22 = (): MatrixRow =>\n    this.f1040.f8582?.deductibleRealEstateLossAfterLimitation() ?? [\n      undefined,\n      undefined,\n      undefined\n    ]\n\n  l23a = (): number => sumFields(this.l3())\n  l23b = (): number => sumFields(this.l4())\n  l23c = (): number => sumFields(this.l12())\n  l23d = (): number => sumFields(this.l18())\n  l23e = (): number => sumFields(this.l20())\n\n  rentalNet = (): MatrixRow =>\n    _.zipWith(this.l3(), this.l20(), (x, y) => (x ?? 0) - (y ?? 0)) as MatrixRow\n\n  l24 = (): number =>\n    sumFields(this.l21().filter((x) => x !== undefined && x > 0))\n\n  // TODO: Royalty losses\n  l25 = (): number => sumFields(this.l22())\n\n  l26 = (): number => sumFields([this.l24(), this.l25()])\n\n  // TODO: required from Pub 596\n  l29ah = (): number | undefined =>\n    this.f1040.info.scheduleK1Form1065s.reduce(\n      (t, k1) => t + Math.max(0, k1.isPassive ? k1.ordinaryBusinessIncome : 0),\n      0\n    )\n  l29ak = (): number | undefined =>\n    this.f1040.info.scheduleK1Form1065s.reduce(\n      (t, k1) => t + Math.max(0, k1.isPassive ? 0 : k1.ordinaryBusinessIncome),\n      0\n    )\n\n  l29bg = (): number | undefined =>\n    this.f1040.info.scheduleK1Form1065s.reduce(\n      (t, k1) => t + Math.min(0, k1.isPassive ? k1.ordinaryBusinessIncome : 0),\n      0\n    )\n  l29bi = (): number | undefined =>\n    this.f1040.info.scheduleK1Form1065s.reduce(\n      (t, k1) => t + Math.min(0, k1.isPassive ? 0 : k1.ordinaryBusinessIncome),\n      0\n    )\n  l29bj = (): number | undefined => undefined\n\n  l30 = (): number | undefined => sumFields([this.l29ah(), this.l29ak()])\n  l31 = (): number | undefined =>\n    sumFields([this.l29bg(), this.l29bi(), this.l29bj()])\n  l32 = (): number | undefined => sumFields([this.l30(), this.l31()])\n\n  l34ad = (): number | undefined => undefined\n  l34af = (): number | undefined => undefined\n  l34bc = (): number | undefined => undefined\n  l34be = (): number | undefined => undefined\n\n  // TODO: Real estate trust income or loss\n  l37 = (): number | undefined => undefined\n\n  // TODO: REMICS income or loss\n  l39 = (): number | undefined => undefined\n\n  // TODO: Farm rental income or loss\n  l40 = (): number | undefined => undefined\n\n  l41 = (): number =>\n    sumFields([this.l26(), this.l32(), this.l37(), this.l39(), this.l40()])\n\n  fields = (): Field[] => {\n    const [p0, p1, p2] = [0, 1, 2].map((i) => this.propForRow(i))\n\n    // TODO: Support more than 4 K1s\n    const k1s = this.f1040.info.scheduleK1Form1065s\n    const l28Fields: Field[] = []\n    l28Fields.push(\n      ...k1s\n        .slice(0, 4)\n        .flatMap((k1) => [\n          k1.partnershipName,\n          k1.partnerOrSCorp,\n          k1.isForeign,\n          k1.partnershipEin,\n          false,\n          false\n        ])\n    )\n    l28Fields.push(\n      ...Array<undefined>(6 * Math.max(0, 4 - k1s.length)).fill(undefined)\n    )\n    l28Fields.push(\n      ...k1s.slice(0, 4).flatMap((k1) => {\n        if (k1.isPassive) {\n          if (k1.ordinaryBusinessIncome < 0) {\n            return [k1.ordinaryBusinessIncome, 0, 0, 0, 0]\n          } else {\n            return [0, k1.ordinaryBusinessIncome, 0, 0, 0]\n          }\n        } else {\n          if (k1.ordinaryBusinessIncome < 0) {\n            return [0, 0, k1.ordinaryBusinessIncome, 0, 0]\n          } else {\n            return [0, 0, 0, 0, k1.ordinaryBusinessIncome]\n          }\n        }\n      })\n    )\n    l28Fields.push(\n      ...Array<undefined>(5 * Math.max(0, 4 - k1s.length)).fill(undefined)\n    )\n\n    return [\n      this.f1040.namesString(),\n      this.f1040.info.taxPayer.primaryPerson.ssid,\n      false,\n      false,\n      false,\n      false,\n      ...[p0, p1, p2].map((p) =>\n        p === undefined ? undefined : this.addressString(p.address)\n      ),\n      p0 === undefined\n        ? undefined\n        : propTypeIndex[PropertyType[p0.propertyType]],\n      p1 === undefined\n        ? undefined\n        : propTypeIndex[PropertyType[p1.propertyType]],\n      p2 === undefined\n        ? undefined\n        : propTypeIndex[PropertyType[p2.propertyType]],\n      p0?.rentalDays,\n      p0?.personalUseDays,\n      p0?.qualifiedJointVenture,\n      p1?.rentalDays,\n      p1?.personalUseDays,\n      p1?.qualifiedJointVenture,\n      p2?.rentalDays,\n      p2?.personalUseDays,\n      p2?.qualifiedJointVenture,\n      [p0, p1, p2].find((p) => p?.propertyType === 'other')\n        ?.otherPropertyType ?? undefined,\n      ...this.l3(),\n      ...this.l4(),\n      ...this.allExpenses().flat(),\n      ...this.l19().flat(),\n      ...this.l20(),\n      ...this.l21(),\n      ...this.l22(),\n      this.l23a(),\n      this.l23b(),\n      this.l23c(),\n      this.l23d(),\n      this.l23e(),\n      this.l24(),\n      Math.abs(this.l25()),\n      displayNegPos(this.l26()),\n      // Page 2 - TODO: Only part II implemented\n      this.f1040.namesString(),\n      this.f1040.info.taxPayer.primaryPerson.ssid,\n      ...[false, false], // l27\n      ...l28Fields,\n      undefined, // grey\n      this.l29ah(),\n      undefined, // grey\n      undefined, // grey\n      this.l29ak(),\n      this.l29bg(),\n      undefined, // grey\n      this.l29bi(),\n      this.l29bj(),\n      undefined, // grey\n      this.l30(),\n      this.l31(),\n      this.l32(), // l32\n      ...Array<undefined>(2 * 6).fill(undefined), // l33\n      undefined,\n      this.l34ad(),\n      undefined,\n      this.l34af(),\n      this.l34bc(),\n      undefined, // grey\n      this.l34be(),\n      undefined, // grey\n      undefined, // l35\n      undefined, // l36\n      this.l37(), // l37\n      ...Array<undefined>(5).fill(undefined), // l38\n      this.l39(), // l39\n      this.l40(), // l40\n      this.l41(), // l41\n      undefined,\n      undefined\n    ]\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleEIC.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Dependent, FilingStatus } from 'ustaxes/core/data'\nimport F1040 from './F1040'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport * as federal from '../data/federal'\nimport F2555 from './F2555'\nimport F4797 from './F4797'\nimport F8814 from './F8814'\nimport Pub596Worksheet1 from './worksheets/Pub596Worksheet1'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { evaluatePiecewise, Piecewise } from 'ustaxes/core/util'\nimport _ from 'lodash'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\ntype PrecludesEIC<F> = (f: F) => boolean\n\n// TODO: check F2555\nconst checks2555: PrecludesEIC<F2555> = (): boolean => false\n\n// TODO: check F4797\nconst checks4797: PrecludesEIC<F4797> = (): boolean => false\n\n// TODO: check F8814\nconst checks8814: PrecludesEIC<F8814> = (): boolean => false\n\nconst checksPub596: PrecludesEIC<Pub596Worksheet1> = (f): boolean =>\n  f.precludesEIC()\n\nconst precludesEIC =\n  <F>(p: PrecludesEIC<F>) =>\n  (f: F | undefined): boolean => {\n    if (f === undefined) {\n      return false\n    }\n    return p(f)\n  }\n\nexport default class ScheduleEIC extends F1040Attachment {\n  tag: FormTag = 'f1040sei'\n  sequenceIndex = 43\n  pub596Worksheet1: Pub596Worksheet1\n  qualifyingStudentCutoffYear = 1996\n  qualifyingCutoffYear = 2001\n  investmentIncomeLimit = 3650\n\n  constructor(f1040: F1040) {\n    super(f1040)\n    this.pub596Worksheet1 = new Pub596Worksheet1(f1040)\n  }\n\n  isNeeded = (): boolean => this.allowed()\n\n  // instructions step 1.1\n  passIncomeLimit = (): boolean => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const incomeLimits = federal.EIC.caps[filingStatus]\n    if (incomeLimits !== undefined) {\n      const limit =\n        incomeLimits[\n          Math.min(this.qualifyingDependents().length, incomeLimits.length - 1)\n        ]\n      return this.f1040.l11() < limit\n    }\n    return false\n  }\n\n  // Step 1.2, todo, both spouses must have a SSN issued before 2020 due date\n  //\n  // TODO: ('Step 1.2 (valid SSNs) unchecked') and without work restriction and valid for eic purpos\n  validSSNs = (): boolean => {\n    return true\n  }\n\n  // Step 1.3\n  allowedFilingStatus = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFS\n\n  // Step 1.4\n  allowedFilling2555 = (): boolean =>\n    !precludesEIC(checks2555)(this.f1040.f2555)\n\n  //\n  // TODO: ('Step 1.5, Not checking non-resident alien') Step 1.5 nonResidentAli\n  allowedNonresidentAlien = (): boolean => {\n    return true\n  }\n\n  // step 2, question 1\n  investmentIncome = (): number =>\n    sumFields([\n      this.f1040.l2a(),\n      this.f1040.l2b(),\n      this.f1040.l3b(),\n      Math.max(this.f1040.l7() ?? 0, 0)\n    ])\n\n  passInvestmentIncomeLimit = (): boolean =>\n    this.investmentIncome() < federal.EIC.maxInvestmentIncome\n\n  // Todo, step 2, question 3\n  f4797AllowsEIC = (): boolean => !precludesEIC(checks4797)(this.f1040.f4797)\n\n  // Todo, instruction 2.4.1\n  filingScheduleE = (): boolean => this.f1040.scheduleE.isNeeded()\n\n  //\n  // TODO: ('Not checking personal property income') 2.4\n  passIncomeFromPersonalProperty = (): boolean => {\n    return true\n  }\n\n  // 2.4.3\n  passForm8814 = (): boolean => !precludesEIC(checks8814)(this.f1040.f8814)\n\n  //\n  // TODO: ('Not checking passive activity') 2.4\n  incomeOrLossFromPassiveActivity = (): boolean => {\n    return false\n  }\n\n  // 2.4.5\n  passPub596 = (): boolean => !precludesEIC(checksPub596)(this.pub596Worksheet1)\n\n  // 3.1\n  atLeastOneChild = (): boolean => this.qualifyingDependents().length > 0\n\n  // 3.2, 4.4\n  jointReturn = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ\n\n  //\n  // TODO: ('3.3: Not checking qualifying child of another') 3.3, 4\n  qualifyingChildOfAnother = (): boolean => {\n    return false\n  }\n\n  // 4.1 - covered by income limit check\n  //\n  // TODO: ('4.2: Not checking taxpayer age') 4\n  over25Under65 = (): boolean => {\n    return true\n  }\n\n  //\n  // TODO: ('4.3: Not checking residency') 4\n  mainHomeInsideUsBothPeople = (): boolean => {\n    return true\n  }\n\n  // 4.4 covered above\n  // 4.5 covered above\n  // 4.6 dependent of another\n  dependentOfAnother = (): boolean =>\n    this.f1040.info.taxPayer.primaryPerson.isTaxpayerDependent ||\n    (this.f1040.info.taxPayer.spouse?.isTaxpayerDependent ?? false)\n\n  //\n  // TODO: ('5.1: Not checking church self-employment income') 5.1 - Filing schedule SE for chur\n  filingSEChurchIncome = (): boolean => {\n    return false\n  }\n\n  //\n  // TODO: ('5.1.2: Not checking scholarship, grants') 5.1\n  taxableScholarshipIncome = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: ('5.1.3: Not checking prison income') 5.1\n  prisonIncome = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: ('5.1.4: Not checking pension income') 5.1\n  pensionPlanIncome = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: ('5.1.5: Not checking medicaid waiver') 5.1\n  medicaidWaiverPayment = (): number => {\n    return 0\n  }\n\n  //\n  // TODO: ('5.1.8: Not checking nontaxable combat pay') 5.1\n  nontaxableCombatPay = (): number => {\n    return 0\n  }\n\n  // 5.1 - Earned income\n  earnedIncome = (): number => {\n    const l1 = this.f1040.l1()\n    const l2 = this.taxableScholarshipIncome()\n    const l3 = this.prisonIncome()\n    const l4 = this.pensionPlanIncome()\n    const l5 = this.medicaidWaiverPayment()\n    const l6 = l2 + l3 + l4 + l5\n    const l7 = l1 - l6\n    const l8 = this.nontaxableCombatPay()\n    const l9 = l7 + l8\n    return l9\n  }\n\n  /**\n   * The credit table in Publication 596 provides an\n   * amount for each interval of $50, calculated from the\n   * midpoint of the interval.\n   *\n   * @param income The earned income\n   * @returns the earned income rounded to the nearest 25\n   */\n  roundIncome = (income: number): number => {\n    if (income < 1) {\n      return 0\n    }\n    return Math.round(Math.round(income) / 50) * 50 + 25\n  }\n\n  /**\n   * Based on the earned income and filing status, calculate the\n   * allowed EITC.\n   *\n   * For tax year 2020, IRS Rev. Proc. 2019-44 outlines the required\n   * calculation for the EITC based on number of qualifying children\n   * and filing status.\n   *\n   * https://www.irs.gov/pub/irs-drop/rp-19-44.pdf\n   *\n   * IRS publication 596 provides a table that can be used\n   * to figure the EITC, and is the basis of online calculators published\n   * by IRS. This table uses the formulas outlined in Rev Proc 2019-44\n   * but applies them to incomes lying in $50 intervals, with the midpoint\n   * of those intervals used to calculate the credit for the entire window.\n   * For example, if the taxpayer has an earned income of $5000, the amount\n   * that is found in the table is calculated based on an income of $5025 and\n   * comes out ahead. Conversely, someone with an earned income of $5049 finds\n   * a credit in the table calculated off the same $5,025 and loses out.\n   *\n   * https://www.irs.gov/pub/irs-pdf/p596.pdf\n   *\n   * @param income The earned income\n   * @returns\n   */\n  calculateEICForIncome = (income: number): number => {\n    const filingStatus = this.f1040.info.taxPayer.filingStatus\n    const f: Piecewise[] | undefined = federal.EIC.formulas[filingStatus]\n    if (f === undefined) {\n      return 0\n    }\n\n    return Math.max(\n      0,\n      evaluatePiecewise(\n        f[this.qualifyingDependents().length],\n        this.roundIncome(income)\n      )\n    )\n  }\n\n  //\n  // TODO: ('5.2: Not checking selfemployment') 5\n  selfEmployed = (): boolean => {\n    return false\n  }\n\n  // 5.3 - covered by income check\n\n  // 6.1 - We will figure the credit.\n\n  // EIC worksheet A calculation\n  credit = (): number =>\n    Math.min(\n      this.calculateEICForIncome(this.earnedIncome()),\n      this.calculateEICForIncome(this.f1040.l11())\n    )\n\n  allowed = (): boolean => {\n    return (\n      // Step 1\n      this.passIncomeLimit() &&\n      this.validSSNs() &&\n      this.allowedFilingStatus() &&\n      this.allowedFilling2555() &&\n      this.allowedNonresidentAlien() &&\n      // Step 2\n      (this.passInvestmentIncomeLimit() || this.f4797AllowsEIC()) &&\n      (!(\n        // Step 3\n        (\n          this.filingScheduleE() ||\n          !this.passIncomeFromPersonalProperty() ||\n          !this.passForm8814() ||\n          this.incomeOrLossFromPassiveActivity()\n        )\n      ) ||\n        this.passPub596()) &&\n      !(\n        // Step 4\n        (\n          this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFJ &&\n          this.dependentOfAnother()\n        )\n      ) &&\n      this.credit() > 0\n    )\n  }\n\n  qualifyingDependents = (): Dependent[] =>\n    this.f1040.info.taxPayer.dependents\n      .filter(\n        (d) =>\n          d.dateOfBirth.getFullYear() >= this.qualifyingCutoffYear ||\n          ((d.qualifyingInfo?.isStudent ?? false) &&\n            d.dateOfBirth.getFullYear() >= this.qualifyingStudentCutoffYear)\n      )\n      .sort((d) => d.dateOfBirth.getFullYear())\n      .slice(0, 3)\n\n  qualifyingDependentsFilled = (): Array<Dependent | undefined> => {\n    const res = this.qualifyingDependents()\n    return _.fill([...res], undefined, res.length, 3)\n  }\n\n  // EIC line 1\n  nameFields = (): Array<string | undefined> =>\n    this.qualifyingDependentsFilled().map(\n      (d) => `${d?.firstName ?? ''} ${d?.lastName ?? ''}`\n    )\n\n  // EIC line 2\n  ssnFields = (): Array<string | undefined> =>\n    this.qualifyingDependentsFilled().map((d) => d?.ssid)\n\n  years = (): Array<number | undefined> =>\n    this.qualifyingDependentsFilled().map((d) => d?.dateOfBirth.getFullYear())\n\n  // EIC line 3\n  birthYearFields = (): Array<string | undefined> =>\n    this.years().flatMap((year) => {\n      if (year !== undefined) {\n        return String(year).split('')\n      }\n      return [undefined, undefined, undefined, undefined]\n    })\n\n  // EIC line 4a: Not handling case of child older than taxpayer\n  ageFields = (): Array<boolean | undefined> =>\n    this.years().flatMap((year) => {\n      if (year !== undefined) {\n        const qualifies = year > 1996\n        return [qualifies, !qualifies]\n      }\n      return [undefined, undefined]\n    })\n\n  // TODO: disability\n  disabledFields = (): Array<boolean | undefined> =>\n    this.years().flatMap((year) => {\n      if (year === undefined || year < this.qualifyingCutoffYear) {\n        return [undefined, undefined]\n      }\n      return [undefined, undefined]\n    })\n\n  // Line 5\n  // TODO: Address eic relationships\n  relationships = (): Array<string | undefined> =>\n    this.qualifyingDependentsFilled().map((d) => d?.relationship)\n\n  // Line 6\n  numberMonths = (): Array<number | undefined> =>\n    this.qualifyingDependents().map((d) => d.qualifyingInfo?.numberOfMonths)\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    ...this.nameFields(), // 6\n    ...this.ssnFields(), // 3\n    ...this.birthYearFields(), // 12\n    ...this.ageFields(), // 6\n    ...this.disabledFields(), // 6\n    ...this.relationships(),\n    ...this.numberMonths()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleR.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\n\nexport default class ScheduleR extends F1040Attachment {\n  tag: FormTag = 'f1040sr'\n  sequenceIndex = 999\n\n  l22 = (): number | undefined => undefined\n\n  fields = (): Field[] => []\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/ScheduleSE.ts",
    "content": "import F1040Attachment from './F1040Attachment'\nimport { FormTag } from 'ustaxes/core/irsForms/Form'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { Field } from 'ustaxes/core/pdfFiller'\n\nexport default class ScheduleSE extends F1040Attachment {\n  tag: FormTag = 'f1040sse'\n  sequenceIndex = 14\n\n  isNeeded = (): boolean =>\n    this.f1040.info.scheduleK1Form1065s\n      .map(\n        (k1) =>\n          k1.selfEmploymentEarningsA +\n          k1.selfEmploymentEarningsB +\n          k1.selfEmploymentEarningsC\n      )\n      .reduce((a, b) => a + b, 0) > 0\n\n  postL4Field = (f: () => number | undefined): number | undefined => {\n    if (this.l4c() < 400) {\n      return undefined\n    }\n    return f()\n  }\n\n  l8aRelatedField = (f: () => number | undefined): number | undefined => {\n    return this.postL4Field(() => {\n      if ((this.l8a() ?? 0) >= 142800) {\n        return undefined\n      }\n      return f()\n    })\n  }\n\n  l1a = (): number => {\n    const schFL34 = 0 // TODO: Net farm profit or (loss) from Schedule F, line 34\n    const k1B14 = 0 // TODO: If a farm partnership\n    return schFL34 + k1B14\n  }\n\n  l1b = (): number => 0\n\n  l2 = (): number => {\n    const schFL34 = 0 // TODO: Net farm profit or (loss) from Schedule F, line 34\n    const k1B14 = this.f1040.info.scheduleK1Form1065s.reduce(\n      (c, k1) => c + k1.selfEmploymentEarningsA,\n      0\n    )\n    return schFL34 + k1B14\n  }\n\n  l3 = (): number => sumFields([this.l1a(), this.l1b(), this.l2()])\n\n  l4a = (): number => {\n    const l3 = this.l3()\n    if (l3 > 0) {\n      return l3 * 0.9235\n    }\n    return l3\n  }\n\n  l4b = (): number | undefined => undefined\n\n  l4c = (): number => sumFields([this.l4a(), this.l4b()])\n\n  l5a = (): number | undefined => this.postL4Field(() => 0)\n  l5b = (): number | undefined =>\n    this.postL4Field(() => {\n      const l5a = this.l5a()\n      if (l5a === undefined) {\n        return undefined\n      }\n      return l5a * 0.9235\n    })\n\n  l6 = (): number | undefined =>\n    this.postL4Field((): number => sumFields([this.l4c(), this.l5b()]))\n\n  l7 = (): number => 142800\n\n  l8a = (): number | undefined =>\n    this.postL4Field((): number =>\n      this.f1040.validW2s().reduce((c, w2) => c + w2.ssWages, 0)\n    )\n\n  l8b = (): number | undefined =>\n    this.l8aRelatedField((): number | undefined => undefined)\n  l8c = (): number | undefined =>\n    this.l8aRelatedField((): number | undefined => undefined)\n  l8d = (): number | undefined =>\n    this.l8aRelatedField((): number =>\n      sumFields([this.l8a(), this.l8b(), this.l8c()])\n    )\n\n  l9 = (): number | undefined =>\n    this.l8aRelatedField((): number =>\n      Math.max(0, this.l7() - (this.l8d() ?? 0))\n    )\n\n  l10 = (): number | undefined =>\n    this.l8aRelatedField(\n      (): number => Math.min(this.l6() ?? 0, this.l9() ?? 0) * 0.124\n    )\n\n  l11 = (): number | undefined =>\n    this.postL4Field((): number => (this.l6() ?? 0) * 0.029)\n\n  l12 = (): number | undefined =>\n    this.postL4Field((): number => sumFields([this.l10(), this.l11()]))\n\n  l13 = (): number | undefined =>\n    this.postL4Field((): number => (this.l12() ?? 0) * 0.5)\n\n  fields = (): Field[] => [\n    this.f1040.namesString(),\n    this.f1040.info.taxPayer.primaryPerson.ssid,\n    false, // Minister\n    this.l1a(),\n    this.l1b(),\n    this.l2(),\n    this.l3(),\n    this.l4a(),\n    this.l4b(),\n    this.l4c(),\n    this.l5a(),\n    this.l5b(),\n    this.l6(),\n    this.l7(),\n    this.l8a(),\n    this.l8b(),\n    this.l8c(),\n    this.l8d(),\n    this.l9(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/TaxTable.ts",
    "content": "import federalBrackets from '../data/federal'\nimport { FilingStatus } from 'ustaxes/core/data'\nimport _ from 'lodash'\n\nconst computeTax =\n  (brackets: (status: FilingStatus) => number[], rates: number[]) =>\n  (filingStatus: FilingStatus, income: number): number =>\n    _.chain([0, ...brackets(filingStatus)]) // Low end of each bracket\n      .zipWith(\n        [...brackets(filingStatus), undefined], // top end of each bracket\n        rates.map((r) => r / 100), // rate for each bracket\n        (low, high, rate) => {\n          if (income < low) {\n            // this bracket is above income, no tax here\n            return 0\n          } else if (high === undefined) {\n            // This is the top bracket\n            return Math.max(0, income - low) * rate\n          } else if (income >= high) {\n            // Taxable income is above the top of this bracket\n            // so add the max tax for this bracket\n            return (high - low) * rate\n          }\n          // Otherwise max income is inside this bracket,\n          // add the tax on the amount falling in this bracket\n\n          if (income < 5) {\n            return 0\n          }\n          // If income is between $5 and $25, tax table computes rate at midpoint of $5 ranges\n          if (income >= 5 && income < 25) {\n            income = Math.floor(income)\n            const over5 = income % 5\n            income += 2.5 - over5\n          }\n          // If income is between $25 and $3,000, tax table computes rate at midpoint of $25 ranges\n          else if (income >= 25 && income < 3000) {\n            income = Math.floor(income)\n            const over25 = income % 25\n            income += 12.5 - over25\n          }\n          // If income is between $3,000 and $100,000, tax table computes rate at midpoint of $50 ranges\n          else if (income >= 3000 && income < 100000) {\n            income = Math.floor(income)\n            const over50 = income % 50\n            income += 25 - over50\n          }\n          return (income - low) * rate\n        }\n      )\n      .sum()\n      .value()\n\nexport const computeOrdinaryTax = computeTax(\n  (status) => federalBrackets.ordinary.status[status].brackets,\n  federalBrackets.ordinary.rates\n)\n\nexport const computeLongTermCapGainsTax = computeTax(\n  (status) => federalBrackets.longTermCapGains.status[status].brackets,\n  federalBrackets.longTermCapGains.rates\n)\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/index.ts",
    "content": "import { PDFDocument } from 'pdf-lib'\nimport { create1040 } from '../irsForms/Main'\nimport { Either, isLeft, isRight, right } from 'ustaxes/core/util'\nimport log from 'ustaxes/core/log'\nimport { combinePdfs, PDFDownloader } from 'ustaxes/core/pdfFiller/pdfHandler'\nimport { Information, Asset } from 'ustaxes/core/data'\nimport { insertFormDataToPdfs } from 'ustaxes/core/irsForms'\nimport { F1040Error } from 'ustaxes/forms/errors'\n\nexport { create1040 }\n\nexport const create1040PDFs =\n  (state: Information, assets: Asset<Date>[]) =>\n  async (\n    downloader: PDFDownloader\n  ): Promise<Either<F1040Error[], PDFDocument[]>> => {\n    if (state.taxPayer.primaryPerson !== undefined) {\n      const f1040Result = create1040(state, assets)\n      // Get data and pdf links applicable to the model state\n      if (isLeft(f1040Result)) {\n        return Promise.reject(f1040Result)\n      }\n\n      const [, forms] = f1040Result.right\n\n      return right(await insertFormDataToPdfs(forms, downloader))\n    }\n\n    log.error('Attempt to create pdf with no data, will be empty')\n    return right([])\n  }\n\nexport const create1040PDF =\n  (state: Information, assets: Asset<Date>[]) =>\n  async (\n    downloader: PDFDownloader\n  ): Promise<Either<F1040Error[], Uint8Array>> => {\n    const pdfResult = await create1040PDFs(state, assets)(downloader)\n    if (isRight(pdfResult)) {\n      const pdf = await combinePdfs(pdfResult.right)\n      const bytes = await pdf.save()\n      return right(bytes)\n    } else {\n      return Promise.resolve(pdfResult)\n    }\n  }\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/Pub596Worksheet1.ts",
    "content": "import { EIC } from '../../data/federal'\nimport { ifNegative, ifPositive } from 'ustaxes/core/util'\nimport F1040 from '../../irsForms/F1040'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\n\nexport default class Pub596Worksheet1 {\n  f1040: F1040\n\n  constructor(f1040: F1040) {\n    this.f1040 = f1040\n  }\n\n  l1 = (): number | undefined => this.f1040.l2b()\n  l2 = (): number | undefined =>\n    sumFields([this.f1040.l2a(), this.f1040.f8814?.l1b()])\n  l3 = (): number | undefined => this.f1040.l3b()\n  l4 = (): number | undefined => {\n    return this.f1040.schedule1.l8f()\n  }\n\n  l5 = (): number => ((this.f1040.l7() ?? 0) < 0 ? 0 : this.f1040.l7() ?? 0)\n  l6 = (): number => {\n    const l7 = this.f1040.f4797?.l7()\n    const l9 = this.f1040.f4797?.l9()\n\n    if (l7 !== undefined && l7 < 0) {\n      return l9 ?? 0\n    }\n\n    return l7 ?? 0\n  }\n\n  l7 = (): number => {\n    const diff = this.l5() - this.l6()\n    return diff < 0 ? 0 : diff\n  }\n\n  l8 = (): number | undefined =>\n    sumFields([this.f1040.scheduleE.l23b(), this.f1040.schedule1.l8k()])\n\n  l9 = (): number | undefined =>\n    sumFields([\n      this.f1040.scheduleE.royaltyExpenses(),\n      this.f1040.schedule1.l24b()\n    ])\n\n  l10 = (): number => Math.max(0, (this.l9() ?? 0) - (this.l8() ?? 0))\n\n  l11 = (): number | undefined =>\n    sumFields([\n      ifPositive(this.f1040.scheduleE.l26()),\n      this.f1040.scheduleE.l29ah(),\n      this.f1040.scheduleE.l34ad(),\n      this.f1040.scheduleE.l40()\n      // todo: FPA form 4797 line 10\n    ])\n\n  l12 = (): number | undefined =>\n    sumFields(\n      [\n        this.f1040.scheduleE.l26(),\n        this.f1040.scheduleE.l29bg() ?? 0,\n        this.f1040.scheduleE.l34bc() ?? 0,\n        this.f1040.scheduleE.l40() ?? 0\n        // TODO: PAL Loss form 4797\n      ].map((x) => ifNegative(x))\n    )\n\n  l13 = (): number | undefined =>\n    ifPositive(sumFields([this.l11(), this.l12()]))\n\n  l14 = (): number | undefined =>\n    sumFields([\n      this.l1(),\n      this.l2(),\n      this.l3(),\n      this.l4(),\n      this.l7(),\n      this.l10(),\n      this.l13()\n    ])\n\n  l15 = (): boolean => (this.l14() ?? 0) > EIC.maxInvestmentIncome\n\n  precludesEIC = (): boolean => this.l15()\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/QualifyingDependents.ts",
    "content": "import F1040 from '../F1040'\nimport { Dependent } from 'ustaxes/core/data'\nimport * as federal from '../../data/federal'\n\n/**\n * As of TY2021, the Child Tax Credit worksheet\n * is no longer published. This just implements\n * the qualifying dependent logic.\n */\nexport default class QualifyingDependents {\n  f1040: F1040\n  year = 2021\n\n  constructor(f1040: F1040) {\n    this.f1040 = f1040\n  }\n\n  qualifiesChild = (d: Dependent): boolean =>\n    this.year - d.dateOfBirth.getFullYear() <\n    federal.QualifyingDependents.childMaxAge\n\n  qualifiesOther = (d: Dependent): boolean =>\n    d.qualifyingInfo !== undefined &&\n    !this.qualifiesChild(d) &&\n    this.year - d.dateOfBirth.getFullYear() <\n      (d.qualifyingInfo.isStudent\n        ? federal.QualifyingDependents.qualifyingDependentMaxAge\n        : federal.QualifyingDependents.qualifyingStudentMaxAge)\n\n  qualifyingChildren = (): Dependent[] =>\n    this.f1040.info.taxPayer.dependents.filter((dep) =>\n      this.qualifiesChild(dep)\n    )\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/SDQualifiedAndCapGains.ts",
    "content": "// Reference implementation for ltcg and cap gains worksheet\nimport { WorksheetData } from 'ustaxes/components/SummaryData'\nimport { FilingStatus } from 'ustaxes/core/data'\nimport federalBrackets from '../../data/federal'\nimport { computeOrdinaryTax } from '../../irsForms/TaxTable'\nimport { Worksheet } from '../F1040Attachment'\n\ntype Bracket = [number, number]\ntype Cutoffs = { [key in FilingStatus]: Bracket }\nconst cutoffAmounts: Cutoffs = {\n  [FilingStatus.S]: [40400, 445850],\n  [FilingStatus.MFJ]: [80800, 501600],\n  [FilingStatus.MFS]: [40400, 250800],\n  [FilingStatus.W]: [80800, 501600],\n  [FilingStatus.HOH]: [54100, 473750]\n}\n\nexport default class QualDivAndCGWorksheet extends Worksheet {\n  // 1. Enter the amount from Form 1040 or 1040-SR, line 15.\n  // However, if you are filing Form 2555(relating to foreign earned income),\n  // enter the amount from line 3 of the Foreign Earned Income Tax Worksheet\n  l1 = (): number => {\n    if (this.f1040.f2555 !== undefined) {\n      return this.f1040.f2555.l3() ?? 0\n    }\n    return this.f1040.l15()\n  }\n  // 2. Enter the amount from Form 1040 or 1040-SR, line 3a*\n  l2 = (): number => this.f1040.l3a() ?? 0\n  // 3. Are you filing Schedule D?*\n  // Yes. Enter the smaller of line 15 or 16 of Schedule D.\n  //      If either line 15 or 16 is blank or a loss, enter - 0 -. 3.\n  // No. Enter the amount from Form 1040 or 1040-SR, line 7.\n  l3 = (): number => {\n    if (this.f1040.scheduleD.isNeeded()) {\n      return Math.min(\n        Math.max(this.f1040.scheduleD.l15(), 0),\n        Math.max(this.f1040.scheduleD.l16(), 0)\n      )\n    }\n    return this.f1040.l7() ?? 0\n  }\n  // 4. Add lines 2 and 3: LTCG + QDIV\n  l4 = (): number => this.l2() + this.l3()\n  // 5. Subtract line 4 from line 1. If zero or less, enter -0-\n  l5 = (): number => Math.max(this.l1() - this.l4(), 0)\n  // 6. Enter:\n  // $40,400 if single or married filing separately,\n  // $80,800 if married filing jointly or qualifying widow(er), $54,100 if head of household.\n  l6 = (): number => cutoffAmounts[this.f1040.info.taxPayer.filingStatus][0]\n  // 7. Enter the smaller of line 1 or line 6\n  l7 = (): number => Math.min(this.l1(), this.l6())\n  // 8. Enter the smaller of line 5 or line 7\n  l8 = (): number => Math.min(this.l5(), this.l7())\n  // 9. Subtract line 8 from line 7. This amount is taxed at 0%\n  l9 = (): number => this.l7() - this.l8()\n  // 10. Enter the smaller of line 1 or line 4\n  l10 = (): number => Math.min(this.l1(), this.l4())\n  // 11. Enter the amount from line 9\n  l11 = (): number => this.l9()\n  // 12. Subtract line 11 from line 10\n  l12 = (): number => this.l10() - this.l11()\n  // 13. Enter:\n  // $445,850 if single, $250,800 if married filing separately, $501,600 if married filing jointly or qualifying widow(er), $473,750 if head of household.\n  //\n  l13 = (): number => cutoffAmounts[this.f1040.info.taxPayer.filingStatus][1]\n  // 14. Enter the smaller of line 1 or line 13\n  l14 = (): number => Math.min(this.l1(), this.l13())\n  // 15. Add lines 5 and 9\n  l15 = (): number => this.l5() + this.l9()\n  // 16. Subtract line 15 from line 14. If zero or less, enter -0-\n  l16 = (): number => Math.max(this.l14() - this.l15(), 0)\n  // 17. Enter the smaller of line 12 or line 16\n  l17 = (): number => Math.min(this.l12(), this.l16())\n  // 18. Multiply line 17 by 15% (0.15)\n  l18 = (): number =>\n    (this.l17() * federalBrackets.longTermCapGains.rates[1]) / 100\n  // 19. Add lines 9 and 17\n  l19 = (): number => this.l9() + this.l17()\n  // 20. Subtract line 19 from line 10\n  l20 = (): number => this.l10() - this.l19()\n  // 21. Multiply line 20 by 20% (0.20)\n  l21 = (): number =>\n    (this.l20() * federalBrackets.longTermCapGains.rates[2]) / 100\n  // 22. Figure the tax on the amount on line 5. If the amount on line 5 is less than $100,000, use the Tax Table to figure the tax. If the amount on line 5 is $100,000 or more, use the Tax Computation Worksheet\n  l22 = (): number =>\n    computeOrdinaryTax(this.f1040.info.taxPayer.filingStatus, this.l5())\n  // 23. Add lines 18, 21, and 22\n  l23 = (): number => this.l18() + this.l21() + this.l22()\n  // 24. Figure the tax on the amount on line 1. If the amount on line 1 is less than $100,000, use the Tax Table to figure the tax. If the amount on line 1 is $100,000 or more, use the Tax Computation Worksheet\n  l24 = (): number =>\n    computeOrdinaryTax(this.f1040.info.taxPayer.filingStatus, this.l1())\n  // 25. Tax on all taxable income. Enter the smaller of line 23 or 24. Also include this amount on the entry space on Form 1040 or 1040-SR, line 16. If you are filing Form 2555, don’t enter this amount on the entry space on Form 1040 or 1040-SR, line 16. Instead, enter it on line 4 of the Foreign Earned Income Tax Worksheet\n  l25 = (): number => Math.min(this.l23(), this.l24())\n\n  tax = (): number => this.l25()\n\n  getSummaryData = (): WorksheetData => {\n    return {\n      name: 'Qualified Dividends and Capital Gains Worksheet — Line 16',\n      lines: [\n        {\n          line: 1,\n          value: this.l1()\n        },\n        {\n          line: 2,\n          value: this.l2()\n        },\n        {\n          line: 3,\n          value: this.l3()\n        },\n        {\n          line: 4,\n          value: this.l4()\n        },\n        {\n          line: 5,\n          value: this.l5()\n        },\n        {\n          line: 6,\n          value: this.l6()\n        },\n        {\n          line: 7,\n          value: this.l7()\n        },\n        {\n          line: 8,\n          value: this.l8()\n        },\n        {\n          line: 9,\n          value: this.l9()\n        },\n        {\n          line: 10,\n          value: this.l10()\n        },\n        {\n          line: 11,\n          value: this.l11()\n        },\n        {\n          line: 12,\n          value: this.l12()\n        },\n        {\n          line: 13,\n          value: this.l13()\n        },\n        {\n          line: 14,\n          value: this.l14()\n        },\n        {\n          line: 15,\n          value: this.l15()\n        },\n        {\n          line: 16,\n          value: this.l16()\n        },\n        {\n          line: 17,\n          value: this.l17()\n        },\n        {\n          line: 18,\n          value: this.l18()\n        },\n        {\n          line: 19,\n          value: this.l19()\n        },\n        {\n          line: 20,\n          value: this.l20()\n        },\n        {\n          line: 21,\n          value: this.l21()\n        },\n        {\n          line: 22,\n          value: this.l22()\n        },\n        {\n          line: 23,\n          value: this.l23()\n        },\n        {\n          line: 24,\n          value: this.l24()\n        },\n        {\n          line: 25,\n          value: this.l25()\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/SDRateGainWorksheet.ts",
    "content": "export default class SDRateGainWorksheet {\n  l7 = (): number | undefined => undefined\n  l10 = (): number | undefined => undefined\n  l13 = (): number | undefined => undefined\n  l14 = (): number | undefined => undefined\n  l21 = (): number | undefined => undefined\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/SDTaxWorksheet.ts",
    "content": "import { Worksheet } from '../F1040Attachment'\n\nexport default class SDTaxWorksheet extends Worksheet {\n  /**\n   * Complete this worksheet only if line 18 or line 19 of Schedule D is more than zero\n   * and lines 15 and 16 of Schedule D are gains or if you file Form 4952 and you have\n   * an amount on line 4g, even if you don’t need to file Schedule D. Otherwise,\n   * complete the Qualified Dividends and Capital Gain Tax Worksheet in the instructions\n   * for Forms 1040 and 1040-SR, line 16 (or in the instructions for Form 1040-NR, line 16)\n   * to figure your tax. Before completing this worksheet, complete Form 1040, 1040-SR, or\n   * 1040-NR through line 15.\n   */\n  isNeeded = (): boolean => {\n    const sd = this.f1040.scheduleD\n    const f4952 = this.f1040.f4952\n\n    const sdCondition =\n      sd.isNeeded() &&\n      ((sd.l18() ?? 0) > 0 || (sd.l19() ?? 0) > 0) &&\n      sd.l15() > 0 &&\n      sd.l16() > 0\n\n    const f4952Condition = f4952 !== undefined && (f4952.l4g() ?? 0) > 0\n\n    return sdCondition || f4952Condition\n  }\n\n  // TODO - Required by 6251,\n  // Might be refigured for AMT\n  l10 = (): number | undefined => undefined\n\n  // TODO - Required by 6251,\n  l13 = (): number | undefined => undefined\n\n  // TODO - Required by 6251,\n  l14 = (): number | undefined => undefined\n\n  // TODO - Required by 6251,\n  l21 = (): number | undefined => undefined\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/SDUnrecaptured1250.ts",
    "content": "export default class SDUnrecaptured1250 {\n  l18 = (): number | undefined => undefined\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/ScheduleDTaxWorksheet.ts",
    "content": "// Reference implementation for Schedule D Tax Worksheet\nimport { FilingStatus } from 'ustaxes/core/data'\nimport { computeOrdinaryTax } from '../../irsForms/TaxTable'\n\nexport interface TestData {\n  qualDiv: number\n  taxableIncome: number\n  f4952l4g: number\n  f4952l4e: number\n  sdl15: number\n  sdl16: number\n  sdl18: number\n  sdl19: number\n  filingStatus: FilingStatus\n}\n\ntype Bracket = [number, number, number]\ntype Cutoffs = { [key in FilingStatus]: Bracket }\nconst cutoffAmounts: Cutoffs = {\n  [FilingStatus.S]: [40000, 163300, 441450],\n  [FilingStatus.MFJ]: [80000, 326600, 496600],\n  [FilingStatus.MFS]: [40000, 163300, 441450],\n  [FilingStatus.W]: [80000, 326600, 496600],\n  [FilingStatus.HOH]: [53600, 163300, 469050]\n}\n\nexport default class LTCGQualDivReference {\n  [k: string]: TestData | (() => number)\n  data: TestData\n\n  constructor(data: TestData) {\n    this.data = data\n  }\n\n  // 1. Enter your taxable income from Form 1040, 1040-SR, or 1040-NR, line 15. (However, if you are filing Form 2555 (relating to foreign earned income), enter instead the amount from line 3 of the Foreign Earned Income Tax Worksheet in the instructions for Forms 1040 and 1040-SR, line 16)\n  l1 = (): number => this.data.taxableIncome\n  // 2. Enter your qualified dividends from Form 1040, 1040-SR, or 1040-NR, line 3a\n  l2 = (): number => this.data.qualDiv\n  // 3. Enter the amount from Form 4952 (used to figure investment interest expense deduction), line 4g\n  l3 = (): number => this.data.f4952l4g\n  // 4. Enter the amount from Form 4952, line 4e*\n  l4 = (): number => this.data.f4952l4e\n  // 5. Subtract line 4 from line 3. If zero or less, enter -0-\n  l5 = (): number => Math.max(0, this.l3() - this.l4())\n  // 6. Subtract line 5 from line 2. If zero or less, enter -0-**\n  l6 = (): number => Math.max(0, this.l2() - this.l5())\n  // 7. Enter the smaller of line 15 or line 16 of Schedule D\n  l7 = (): number => Math.min(this.data.sdl15, this.data.sdl16)\n  // 8. Enter the smaller of line 3 or line 4\n  l8 = (): number => Math.min(this.l3(), this.l4())\n  // 9. Subtract line 8 from line 7. If zero or less, enter -0-**\n  l9 = (): number => Math.max(0, this.l7() - this.l8())\n  // 10. Add lines 6 and 9\n  l10 = (): number => this.l6() + this.l9()\n  // 11. Add lines 18 and 19 of Schedule D**\n  l11 = (): number => this.data.sdl18 + this.data.sdl19\n  // 12. Enter the smaller of line 9 or line 11\n  l12 = (): number => Math.min(this.l9(), this.l11())\n  // 13. Subtract line 12 from line 10\n  l13 = (): number => this.l10() - this.l12()\n  // 14. Subtract line 13 from line 1. If zero or less, enter -0-\n  l14 = (): number => Math.max(0, this.l1() - this.l13())\n  // 15. Enter:\n  l15 = (): number => cutoffAmounts[this.data.filingStatus][0]\n  // 16. Enter the smaller of line 1 or line 15\n  l16 = (): number => Math.min(this.l1(), this.l15())\n  // 17. Enter the smaller of line 14 or line 16\n  l17 = (): number => Math.min(this.l14(), this.l16())\n  // 18. Subtract line 10 from line 1. If zero or less, enter -0-\n  l18 = (): number => Math.max(0, this.l1() - this.l10())\n  // 19. Enter the smaller of line 1 or [ltcg bracket 2]\n  l19 = (): number =>\n    Math.min(this.l1(), cutoffAmounts[this.data.filingStatus][1])\n  // 20. Enter the smaller of line 14 or line 19\n  l20 = (): number => Math.min(this.l14(), this.l19())\n  // 21. Enter the larger of line 18 or line 20\n  l21 = (): number => Math.max(this.l18(), this.l20())\n  // 22. Subtract line 17 from line 16. This amount is taxed at 0%.\n  l22 = (): number => Math.max(0, this.l16() - this.l17())\n  // If lines 1 and 16 are the same, skip lines 23 through 43 and go to line 44. Otherwise, go to line 23.\n  // 23. Enter the smaller of line 1 or line 13\n  l23 = (): number => Math.min(this.l1(), this.l13())\n  // 24. Enter the amount from line 22. (If line 22 is blank, enter -0-.)\n  l24 = (): number => this.l22()\n  // 25. Subtract line 24 from line 23. If zero or less, enter -0-\n  l25 = (): number => Math.max(0, this.l23() - this.l24())\n  // 26. Enter top bracket amount\n  l26 = (): number => cutoffAmounts[this.data.filingStatus][1]\n  // 27. Enter the smaller of line 1 or line 26\n  l27 = (): number => Math.min(this.l1(), this.l26())\n  // 28. Add lines 21 and 22\n  l28 = (): number => this.l21() + this.l22()\n  // 29. Subtract line 28 from line 27. If zero or less, enter -0-\n  l29 = (): number => Math.max(0, this.l27() - this.l28())\n  // 30. Enter the smaller of line 25 or line 29\n  l30 = (): number => Math.min(this.l25(), this.l29())\n  // 31. Multiply line 30 by 15% (0.15)\n  l31 = (): number => this.l30() * 0.15\n  // 32. Add lines 24 and 30\n  l32 = (): number => this.l24() + this.l30()\n  // If lines 1 and 32 are the same, skip lines 33 through 43 and go to line 44. Otherwise, go to line 33.\n  // 33. Subtract line 32 from line 23\n  l33 = (): number => Math.max(0, this.l23() - this.l32())\n  // 34. Multiply line 33 by 20% (0.20)\n  l34 = (): number => this.l33() * 0.2\n  // If Schedule D, line 19, is zero or blank, skip lines 35 through 40 and go to line 41. Otherwise, go to line 35.\n  // 35. Enter the smaller of line 9 above or Schedule D, line 19\n  l35 = (): number => Math.min(this.l9(), this.data.sdl19)\n  // 36. Add lines 10 and 21\n  l36 = (): number => this.l10() + this.l21()\n  // 37. Enter the amount from line 1 above\n  l37 = (): number => this.l1()\n  // 38. Subtract line 37 from line 36. If zero or less, enter -0-\n  l38 = (): number => Math.max(0, this.l36() - this.l37())\n  // 39. Subtract line 38 from line 35. If zero or less, enter -0-\n  l39 = (): number => Math.max(0, this.l35() - this.l38())\n  // 40. Multiply line 39 by 25% (0.25)\n  l40 = (): number => this.l39() * 0.25\n  // If Schedule D, line 18, is zero or blank, skip lines 41 through 43 and go to line 44. Otherwise, go to line 41.\n  // 41. Add lines 21, 22, 30, 33, and 39\n  l41 = (): number =>\n    this.l21() + this.l22() + this.l30() + this.l33() + this.l39()\n  // 42. Subtract line 41 from line 1\n  l42 = (): number => Math.max(0, this.l1() - this.l41())\n  // 43. Multiply line 42 by 28% (0.28)\n  l43 = (): number => this.l42() * 0.28\n  // 44. Figure the tax on the amount on line 21. If the amount on line 21 is less than $100,000, use the Tax Table to\n  l44 = (): number => computeOrdinaryTax(this.data.filingStatus, this.l21())\n  // 45. Add lines 31, 34, 40, 43, and 44\n  l45 = (): number =>\n    this.l31() + this.l34() + this.l40() + this.l43() + this.l44()\n  // 46. Figure the tax on the amount on line 1. If the amount on line 1 is less than $100,000, use the Tax Table to\n  l46 = (): number => computeOrdinaryTax(this.data.filingStatus, this.l1())\n  // figure the tax. If the amount on line 1 is $100,000 or more, use the Tax Computation Worksheet\n  // 47. Tax on all taxable income (including capital gains and qualified dividends). Enter the smaller of line 45\n  // or line 46. Also, include this amount on Form 1040, 1040-SR, or 1040-NR, line 16. (If you are filing Form\n  // 2555, don't enter this amount on Form 1040 or 1040-SR, line 16. Instead, enter it on line 4 of the Foreign\n  // Earned Income Tax Worksheet in the Instructions for Forms 1040 and 1040-SR)\n  l47 = (): number => Math.round(Math.min(this.l45(), this.l46()))\n}\n\nexport const showReference = (r: LTCGQualDivReference): string =>\n  Array.from(Array(47))\n    .map((_, i) => `l${i + 1}`)\n    .map((x) => [x, (r[x] as () => number)()])\n    .map(([l, v]) => `${l}: ${v}`)\n    .join('\\n')\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/SocialSecurityBenefits.ts",
    "content": "import { FilingStatus } from 'ustaxes/core/data'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { SSBenefits } from '../../data/federal'\nimport { Worksheet } from '../F1040Attachment'\n\nexport default class SocialSecurityBenefitsWorksheet extends Worksheet {\n  totalNetBenefits = (): number =>\n    this.f1040\n      .f1099ssas()\n      .map((f) => f.form.netBenefits)\n      .reduce((l, r) => l + r, 0)\n\n  /* Enter the total amount from box 5 of all your Forms SSA-1099 and RRB-1099.\n      Also enter this amount on Form 1040 or 1040-SR, line 6a\n   */\n  l1 = (): number => this.totalNetBenefits()\n  // Multiply line 1 by 50% (0.50)\n  l2 = (): number => this.l1() / 2\n  /* If you are not excluding unemployment compensation from income,\n      combine the amounts from Form 1040 or 1040-SR, lines 1, 2b, 3b, 4b, 5b, 7, and 8.\n      If you are excluding unemployment compensation from income,\n      combine the amounts from Form 1040 or 1040-SR , lines 1, 2b, 3b, 4b, 5b, 7,\n      Schedule 1, lines 1 through 7, and line 3 of the Unemployment Compensation Exclusion Worksheet\n   */\n  l3 = (): number =>\n    sumFields([\n      this.f1040.l1(),\n      this.f1040.l2b(),\n      this.f1040.l3b(),\n      this.f1040.l4b(),\n      this.f1040.l5b(),\n      this.f1040.l7(),\n      this.f1040.l8()\n    ])\n  // Enter the amount, if any, from Form 1040 or 1040-SR, line 2a\n  l4 = (): number | undefined => this.f1040.l2a()\n  // Combine lines 2, 3, and 4\n  l5 = (): number => sumFields([this.l2(), this.l3(), this.l4()])\n  /* Enter the total of the amounts from Form 1040 or 1040-SR, line 10b, \n      Schedule 1, lines 10 through 19, \n      plus any write-in adjustments you entered on the dotted line next to Schedule 1, line 22\n   */\n  l6 = (): number =>\n    sumFields([\n      this.f1040.l12b(),\n      this.f1040.schedule1.l10(),\n      this.f1040.schedule1.l11(),\n      this.f1040.schedule1.l12(),\n      this.f1040.schedule1.l13(),\n      this.f1040.schedule1.l14(),\n      this.f1040.schedule1.l15(),\n      this.f1040.schedule1.l16(),\n      this.f1040.schedule1.l17(),\n      this.f1040.schedule1.l18(),\n      this.f1040.schedule1.l19a(),\n      this.f1040.schedule1.l20()\n    ])\n\n  /* Line 7: Is the amount on line 6 less than the amount on line 5?\n    If No, None of your social security benefits are taxable. Enter -0- on Form 1040 or 1040-SR, line 6b.\n    If Yes, Subtract line 6 from line 5\n  */\n\n  l7 = (): number => {\n    if (this.l6() < this.l5()) {\n      return this.l5() - this.l6()\n    } else {\n      return 0\n    }\n  }\n  /*\n    If you are:\n    Married filing jointly, enter $32,000\n    Single, head of household, qualifying widow(er), or married filing\n    separately and you lived apart from your spouse for all of the year,\n    enter $25,000\n    Married filing separately and you lived with your spouse at any time\n    in the year, skip lines 8 through 15; multiply line 7 by 85% (0.85) and\n    enter the result on line 16. Then, go to line 17\n  */\n  l8 = (): number => {\n    if (this.f1040.info.taxPayer.filingStatus == FilingStatus.MFS) {\n      // treat Married filing separately specially due to the extra question below\n      // and resulting logic in the worksheet\n      if (this.f1040.info.questions.LIVE_APART_FROM_SPOUSE) {\n        return SSBenefits.caps[this.f1040.info.taxPayer.filingStatus].l8\n      } else {\n        // Note that this value won't be taken into account. Instead,\n        // the line 16 function will also check for this and perform\n        // the right math.\n        return 0\n      }\n    } else {\n      return SSBenefits.caps[this.f1040.info.taxPayer.filingStatus].l8\n    }\n  }\n  /*\n  Is the amount on line 8 less than the amount on line 7?\n  \n  If No, None of your social security benefits are taxable. \n  Enter -0- on Form 1040 or 1040-SR, line 6b. \n  If you are married filing separately and you lived apart from your spouse for all of 2020, \n  be sure you entered \"D\" to the right of the word \"benefits\" on line 6a.\n\n  If Yes, Subtract line 8 from line 7.\n  */\n  l9 = (): number => {\n    if (this.l8() < this.l7()) {\n      return this.l7() - this.l8()\n    } else {\n      return 0\n    }\n  }\n\n  /*\n  Enter: $12,000 if married filing jointly; \n  $9,000 if single, head of household, qualifying widow(er), or married filing separately \n  and you lived apart from your spouse for all of 2020\n  */\n  l10 = (): number => SSBenefits.caps[this.f1040.info.taxPayer.filingStatus].l10\n\n  // Subtract line 10 from line 9. If zero or less, enter -0-\n  l11 = (): number => {\n    const tmp = this.l9() - this.l10()\n    if (tmp < 0) {\n      return 0\n    } else {\n      return tmp\n    }\n  }\n\n  // Enter the smaller of line 9 or line 10\n  l12 = (): number => Math.min(this.l9(), this.l10())\n\n  // Enter one-half of line 12\n  l13 = (): number => this.l12() / 2\n\n  // Enter the smaller of line 2 or line 13\n  l14 = (): number => Math.min(this.l13(), this.l2())\n\n  // Multiply line 11 by 85% (0.85). If line 11 is zero, enter -0-\n  l15 = (): number => {\n    if (this.l11() == 0) {\n      return 0\n    } else {\n      return this.l11() * 0.85\n    }\n  }\n\n  // Add lines 14 and 15\n  l16 = (): number => {\n    // From line 7 instructions:\n    // Married filing separately and you lived with your spouse at any time\n    // in 2020, skip lines 8 through 15; multiply line 7 by 85% (0.85) and\n    // enter the result on line 16. Then, go to line 17\n    if (\n      this.f1040.info.taxPayer.filingStatus == FilingStatus.MFS &&\n      !this.f1040.info.questions.LIVE_APART_FROM_SPOUSE\n    ) {\n      return this.l7() * 0.85\n    } else {\n      return sumFields([this.l14(), this.l15()])\n    }\n  }\n\n  // Multiply line 1 by 85% (0.85)\n  l17 = (): number => this.l1() * 0.85\n\n  // Taxable social security benefits. Enter the smaller of line 16 or line 17.\n  // Also enter this amount on Form 1040 or 1040-SR, line 6b\n  l18 = (): number => Math.min(this.l16(), this.l17())\n\n  // This is the function used to return the taxable amount of the social security\n  // benefits to be entered in line 6b of 1040. It takes into account the various\n  // stopping points in the worksheet.\n  taxableAmount = (): number => {\n    const line7 = this.l7()\n    if (line7 == 0) {\n      return line7\n    }\n\n    const line9 = this.l9()\n    if (line9 == 0) {\n      return line9\n    }\n\n    return this.l18()\n  }\n}\n"
  },
  {
    "path": "src/forms/Y2021/irsForms/worksheets/StudentLoanInterestWorksheet.ts",
    "content": "import { F1098e, FilingStatus } from 'ustaxes/core/data'\nimport F1040 from '../../irsForms/F1040'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\n\nexport default class StudentLoanInterestWorksheet {\n  f1040: F1040\n  f1098es: F1098e[]\n\n  constructor(f1040: F1040, f1098es: F1098e[]) {\n    this.f1040 = f1040\n    this.f1098es = f1098es\n  }\n\n  // Can't take deduction if filling Married Filling Seperate\n  notMFS = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFS\n\n  // Can't take deduction if MFJ and spouse is a dependent\n  isNotDependentSpouse = (): boolean =>\n    this.f1040.info.taxPayer.filingStatus !== FilingStatus.MFJ ||\n    this.f1040.info.taxPayer.spouse === undefined ||\n    !this.f1040.info.taxPayer.spouse.isTaxpayerDependent\n\n  // Can't take deduction if someone else claims you as a dependent\n  isNotDependentSelf = (): boolean =>\n    !this.f1040.info.taxPayer.primaryPerson.isTaxpayerDependent\n\n  isNotDependent = (): boolean =>\n    this.isNotDependentSpouse() && this.isNotDependentSelf()\n\n  // Sum interest, but maximum of 2500 can be deducted\n  l1 = (): number =>\n    Math.min(\n      this.f1098es.map((f1098e) => f1098e.interest).reduce((l, r) => l + r, 0),\n      2500\n    )\n\n  // Currently do not support unemployment compensation exclusion\n  // TO DO: add unemployment compensation exclusion\n  l2 = (): number => this.f1040.l9()\n\n  // Schedule 1 deductions\n  l3 = (): number =>\n    sumFields([\n      this.f1040.l12b(),\n      this.f1040.schedule1.l11(),\n      this.f1040.schedule1.l12(),\n      this.f1040.schedule1.l13(),\n      this.f1040.schedule1.l14(),\n      this.f1040.schedule1.l15(),\n      this.f1040.schedule1.l16(),\n      this.f1040.schedule1.l17(),\n      this.f1040.schedule1.l18(),\n      this.f1040.schedule1.l19a(),\n      this.f1040.schedule1.l20()\n      // TODO: missing write-in deduction ?\n    ])\n\n  l4 = (): number => Math.max(0, this.l2() - this.l3())\n\n  l5 = (): number =>\n    this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ ? 140000 : 70000\n\n  l6 = (): number => Math.max(0, this.l4() - this.l5())\n\n  l7 = (): number => Math.min(this.l6() / 15000, 1)\n\n  l8 = (): number => this.l1() * this.l7()\n\n  l9 = (): number | undefined =>\n    this.notMFS() && this.isNotDependent()\n      ? Math.max(0, this.l1() - this.l8())\n      : undefined\n}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/AK/Form.ts",
    "content": "export default class AKForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/AL/Form.ts",
    "content": "export default class ALForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/AR/Form.ts",
    "content": "export default class ARForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/AZ/Form.ts",
    "content": "export default class AZForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/CA/Form.ts",
    "content": "export default class CAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/CO/Form.ts",
    "content": "export default class COForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/CT/Form.ts",
    "content": "export default class CTForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/DC/Form.ts",
    "content": "export default class DCForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/DE/Form.ts",
    "content": "export default class DEForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/FL/Form.ts",
    "content": "export default class FLForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/GA/Form.ts",
    "content": "export default class GAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/HI/Form.ts",
    "content": "export default class HIForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IA/Form.ts",
    "content": "export default class IAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/ID/Form.ts",
    "content": "export default class IDForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IL/IL1040.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field, RadioSelect } from 'ustaxes/core/pdfFiller'\nimport { sumFields } from 'ustaxes/core/irsForms/util'\nimport { AccountType, FilingStatus, State } from 'ustaxes/core/data'\nimport parameters from './Parameters'\nimport { IL1040scheduleileeic } from './IL1040ScheduleILEIC'\nimport IL1040V from './IL1040V'\nimport { ILWIT } from './ILWit'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class IL1040 extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  scheduleEIC: IL1040scheduleileeic\n  il1040V: IL1040V\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'IL-1040'\n    this.state = 'IL'\n    this.scheduleEIC = new IL1040scheduleileeic(f1040)\n    this.il1040V = new IL1040V(f1040, this)\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    const pmt = this.payment()\n    const result: Form[] = []\n    if ((pmt ?? 0) > 0) {\n      result.push(this.il1040V)\n    }\n    if (this.scheduleEIC.isRequired()) {\n      result.push(this.scheduleEIC)\n    }\n    if (this.methods.stateWithholding() > 0) {\n      const ilwit = new ILWIT(this.f1040)\n      result.push(ilwit)\n      ilwit.attachments().forEach((f) => result.push(f))\n    }\n\n    return result\n  }\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: month\n   */\n  month = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.month()\n\n  /**\n   * Index 2: year\n   */\n  year = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.year()\n\n  /**\n   * Index 3: name2\n   * Primary First Name\n   */\n  name2 = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.firstName\n\n  f3 = (): string | undefined => this.name2()\n\n  /**\n   * Index 4: YoB\n   */\n  YoB = (): string | undefined => {\n    return undefined\n  }\n\n  f4 = (): string | undefined => this.YoB()\n\n  /**\n   * Index 5: ssn1\n   */\n  ssn1 = (): string | undefined => this.f1040.info.taxPayer.primaryPerson.ssid\n\n  f5 = (): string | undefined => this.ssn1()\n\n  /**\n   * Primary last name?\n   * Index 6: name3\n   */\n  name3 = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.lastName\n\n  f6 = (): string | undefined => this.name3()\n\n  /**\n   * Spouse Fist name?\n   * Index 7: name4\n   */\n  name4 = (): string | undefined => this.f1040.info.taxPayer.spouse?.firstName\n\n  f7 = (): string | undefined => this.name4()\n\n  /**\n   * Index 8: SpYoB\n   */\n  SpYoB = (): string | undefined => undefined\n\n  f8 = (): string | undefined => this.SpYoB()\n\n  /**\n   * Spouse SSN\n   * Index 9: ssn4\n   */\n  ssn4 = (): string | undefined => this.f1040.info.taxPayer.spouse?.ssid\n\n  f9 = (): string | undefined => this.ssn4()\n\n  /**\n   * Index 10: address\n   */\n  address = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.address.address\n\n  f10 = (): string | undefined => this.address()\n\n  /**\n   * Index 11: apt\n   */\n  apt = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.address.aptNo\n\n  f11 = (): string | undefined => this.apt()\n\n  /**\n   * Index 12: County\n   */\n  County = (): string | undefined => undefined\n\n  f12 = (): string | undefined => this.County()\n\n  /**\n   * Index 13: city\n   */\n  city = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.address.city\n\n  f13 = (): string | undefined => this.city()\n\n  /**\n   * Index 14: st\n   */\n  st = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.address.state ??\n    this.f1040.info.taxPayer.primaryPerson.address.province\n\n  f14 = (): string | undefined => this.st()\n\n  /**\n   * Index 15: zip\n   */\n  zip = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.address.zip\n\n  f15 = (): string | undefined => this.zip()\n\n  /**\n   * Index 16: foreign\n   */\n  foreign = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.address.foreignCountry\n\n  f16 = (): string | undefined => this.foreign()\n\n  /**\n   * Index 17: Check Box1\n   * This is actually a radio group, so indicate the correct selection\n   * by index.\n   */\n  CheckBox1 = (): RadioSelect | undefined => ({\n    select: [\n      FilingStatus.S,\n      FilingStatus.MFJ,\n      FilingStatus.MFS,\n      FilingStatus.W,\n      FilingStatus.HOH\n    ].findIndex((x) => x === this.f1040.info.taxPayer.filingStatus)\n  })\n\n  f17 = (): RadioSelect | undefined => this.CheckBox1()\n\n  /**\n   * Index 18: Check Box1c\n   */\n  CheckBox1c = (): boolean | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.isTaxpayerDependent\n\n  f18 = (): boolean | undefined => this.CheckBox1c()\n\n  /**\n   * Index 19: Check Box1cc\n   */\n  CheckBox1cc = (): boolean | undefined =>\n    this.f1040.info.taxPayer.spouse?.isTaxpayerDependent\n\n  f19 = (): boolean | undefined => this.CheckBox1cc()\n\n  /**\n   * Index 20: Check Box7\n   * TODO - nonresident, part year\n   */\n  CheckBox7 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f20 = (): boolean | undefined => this.CheckBox7()\n\n  /**\n   * Spouse last name !\n   * Index 21: name1\n   */\n  name1 = (): string | undefined => this.f1040.info.taxPayer.spouse?.lastName\n\n  f21 = (): string | undefined => this.name1()\n\n  /**\n   * Index 22: emailadd\n   */\n  emailadd = (): string | undefined => this.f1040.info.taxPayer.contactEmail\n\n  f22 = (): string | undefined => this.emailadd()\n\n  /**\n   * Index 23: 1\n   */\n  l1 = (): number | undefined => this.f1040.l11()\n\n  /**\n   * Index 24: 2\n   */\n  l2 = (): number | undefined => this.f1040.l2a()\n\n  /**\n   * Index 25: 3\n   * TODO: Schedule M, other additions\n   */\n  l3 = (): number | undefined => undefined\n\n  /**\n   * Index 26: 4\n   */\n  l4 = (): number => sumFields([this.l1(), this.l2(), this.l3()])\n\n  /**\n   * Index 27: 5\n   * TODO - ss benefits and certain retirement plan income received if included in line 1, attach p1 of federal return\n   */\n  l5 = (): number | undefined => undefined\n\n  /**\n   * Index 28: 6\n   * TODO IL income tax overpayment included in federal form 1040 S1 L1\n   */\n  l6 = (): number | undefined => undefined\n\n  /**\n   * Index 29: 7\n   * TODO: other subtractions, attach Schedule M\n   */\n  l7 = (): number | undefined => undefined\n\n  /**\n   * Index 30: Check Box2\n   * Check if L7 includes any amount from Schedule 1299-C\n   */\n  CheckBox2 = (): boolean | undefined => undefined\n\n  f30 = (): boolean | undefined => this.CheckBox2()\n\n  /**\n   * Index 31: 8\n   */\n  l8 = (): number => sumFields([this.l5(), this.l6(), this.l7()])\n\n  /**\n   * Index 32: 9\n   */\n  l9 = (): number => Math.max(0, this.l4() - this.l8())\n\n  /**\n   * Index 33: 10a\n   */\n  l10a = (): number => {\n    if (this.f1040.info.taxPayer.filingStatus === FilingStatus.MFJ)\n      return parameters.exemptions.MFJ.exemptionAmount\n    return parameters.exemptions.S.exemptionAmount\n  }\n\n  /**\n   * Index 34: Check Box3\n   * Check if TP senior\n   */\n  primarySenior = (): boolean | undefined => undefined\n\n  f34 = (): boolean | undefined => this.primarySenior()\n\n  /**\n   * Index 35: Check Box4\n   * Check if spouse senior\n   */\n  spouseSenior = (): boolean | undefined => {\n    return undefined\n  }\n\n  f35 = (): boolean | undefined => this.spouseSenior()\n\n  /**\n   * Index 36: 10b\n   */\n  l10b = (): number =>\n    [this.primarySenior() ?? false, this.spouseSenior() ?? false].filter(\n      (x) => x\n    ).length * parameters.seniorExemption\n\n  /**\n   * Index 37: Check Box5\n   * TODO: TP blind\n   */\n  primaryBlind = (): boolean | undefined => undefined\n\n  f37 = (): boolean | undefined => this.primaryBlind()\n\n  /**\n   * Index 38: Check Box6\n   * TODO: Spouse blind\n   */\n  spouseBlind = (): boolean | undefined => undefined\n\n  f38 = (): boolean | undefined => this.spouseBlind()\n\n  /**\n   * Index 39: 10c\n   */\n  l10c = (): number | undefined =>\n    [this.primaryBlind(), this.spouseBlind()].filter((x) => x).length *\n    parameters.blindExemption\n\n  /**\n   * Index 40: 10d\n   * TODO: Schedule EC step 2, line 1\n   */\n  l10d = (): number | undefined => undefined\n\n  /**\n   * Index 41: 10\n   * Net income\n   */\n  l10 = (): number =>\n    sumFields([this.l10a(), this.l10b(), this.l10c(), this.l10d()])\n\n  /**\n   * Index 42: 11\n   * TODO: handle non-residents, part year residents\n   */\n  l11 = (): number => Math.max(0, this.l9() - this.l10())\n\n  /**\n   * Index 43: 12\n   */\n  l12 = (): number => this.l11() * parameters.taxRate\n\n  /**\n   * Index 44: 13\n   * TODO: recapture investment tax credits, schedule 4255\n   */\n  l13 = (): number | undefined => undefined\n\n  /**\n   * Index 45: 14\n   * Income tax\n   */\n  l14 = (): number => sumFields([this.l12(), this.l13()])\n\n  /**\n   * Index 46: 15\n   * TODO: income tax paid to another state while IL resident\n   */\n  l15 = (): number | undefined => undefined\n\n  /**\n   * Index 47: 16\n   * Property tax and K12 education expense credit amount from Schedule ICR\n   */\n  l16 = (): number | undefined => undefined\n\n  /**\n   * Index 48: 17\n   * TODO: Credit amount from Schedule 1299-C Attach 1299-C\n   */\n  l17 = (): number | undefined => undefined\n\n  /**\n   * Index 49: 18\n   * Total credits\n   */\n  l18 = (): number => sumFields([this.l15(), this.l16(), this.l17()])\n\n  /**\n   * Index 50: 19\n   */\n  l19 = (): number => Math.max(0, this.l14() - this.l18())\n\n  /**\n   * Index 51: 20\n   * TODO: Household employment tax\n   */\n  l20 = (): number | undefined => undefined\n\n  /**\n   * Index 52: 21\n   * TODO: Use tax on internet, mail order, or other out-of-state purchases\n   */\n  l21 = (): number | undefined => undefined\n\n  /**\n   * Index 53: 22\n   * TODO: Compassionate use of medical cannabis program act and sale of assets by gaming licensee\n   */\n  l22 = (): number | undefined => undefined\n\n  /**\n   * Index 54: 23\n   */\n  l23 = (): number =>\n    sumFields([this.l19(), this.l20(), this.l21(), this.l22()])\n\n  /**\n   * Index 55: 24\n   */\n  l24 = (): number => this.l23()\n\n  /**\n   * Index 56: 25\n   */\n  l25 = (): number | undefined => this.methods.witholdingForState('IL')\n\n  /**\n   * Index 57: 26\n   * TODO: Estimated tax payments\n   */\n  l26 = (): number | undefined => undefined\n\n  /**\n   * Index 58: 27\n   * Pass-through withholding\n   */\n  l27 = (): number | undefined => undefined\n\n  // After line 27, PDF form skips to Step 11 (after line 35)\n\n  /**\n   * Index 59: Check Box8a\n   * TODO: 2/3 of income from farming\n   */\n  CheckBox8a = (): boolean | undefined => undefined\n\n  f59 = (): boolean | undefined => this.CheckBox8a()\n\n  /**\n   * Index 60: Check Box8b ?? what\n   * TODO: You or spouse is 65 or older and permanently in nursing home\n   */\n  CheckBox8b = (): boolean | undefined => undefined\n\n  f60 = (): boolean | undefined => this.CheckBox8b()\n\n  /**\n   * Index 61: Check Box8c ?? what\n   * TODO: Income not received evenly during the year and you annualized your income on IL-2210\n   */\n  CheckBox8c = (): boolean | undefined => undefined\n\n  f61 = (): boolean | undefined => this.CheckBox8c()\n\n  /**\n   * Index 62: rn1\n   */\n  rn1 = (): string | undefined => this.f1040.info.refund?.routingNumber\n\n  f62 = (): string | undefined => this.rn1()\n\n  /**\n   * Index 63: Check Box11\n   * TODO: support savings account checkbox - radio field issue\n   */\n  CheckBox11 = (): boolean | undefined =>\n    this.f1040.info.refund?.accountType === AccountType.checking\n\n  f63 = (): boolean | undefined => this.CheckBox11()\n\n  /**\n   * Index 64: ac1\n   */\n  ac1 = (): string | undefined => this.f1040.info.refund?.accountNumber\n\n  f64 = (): string | undefined => this.ac1()\n\n  /**\n   * Index 65: Refund Method\n   * TODO: not supporting credit forward\n   */\n  RefundMethod = (): boolean => true\n\n  f65 = (): boolean | undefined => this.RefundMethod()\n\n  /**\n   * Index 66: YourSignatureDate\n   */\n  YourSignatureDate = (): string | undefined => undefined\n\n  f66 = (): string | undefined => this.YourSignatureDate()\n\n  /**\n   * Index 67: SpouseSignatureDate\n   */\n  SpouseSignatureDate = (): string | undefined => undefined\n\n  f67 = (): string | undefined => this.SpouseSignatureDate()\n\n  /**\n   * Index 68: DaytimeAreaCode\n   */\n  DaytimeAreaCode = (): string | undefined =>\n    this.f1040.info.taxPayer.contactPhoneNumber?.slice(0, 3)\n\n  f68 = (): string | undefined => this.DaytimeAreaCode()\n\n  /**\n   * Index 69: DaytimePhoneNumber\n   */\n  DaytimePhoneNumber = (): string | undefined =>\n    this.f1040.info.taxPayer.contactPhoneNumber?.slice(3)\n\n  f69 = (): string | undefined => this.DaytimePhoneNumber()\n\n  /**\n   * Index 70: PreparerName\n   */\n  PreparerName = (): string | undefined => undefined\n\n  f70 = (): string | undefined => this.PreparerName()\n\n  /**\n   * Index 71: PreparerSignatureDate\n   */\n  PreparerSignatureDate = (): string | undefined => undefined\n\n  f71 = (): string | undefined => this.PreparerSignatureDate()\n\n  /**\n   * Index 72: CheckBoxSelfEmployed\n   */\n  CheckBoxSelfEmployed = (): undefined => undefined\n\n  f72 = (): boolean | undefined => this.CheckBoxSelfEmployed()\n\n  /**\n   * Index 73: PreparerPTIN\n   */\n  PreparerPTIN = (): string | undefined => undefined\n\n  f73 = (): string | undefined => this.PreparerPTIN()\n\n  /**\n   * Index 74: PreparerFirmName\n   */\n  PreparerFirmName = (): string | undefined => undefined\n\n  f74 = (): string | undefined => this.PreparerFirmName()\n\n  /**\n   * Index 75: PreparerFirmFEIN\n   */\n  PreparerFirmFEIN = (): string | undefined => undefined\n\n  f75 = (): string | undefined => this.PreparerFirmFEIN()\n\n  /**\n   * Index 76: PreparerFirmAddress\n   */\n  PreparerFirmAddress = (): string | undefined => undefined\n\n  f76 = (): string | undefined => this.PreparerFirmAddress()\n\n  /**\n   * Index 77: PreparerFirmAreaCode\n   */\n  PreparerFirmAreaCode = (): string | undefined => undefined\n\n  f77 = (): string | undefined => this.PreparerFirmAreaCode()\n\n  /**\n   * Index 78: PreparerFirmPhoneNumber\n   */\n  PreparerFirmPhoneNumber = (): string | undefined => undefined\n\n  f78 = (): string | undefined => this.PreparerFirmPhoneNumber()\n\n  /**\n   * Index 79: ThirdPartyName\n   */\n  ThirdPartyName = (): string | undefined => undefined\n\n  f79 = (): string | undefined => this.ThirdPartyName()\n\n  /**\n   * Index 80: ThirdPartyAreaCode\n   */\n  ThirdPartyAreaCode = (): string | undefined => undefined\n\n  f80 = (): string | undefined => this.ThirdPartyAreaCode()\n\n  /**\n   * Index 81: ThirdPartyPhoneNumber\n   */\n  ThirdPartyPhoneNumber = (): string | undefined => undefined\n\n  f81 = (): string | undefined => this.ThirdPartyPhoneNumber()\n\n  /**\n   * Index 82: CheckBoxDiscuss\n   */\n  CheckBoxDiscuss = (): boolean | undefined => undefined\n\n  f82 = (): boolean | undefined => this.CheckBoxDiscuss()\n\n  /**\n   * Index 83: Reset\n   */\n  Reset = (): string | undefined => undefined\n\n  f83 = (): string | undefined => this.Reset()\n\n  /**\n   * Index 84: Print\n   */\n  Print = (): string | undefined => undefined\n\n  f84 = (): string | undefined => this.Print()\n\n  /**\n   * Index 85: 28\n   * TODO: Pass-through entity tax credit, Schedule K-1-P / Schedule K-1-T\n   */\n  l28 = (): number | undefined => undefined\n\n  /**\n   * Index 86: 29\n   * Earned income credit from Schedule IL-E/EIC, Step 4, line 8\n   */\n  l29 = (): number | undefined => this.scheduleEIC.earnedIncomeCredit()\n\n  /**\n   * Index 87: 31\n   */\n  l31 = (): number => Math.max(0, this.l30() - this.l24())\n\n  /**\n   * Index 88: 30\n   */\n  l30 = (): number =>\n    sumFields([this.l25(), this.l26(), this.l27(), this.l28(), this.l29()])\n\n  /**\n   * Index 89: 32\n   */\n  l32 = (): number => Math.max(0, this.l24() - this.l30())\n\n  /**\n   * Index 90: 33\n   * TODO: late payment penalty for underpayment of estimated tax\n   */\n  l33 = (): number | undefined => undefined\n\n  /**\n   * Index 91: 34\n   * TODO: Voluntary charitable contributions\n   */\n  l34 = (): number | undefined => undefined\n\n  /**\n   * Index 92: 35\n   */\n  l35 = (): number => sumFields([this.l33(), this.l34()])\n\n  /**\n   * Index 93: 36\n   * Overpayment\n   */\n  l36 = (): number => Math.max(this.l31() - this.l35())\n\n  /**\n   * Index 94: 37\n   * TODO: not supporting credit forward\n   */\n  l37 = (): number => this.l36()\n\n  /**\n   * Index 95: 39\n   * TODO: not supporting credit forward\n   */\n  l39 = (): number | undefined => undefined\n\n  /**\n   * Index 96: 40\n   */\n  l40 = (): number | undefined => {\n    const l31 = this.l31()\n    const l32 = this.l32()\n    const l35 = this.l35()\n    if (l32 > 0) return l32 + l35\n    if (l31 > 0) return Math.max(0, l35 - l31)\n  }\n\n  payment = (): number | undefined => this.l40()\n\n  /**\n   * This box is left over from line 33\n   * Index 97: CheckBox8d\n   * TODO: Check if you were not required to file an IL individual tax return in the previous tax year.\n   */\n  CheckBox8d = (): boolean | undefined => undefined\n\n  f97 = (): boolean | undefined => this.CheckBox8d()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.l1(),\n    this.l2(),\n    this.l3(),\n    this.l4(),\n    this.l5(),\n    this.l6(),\n    this.l7(),\n    this.f30(),\n    this.l8(),\n    this.l9(),\n    this.l10a(),\n    this.f34(),\n    this.f35(),\n    this.l10b(),\n    this.f37(),\n    this.f38(),\n    this.l10c(),\n    this.l10d(),\n    this.l10(),\n    this.l11(),\n    this.l12(),\n    this.l13(),\n    this.l14(),\n    this.l15(),\n    this.l16(),\n    this.l17(),\n    this.l18(),\n    this.l19(),\n    this.l20(),\n    this.l21(),\n    this.l22(),\n    this.l23(),\n    this.l24(),\n    this.l25(),\n    this.l26(),\n    this.l27(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.l28(),\n    this.l29(),\n    this.l31(),\n    this.l30(),\n    this.l32(),\n    this.l33(),\n    this.l34(),\n    this.l35(),\n    this.l36(),\n    this.l37(),\n    this.l39(),\n    this.l40(),\n    this.f97()\n  ]\n}\n\nconst makeIL1040 = (f1040: F1040): IL1040 => new IL1040(f1040)\n\nexport default makeIL1040\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IL/IL1040ScheduleILEIC.ts",
    "content": "import Form from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { Dependent, PrimaryPerson, Spouse, State } from 'ustaxes/core/data'\nimport parameters from './Parameters'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class IL1040scheduleileeic extends Form {\n  f1040: F1040\n  info: ValidatedInformation\n  formName: string\n  state: State\n  formOrder = 1\n  attachments: () => Form[] = () => []\n  qualifyingDependents: Dependent[]\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'il-1040-schedule-il-e-eic'\n    this.state = 'IL'\n    this.qualifyingDependents = this.f1040.scheduleEIC.qualifyingDependents()\n  }\n\n  get primary(): PrimaryPerson | undefined {\n    return this.f1040.info.taxPayer.primaryPerson\n  }\n\n  get spouse(): Spouse | undefined {\n    return this.f1040.info.taxPayer.spouse\n  }\n\n  isRequired = (): boolean => (this.earnedIncomeCredit() ?? 0) > 0\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: X  2325\n   */\n  X2325 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.X2325()\n\n  /**\n   * Index 2: Reset\n   */\n  Reset = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.Reset()\n\n  /**\n   * Index 3: Print\n   */\n  Print = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.Print()\n\n  /**\n   * Index 4: Your name\n   */\n  Yourname = (): string | undefined =>\n    [this.primary?.firstName, this.primary?.lastName].flat().join(' ')\n\n  f4 = (): string | undefined => this.Yourname()\n\n  /**\n   * Index 5: Dependents first name - 2\n   */\n  Dependentsfirstname2 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[1]?.firstName\n\n  f5 = (): string | undefined => this.Dependentsfirstname2()\n\n  /**\n   * Index 6: Dependent's first name - 1\n   */\n  Dependentsfirstname1 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[0]?.firstName\n\n  f6 = (): string | undefined => this.Dependentsfirstname1()\n\n  /**\n   * Index 7: Dependent's first name - 3\n   */\n  Dependentsfirstname3 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[2]?.firstName\n\n  f7 = (): string | undefined => this.Dependentsfirstname3()\n\n  /**\n   * Index 8: Dependent's first name - 4\n   */\n  Dependentsfirstname4 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[3]?.firstName\n\n  f8 = (): string | undefined => this.Dependentsfirstname4()\n\n  /**\n   * Index 9: Dependent's first name - 5\n   */\n  Dependentsfirstname5 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[4]?.firstName\n\n  f9 = (): string | undefined => this.Dependentsfirstname5()\n\n  /**\n   * Index 10: Dependent's first name - 6\n   */\n  Dependentsfirstname6 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[5]?.firstName\n\n  f10 = (): string | undefined => this.Dependentsfirstname6()\n\n  /**\n   * Index 11: Dependent's first name - 7\n   */\n  Dependentsfirstname7 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[6]?.firstName\n\n  f11 = (): string | undefined => this.Dependentsfirstname7()\n\n  /**\n   * Index 12: Dependent's first name - 8\n   */\n  Dependentsfirstname8 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[7]?.firstName\n\n  f12 = (): string | undefined => this.Dependentsfirstname8()\n\n  /**\n   * Index 13: Dependent's first name - 9\n   */\n  Dependentsfirstname9 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[8]?.firstName\n\n  f13 = (): string | undefined => this.Dependentsfirstname9()\n\n  /**\n   * Index 14: Dependent's first name - 10\n   */\n  Dependentsfirstname10 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[9]?.firstName\n\n  f14 = (): string | undefined => this.Dependentsfirstname10()\n\n  /**\n   * Index 15: Dependent's last name - 2\n   */\n  Dependentslastname2 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[1]?.lastName\n\n  f15 = (): string | undefined => this.Dependentslastname2()\n\n  /**\n   * Index 16: Dependent's last name - 1\n   */\n  Dependentslastname1 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[0]?.lastName\n\n  f16 = (): string | undefined => this.Dependentslastname1()\n\n  /**\n   * Index 17: Dependent's last name - 3\n   */\n  Dependentslastname3 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[2]?.lastName\n\n  f17 = (): string | undefined => this.Dependentslastname3()\n\n  /**\n   * Index 18: Dependent's last name - 4\n   */\n  Dependentslastname4 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[3]?.lastName\n\n  f18 = (): string | undefined => this.Dependentslastname4()\n\n  /**\n   * Index 19: Dependent's last name - 5\n   */\n  Dependentslastname5 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[4]?.lastName\n\n  f19 = (): string | undefined => this.Dependentslastname5()\n\n  /**\n   * Index 20: Dependent's last name - 6\n   */\n  Dependentslastname6 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[5]?.lastName\n\n  f20 = (): string | undefined => this.Dependentslastname6()\n\n  /**\n   * Index 21: Dependent's last name - 7\n   */\n  Dependentslastname7 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[6]?.lastName\n\n  f21 = (): string | undefined => this.Dependentslastname7()\n\n  /**\n   * Index 22: Dependent's last name - 8\n   */\n  Dependentslastname8 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[7]?.lastName\n\n  f22 = (): string | undefined => this.Dependentslastname8()\n\n  /**\n   * Index 23: Dependent's last name - 9\n   */\n  Dependentslastname9 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[8]?.lastName\n\n  f23 = (): string | undefined => this.Dependentslastname9()\n\n  /**\n   * Index 24: Dependent's last name - 10\n   */\n  Dependentslastname10 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[9]?.lastName\n\n  f24 = (): string | undefined => this.Dependentslastname10()\n\n  /**\n   * Index 25: Social Security number - 2\n   */\n  SocialSecuritynumber2 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[1]?.ssid\n\n  f25 = (): string | undefined => this.SocialSecuritynumber2()\n\n  /**\n   * Index 26: Social Security number - 3\n   */\n  SocialSecuritynumber3 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[2]?.ssid\n\n  f26 = (): string | undefined => this.SocialSecuritynumber3()\n\n  /**\n   * Index 27: Social Security number - 4\n   */\n  SocialSecuritynumber4 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[3]?.ssid\n\n  f27 = (): string | undefined => this.SocialSecuritynumber4()\n\n  /**\n   * Index 28: Social Security number - 5\n   */\n  SocialSecuritynumber5 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[4]?.ssid\n\n  f28 = (): string | undefined => this.SocialSecuritynumber5()\n\n  /**\n   * Index 29: Social Security number - 6\n   */\n  SocialSecuritynumber6 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[5]?.ssid\n\n  f29 = (): string | undefined => this.SocialSecuritynumber6()\n\n  /**\n   * Index 30: Social Security number - 7\n   */\n  SocialSecuritynumber7 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[6]?.ssid\n\n  f30 = (): string | undefined => this.SocialSecuritynumber7()\n\n  /**\n   * Index 31: Social Security number - 8\n   */\n  SocialSecuritynumber8 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[7]?.ssid\n\n  f31 = (): string | undefined => this.SocialSecuritynumber8()\n\n  /**\n   * Index 32: Social Security number - 9\n   */\n  SocialSecuritynumber9 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[8]?.ssid\n\n  f32 = (): string | undefined => this.SocialSecuritynumber9()\n\n  /**\n   * Index 33: Social Security number - 10\n   */\n  SocialSecuritynumber10 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[9]?.ssid\n\n  f33 = (): string | undefined => this.SocialSecuritynumber10()\n\n  /**\n   * Index 34: Dependent's relationship to you - 1\n   */\n  Dependentsrelationshiptoyou1 = (): string | undefined => {\n    return undefined\n  }\n\n  f34 = (): string | undefined => this.Dependentsrelationshiptoyou1()\n\n  /**\n   * Index 35: Dependent's relationship to you - 2\n   */\n  Dependentsrelationshiptoyou2 = (): string | undefined => {\n    return undefined\n  }\n\n  f35 = (): string | undefined => this.Dependentsrelationshiptoyou2()\n\n  /**\n   * Index 36: Dependent's relationship to you - 3\n   */\n  Dependentsrelationshiptoyou3 = (): string | undefined => {\n    return undefined\n  }\n\n  f36 = (): string | undefined => this.Dependentsrelationshiptoyou3()\n\n  /**\n   * Index 37: Dependent's relationship to you - 4\n   */\n  Dependentsrelationshiptoyou4 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.Dependentsrelationshiptoyou4()\n\n  /**\n   * Index 38: Dependent's relationship to you - 5\n   */\n  Dependentsrelationshiptoyou5 = (): string | undefined => {\n    return undefined\n  }\n\n  f38 = (): string | undefined => this.Dependentsrelationshiptoyou5()\n\n  /**\n   * Index 39: Dependent's relationship to you - 6\n   */\n  Dependentsrelationshiptoyou6 = (): string | undefined => {\n    return undefined\n  }\n\n  f39 = (): string | undefined => this.Dependentsrelationshiptoyou6()\n\n  /**\n   * Index 40: Dependent's relationship to you - 7\n   */\n  Dependentsrelationshiptoyou7 = (): string | undefined => {\n    return undefined\n  }\n\n  f40 = (): string | undefined => this.Dependentsrelationshiptoyou7()\n\n  /**\n   * Index 41: Dependent's relationship to you - 8\n   */\n  Dependentsrelationshiptoyou8 = (): string | undefined => {\n    return undefined\n  }\n\n  f41 = (): string | undefined => this.Dependentsrelationshiptoyou8()\n\n  /**\n   * Index 42: Dependent's relationship to you - 9\n   */\n  Dependentsrelationshiptoyou9 = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.Dependentsrelationshiptoyou9()\n\n  /**\n   * Index 43: Dependent's relationship to you - 10\n   */\n  Dependentsrelationshiptoyou10 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.Dependentsrelationshiptoyou10()\n\n  /**\n   * Index 44: Dependent's date of birth (mm/dd/yyyy) - 1\n   */\n  Dependentsdateofbirthmmddyyyy1 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy1()\n\n  /**\n   * Index 45: Dependent's date of birth (mm/dd/yyyy) - 2\n   */\n  Dependentsdateofbirthmmddyyyy2 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy2()\n\n  /**\n   * Index 46: Dependent's date of birth (mm/dd/yyyy) - 3\n   */\n  Dependentsdateofbirthmmddyyyy3 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy3()\n\n  /**\n   * Index 47: Dependent's date of birth (mm/dd/yyyy) - 4\n   */\n  Dependentsdateofbirthmmddyyyy4 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy4()\n\n  /**\n   * Index 48: Dependent's date of birth (mm/dd/yyyy) - 5\n   */\n  Dependentsdateofbirthmmddyyyy5 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy5()\n\n  /**\n   * Index 49: Dependent's date of birth (mm/dd/yyyy) - 6\n   */\n  Dependentsdateofbirthmmddyyyy6 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy6()\n\n  /**\n   * Index 50: Dependent's date of birth (mm/dd/yyyy) - 7\n   */\n  Dependentsdateofbirthmmddyyyy7 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy7()\n\n  /**\n   * Index 51: Dependent's date of birth (mm/dd/yyyy) - 8\n   */\n  Dependentsdateofbirthmmddyyyy8 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy8()\n\n  /**\n   * Index 52: Dependent's date of birth (mm/dd/yyyy) - 9\n   */\n  Dependentsdateofbirthmmddyyyy9 = (): string | undefined => {\n    return undefined\n  }\n\n  f52 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy9()\n\n  /**\n   * Index 53: Dependent's date of birth (mm/dd/yyyy) - 10\n   */\n  Dependentsdateofbirthmmddyyyy10 = (): string | undefined => {\n    return undefined\n  }\n\n  f53 = (): string | undefined => this.Dependentsdateofbirthmmddyyyy10()\n\n  /**\n   * Index 54: Full Time Student - 1\n   */\n  FullTimeStudent1 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[0]?.qualifyingInfo?.isStudent\n\n  f54 = (): boolean | undefined => this.FullTimeStudent1()\n\n  /**\n   * Index 55: Full Time Student - 2\n   */\n  FullTimeStudent2 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[1]?.qualifyingInfo?.isStudent\n\n  f55 = (): boolean | undefined => this.FullTimeStudent2()\n\n  /**\n   * Index 56: Full Time Student - 3\n   */\n  FullTimeStudent3 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[2]?.qualifyingInfo?.isStudent\n\n  f56 = (): boolean | undefined => this.FullTimeStudent3()\n\n  /**\n   * Index 57: Full Time Student - 4\n   */\n  FullTimeStudent4 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[3]?.qualifyingInfo?.isStudent\n\n  f57 = (): boolean | undefined => this.FullTimeStudent4()\n\n  /**\n   * Index 58: Full Time Student - 5\n   */\n  FullTimeStudent5 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[4]?.qualifyingInfo?.isStudent\n\n  f58 = (): boolean | undefined => this.FullTimeStudent5()\n\n  /**\n   * Index 59: Full Time Student - 6\n   */\n  FullTimeStudent6 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[5]?.qualifyingInfo?.isStudent\n\n  f59 = (): boolean | undefined => this.FullTimeStudent6()\n\n  /**\n   * Index 60: Full Time Student - 7\n   */\n  FullTimeStudent7 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[6]?.qualifyingInfo?.isStudent\n\n  f60 = (): boolean | undefined => this.FullTimeStudent7()\n\n  /**\n   * Index 61: Full Time Student - 8\n   */\n  FullTimeStudent8 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[7]?.qualifyingInfo?.isStudent\n\n  f61 = (): boolean | undefined => this.FullTimeStudent8()\n\n  /**\n   * Index 62: Full Time Student - 9\n   */\n  FullTimeStudent9 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[8]?.qualifyingInfo?.isStudent\n\n  f62 = (): boolean | undefined => this.FullTimeStudent9()\n\n  /**\n   * Index 63: Full Time Student - 10\n   */\n  FullTimeStudent10 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents[9]?.qualifyingInfo?.isStudent\n\n  f63 = (): boolean | undefined => this.FullTimeStudent10()\n\n  /**\n   * Index 64: Person with disability - 1\n   * TODO: Handle disabilities\n   */\n  Personwithdisability1 = (): boolean | undefined => undefined\n\n  f64 = (): boolean | undefined => this.Personwithdisability1()\n\n  /**\n   * Index 65: Person with disability - 2\n   * TODO: Handle disabilities\n   */\n  Personwithdisability2 = (): boolean | undefined => undefined\n\n  f65 = (): boolean | undefined => this.Personwithdisability2()\n\n  /**\n   * Index 66: Person with disability - 3\n   * TODO: Handle disabilities\n   */\n  Personwithdisability3 = (): boolean | undefined => undefined\n\n  f66 = (): boolean | undefined => this.Personwithdisability3()\n\n  /**\n   * Index 67: Person with disability - 4\n   * TODO: Handle disabilities\n   */\n  Personwithdisability4 = (): boolean | undefined => undefined\n\n  f67 = (): boolean | undefined => this.Personwithdisability4()\n\n  /**\n   * Index 68: Person with disability - 5\n   * TODO: Handle disabilities\n   */\n  Personwithdisability5 = (): boolean | undefined => undefined\n\n  f68 = (): boolean | undefined => this.Personwithdisability5()\n\n  /**\n   * Index 69: Person with disability - 6\n   * TODO: Handle disabilities\n   */\n  Personwithdisability6 = (): boolean | undefined => undefined\n\n  f69 = (): boolean | undefined => this.Personwithdisability6()\n\n  /**\n   * Index 70: Person with disability - 7\n   * TODO: Handle disabilities\n   */\n  Personwithdisability7 = (): boolean | undefined => undefined\n\n  f70 = (): boolean | undefined => this.Personwithdisability7()\n\n  /**\n   * Index 71: Person with disability - 8\n   * TODO: Handle disabilities\n   */\n  Personwithdisability8 = (): boolean | undefined => undefined\n\n  f71 = (): boolean | undefined => this.Personwithdisability8()\n\n  /**\n   * Index 72: Person with disability - 9\n   * TODO: Handle disabilities\n   */\n  Personwithdisability9 = (): boolean | undefined => undefined\n\n  f72 = (): boolean | undefined => this.Personwithdisability9()\n\n  /**\n   * Index 73: Person with disability - 10\n   * TODO: Handle disabilities\n   */\n  Personwithdisability10 = (): boolean | undefined => undefined\n\n  f73 = (): boolean | undefined => this.Personwithdisability10()\n\n  /**\n   * Index 74: Number of months living with you - 1\n   */\n  Numberofmonthslivingwithyou1 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[0]?.qualifyingInfo?.numberOfMonths\n\n  f74 = (): number | undefined => this.Numberofmonthslivingwithyou1()\n\n  /**\n   * Index 75: Number of months living with you - 2\n   */\n  Numberofmonthslivingwithyou2 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[1]?.qualifyingInfo?.numberOfMonths\n\n  f75 = (): number | undefined => this.Numberofmonthslivingwithyou2()\n\n  /**\n   * Index 76: Number of months living with you - 3\n   */\n  Numberofmonthslivingwithyou3 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[2]?.qualifyingInfo?.numberOfMonths\n\n  f76 = (): number | undefined => this.Numberofmonthslivingwithyou3()\n\n  /**\n   * Index 77: Number of months living with you - 4\n   */\n  Numberofmonthslivingwithyou4 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[3]?.qualifyingInfo?.numberOfMonths\n\n  f77 = (): number | undefined => this.Numberofmonthslivingwithyou4()\n\n  /**\n   * Index 78: Number of months living with you - 5\n   */\n  Numberofmonthslivingwithyou5 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[4]?.qualifyingInfo?.numberOfMonths\n\n  f78 = (): number | undefined => this.Numberofmonthslivingwithyou5()\n\n  /**\n   * Index 79: Number of months living with you - 6\n   */\n  Numberofmonthslivingwithyou6 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[5]?.qualifyingInfo?.numberOfMonths\n\n  f79 = (): number | undefined => this.Numberofmonthslivingwithyou6()\n\n  /**\n   * Index 80: Number of months living with you - 7\n   */\n  Numberofmonthslivingwithyou7 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[6]?.qualifyingInfo?.numberOfMonths\n\n  f80 = (): number | undefined => this.Numberofmonthslivingwithyou7()\n\n  /**\n   * Index 81: Number of months living with you - 8\n   */\n  Numberofmonthslivingwithyou8 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[7]?.qualifyingInfo?.numberOfMonths\n\n  f81 = (): number | undefined => this.Numberofmonthslivingwithyou8()\n\n  /**\n   * Index 82: Number of months living with you - 9\n   */\n  Numberofmonthslivingwithyou9 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[8]?.qualifyingInfo?.numberOfMonths\n\n  f82 = (): number | undefined => this.Numberofmonthslivingwithyou9()\n\n  /**\n   * Index 83: Number of months living with you - 10\n   */\n  Numberofmonthslivingwithyou10 = (): number | undefined =>\n    this.f1040.info.taxPayer.dependents[9]?.qualifyingInfo?.numberOfMonths\n\n  f83 = (): number | undefined => this.Numberofmonthslivingwithyou10()\n\n  /**\n   * Index 84: Eligible for Earned Income Credit - 1\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit1 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 0\n\n  f84 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit1()\n\n  /**\n   * Index 85: Eligible for Earned Income Credit - 2\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit2 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 1\n\n  f85 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit2()\n\n  /**\n   * Index 86: Eligible for Earned Income Credit - 3\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit3 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 2\n\n  f86 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit3()\n\n  /**\n   * Index 87: Eligible for Earned Income Credit - 4\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit4 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 3\n\n  f87 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit4()\n\n  /**\n   * Index 88: Eligible for Earned Income Credit - 5\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit5 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 4\n\n  f88 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit5()\n\n  /**\n   * Index 89: Eligible for Earned Income Credit - 6\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit6 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 5\n\n  f89 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit6()\n\n  /**\n   * Index 90: Eligible for Earned Income Credit - 7\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit7 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 6\n\n  f90 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit7()\n\n  /**\n   * Index 91: Eligible for Earned Income Credit - 8\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit8 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 7\n\n  f91 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit8()\n\n  /**\n   * Index 92: Eligible for Earned Income Credit - 9\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit9 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 8\n\n  f92 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit9()\n\n  /**\n   * Index 93: Eligible for Earned Income Credit - 10\n   * TODO: Confirm this checkbox\n   */\n  EligibleforEarnedIncomeCredit10 = (): boolean | undefined =>\n    this.f1040.info.taxPayer.dependents.length > 9\n\n  f93 = (): boolean | undefined => this.EligibleforEarnedIncomeCredit10()\n\n  /**\n   * Index 94: Mutiplied total number of dependents\n   */\n  Mutipliedtotalnumberofdependents = (): number | undefined =>\n    this.qualifyingDependents.length * parameters.eicDependentCredit\n\n  f94 = (): number | undefined => this.Mutipliedtotalnumberofdependents()\n\n  /**\n   * Index 95: Child's first name -1\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname1 = (): string | undefined => {\n    return undefined\n  }\n\n  f95 = (): string | undefined => this.Childsfirstname1()\n\n  /**\n   * Index 96: Child's first name -2\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname2 = (): string | undefined => {\n    return undefined\n  }\n\n  f96 = (): string | undefined => this.Childsfirstname2()\n\n  /**\n   * Index 97: Child's first name -3\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname3 = (): string | undefined => {\n    return undefined\n  }\n\n  f97 = (): string | undefined => this.Childsfirstname3()\n\n  /**\n   * Index 98: Child's first name - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname4 = (): string | undefined => {\n    return undefined\n  }\n\n  f98 = (): string | undefined => this.Childsfirstname4()\n\n  /**\n   * Index 99: Child's first name - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname5 = (): string | undefined => {\n    return undefined\n  }\n\n  f99 = (): string | undefined => this.Childsfirstname5()\n\n  /**\n   * Index 100: Child's first name - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname6 = (): string | undefined => {\n    return undefined\n  }\n\n  f100 = (): string | undefined => this.Childsfirstname6()\n\n  /**\n   * Index 101: Child's first name - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname7 = (): string | undefined => {\n    return undefined\n  }\n\n  f101 = (): string | undefined => this.Childsfirstname7()\n\n  /**\n   * Index 102: Child's first name - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childsfirstname8 = (): string | undefined => {\n    return undefined\n  }\n\n  f102 = (): string | undefined => this.Childsfirstname8()\n\n  /**\n   * Index 103: Child's last name - 1\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname1 = (): string | undefined => {\n    return undefined\n  }\n\n  f103 = (): string | undefined => this.Childslastname1()\n\n  /**\n   * Index 104: Child's last name - 2\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname2 = (): string | undefined => {\n    return undefined\n  }\n\n  f104 = (): string | undefined => this.Childslastname2()\n\n  /**\n   * Index 105: Child's last name - 3\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname3 = (): string | undefined => {\n    return undefined\n  }\n\n  f105 = (): string | undefined => this.Childslastname3()\n\n  /**\n   * Index 106: Child's last name - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname4 = (): string | undefined => {\n    return undefined\n  }\n\n  f106 = (): string | undefined => this.Childslastname4()\n\n  /**\n   * Index 107: Child's last name - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname5 = (): string | undefined => {\n    return undefined\n  }\n\n  f107 = (): string | undefined => this.Childslastname5()\n\n  /**\n   * Index 108: Child's last name - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname6 = (): string | undefined => {\n    return undefined\n  }\n\n  f108 = (): string | undefined => this.Childslastname6()\n\n  /**\n   * Index 109: Child's last name - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname7 = (): string | undefined => {\n    return undefined\n  }\n\n  f109 = (): string | undefined => this.Childslastname7()\n\n  /**\n   * Index 110: Child's last name - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childslastname8 = (): string | undefined => {\n    return undefined\n  }\n\n  f110 = (): string | undefined => this.Childslastname8()\n\n  /**\n   * Index 111: Social Security number - 1\n   */\n  SocialSecuritynumber1 = (): string | undefined =>\n    this.f1040.info.taxPayer.dependents[0]?.ssid\n\n  f111 = (): string | undefined => this.SocialSecuritynumber1()\n\n  /**\n   * Index 112: Child's Social Security number - 1\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber1 = (): string | undefined => {\n    return undefined\n  }\n\n  f112 = (): string | undefined => this.ChildsSocialSecuritynumber1()\n\n  /**\n   * Index 113: Child's Social Security number - 2\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber2 = (): string | undefined => {\n    return undefined\n  }\n\n  f113 = (): string | undefined => this.ChildsSocialSecuritynumber2()\n\n  /**\n   * Index 114: Child's Social Security number - 3\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber3 = (): string | undefined => {\n    return undefined\n  }\n\n  f114 = (): string | undefined => this.ChildsSocialSecuritynumber3()\n\n  /**\n   * Index 115: Child's Social Security number - 4\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber4 = (): string | undefined => {\n    return undefined\n  }\n\n  f115 = (): string | undefined => this.ChildsSocialSecuritynumber4()\n\n  /**\n   * Index 116: Child's Social Security number - 5\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber5 = (): string | undefined => {\n    return undefined\n  }\n\n  f116 = (): string | undefined => this.ChildsSocialSecuritynumber5()\n\n  /**\n   * Index 117: Child's Social Security number - 6\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber6 = (): string | undefined => {\n    return undefined\n  }\n\n  f117 = (): string | undefined => this.ChildsSocialSecuritynumber6()\n\n  /**\n   * Index 118: Child's Social Security number - 7\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber7 = (): string | undefined => {\n    return undefined\n  }\n\n  f118 = (): string | undefined => this.ChildsSocialSecuritynumber7()\n\n  /**\n   * Index 119: Child's Social Security number - 8\n   * TODO: non-dependent children not handled.\n   */\n  ChildsSocialSecuritynumber8 = (): string | undefined => {\n    return undefined\n  }\n\n  f119 = (): string | undefined => this.ChildsSocialSecuritynumber8()\n\n  /**\n   * Index 120: Child's relationship to you - 1\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou1 = (): string | undefined => {\n    return undefined\n  }\n\n  f120 = (): string | undefined => this.Childsrelationshiptoyou1()\n\n  /**\n   * Index 121: Child's relationship to you - 2\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou2 = (): string | undefined => {\n    return undefined\n  }\n\n  f121 = (): string | undefined => this.Childsrelationshiptoyou2()\n\n  /**\n   * Index 122: Child's relationship to you - 3\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou3 = (): string | undefined => {\n    return undefined\n  }\n\n  f122 = (): string | undefined => this.Childsrelationshiptoyou3()\n\n  /**\n   * Index 123: Child's relationship to you - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou4 = (): string | undefined => {\n    return undefined\n  }\n\n  f123 = (): string | undefined => this.Childsrelationshiptoyou4()\n\n  /**\n   * Index 124: Child's relationship to you - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou5 = (): string | undefined => {\n    return undefined\n  }\n\n  f124 = (): string | undefined => this.Childsrelationshiptoyou5()\n\n  /**\n   * Index 125: Child's relationship to you - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou6 = (): string | undefined => {\n    return undefined\n  }\n\n  f125 = (): string | undefined => this.Childsrelationshiptoyou6()\n\n  /**\n   * Index 126: Child's relationship to you - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou7 = (): string | undefined => {\n    return undefined\n  }\n\n  f126 = (): string | undefined => this.Childsrelationshiptoyou7()\n\n  /**\n   * Index 127: Child's relationship to you - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childsrelationshiptoyou8 = (): string | undefined => {\n    return undefined\n  }\n\n  f127 = (): string | undefined => this.Childsrelationshiptoyou8()\n\n  /**\n   * Index 128: Child's date of birth (mm/dd/yyyy) - 1\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy1 = (): string | undefined => {\n    return undefined\n  }\n\n  f128 = (): string | undefined => this.Childsdateofbirthmmddyyyy1()\n\n  /**\n   * Index 129: Child's date of birth (mm/dd/yyyy) - 2\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy2 = (): string | undefined => {\n    return undefined\n  }\n\n  f129 = (): string | undefined => this.Childsdateofbirthmmddyyyy2()\n\n  /**\n   * Index 130: Child's date of birth (mm/dd/yyyy) - 3\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy3 = (): string | undefined => {\n    return undefined\n  }\n\n  f130 = (): string | undefined => this.Childsdateofbirthmmddyyyy3()\n\n  /**\n   * Index 131: Child's date of birth (mm/dd/yyyy) - 4\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy4 = (): string | undefined => {\n    return undefined\n  }\n\n  f131 = (): string | undefined => this.Childsdateofbirthmmddyyyy4()\n\n  /**\n   * Index 132: Child's date of birth (mm/dd/yyyy) - 5\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy5 = (): string | undefined => {\n    return undefined\n  }\n\n  f132 = (): string | undefined => this.Childsdateofbirthmmddyyyy5()\n\n  /**\n   * Index 133: Child's date of birth (mm/dd/yyyy) - 6\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy6 = (): string | undefined => {\n    return undefined\n  }\n\n  f133 = (): string | undefined => this.Childsdateofbirthmmddyyyy6()\n\n  /**\n   * Index 134: Child's date of birth (mm/dd/yyyy) - 7\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy7 = (): string | undefined => {\n    return undefined\n  }\n\n  f134 = (): string | undefined => this.Childsdateofbirthmmddyyyy7()\n\n  /**\n   * Index 135: Child's date of birth (mm/dd/yyyy) - 8\n   * TODO: non-dependent children not handled.\n   */\n  Childsdateofbirthmmddyyyy8 = (): string | undefined => {\n    return undefined\n  }\n\n  f135 = (): string | undefined => this.Childsdateofbirthmmddyyyy8()\n\n  /**\n   * Index 136: Child - Full Time Student - 1\n   */\n  ChildFullTimeStudent1 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f136 = (): boolean | undefined => this.ChildFullTimeStudent1()\n\n  /**\n   * Index 137: Child - Full Time Student - 2\n   */\n  ChildFullTimeStudent2 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f137 = (): boolean | undefined => this.ChildFullTimeStudent2()\n\n  /**\n   * Index 138: Child - Full Time Student - 3\n   */\n  ChildFullTimeStudent3 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f138 = (): boolean | undefined => this.ChildFullTimeStudent3()\n\n  /**\n   * Index 139: Child - Full Time Student - 4\n   */\n  ChildFullTimeStudent4 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f139 = (): boolean | undefined => this.ChildFullTimeStudent4()\n\n  /**\n   * Index 140: Child - Full Time Student - 5\n   */\n  ChildFullTimeStudent5 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f140 = (): boolean | undefined => this.ChildFullTimeStudent5()\n\n  /**\n   * Index 141: Child - Full Time Student - 6\n   */\n  ChildFullTimeStudent6 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f141 = (): boolean | undefined => this.ChildFullTimeStudent6()\n\n  /**\n   * Index 142: Child - Full Time Student - 7\n   */\n  ChildFullTimeStudent7 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f142 = (): boolean | undefined => this.ChildFullTimeStudent7()\n\n  /**\n   * Index 143: Child - Full Time Student - 8\n   */\n  ChildFullTimeStudent8 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f143 = (): boolean | undefined => this.ChildFullTimeStudent8()\n\n  /**\n   * Index 144: Child - Person with disability - 2\n   */\n  ChildPersonwithdisability2 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f144 = (): boolean | undefined => this.ChildPersonwithdisability2()\n\n  /**\n   * Index 145: Child - Person with disability - 1\n   */\n  ChildPersonwithdisability1 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f145 = (): boolean | undefined => this.ChildPersonwithdisability1()\n\n  /**\n   * Index 146: Child - Person with disability - 3\n   */\n  ChildPersonwithdisability3 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f146 = (): boolean | undefined => this.ChildPersonwithdisability3()\n\n  /**\n   * Index 147: Child - Person with disability - 4\n   */\n  ChildPersonwithdisability4 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f147 = (): boolean | undefined => this.ChildPersonwithdisability4()\n\n  /**\n   * Index 148: Child - Person with disability - 5\n   */\n  ChildPersonwithdisability5 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f148 = (): boolean | undefined => this.ChildPersonwithdisability5()\n\n  /**\n   * Index 149: Child - Person with disability - 6\n   */\n  ChildPersonwithdisability6 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f149 = (): boolean | undefined => this.ChildPersonwithdisability6()\n\n  /**\n   * Index 150: Child - Person with disability - 7\n   */\n  ChildPersonwithdisability7 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f150 = (): boolean | undefined => this.ChildPersonwithdisability7()\n\n  /**\n   * Index 151: Child - Person with disability - 8\n   */\n  ChildPersonwithdisability8 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f151 = (): boolean | undefined => this.ChildPersonwithdisability8()\n\n  /**\n   * Index 152: Child - Number of months living with you - 1\n   */\n  ChildNumberofmonthslivingwithyou1 = (): string | undefined => {\n    return undefined\n  }\n\n  f152 = (): string | undefined => this.ChildNumberofmonthslivingwithyou1()\n\n  /**\n   * Index 153: Child - Number of months living with you - 2\n   */\n  ChildNumberofmonthslivingwithyou2 = (): string | undefined => {\n    return undefined\n  }\n\n  f153 = (): string | undefined => this.ChildNumberofmonthslivingwithyou2()\n\n  /**\n   * Index 154: Child - Number of months living with you - 3\n   */\n  ChildNumberofmonthslivingwithyou3 = (): string | undefined => {\n    return undefined\n  }\n\n  f154 = (): string | undefined => this.ChildNumberofmonthslivingwithyou3()\n\n  /**\n   * Index 155: Child - Number of months living with you - 4\n   */\n  ChildNumberofmonthslivingwithyou4 = (): string | undefined => {\n    return undefined\n  }\n\n  f155 = (): string | undefined => this.ChildNumberofmonthslivingwithyou4()\n\n  /**\n   * Index 156: Child - Number of months living with you - 5\n   */\n  ChildNumberofmonthslivingwithyou5 = (): string | undefined => {\n    return undefined\n  }\n\n  f156 = (): string | undefined => this.ChildNumberofmonthslivingwithyou5()\n\n  /**\n   * Index 157: Child - Number of months living with you - 6\n   */\n  ChildNumberofmonthslivingwithyou6 = (): string | undefined => {\n    return undefined\n  }\n\n  f157 = (): string | undefined => this.ChildNumberofmonthslivingwithyou6()\n\n  /**\n   * Index 158: Child - Number of months living with you - 7\n   */\n  ChildNumberofmonthslivingwithyou7 = (): string | undefined => {\n    return undefined\n  }\n\n  f158 = (): string | undefined => this.ChildNumberofmonthslivingwithyou7()\n\n  /**\n   * Index 159: Child - Number of months living with you - 8\n   */\n  ChildNumberofmonthslivingwithyou8 = (): string | undefined => {\n    return undefined\n  }\n\n  f159 = (): string | undefined => this.ChildNumberofmonthslivingwithyou8()\n\n  /**\n   * Index 160: Wages - Salaries - Tips\n   */\n  WagesSalariesTips = (): number | undefined => this.f1040.l1()\n\n  f160 = (): number | undefined => this.WagesSalariesTips()\n\n  /**\n   * Index 161: Business income/loss\n   */\n  Businessincomeloss = (): number | undefined => this.f1040.schedule1.l3()\n\n  f161 = (): number | undefined => this.Businessincomeloss()\n\n  /**\n   * Index 162: Occupation requirement\n   * TODO: jurisdictional license question\n   */\n  Occupationrequirement = (): boolean | undefined => undefined\n\n  f162 = (): boolean | undefined => this.Occupationrequirement()\n\n  /**\n   * Index 163: Issuing agency - 1\n   */\n  Issuingagency1 = (): string | undefined => undefined\n\n  f163 = (): string | undefined => this.Issuingagency1()\n\n  /**\n   * Index 164: Issuing agency - 2\n   */\n  Issuingagency2 = (): string | undefined => undefined\n\n  f164 = (): string | undefined => this.Issuingagency2()\n\n  /**\n   * Index 165: Issuing agency - 3\n   */\n  Issuingagency3 = (): string | undefined => undefined\n\n  f165 = (): string | undefined => this.Issuingagency3()\n\n  /**\n   * Index 166: Issuing agency - 5\n   */\n  Issuingagency5 = (): string | undefined => undefined\n\n  f166 = (): string | undefined => this.Issuingagency5()\n\n  /**\n   * Index 167: Issuing agency - 4\n   */\n  Issuingagency4 = (): string | undefined => undefined\n\n  f167 = (): string | undefined => this.Issuingagency4()\n\n  /**\n   * Index 168: License/Registration/Certification - 1\n   */\n  LicenseRegistrationCertification1 = (): string | undefined => undefined\n\n  f168 = (): string | undefined => this.LicenseRegistrationCertification1()\n\n  /**\n   * Index 169: License/Registration/Certification - 2\n   */\n  LicenseRegistrationCertification2 = (): string | undefined => undefined\n\n  f169 = (): string | undefined => this.LicenseRegistrationCertification2()\n\n  /**\n   * Index 170: License/Registration/Certification - 3\n   */\n  LicenseRegistrationCertification3 = (): string | undefined => undefined\n\n  f170 = (): string | undefined => this.LicenseRegistrationCertification3()\n\n  /**\n   * Index 171: License/Registration/Certification - 4\n   */\n  LicenseRegistrationCertification4 = (): string | undefined => undefined\n\n  f171 = (): string | undefined => this.LicenseRegistrationCertification4()\n\n  /**\n   * Index 172: License/Registration/Certification - 5\n   */\n  LicenseRegistrationCertification5 = (): string | undefined => undefined\n\n  f172 = (): string | undefined => this.LicenseRegistrationCertification5()\n\n  /**\n   * Index 173: Filing - married filing jointly\n   * TODO: Handle MFJ federal / MFS state issue.\n   */\n  Filingmarriedfilingjointly = (): string | undefined => {\n    return undefined\n  }\n\n  f173 = (): string | undefined => this.Filingmarriedfilingjointly()\n\n  /**\n   * Index 174: Spouse' s SSN3-2\n   * TODO - only applicable for MFS state and MFJ federal return\n   */\n  SpousesSSN32 = (): string | undefined => undefined\n\n  f174 = (): string | undefined => this.SpousesSSN32()\n\n  /**\n   * Index 175: Spouse's SSN2-2\n   */\n  SpousesSSN22 = (): string | undefined => undefined\n\n  f175 = (): string | undefined => this.SpousesSSN22()\n\n  /**\n   * Index 176: Spouse's SSN4-2\n   */\n  SpousesSSN42 = (): string | undefined => undefined\n\n  f176 = (): string | undefined => this.SpousesSSN42()\n\n  /**\n   * Index 177: Statutory employee box marked\n   */\n  Statutoryemployeeboxmarked = (): boolean | undefined => {\n    return undefined\n  }\n\n  f177 = (): boolean | undefined => this.Statutoryemployeeboxmarked()\n\n  /**\n   * Index 178: Federal Earned Income Credit amount\n   */\n  FederalEarnedIncomeCreditamount = (): number | undefined => this.f1040.l27a()\n\n  f178 = (): number | undefined => this.FederalEarnedIncomeCreditamount()\n\n  /**\n   * Index 179: Multiply L5\n   */\n  MultiplyL5 = (): number =>\n    (this.FederalEarnedIncomeCreditamount() ?? 0) *\n    parameters.earnedIncomeCreditFactor\n\n  f179 = (): number => Math.round(this.MultiplyL5())\n\n  /**\n   * Index 180: Residents / Non-Residents rate - 1\n   * TODO: Handle non-residents rate\n   */\n  ResidentsNonResidentsrate1 = (): number => 1\n\n  f180 = (): number => this.ResidentsNonResidentsrate1()\n\n  /**\n   * Index 181: Residents / Non-Residents rate - 2\n   * TODO: Handle non-residents rate and Schedule NR\n   */\n  ResidentsNonResidentsrate2 = (): number => 0\n\n  f181 = (): number => this.ResidentsNonResidentsrate2()\n\n  /**\n   * Index 182: Multiply L6 - L7\n   */\n  MultiplyL6L7 = (): number | undefined =>\n    this.MultiplyL5() *\n    (this.ResidentsNonResidentsrate1() +\n      this.ResidentsNonResidentsrate2() / 100)\n\n  earnedIncomeCredit = (): number | undefined => this.MultiplyL6L7()\n\n  f182 = (): number => Math.round(this.MultiplyL6L7() ?? 0)\n\n  /**\n   * Index 183: Your SSN3\n   */\n  YourSSN3 = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f183 = (): string | undefined => this.YourSSN3()\n\n  /**\n   * Index 184: Your SSN2\n   */\n  YourSSN2 = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f184 = (): string | undefined => this.YourSSN2()\n\n  /**\n   * Index 185: Your SSN4\n   */\n  YourSSN4 = (): string | undefined =>\n    this.f1040.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f185 = (): string | undefined => this.YourSSN4()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.f85(),\n    this.f86(),\n    this.f87(),\n    this.f88(),\n    this.f89(),\n    this.f90(),\n    this.f91(),\n    this.f92(),\n    this.f93(),\n    this.f94(),\n    this.f95(),\n    this.f96(),\n    this.f97(),\n    this.f98(),\n    this.f99(),\n    this.f100(),\n    this.f101(),\n    this.f102(),\n    this.f103(),\n    this.f104(),\n    this.f105(),\n    this.f106(),\n    this.f107(),\n    this.f108(),\n    this.f109(),\n    this.f110(),\n    this.f111(),\n    this.f112(),\n    this.f113(),\n    this.f114(),\n    this.f115(),\n    this.f116(),\n    this.f117(),\n    this.f118(),\n    this.f119(),\n    this.f120(),\n    this.f121(),\n    this.f122(),\n    this.f123(),\n    this.f124(),\n    this.f125(),\n    this.f126(),\n    this.f127(),\n    this.f128(),\n    this.f129(),\n    this.f130(),\n    this.f131(),\n    this.f132(),\n    this.f133(),\n    this.f134(),\n    this.f135(),\n    this.f136(),\n    this.f137(),\n    this.f138(),\n    this.f139(),\n    this.f140(),\n    this.f141(),\n    this.f142(),\n    this.f143(),\n    this.f144(),\n    this.f145(),\n    this.f146(),\n    this.f147(),\n    this.f148(),\n    this.f149(),\n    this.f150(),\n    this.f151(),\n    this.f152(),\n    this.f153(),\n    this.f154(),\n    this.f155(),\n    this.f156(),\n    this.f157(),\n    this.f158(),\n    this.f159(),\n    this.f160(),\n    this.f161(),\n    this.f162(),\n    this.f163(),\n    this.f164(),\n    this.f165(),\n    this.f166(),\n    this.f167(),\n    this.f168(),\n    this.f169(),\n    this.f170(),\n    this.f171(),\n    this.f172(),\n    this.f173(),\n    this.f174(),\n    this.f175(),\n    this.f176(),\n    this.f177(),\n    this.f178(),\n    this.f179(),\n    this.f180(),\n    this.f181(),\n    this.f182(),\n    this.f183(),\n    this.f184(),\n    this.f185()\n  ]\n}\n\nconst makeil1040scheduleileeic = (f1040: F1040): IL1040scheduleileeic =>\n  new IL1040scheduleileeic(f1040)\n\nexport default makeil1040scheduleileeic\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IL/IL1040V.ts",
    "content": "import Form from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { IL1040 } from './IL1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport default class IL1040V extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  il1040: IL1040\n  formOrder = -1\n  attachments: () => Form[] = () => []\n\n  constructor(f1040: F1040, il1040: IL1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'IL-1040-V'\n    this.state = 'IL'\n    this.il1040 = il1040\n  }\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: PrimarySSN1\n   */\n  PrimarySSN1 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f1 = (): string | undefined => this.PrimarySSN1()\n\n  /**\n   * Index 2: PrimarySSN2\n   */\n  PrimarySSN2 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f2 = (): string | undefined => this.PrimarySSN2()\n\n  /**\n   * Index 3: PrimarySSN3\n   */\n  PrimarySSN3 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f3 = (): string | undefined => this.PrimarySSN3()\n\n  /**\n   * Index 4: SpouseSSN1\n   */\n  SpouseSSN1 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(0, 3)\n\n  f4 = (): string | undefined => this.SpouseSSN1()\n\n  /**\n   * Index 5: SpouseSSN2\n   */\n  SpouseSSN2 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(3, 5)\n\n  f5 = (): string | undefined => this.SpouseSSN2()\n\n  /**\n   * Index 6: SpouseSSN3\n   */\n  SpouseSSN3 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(5)\n\n  f6 = (): string | undefined => this.SpouseSSN3()\n\n  /**\n   * Index 7: FirstName\n   */\n  FirstName = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.firstName\n\n  f7 = (): string | undefined => this.FirstName()\n\n  /**\n   * Index 8: SpouseFirstName\n   */\n  SpouseFirstName = (): string | undefined =>\n    this.info.taxPayer.spouse?.firstName\n\n  f8 = (): string | undefined => this.SpouseFirstName()\n\n  /**\n   * Index 9: LastName\n   */\n  LastName = (): string | undefined => this.info.taxPayer.primaryPerson.lastName\n\n  f9 = (): string | undefined => this.LastName()\n\n  /**\n   * Index 10: Address\n   */\n  Address = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.address\n\n  f10 = (): string | undefined => this.Address()\n\n  /**\n   * Index 11: City\n   */\n  City = (): string | undefined => this.info.taxPayer.primaryPerson.address.city\n\n  f11 = (): string | undefined => this.City()\n\n  /**\n   * Index 12: State\n   */\n  State = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.address.state\n\n  f12 = (): string | undefined => this.State()\n\n  /**\n   * Index 13: ZIP\n   */\n  ZIP = (): string | undefined => this.info.taxPayer.primaryPerson.address.zip\n\n  f13 = (): string | undefined => this.ZIP()\n\n  /**\n   * Index 14: PaymentAmount\n   */\n  PaymentAmount = (): number | undefined => {\n    const amount = this.il1040.payment()\n    if (amount !== undefined) {\n      return Math.trunc(amount)\n    }\n  }\n\n  f14 = (): number | undefined => this.PaymentAmount()\n\n  /**\n   * Index 15: PaymentAmountCents\n   */\n  PaymentAmountCents = (): number | undefined => {\n    const amount = this.il1040.payment()\n    if (amount !== undefined) {\n      return Math.round((amount - Math.trunc(amount)) * 100)\n    }\n  }\n\n  f15 = (): number | undefined => this.PaymentAmountCents()\n\n  /**\n   * Index 16: Reset\n   */\n  Reset = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.Reset()\n\n  /**\n   * Index 17: Print\n   */\n  Print = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.Print()\n\n  /**\n   * Index 18: scanline\n   */\n  scanline = (): string | undefined => {\n    return undefined\n  }\n\n  f18 = (): string | undefined => this.scanline()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IL/ILWit.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { IncomeW2, PersonRole, State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\ntype FormType =\n  | 'W' // W-2\n  | 'WG' // W2-G\n  | 'R' // 1099-R\n  | 'G' // 1099-G\n  | 'M' // 1099-MISC\n  | 'O' // 1099-OID\n  | 'D' // 1099-DIV\n  | 'I' // 1099-INT\n  | 'S' // 1042-S\n  | 'B' // 1099-B\n  | 'K' // 1099-K\n  | 'N' // 1099-NEC\n\ninterface WithholdingForm {\n  formType: [FormType, FormType | undefined]\n  role: PersonRole\n  ein: string\n  federalWages: number\n  ilWages: number\n  ilTax: number\n}\n\nconst toWithholdingForm = (w2: IncomeW2): WithholdingForm | undefined => {\n  if (\n    w2.stateWages !== undefined &&\n    w2.stateWithholding !== undefined &&\n    w2.employer?.EIN !== undefined\n  ) {\n    return {\n      formType: ['W', undefined],\n      ein: w2.employer.EIN,\n      federalWages: w2.income,\n      ilWages: w2.stateWages,\n      ilTax: w2.stateWithholding,\n      role: w2.personRole\n    }\n  }\n}\n\n/**\n * Each ILWIT form supports 5 withholding forms for\n * primary taxpayer and 5 for spouse\n * TODO: support more than 5 for each\n */\nexport class ILWIT extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName = 'IL-WIT'\n  state: State = 'IL'\n  formOrder = 31\n  methods: FormMethods\n  formIndex: number\n\n  static WITHHOLDING_FORMS_PER_PAGE = 5\n\n  constructor(f1040: F1040, subFormIndex = 0) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.methods = new FormMethods(this)\n    this.formIndex = subFormIndex\n  }\n\n  attachments = (): Form[] => {\n    // If this is the head form, see if we need\n    // more copies. For example if the SSIDs have 4 and 11 forms,\n    // we will need 2 extra copies. this one will have 4 + 5,\n    // next will have 0 + 5, last will have 0 + 1\n    if (this.formIndex === 0) {\n      const copiesNeeded =\n        Math.ceil(\n          Math.max(\n            ...[PersonRole.PRIMARY, PersonRole.SPOUSE].map(\n              (r) =>\n                this.methods\n                  .stateW2s()\n                  .filter((w2) => (w2.stateWithholding ?? 0) > 0)\n                  .filter((w2) => w2.personRole === r).length\n            )\n          ) / ILWIT.WITHHOLDING_FORMS_PER_PAGE\n        ) - 1\n\n      return Array(copiesNeeded)\n        .fill(undefined)\n        .map((x, i) => new ILWIT(this.f1040, i + 1))\n    }\n\n    return []\n  }\n\n  /**\n   * Index 0: Help\n   */\n  Help = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.Help()\n\n  /**\n   * Index 1: Your name\n   */\n  Yourname = (): string | undefined => {\n    const person = this.info.taxPayer.primaryPerson\n    return [person.firstName, person.lastName].flat().join(' ')\n  }\n\n  f1 = (): string | undefined => this.Yourname()\n\n  /**\n   * Index 2: Your SSN-3\n   */\n  YourSSN3 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(0, 3)\n\n  f2 = (): string | undefined => this.YourSSN3()\n\n  /**\n   * Index 3: Your SSN-2\n   */\n  YourSSN2 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(3, 5)\n\n  f3 = (): string | undefined => this.YourSSN2()\n\n  /**\n   * Index 4: Your SSN-4\n   */\n  YourSSN4 = (): string | undefined =>\n    this.info.taxPayer.primaryPerson.ssid.slice(5)\n\n  f4 = (): string | undefined => this.YourSSN4()\n\n  allWithholdingForms = (): WithholdingForm[] =>\n    this.methods\n      .stateW2s()\n      .map((w2) => toWithholdingForm(w2))\n      .filter((x) => x !== undefined) as WithholdingForm[]\n\n  formsByRole = (role: PersonRole): WithholdingForm[] =>\n    this.allWithholdingForms().filter((w2) => w2.role === role)\n\n  // TODO: handle more than 5 withholding forms.\n  primaryForms = (): WithholdingForm[] =>\n    this.formsByRole(PersonRole.PRIMARY).slice(0, 5)\n\n  // TODO: handle more than 5 withholding forms.\n  spouseForms = (): WithholdingForm[] =>\n    this.formsByRole(PersonRole.SPOUSE).slice(0, 5)\n\n  /**\n   * 6 x 5 grid for primary taxpayer, rowwise.\n   */\n  formGrid = (forms: WithholdingForm[]): (string | number | undefined)[] => [\n    ...forms.flatMap((form) => [\n      ...form.formType,\n      form.ein,\n      form.federalWages,\n      form.ilWages,\n      form.ilTax\n    ]),\n    ...Array.from<undefined>(Array(5 - forms.length)).flatMap(() =>\n      Array<undefined>(5).fill(undefined)\n    )\n  ]\n\n  /**\n   * Primary ssid withholding, Column B -> Column E\n   */\n  f5tof34 = (): (string | number | undefined)[] =>\n    this.formGrid(this.primaryForms())\n\n  /**\n   * Index 35: Spouse's name\n   */\n  Spousesname = (): string | undefined => {\n    const spouse = this.info.taxPayer.spouse\n    if (spouse !== undefined) {\n      return `${spouse.firstName} ${spouse.lastName}`\n    }\n  }\n\n  f35 = (): string | undefined => this.Spousesname()\n\n  /**\n   * Index 28: Spouse's SSN-3\n   */\n  SpousesSSN3 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(0, 3)\n\n  f36 = (): string | undefined => this.SpousesSSN3()\n\n  /**\n   * Index 29: Spouse's SSN-2\n   */\n  SpousesSSN2 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(3, 5)\n\n  f37 = (): string | undefined => this.SpousesSSN2()\n\n  /**\n   * Index 30: Spouse's SSN-4\n   */\n  SpousesSSN4 = (): string | undefined =>\n    this.info.taxPayer.spouse?.ssid.slice(5)\n\n  f38 = (): string | undefined => this.SpousesSSN4()\n\n  /**\n   * Spouse ssid forms, Column B -> Column E\n   */\n  f39tof68 = (): (string | number | undefined)[] =>\n    this.formGrid(this.spouseForms())\n\n  /**\n   * Index 51: Total amount\n   */\n  Totalamount = (): number | undefined => {\n    if (this.formIndex === 0) {\n      return this.allWithholdingForms().reduce((s, f) => s + f.ilTax, 0)\n    }\n  }\n\n  f69 = (): number | undefined => this.Totalamount()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    ...this.f5tof34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    ...this.f39tof68()\n  ]\n}\n\nconst makeILWIT = (f1040: F1040): ILWIT => new ILWIT(f1040)\n\nexport default makeILWIT\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IL/Parameters.ts",
    "content": "import { FilingStatus } from 'ustaxes/core/data'\n\nconst parameters = {\n  exemptions: {\n    [FilingStatus.S]: {\n      incomeLowerLimit: 2375,\n      incomeUpperLimit: 250000,\n      exemptionAmount: 2375\n    },\n    [FilingStatus.MFJ]: {\n      incomeLowerLimit: 4750,\n      incomeUpperLimit: 500000,\n      exemptionAmount: 4750\n    }\n  },\n  taxRate: 0.0495,\n  seniorExemption: 1000,\n  blindExemption: 1000,\n  earnedIncomeCreditFactor: 0.18,\n  eicDependentCredit: 2325\n}\n\nexport default parameters\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/IN/Form.ts",
    "content": "export default class INForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/KS/Form.ts",
    "content": "export default class KSForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/KY/Form.ts",
    "content": "export default class KYForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/LA/Form.ts",
    "content": "export default class LAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MA/Form.ts",
    "content": "export default class MAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MD/Form.ts",
    "content": "export default class MDForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/ME/Form.ts",
    "content": "export default class MEForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MI/Form.ts",
    "content": "export default class MIForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MN/Form.ts",
    "content": "export default class MNForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MO/Form.ts",
    "content": "export default class MOForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MS/Form.ts",
    "content": "export default class MSForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/MT/Form.ts",
    "content": "export default class MTForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NC/Form.ts",
    "content": "export default class NCForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/ND/Form.ts",
    "content": "export default class NDForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NE/Form.ts",
    "content": "export default class NEForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NH/Form.ts",
    "content": "export default class NHForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NJ/Form.ts",
    "content": "export default class NJForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NM/Form.ts",
    "content": "export default class NMForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NV/Form.ts",
    "content": "export default class NVForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/NY/Form.ts",
    "content": "export default class NYForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OH/Form.ts",
    "content": "export default class OHForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OK/Form.ts",
    "content": "export default class OKForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/Form.ts",
    "content": "export default class ORForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/OR40.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\n// import { sumFields } from 'ustaxes/core/irsForms/util'\nimport { State } from 'ustaxes/core/data'\n// import parameters from './Parameters'\nimport { ORWFHDC } from './ORWFHDC'\nimport OR40V from './OR40V'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class OR40 extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  scheduleWFHDC: ORWFHDC\n  or40V: OR40V\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-40'\n    this.state = 'OR'\n    this.scheduleWFHDC = new ORWFHDC(f1040)\n    this.or40V = new OR40V(f1040, this)\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    // const pmt = this.payment()\n    const result: Form[] = []\n    // if ((pmt ?? 0) > 0) {\n    //   result.push(this.il1040V)\n    // }\n    // if (this.scheduleEIC.isRequired()) {\n    //   result.push(this.scheduleEIC)\n    // }\n    // if (this.methods.stateWithholding() > 0) {\n    //   const ilwit = new ILWIT(this.info, this.f1040)\n    //   result.push(ilwit)\n    //   ilwit.attachments().forEach((f) => result.push(f))\n    // }\n\n    return result\n  }\n\n  /**\n   * Index 0: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 1: or-40-p1-1\n   */\n  or40p11 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.or40p11()\n\n  /**\n   * Index 2: or-40-p1-2\n   */\n  or40p12 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f2 = (): boolean | undefined => this.or40p12()\n\n  /**\n   * Index 3: or-40-p1-4\n   */\n  or40p14 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f3 = (): boolean | undefined => this.or40p14()\n\n  /**\n   * Index 4: or-40-p1-5\n   */\n  or40p15 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f4 = (): boolean | undefined => this.or40p15()\n\n  /**\n   * Index 5: or-40-p1-6\n   */\n  or40p16 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f5 = (): boolean | undefined => this.or40p16()\n\n  /**\n   * Index 6: or-40-p1-7\n   */\n  or40p17 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f6 = (): boolean | undefined => this.or40p17()\n\n  /**\n   * Index 7: or-40-p1-8\n   */\n  or40p18 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f7 = (): boolean | undefined => this.or40p18()\n\n  /**\n   * Index 8: or-40-p1-9\n   */\n  or40p19 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f8 = (): boolean | undefined => this.or40p19()\n\n  /**\n   * Index 9: or-40-p1-10\n   */\n  or40p110 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f9 = (): boolean | undefined => this.or40p110()\n\n  /**\n   * Index 10: or-40-p1-11\n   */\n  or40p111 = (): string | undefined => {\n    return undefined\n  }\n\n  f10 = (): string | undefined => this.or40p111()\n\n  /**\n   * Index 11: or-40-p1-12\n   */\n  or40p112 = (): string | undefined => {\n    return undefined\n  }\n\n  f11 = (): string | undefined => this.or40p112()\n\n  /**\n   * Index 12: or-40-p1-13\n   */\n  or40p113 = (): string | undefined => {\n    return undefined\n  }\n\n  f12 = (): string | undefined => this.or40p113()\n\n  /**\n   * Index 13: or-40-p1-16\n   */\n  or40p116 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f13 = (): boolean | undefined => this.or40p116()\n\n  /**\n   * Index 14: or-40-p1-17\n   */\n  or40p117 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f14 = (): boolean | undefined => this.or40p117()\n\n  /**\n   * Index 15: or-40-p1-18\n   */\n  or40p118 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f15 = (): boolean | undefined => this.or40p118()\n\n  /**\n   * Index 16: or-40-p1-14\n   */\n  or40p114 = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.or40p114()\n\n  /**\n   * Index 17: or-40-p1-15\n   */\n  or40p115 = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.or40p115()\n\n  /**\n   * Index 18: or-40-p2-2\n   */\n  or40p22 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f18 = (): boolean | undefined => this.or40p22()\n\n  /**\n   * Index 19: or-40-p2-3\n   */\n  or40p23 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f19 = (): boolean | undefined => this.or40p23()\n\n  /**\n   * Index 20: or-40-p2-4\n   */\n  or40p24 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f20 = (): boolean | undefined => this.or40p24()\n\n  /**\n   * Index 21: or-40-p2-5\n   */\n  or40p25 = (): string | undefined => {\n    return undefined\n  }\n\n  f21 = (): string | undefined => this.or40p25()\n\n  /**\n   * Index 22: or-40-p2-9\n   */\n  or40p29 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f22 = (): boolean | undefined => this.or40p29()\n\n  /**\n   * Index 23: or-40-p2-12\n   */\n  or40p212 = (): string | undefined => {\n    return undefined\n  }\n\n  f23 = (): string | undefined => this.or40p212()\n\n  /**\n   * Index 24: or-40-p2-13\n   */\n  or40p213 = (): string | undefined => {\n    return undefined\n  }\n\n  f24 = (): string | undefined => this.or40p213()\n\n  /**\n   * Index 25: or-40-p2-14\n   */\n  or40p214 = (): string | undefined => {\n    return undefined\n  }\n\n  f25 = (): string | undefined => this.or40p214()\n\n  /**\n   * Index 26: or-40-p2-15\n   */\n  or40p215 = (): string | undefined => {\n    return undefined\n  }\n\n  f26 = (): string | undefined => this.or40p215()\n\n  /**\n   * Index 27: or-40-p2-17\n   */\n  or40p217 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f27 = (): boolean | undefined => this.or40p217()\n\n  /**\n   * Index 28: or-40-p2-18\n   */\n  or40p218 = (): string | undefined => {\n    return undefined\n  }\n\n  f28 = (): string | undefined => this.or40p218()\n\n  /**\n   * Index 29: or-40-p2-19\n   */\n  or40p219 = (): string | undefined => {\n    return undefined\n  }\n\n  f29 = (): string | undefined => this.or40p219()\n\n  /**\n   * Index 30: or-40-p2-20\n   */\n  or40p220 = (): string | undefined => {\n    return undefined\n  }\n\n  f30 = (): string | undefined => this.or40p220()\n\n  /**\n   * Index 31: or-40-p2-21\n   */\n  or40p221 = (): string | undefined => {\n    return undefined\n  }\n\n  f31 = (): string | undefined => this.or40p221()\n\n  /**\n   * Index 32: or-40-p2-22\n   */\n  or40p222 = (): string | undefined => {\n    return undefined\n  }\n\n  f32 = (): string | undefined => this.or40p222()\n\n  /**\n   * Index 33: or-40-p2-24\n   */\n  or40p224 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f33 = (): boolean | undefined => this.or40p224()\n\n  /**\n   * Index 34: or-40-p2-25\n   */\n  or40p225 = (): string | undefined => {\n    return undefined\n  }\n\n  f34 = (): string | undefined => this.or40p225()\n\n  /**\n   * Index 35: or-40-p2-26\n   */\n  or40p226 = (): string | undefined => {\n    return undefined\n  }\n\n  f35 = (): string | undefined => this.or40p226()\n\n  /**\n   * Index 36: or-40-p2-27\n   */\n  or40p227 = (): string | undefined => {\n    return undefined\n  }\n\n  f36 = (): string | undefined => this.or40p227()\n\n  /**\n   * Index 37: or-40-p2-29\n   */\n  or40p229 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.or40p229()\n\n  /**\n   * Index 38: or-40-p2-31\n   */\n  or40p231 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f38 = (): boolean | undefined => this.or40p231()\n\n  /**\n   * Index 39: or-40-p2-33\n   */\n  or40p233 = (): string | undefined => {\n    return undefined\n  }\n\n  f39 = (): string | undefined => this.or40p233()\n\n  /**\n   * Index 40: or-40-p2-34\n   */\n  or40p234 = (): string | undefined => {\n    return undefined\n  }\n\n  f40 = (): string | undefined => this.or40p234()\n\n  /**\n   * Index 41: or-40-p2-6\n   */\n  or40p26 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f41 = (): boolean | undefined => this.or40p26()\n\n  /**\n   * Index 42: or-40-p2-7\n   */\n  or40p27 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f42 = (): boolean | undefined => this.or40p27()\n\n  /**\n   * Index 43: or-40-p2-8\n   */\n  or40p28 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f43 = (): boolean | undefined => this.or40p28()\n\n  /**\n   * Index 44: or-40-p2-32\n   */\n  or40p232 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.or40p232()\n\n  /**\n   * Index 45: or-40-p2-1\n   */\n  or40p21 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.or40p21()\n\n  /**\n   * Index 46: or-40-p2-28\n   */\n  or40p228 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.or40p228()\n\n  /**\n   * Index 47: or-40-p1-19\n   */\n  or40p119 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.or40p119()\n\n  /**\n   * Index 48: or-40-p1-20\n   */\n  or40p120 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.or40p120()\n\n  /**\n   * Index 49: or-40-p1-21\n   */\n  or40p121 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.or40p121()\n\n  /**\n   * Index 50: or-40-p1-22\n   */\n  or40p122 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.or40p122()\n\n  /**\n   * Index 51: or-40-p1-23\n   */\n  or40p123 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.or40p123()\n\n  /**\n   * Index 52: or-40-p1-24\n   */\n  or40p124 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f52 = (): boolean | undefined => this.or40p124()\n\n  /**\n   * Index 53: or-40-p1-25\n   */\n  or40p125 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f53 = (): boolean | undefined => this.or40p125()\n\n  /**\n   * Index 54: or-40-p1-26\n   */\n  or40p126 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f54 = (): boolean | undefined => this.or40p126()\n\n  /**\n   * Index 55: or-40-p1-27\n   */\n  or40p127 = (): string | undefined => {\n    return undefined\n  }\n\n  f55 = (): string | undefined => this.or40p127()\n\n  /**\n   * Index 56: or-40-p1-28\n   */\n  or40p128 = (): string | undefined => {\n    return undefined\n  }\n\n  f56 = (): string | undefined => this.or40p128()\n\n  /**\n   * Index 57: or-40-p1-31\n   */\n  or40p131 = (): string | undefined => {\n    return undefined\n  }\n\n  f57 = (): string | undefined => this.or40p131()\n\n  /**\n   * Index 58: or-40-p1-32\n   */\n  or40p132 = (): string | undefined => {\n    return undefined\n  }\n\n  f58 = (): string | undefined => this.or40p132()\n\n  /**\n   * Index 59: or-40-p1-3\n   */\n  or40p13 = (): string | undefined => {\n    return undefined\n  }\n\n  f59 = (): string | undefined => this.or40p13()\n\n  /**\n   * Index 60: or-40-p2-11\n   */\n  or40p211 = (): string | undefined => {\n    return undefined\n  }\n\n  f60 = (): string | undefined => this.or40p211()\n\n  /**\n   * Index 61: or-40-p3-12\n   */\n  or40p312 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f61 = (): boolean | undefined => this.or40p312()\n\n  /**\n   * Index 62: or-40-p3-13\n   */\n  or40p313 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f62 = (): boolean | undefined => this.or40p313()\n\n  /**\n   * Index 63: or-40-p3-14\n   */\n  or40p314 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f63 = (): boolean | undefined => this.or40p314()\n\n  /**\n   * Index 64: or-40-p3-15\n   */\n  or40p315 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f64 = (): boolean | undefined => this.or40p315()\n\n  /**\n   * Index 65: or-40-p4-2\n   */\n  or40p42 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f65 = (): boolean | undefined => this.or40p42()\n\n  /**\n   * Index 66: or-40-p4-3\n   */\n  or40p43 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f66 = (): boolean | undefined => this.or40p43()\n\n  /**\n   * Index 67: or-40-p4-4\n   */\n  or40p44 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f67 = (): boolean | undefined => this.or40p44()\n\n  /**\n   * Index 68: or-40-p5-12\n   */\n  or40p512 = (): string | undefined => {\n    return undefined\n  }\n\n  f68 = (): string | undefined => this.or40p512()\n\n  /**\n   * Index 69: or-40-p5-13\n   */\n  or40p513 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f69 = (): boolean | undefined => this.or40p513()\n\n  /**\n   * Index 70: or-40-p6-6\n   */\n  or40p66 = (): string | undefined => {\n    return undefined\n  }\n\n  f70 = (): string | undefined => this.or40p66()\n\n  /**\n   * Index 71: or-40-p6-7\n   */\n  or40p67 = (): string | undefined => {\n    return undefined\n  }\n\n  f71 = (): string | undefined => this.or40p67()\n\n  /**\n   * Index 72: or-40-p6-11\n   */\n  or40p611 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f72 = (): boolean | undefined => this.or40p611()\n\n  /**\n   * Index 73: or-40-p6-14\n   */\n  or40p614 = (): string | undefined => {\n    return undefined\n  }\n\n  f73 = (): string | undefined => this.or40p614()\n\n  /**\n   * Index 74: or-40-p6-15\n   */\n  or40p615 = (): string | undefined => {\n    return undefined\n  }\n\n  f74 = (): string | undefined => this.or40p615()\n\n  /**\n   * Index 75: or-40-p6-16\n   */\n  or40p616 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f75 = (): boolean | undefined => this.or40p616()\n\n  /**\n   * Index 76: or-40-p7-1\n   */\n  or40p71 = (): string | undefined => {\n    return undefined\n  }\n\n  f76 = (): string | undefined => this.or40p71()\n\n  /**\n   * Index 77: or-40-p7-2\n   */\n  or40p72 = (): string | undefined => {\n    return undefined\n  }\n\n  f77 = (): string | undefined => this.or40p72()\n\n  /**\n   * Index 78: or-40-p7-3\n   */\n  or40p73 = (): string | undefined => {\n    return undefined\n  }\n\n  f78 = (): string | undefined => this.or40p73()\n\n  /**\n   * Index 79: or-40-p7-4\n   */\n  or40p74 = (): string | undefined => {\n    return undefined\n  }\n\n  f79 = (): string | undefined => this.or40p74()\n\n  /**\n   * Index 80: or-40-p7-5\n   */\n  or40p75 = (): string | undefined => {\n    return undefined\n  }\n\n  f80 = (): string | undefined => this.or40p75()\n\n  /**\n   * Index 81: or-40-p7-6\n   */\n  or40p76 = (): string | undefined => {\n    return undefined\n  }\n\n  f81 = (): string | undefined => this.or40p76()\n\n  /**\n   * Index 82: or-40-p7-7\n   */\n  or40p77 = (): string | undefined => {\n    return undefined\n  }\n\n  f82 = (): string | undefined => this.or40p77()\n\n  /**\n   * Index 83: or-40-p7-8\n   */\n  or40p78 = (): string | undefined => {\n    return undefined\n  }\n\n  f83 = (): string | undefined => this.or40p78()\n\n  /**\n   * Index 84: or-40-p7-9\n   */\n  or40p79 = (): string | undefined => {\n    return undefined\n  }\n\n  f84 = (): string | undefined => this.or40p79()\n\n  /**\n   * Index 85: or-40-p7-10\n   */\n  or40p710 = (): string | undefined => {\n    return undefined\n  }\n\n  f85 = (): string | undefined => this.or40p710()\n\n  /**\n   * Index 86: or-40-p7-11\n   */\n  or40p711 = (): string | undefined => {\n    return undefined\n  }\n\n  f86 = (): string | undefined => this.or40p711()\n\n  /**\n   * Index 87: or-40-p8-1\n   */\n  or40p81 = (): string | undefined => {\n    return undefined\n  }\n\n  f87 = (): string | undefined => this.or40p81()\n\n  /**\n   * Index 88: or-40-p3-1\n   */\n  or40p31 = (): string | undefined => {\n    return undefined\n  }\n\n  f88 = (): string | undefined => this.or40p31()\n\n  /**\n   * Index 89: or-40-p3-2\n   */\n  or40p32 = (): string | undefined => {\n    return undefined\n  }\n\n  f89 = (): string | undefined => this.or40p32()\n\n  /**\n   * Index 90: or-40-p3-3\n   */\n  or40p33 = (): string | undefined => {\n    return undefined\n  }\n\n  f90 = (): string | undefined => this.or40p33()\n\n  /**\n   * Index 91: or-40-p3-10\n   */\n  or40p310 = (): string | undefined => {\n    return undefined\n  }\n\n  f91 = (): string | undefined => this.or40p310()\n\n  /**\n   * Index 92: or-40-p3-11\n   */\n  or40p311 = (): string | undefined => {\n    return undefined\n  }\n\n  f92 = (): string | undefined => this.or40p311()\n\n  /**\n   * Index 93: or-40-p3-16\n   */\n  or40p316 = (): string | undefined => {\n    return undefined\n  }\n\n  f93 = (): string | undefined => this.or40p316()\n\n  /**\n   * Index 94: or-40-p3-17\n   */\n  or40p317 = (): string | undefined => {\n    return undefined\n  }\n\n  f94 = (): string | undefined => this.or40p317()\n\n  /**\n   * Index 95: or-40-p3-4\n   */\n  or40p34 = (): string | undefined => {\n    return undefined\n  }\n\n  f95 = (): string | undefined => this.or40p34()\n\n  /**\n   * Index 96: or-40-p3-5\n   */\n  or40p35 = (): string | undefined => {\n    return undefined\n  }\n\n  f96 = (): string | undefined => this.or40p35()\n\n  /**\n   * Index 97: or-40-p3-6\n   */\n  or40p36 = (): string | undefined => {\n    return undefined\n  }\n\n  f97 = (): string | undefined => this.or40p36()\n\n  /**\n   * Index 98: or-40-p3-7\n   */\n  or40p37 = (): string | undefined => {\n    return undefined\n  }\n\n  f98 = (): string | undefined => this.or40p37()\n\n  /**\n   * Index 99: or-40-p3-8\n   */\n  or40p38 = (): string | undefined => {\n    return undefined\n  }\n\n  f99 = (): string | undefined => this.or40p38()\n\n  /**\n   * Index 100: or-40-p3-9\n   */\n  or40p39 = (): string | undefined => {\n    return undefined\n  }\n\n  f100 = (): string | undefined => this.or40p39()\n\n  /**\n   * Index 101: or-40-p4-1\n   */\n  or40p41 = (): string | undefined => {\n    return undefined\n  }\n\n  f101 = (): string | undefined => this.or40p41()\n\n  /**\n   * Index 102: or-40-p4-5\n   */\n  or40p45 = (): string | undefined => {\n    return undefined\n  }\n\n  f102 = (): string | undefined => this.or40p45()\n\n  /**\n   * Index 103: or-40-p4-6\n   */\n  or40p46 = (): string | undefined => {\n    return undefined\n  }\n\n  f103 = (): string | undefined => this.or40p46()\n\n  /**\n   * Index 104: or-40-p4-7\n   */\n  or40p47 = (): string | undefined => {\n    return undefined\n  }\n\n  f104 = (): string | undefined => this.or40p47()\n\n  /**\n   * Index 105: or-40-p4-8\n   */\n  or40p48 = (): string | undefined => {\n    return undefined\n  }\n\n  f105 = (): string | undefined => this.or40p48()\n\n  /**\n   * Index 106: or-40-p4-9\n   */\n  or40p49 = (): string | undefined => {\n    return undefined\n  }\n\n  f106 = (): string | undefined => this.or40p49()\n\n  /**\n   * Index 107: or-40-p4-10\n   */\n  or40p410 = (): string | undefined => {\n    return undefined\n  }\n\n  f107 = (): string | undefined => this.or40p410()\n\n  /**\n   * Index 108: or-40-p5-1\n   */\n  or40p51 = (): string | undefined => {\n    return undefined\n  }\n\n  f108 = (): string | undefined => this.or40p51()\n\n  /**\n   * Index 109: or-40-p5-2\n   */\n  or40p52 = (): string | undefined => {\n    return undefined\n  }\n\n  f109 = (): string | undefined => this.or40p52()\n\n  /**\n   * Index 110: or-40-p5-3\n   */\n  or40p53 = (): string | undefined => {\n    return undefined\n  }\n\n  f110 = (): string | undefined => this.or40p53()\n\n  /**\n   * Index 111: or-40-p5-4\n   */\n  or40p54 = (): string | undefined => {\n    return undefined\n  }\n\n  f111 = (): string | undefined => this.or40p54()\n\n  /**\n   * Index 112: or-40-p5-5\n   */\n  or40p55 = (): string | undefined => {\n    return undefined\n  }\n\n  f112 = (): string | undefined => this.or40p55()\n\n  /**\n   * Index 113: or-40-p5-6\n   */\n  or40p56 = (): string | undefined => {\n    return undefined\n  }\n\n  f113 = (): string | undefined => this.or40p56()\n\n  /**\n   * Index 114: or-40-p5-7\n   */\n  or40p57 = (): string | undefined => {\n    return undefined\n  }\n\n  f114 = (): string | undefined => this.or40p57()\n\n  /**\n   * Index 115: or-40-p5-8\n   */\n  or40p58 = (): string | undefined => {\n    return undefined\n  }\n\n  f115 = (): string | undefined => this.or40p58()\n\n  /**\n   * Index 116: or-40-p5-9\n   */\n  or40p59 = (): string | undefined => {\n    return undefined\n  }\n\n  f116 = (): string | undefined => this.or40p59()\n\n  /**\n   * Index 117: or-40-p5-10\n   */\n  or40p510 = (): string | undefined => {\n    return undefined\n  }\n\n  f117 = (): string | undefined => this.or40p510()\n\n  /**\n   * Index 118: or-40-p5-11\n   */\n  or40p511 = (): string | undefined => {\n    return undefined\n  }\n\n  f118 = (): string | undefined => this.or40p511()\n\n  /**\n   * Index 119: or-40-p5-14\n   */\n  or40p514 = (): string | undefined => {\n    return undefined\n  }\n\n  f119 = (): string | undefined => this.or40p514()\n\n  /**\n   * Index 120: or-40-p4-11\n   */\n  or40p411 = (): string | undefined => {\n    return undefined\n  }\n\n  f120 = (): string | undefined => this.or40p411()\n\n  /**\n   * Index 121: or-40-p4-12\n   */\n  or40p412 = (): string | undefined => {\n    return undefined\n  }\n\n  f121 = (): string | undefined => this.or40p412()\n\n  /**\n   * Index 122: or-40-p4-13\n   */\n  or40p413 = (): string | undefined => {\n    return undefined\n  }\n\n  f122 = (): string | undefined => this.or40p413()\n\n  /**\n   * Index 123: or-40-p4-14\n   */\n  or40p414 = (): string | undefined => {\n    return undefined\n  }\n\n  f123 = (): string | undefined => this.or40p414()\n\n  /**\n   * Index 124: or-40-p4-15\n   */\n  or40p415 = (): string | undefined => {\n    return undefined\n  }\n\n  f124 = (): string | undefined => this.or40p415()\n\n  /**\n   * Index 125: or-40-p6-1\n   */\n  or40p61 = (): string | undefined => {\n    return undefined\n  }\n\n  f125 = (): string | undefined => this.or40p61()\n\n  /**\n   * Index 126: or-40-p6-2\n   */\n  or40p62 = (): string | undefined => {\n    return undefined\n  }\n\n  f126 = (): string | undefined => this.or40p62()\n\n  /**\n   * Index 127: or-40-p6-3\n   */\n  or40p63 = (): string | undefined => {\n    return undefined\n  }\n\n  f127 = (): string | undefined => this.or40p63()\n\n  /**\n   * Index 128: or-40-p6-4\n   */\n  or40p64 = (): string | undefined => {\n    return undefined\n  }\n\n  f128 = (): string | undefined => this.or40p64()\n\n  /**\n   * Index 129: or-40-p6-5\n   */\n  or40p65 = (): string | undefined => {\n    return undefined\n  }\n\n  f129 = (): string | undefined => this.or40p65()\n\n  /**\n   * Index 130: or-40-p6-8\n   */\n  or40p68 = (): string | undefined => {\n    return undefined\n  }\n\n  f130 = (): string | undefined => this.or40p68()\n\n  /**\n   * Index 131: or-40-p6-9\n   */\n  or40p69 = (): string | undefined => {\n    return undefined\n  }\n\n  f131 = (): string | undefined => this.or40p69()\n\n  /**\n   * Index 132: or-40-p6-17\n   */\n  or40p617 = (): string | undefined => {\n    return undefined\n  }\n\n  f132 = (): string | undefined => this.or40p617()\n\n  /**\n   * Index 133: or-40-p6-10\n   */\n  or40p610 = (): string | undefined => {\n    return undefined\n  }\n\n  f133 = (): string | undefined => this.or40p610()\n\n  /**\n   * Index 134: or-40_p1_33\n   */\n  or40p133 = (): string | undefined => {\n    return undefined\n  }\n\n  f134 = (): string | undefined => this.or40p133()\n\n  /**\n   * Index 135: or-40-p1-29\n   */\n  or40p129 = (): string | undefined => {\n    return undefined\n  }\n\n  f135 = (): string | undefined => this.or40p129()\n\n  /**\n   * Index 136: or-40-p2-16\n   */\n  or40p216 = (): string | undefined => {\n    return undefined\n  }\n\n  f136 = (): string | undefined => this.or40p216()\n\n  /**\n   * Index 137: or-40-p2-23\n   */\n  or40p223 = (): string | undefined => {\n    return undefined\n  }\n\n  f137 = (): string | undefined => this.or40p223()\n\n  /**\n   * Index 138: or-40-p2-30\n   */\n  or40p230 = (): string | undefined => {\n    return undefined\n  }\n\n  f138 = (): string | undefined => this.or40p230()\n\n  /**\n   * Index 139: or-40-p6-12\n   */\n  or40p612 = (): string | undefined => {\n    return undefined\n  }\n\n  f139 = (): string | undefined => this.or40p612()\n\n  /**\n   * Index 140: or-40-p7-13\n   */\n  or40p713 = (): string | undefined => {\n    return undefined\n  }\n\n  f140 = (): string | undefined => this.or40p713()\n\n  /**\n   * Index 141: or-40-p7-14\n   */\n  or40p714 = (): string | undefined => {\n    return undefined\n  }\n\n  f141 = (): string | undefined => this.or40p714()\n\n  /**\n   * Index 142: or-40-p1-30a\n   */\n  or40p130a = (): string | undefined => {\n    return undefined\n  }\n\n  f142 = (): string | undefined => this.or40p130a()\n\n  /**\n   * Index 143: or-40-p1-30b\n   */\n  or40p130b = (): string | undefined => {\n    return undefined\n  }\n\n  f143 = (): string | undefined => this.or40p130b()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.f85(),\n    this.f86(),\n    this.f87(),\n    this.f88(),\n    this.f89(),\n    this.f90(),\n    this.f91(),\n    this.f92(),\n    this.f93(),\n    this.f94(),\n    this.f95(),\n    this.f96(),\n    this.f97(),\n    this.f98(),\n    this.f99(),\n    this.f100(),\n    this.f101(),\n    this.f102(),\n    this.f103(),\n    this.f104(),\n    this.f105(),\n    this.f106(),\n    this.f107(),\n    this.f108(),\n    this.f109(),\n    this.f110(),\n    this.f111(),\n    this.f112(),\n    this.f113(),\n    this.f114(),\n    this.f115(),\n    this.f116(),\n    this.f117(),\n    this.f118(),\n    this.f119(),\n    this.f120(),\n    this.f121(),\n    this.f122(),\n    this.f123(),\n    this.f124(),\n    this.f125(),\n    this.f126(),\n    this.f127(),\n    this.f128(),\n    this.f129(),\n    this.f130(),\n    this.f131(),\n    this.f132(),\n    this.f133(),\n    this.f134(),\n    this.f135(),\n    this.f136(),\n    this.f137(),\n    this.f138(),\n    this.f139(),\n    this.f140(),\n    this.f141(),\n    this.f142(),\n    this.f143()\n  ]\n}\n\nconst makeOR40 = (f1040: F1040): OR40 => new OR40(f1040)\n\nexport default makeOR40\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/OR40N.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class OR40N extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-40-N'\n    this.state = 'OR'\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    // const pmt = this.payment()\n    const result: Form[] = []\n    // if ((pmt ?? 0) > 0) {\n    //   result.push(this.il1040V)\n    // }\n    // if (this.scheduleEIC.isRequired()) {\n    //   result.push(this.scheduleEIC)\n    // }\n    // if (this.methods.stateWithholding() > 0) {\n    //   const ilwit = new ILWIT(this.info, this.f1040)\n    //   result.push(ilwit)\n    //   ilwit.attachments().forEach((f) => result.push(f))\n    // }\n\n    return result\n  }\n\n  /**\n   * Index 0: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 1: or-40-n-p1-1\n   */\n  or40np11 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.or40np11()\n\n  /**\n   * Index 2: or-40-n-p1-2\n   */\n  or40np12 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f2 = (): boolean | undefined => this.or40np12()\n\n  /**\n   * Index 3: or-40-n-p1-3\n   */\n  or40np13 = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.or40np13()\n\n  /**\n   * Index 4: or-40-n-p1-4\n   */\n  or40np14 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f4 = (): boolean | undefined => this.or40np14()\n\n  /**\n   * Index 5: or-40-n-p1-5\n   */\n  or40np15 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f5 = (): boolean | undefined => this.or40np15()\n\n  /**\n   * Index 6: or-40-n-p1-6\n   */\n  or40np16 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f6 = (): boolean | undefined => this.or40np16()\n\n  /**\n   * Index 7: or-40-n-p1-7\n   */\n  or40np17 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f7 = (): boolean | undefined => this.or40np17()\n\n  /**\n   * Index 8: or-40-n-p1-8\n   */\n  or40np18 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f8 = (): boolean | undefined => this.or40np18()\n\n  /**\n   * Index 9: or-40-n-p1-9\n   */\n  or40np19 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f9 = (): boolean | undefined => this.or40np19()\n\n  /**\n   * Index 10: or-40-n-p1-10\n   */\n  or40np110 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f10 = (): boolean | undefined => this.or40np110()\n\n  /**\n   * Index 11: or-40-n-p1-11\n   */\n  or40np111 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f11 = (): boolean | undefined => this.or40np111()\n\n  /**\n   * Index 12: or-40-n-p1-12\n   */\n  or40np112 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f12 = (): boolean | undefined => this.or40np112()\n\n  /**\n   * Index 13: or-40-n-p1-13\n   */\n  or40np113 = (): string | undefined => {\n    return undefined\n  }\n\n  f13 = (): string | undefined => this.or40np113()\n\n  /**\n   * Index 14: or-40-n-p1-14\n   */\n  or40np114 = (): string | undefined => {\n    return undefined\n  }\n\n  f14 = (): string | undefined => this.or40np114()\n\n  /**\n   * Index 15: or-40-n-p1-15\n   */\n  or40np115 = (): string | undefined => {\n    return undefined\n  }\n\n  f15 = (): string | undefined => this.or40np115()\n\n  /**\n   * Index 16: or-40-n-p1-18\n   */\n  or40np118 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f16 = (): boolean | undefined => this.or40np118()\n\n  /**\n   * Index 17: or-40-n-p1-19\n   */\n  or40np119 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f17 = (): boolean | undefined => this.or40np119()\n\n  /**\n   * Index 18: or-40-n-p1-20\n   */\n  or40np120 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f18 = (): boolean | undefined => this.or40np120()\n\n  /**\n   * Index 19: or-40-n-p1-21\n   */\n  or40np121 = (): string | undefined => {\n    return undefined\n  }\n\n  f19 = (): string | undefined => this.or40np121()\n\n  /**\n   * Index 20: or-40-n-p1-22\n   */\n  or40np122 = (): string | undefined => {\n    return undefined\n  }\n\n  f20 = (): string | undefined => this.or40np122()\n\n  /**\n   * Index 21: or-40-n-p1-23\n   */\n  or40np123 = (): string | undefined => {\n    return undefined\n  }\n\n  f21 = (): string | undefined => this.or40np123()\n\n  /**\n   * Index 22: or-40-n-p1-24\n   */\n  or40np124 = (): string | undefined => {\n    return undefined\n  }\n\n  f22 = (): string | undefined => this.or40np124()\n\n  /**\n   * Index 23: or-40-n-p1-25\n   */\n  or40np125 = (): string | undefined => {\n    return undefined\n  }\n\n  f23 = (): string | undefined => this.or40np125()\n\n  /**\n   * Index 24: or-40-n-p1-26\n   */\n  or40np126 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f24 = (): boolean | undefined => this.or40np126()\n\n  /**\n   * Index 25: or-40-n-p1-27\n   */\n  or40np127 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f25 = (): boolean | undefined => this.or40np127()\n\n  /**\n   * Index 26: or-40-n-p1-28\n   */\n  or40np128 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f26 = (): boolean | undefined => this.or40np128()\n\n  /**\n   * Index 27: or-40-n-p1-29\n   */\n  or40np129 = (): string | undefined => {\n    return undefined\n  }\n\n  f27 = (): string | undefined => this.or40np129()\n\n  /**\n   * Index 28: or-40-n-p1-30\n   */\n  or40np130 = (): string | undefined => {\n    return undefined\n  }\n\n  f28 = (): string | undefined => this.or40np130()\n\n  /**\n   * Index 29: or-40-n-p1-33\n   */\n  or40np133 = (): string | undefined => {\n    return undefined\n  }\n\n  f29 = (): string | undefined => this.or40np133()\n\n  /**\n   * Index 30: or-40-n-p1-34\n   */\n  or40np134 = (): string | undefined => {\n    return undefined\n  }\n\n  f30 = (): string | undefined => this.or40np134()\n\n  /**\n   * Index 31: or-40-n-p1-16\n   */\n  or40np116 = (): string | undefined => {\n    return undefined\n  }\n\n  f31 = (): string | undefined => this.or40np116()\n\n  /**\n   * Index 32: or-40-n-p1-17\n   */\n  or40np117 = (): string | undefined => {\n    return undefined\n  }\n\n  f32 = (): string | undefined => this.or40np117()\n\n  /**\n   * Index 33: or-40-n-p2-1\n   */\n  or40np21 = (): string | undefined => {\n    return undefined\n  }\n\n  f33 = (): string | undefined => this.or40np21()\n\n  /**\n   * Index 34: or-40-n-p2-2\n   */\n  or40np22 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f34 = (): boolean | undefined => this.or40np22()\n\n  /**\n   * Index 35: or-40-n-p2-3\n   */\n  or40np23 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f35 = (): boolean | undefined => this.or40np23()\n\n  /**\n   * Index 36: or-40-n-p2-4\n   */\n  or40np24 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f36 = (): boolean | undefined => this.or40np24()\n\n  /**\n   * Index 37: or-40-n-p2-5\n   */\n  or40np25 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.or40np25()\n\n  /**\n   * Index 38: or-40-n-p2-6\n   */\n  or40np26 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f38 = (): boolean | undefined => this.or40np26()\n\n  /**\n   * Index 39: or-40-n-p2-7\n   */\n  or40np27 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f39 = (): boolean | undefined => this.or40np27()\n\n  /**\n   * Index 40: or-40-n-p2-8\n   */\n  or40np28 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f40 = (): boolean | undefined => this.or40np28()\n\n  /**\n   * Index 41: or-40-n-p2-9\n   */\n  or40np29 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f41 = (): boolean | undefined => this.or40np29()\n\n  /**\n   * Index 42: or-40-n-p2-10\n   */\n  or40np210 = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.or40np210()\n\n  /**\n   * Index 43: or-40-n-p2-11\n   */\n  or40np211 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.or40np211()\n\n  /**\n   * Index 44: or-40-n-p2-12\n   */\n  or40np212 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.or40np212()\n\n  /**\n   * Index 45: or-40-n-p2-13\n   */\n  or40np213 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.or40np213()\n\n  /**\n   * Index 46: or-40-n-p2-14\n   */\n  or40np214 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.or40np214()\n\n  /**\n   * Index 47: or-40-n-p2-16\n   */\n  or40np216 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f47 = (): boolean | undefined => this.or40np216()\n\n  /**\n   * Index 48: or-40-n-p2-17\n   */\n  or40np217 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.or40np217()\n\n  /**\n   * Index 49: or-40-n-p2-18\n   */\n  or40np218 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.or40np218()\n\n  /**\n   * Index 50: or-40-n-p2-19\n   */\n  or40np219 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.or40np219()\n\n  /**\n   * Index 51: or-40-n-p2-20\n   */\n  or40np220 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.or40np220()\n\n  /**\n   * Index 52: or-40-n-p2-21\n   */\n  or40np221 = (): string | undefined => {\n    return undefined\n  }\n\n  f52 = (): string | undefined => this.or40np221()\n\n  /**\n   * Index 53: or-40-n-p2-23\n   */\n  or40np223 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f53 = (): boolean | undefined => this.or40np223()\n\n  /**\n   * Index 54: or-40-n-p2-24\n   */\n  or40np224 = (): string | undefined => {\n    return undefined\n  }\n\n  f54 = (): string | undefined => this.or40np224()\n\n  /**\n   * Index 55: or-40-n-p2-25\n   */\n  or40np225 = (): string | undefined => {\n    return undefined\n  }\n\n  f55 = (): string | undefined => this.or40np225()\n\n  /**\n   * Index 56: or-40-n-p2-26\n   */\n  or40np226 = (): string | undefined => {\n    return undefined\n  }\n\n  f56 = (): string | undefined => this.or40np226()\n\n  /**\n   * Index 57: or-40-n-p2-27\n   */\n  or40np227 = (): string | undefined => {\n    return undefined\n  }\n\n  f57 = (): string | undefined => this.or40np227()\n\n  /**\n   * Index 58: or-40-n-p2-28\n   */\n  or40np228 = (): string | undefined => {\n    return undefined\n  }\n\n  f58 = (): string | undefined => this.or40np228()\n\n  /**\n   * Index 59: or-40-n-p2-30\n   */\n  or40np230 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f59 = (): boolean | undefined => this.or40np230()\n\n  /**\n   * Index 60: or-40-n-p2-31\n   */\n  or40np231 = (): string | undefined => {\n    return undefined\n  }\n\n  f60 = (): string | undefined => this.or40np231()\n\n  /**\n   * Index 61: or-40-n-p2-32\n   */\n  or40np232 = (): string | undefined => {\n    return undefined\n  }\n\n  f61 = (): string | undefined => this.or40np232()\n\n  /**\n   * Index 62: or-40-n-p2-33\n   */\n  or40np233 = (): string | undefined => {\n    return undefined\n  }\n\n  f62 = (): string | undefined => this.or40np233()\n\n  /**\n   * Index 63: or-40-n-p3-1\n   */\n  or40np31 = (): string | undefined => {\n    return undefined\n  }\n\n  f63 = (): string | undefined => this.or40np31()\n\n  /**\n   * Index 64: or-40-n-p3-2\n   */\n  or40np32 = (): string | undefined => {\n    return undefined\n  }\n\n  f64 = (): string | undefined => this.or40np32()\n\n  /**\n   * Index 65: or-40-n-p3-3\n   */\n  or40np33 = (): string | undefined => {\n    return undefined\n  }\n\n  f65 = (): string | undefined => this.or40np33()\n\n  /**\n   * Index 66: or-40-n-p3-4\n   */\n  or40np34 = (): string | undefined => {\n    return undefined\n  }\n\n  f66 = (): string | undefined => this.or40np34()\n\n  /**\n   * Index 67: or-40-n-p3-5\n   */\n  or40np35 = (): string | undefined => {\n    return undefined\n  }\n\n  f67 = (): string | undefined => this.or40np35()\n\n  /**\n   * Index 68: or-40-n-p3-6\n   */\n  or40np36 = (): string | undefined => {\n    return undefined\n  }\n\n  f68 = (): string | undefined => this.or40np36()\n\n  /**\n   * Index 69: or-40-n-p3-7\n   */\n  or40np37 = (): string | undefined => {\n    return undefined\n  }\n\n  f69 = (): string | undefined => this.or40np37()\n\n  /**\n   * Index 70: or-40-n-p3-8\n   */\n  or40np38 = (): string | undefined => {\n    return undefined\n  }\n\n  f70 = (): string | undefined => this.or40np38()\n\n  /**\n   * Index 71: or-40-n-p3-9\n   */\n  or40np39 = (): string | undefined => {\n    return undefined\n  }\n\n  f71 = (): string | undefined => this.or40np39()\n\n  /**\n   * Index 72: or-40-n-p3-10\n   */\n  or40np310 = (): string | undefined => {\n    return undefined\n  }\n\n  f72 = (): string | undefined => this.or40np310()\n\n  /**\n   * Index 73: or-40-n-p3-11\n   */\n  or40np311 = (): string | undefined => {\n    return undefined\n  }\n\n  f73 = (): string | undefined => this.or40np311()\n\n  /**\n   * Index 74: or-40-n-p3-12\n   */\n  or40np312 = (): string | undefined => {\n    return undefined\n  }\n\n  f74 = (): string | undefined => this.or40np312()\n\n  /**\n   * Index 75: or-40-n-p3-13\n   */\n  or40np313 = (): string | undefined => {\n    return undefined\n  }\n\n  f75 = (): string | undefined => this.or40np313()\n\n  /**\n   * Index 76: or-40-n-p3-14\n   */\n  or40np314 = (): string | undefined => {\n    return undefined\n  }\n\n  f76 = (): string | undefined => this.or40np314()\n\n  /**\n   * Index 77: or-40-n-p3-17\n   */\n  or40np317 = (): string | undefined => {\n    return undefined\n  }\n\n  f77 = (): string | undefined => this.or40np317()\n\n  /**\n   * Index 78: or-40-n-p3-18\n   */\n  or40np318 = (): string | undefined => {\n    return undefined\n  }\n\n  f78 = (): string | undefined => this.or40np318()\n\n  /**\n   * Index 79: or-40-n-p3-15\n   */\n  or40np315 = (): string | undefined => {\n    return undefined\n  }\n\n  f79 = (): string | undefined => this.or40np315()\n\n  /**\n   * Index 80: or-40-n-p3-16\n   */\n  or40np316 = (): string | undefined => {\n    return undefined\n  }\n\n  f80 = (): string | undefined => this.or40np316()\n\n  /**\n   * Index 81: or-40-n-p4-1\n   */\n  or40np41 = (): string | undefined => {\n    return undefined\n  }\n\n  f81 = (): string | undefined => this.or40np41()\n\n  /**\n   * Index 82: or-40-n-p4-2\n   */\n  or40np42 = (): string | undefined => {\n    return undefined\n  }\n\n  f82 = (): string | undefined => this.or40np42()\n\n  /**\n   * Index 83: or-40-n-p4-3\n   */\n  or40np43 = (): string | undefined => {\n    return undefined\n  }\n\n  f83 = (): string | undefined => this.or40np43()\n\n  /**\n   * Index 84: or-40-n-p4-4\n   */\n  or40np44 = (): string | undefined => {\n    return undefined\n  }\n\n  f84 = (): string | undefined => this.or40np44()\n\n  /**\n   * Index 85: or-40-n-p4-5\n   */\n  or40np45 = (): string | undefined => {\n    return undefined\n  }\n\n  f85 = (): string | undefined => this.or40np45()\n\n  /**\n   * Index 86: or-40-n-p4-6\n   */\n  or40np46 = (): string | undefined => {\n    return undefined\n  }\n\n  f86 = (): string | undefined => this.or40np46()\n\n  /**\n   * Index 87: or-40-n-p4-7\n   */\n  or40np47 = (): string | undefined => {\n    return undefined\n  }\n\n  f87 = (): string | undefined => this.or40np47()\n\n  /**\n   * Index 88: or-40-n-p4-8\n   */\n  or40np48 = (): string | undefined => {\n    return undefined\n  }\n\n  f88 = (): string | undefined => this.or40np48()\n\n  /**\n   * Index 89: or-40-n-p4-9\n   */\n  or40np49 = (): string | undefined => {\n    return undefined\n  }\n\n  f89 = (): string | undefined => this.or40np49()\n\n  /**\n   * Index 90: or-40-n-p4-10\n   */\n  or40np410 = (): string | undefined => {\n    return undefined\n  }\n\n  f90 = (): string | undefined => this.or40np410()\n\n  /**\n   * Index 91: or-40-n-p4-11\n   */\n  or40np411 = (): string | undefined => {\n    return undefined\n  }\n\n  f91 = (): string | undefined => this.or40np411()\n\n  /**\n   * Index 92: or-40-n-p4-12\n   */\n  or40np412 = (): string | undefined => {\n    return undefined\n  }\n\n  f92 = (): string | undefined => this.or40np412()\n\n  /**\n   * Index 93: or-40-n-p4-13\n   */\n  or40np413 = (): string | undefined => {\n    return undefined\n  }\n\n  f93 = (): string | undefined => this.or40np413()\n\n  /**\n   * Index 94: or-40-n-p4-14\n   */\n  or40np414 = (): string | undefined => {\n    return undefined\n  }\n\n  f94 = (): string | undefined => this.or40np414()\n\n  /**\n   * Index 95: or-40-n-p4-15\n   */\n  or40np415 = (): string | undefined => {\n    return undefined\n  }\n\n  f95 = (): string | undefined => this.or40np415()\n\n  /**\n   * Index 96: or-40-n-p4-16\n   */\n  or40np416 = (): string | undefined => {\n    return undefined\n  }\n\n  f96 = (): string | undefined => this.or40np416()\n\n  /**\n   * Index 97: or-40-n-p5-1\n   */\n  or40np51 = (): string | undefined => {\n    return undefined\n  }\n\n  f97 = (): string | undefined => this.or40np51()\n\n  /**\n   * Index 98: or-40-n-p5-2\n   */\n  or40np52 = (): string | undefined => {\n    return undefined\n  }\n\n  f98 = (): string | undefined => this.or40np52()\n\n  /**\n   * Index 99: or-40-n-p5-3\n   */\n  or40np53 = (): string | undefined => {\n    return undefined\n  }\n\n  f99 = (): string | undefined => this.or40np53()\n\n  /**\n   * Index 100: or-40-n-p5-4\n   */\n  or40np54 = (): string | undefined => {\n    return undefined\n  }\n\n  f100 = (): string | undefined => this.or40np54()\n\n  /**\n   * Index 101: or-40-n-p5-5\n   */\n  or40np55 = (): string | undefined => {\n    return undefined\n  }\n\n  f101 = (): string | undefined => this.or40np55()\n\n  /**\n   * Index 102: or-40-n-p5-6\n   */\n  or40np56 = (): string | undefined => {\n    return undefined\n  }\n\n  f102 = (): string | undefined => this.or40np56()\n\n  /**\n   * Index 103: or-40-n-p5-7\n   */\n  or40np57 = (): string | undefined => {\n    return undefined\n  }\n\n  f103 = (): string | undefined => this.or40np57()\n\n  /**\n   * Index 104: or-40-n-p5-8\n   */\n  or40np58 = (): string | undefined => {\n    return undefined\n  }\n\n  f104 = (): string | undefined => this.or40np58()\n\n  /**\n   * Index 105: or-40-n-p5-9\n   */\n  or40np59 = (): string | undefined => {\n    return undefined\n  }\n\n  f105 = (): string | undefined => this.or40np59()\n\n  /**\n   * Index 106: or-40-n-p5-10\n   */\n  or40np510 = (): string | undefined => {\n    return undefined\n  }\n\n  f106 = (): string | undefined => this.or40np510()\n\n  /**\n   * Index 107: or-40-n-p5-11\n   */\n  or40np511 = (): string | undefined => {\n    return undefined\n  }\n\n  f107 = (): string | undefined => this.or40np511()\n\n  /**\n   * Index 108: or-40-n-p5-12\n   */\n  or40np512 = (): string | undefined => {\n    return undefined\n  }\n\n  f108 = (): string | undefined => this.or40np512()\n\n  /**\n   * Index 109: or-40-n-p5-13\n   */\n  or40np513 = (): string | undefined => {\n    return undefined\n  }\n\n  f109 = (): string | undefined => this.or40np513()\n\n  /**\n   * Index 110: or-40-n-p5-14\n   */\n  or40np514 = (): string | undefined => {\n    return undefined\n  }\n\n  f110 = (): string | undefined => this.or40np514()\n\n  /**\n   * Index 111: or-40-n-p5-15\n   */\n  or40np515 = (): string | undefined => {\n    return undefined\n  }\n\n  f111 = (): string | undefined => this.or40np515()\n\n  /**\n   * Index 112: or-40-n-p5-16\n   */\n  or40np516 = (): string | undefined => {\n    return undefined\n  }\n\n  f112 = (): string | undefined => this.or40np516()\n\n  /**\n   * Index 113: or-40-n-p6-1\n   */\n  or40np61 = (): string | undefined => {\n    return undefined\n  }\n\n  f113 = (): string | undefined => this.or40np61()\n\n  /**\n   * Index 114: or-40-n-p6-2\n   */\n  or40np62 = (): string | undefined => {\n    return undefined\n  }\n\n  f114 = (): string | undefined => this.or40np62()\n\n  /**\n   * Index 115: or-40-n-p6-3\n   */\n  or40np63 = (): string | undefined => {\n    return undefined\n  }\n\n  f115 = (): string | undefined => this.or40np63()\n\n  /**\n   * Index 116: or-40-n-p6-4\n   */\n  or40np64 = (): string | undefined => {\n    return undefined\n  }\n\n  f116 = (): string | undefined => this.or40np64()\n\n  /**\n   * Index 117: or-40-n-p6-5\n   */\n  or40np65 = (): string | undefined => {\n    return undefined\n  }\n\n  f117 = (): string | undefined => this.or40np65()\n\n  /**\n   * Index 118: or-40-n-p6-6\n   */\n  or40np66 = (): string | undefined => {\n    return undefined\n  }\n\n  f118 = (): string | undefined => this.or40np66()\n\n  /**\n   * Index 119: or-40-n-p6-7\n   */\n  or40np67 = (): string | undefined => {\n    return undefined\n  }\n\n  f119 = (): string | undefined => this.or40np67()\n\n  /**\n   * Index 120: or-40-n-p6-8\n   */\n  or40np68 = (): string | undefined => {\n    return undefined\n  }\n\n  f120 = (): string | undefined => this.or40np68()\n\n  /**\n   * Index 121: or-40-n-p6-9\n   */\n  or40np69 = (): string | undefined => {\n    return undefined\n  }\n\n  f121 = (): string | undefined => this.or40np69()\n\n  /**\n   * Index 122: or-40-n-p6-10\n   */\n  or40np610 = (): string | undefined => {\n    return undefined\n  }\n\n  f122 = (): string | undefined => this.or40np610()\n\n  /**\n   * Index 123: or-40-n-p6-11\n   */\n  or40np611 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f123 = (): boolean | undefined => this.or40np611()\n\n  /**\n   * Index 124: or-40-n-p6-12\n   */\n  or40np612 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f124 = (): boolean | undefined => this.or40np612()\n\n  /**\n   * Index 125: or-40-n-p6-13\n   */\n  or40np613 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f125 = (): boolean | undefined => this.or40np613()\n\n  /**\n   * Index 126: or-40-n-p6-14\n   */\n  or40np614 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f126 = (): boolean | undefined => this.or40np614()\n\n  /**\n   * Index 127: or-40-n-p6-15\n   */\n  or40np615 = (): string | undefined => {\n    return undefined\n  }\n\n  f127 = (): string | undefined => this.or40np615()\n\n  /**\n   * Index 128: or-40-n-p6-16\n   */\n  or40np616 = (): string | undefined => {\n    return undefined\n  }\n\n  f128 = (): string | undefined => this.or40np616()\n\n  /**\n   * Index 129: or-40-n-p6-17\n   */\n  or40np617 = (): string | undefined => {\n    return undefined\n  }\n\n  f129 = (): string | undefined => this.or40np617()\n\n  /**\n   * Index 130: or-40-n-p6-18\n   */\n  or40np618 = (): string | undefined => {\n    return undefined\n  }\n\n  f130 = (): string | undefined => this.or40np618()\n\n  /**\n   * Index 131: or-40-n-p7-1\n   */\n  or40np71 = (): string | undefined => {\n    return undefined\n  }\n\n  f131 = (): string | undefined => this.or40np71()\n\n  /**\n   * Index 132: or-40-n-p7-2\n   */\n  or40np72 = (): string | undefined => {\n    return undefined\n  }\n\n  f132 = (): string | undefined => this.or40np72()\n\n  /**\n   * Index 133: or-40-n-p7-3\n   */\n  or40np73 = (): string | undefined => {\n    return undefined\n  }\n\n  f133 = (): string | undefined => this.or40np73()\n\n  /**\n   * Index 134: or-40-n-p7-4\n   */\n  or40np74 = (): string | undefined => {\n    return undefined\n  }\n\n  f134 = (): string | undefined => this.or40np74()\n\n  /**\n   * Index 135: or-40-n-p7-5\n   */\n  or40np75 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f135 = (): boolean | undefined => this.or40np75()\n\n  /**\n   * Index 136: or-40-n-p7-6\n   */\n  or40np76 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f136 = (): boolean | undefined => this.or40np76()\n\n  /**\n   * Index 137: or-40-n-p7-7\n   */\n  or40np77 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f137 = (): boolean | undefined => this.or40np77()\n\n  /**\n   * Index 138: or-40-n-p7-8\n   */\n  or40np78 = (): string | undefined => {\n    return undefined\n  }\n\n  f138 = (): string | undefined => this.or40np78()\n\n  /**\n   * Index 139: or-40-n-p7-9\n   */\n  or40np79 = (): string | undefined => {\n    return undefined\n  }\n\n  f139 = (): string | undefined => this.or40np79()\n\n  /**\n   * Index 140: or-40-n-p7-10\n   */\n  or40np710 = (): string | undefined => {\n    return undefined\n  }\n\n  f140 = (): string | undefined => this.or40np710()\n\n  /**\n   * Index 141: or-40-n-p7-11\n   */\n  or40np711 = (): string | undefined => {\n    return undefined\n  }\n\n  f141 = (): string | undefined => this.or40np711()\n\n  /**\n   * Index 142: or-40-n-p7-12\n   */\n  or40np712 = (): string | undefined => {\n    return undefined\n  }\n\n  f142 = (): string | undefined => this.or40np712()\n\n  /**\n   * Index 143: or-40-n-p7-13\n   */\n  or40np713 = (): string | undefined => {\n    return undefined\n  }\n\n  f143 = (): string | undefined => this.or40np713()\n\n  /**\n   * Index 144: or-40-n-p7-14\n   */\n  or40np714 = (): string | undefined => {\n    return undefined\n  }\n\n  f144 = (): string | undefined => this.or40np714()\n\n  /**\n   * Index 145: or-40-n-p7-15\n   */\n  or40np715 = (): string | undefined => {\n    return undefined\n  }\n\n  f145 = (): string | undefined => this.or40np715()\n\n  /**\n   * Index 146: or-40-n-p8-1\n   */\n  or40np81 = (): string | undefined => {\n    return undefined\n  }\n\n  f146 = (): string | undefined => this.or40np81()\n\n  /**\n   * Index 147: or-40-n-p8-2\n   */\n  or40np82 = (): string | undefined => {\n    return undefined\n  }\n\n  f147 = (): string | undefined => this.or40np82()\n\n  /**\n   * Index 148: or-40-n-p8-3\n   */\n  or40np83 = (): string | undefined => {\n    return undefined\n  }\n\n  f148 = (): string | undefined => this.or40np83()\n\n  /**\n   * Index 149: or-40-n-p8-4\n   */\n  or40np84 = (): string | undefined => {\n    return undefined\n  }\n\n  f149 = (): string | undefined => this.or40np84()\n\n  /**\n   * Index 150: or-40-n-p8-5\n   */\n  or40np85 = (): string | undefined => {\n    return undefined\n  }\n\n  f150 = (): string | undefined => this.or40np85()\n\n  /**\n   * Index 151: or-40-n-p8-6\n   */\n  or40np86 = (): string | undefined => {\n    return undefined\n  }\n\n  f151 = (): string | undefined => this.or40np86()\n\n  /**\n   * Index 152: or-40-n-p8-7\n   */\n  or40np87 = (): string | undefined => {\n    return undefined\n  }\n\n  f152 = (): string | undefined => this.or40np87()\n\n  /**\n   * Index 153: or-40-n-p8-8\n   */\n  or40np88 = (): string | undefined => {\n    return undefined\n  }\n\n  f153 = (): string | undefined => this.or40np88()\n\n  /**\n   * Index 154: or-40-n-p8-9\n   */\n  or40np89 = (): string | undefined => {\n    return undefined\n  }\n\n  f154 = (): string | undefined => this.or40np89()\n\n  /**\n   * Index 155: or-40-n-p8-10\n   */\n  or40np810 = (): string | undefined => {\n    return undefined\n  }\n\n  f155 = (): string | undefined => this.or40np810()\n\n  /**\n   * Index 156: or-40-n-p8-11\n   */\n  or40np811 = (): string | undefined => {\n    return undefined\n  }\n\n  f156 = (): string | undefined => this.or40np811()\n\n  /**\n   * Index 157: or-40-n-p8-12\n   */\n  or40np812 = (): string | undefined => {\n    return undefined\n  }\n\n  f157 = (): string | undefined => this.or40np812()\n\n  /**\n   * Index 158: or-40-n-p8-13\n   */\n  or40np813 = (): string | undefined => {\n    return undefined\n  }\n\n  f158 = (): string | undefined => this.or40np813()\n\n  /**\n   * Index 159: or-40-n-p9-1\n   */\n  or40np91 = (): string | undefined => {\n    return undefined\n  }\n\n  f159 = (): string | undefined => this.or40np91()\n\n  /**\n   * Index 160: or-40-n-p9-2\n   */\n  or40np92 = (): string | undefined => {\n    return undefined\n  }\n\n  f160 = (): string | undefined => this.or40np92()\n\n  /**\n   * Index 161: or-40-n-p9-3\n   */\n  or40np93 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f161 = (): boolean | undefined => this.or40np93()\n\n  /**\n   * Index 162: or-40-n-p9-4\n   */\n  or40np94 = (): string | undefined => {\n    return undefined\n  }\n\n  f162 = (): string | undefined => this.or40np94()\n\n  /**\n   * Index 163: or-40-n-p9-5\n   */\n  or40np95 = (): string | undefined => {\n    return undefined\n  }\n\n  f163 = (): string | undefined => this.or40np95()\n\n  /**\n   * Index 164: or-40-n-p9-6\n   */\n  or40np96 = (): string | undefined => {\n    return undefined\n  }\n\n  f164 = (): string | undefined => this.or40np96()\n\n  /**\n   * Index 165: or-40-n-p9-7\n   */\n  or40np97 = (): string | undefined => {\n    return undefined\n  }\n\n  f165 = (): string | undefined => this.or40np97()\n\n  /**\n   * Index 166: or-40-n-p9-8\n   */\n  or40np98 = (): string | undefined => {\n    return undefined\n  }\n\n  f166 = (): string | undefined => this.or40np98()\n\n  /**\n   * Index 167: or-40-n-p9-9\n   */\n  or40np99 = (): string | undefined => {\n    return undefined\n  }\n\n  f167 = (): string | undefined => this.or40np99()\n\n  /**\n   * Index 168: or-40-n-p9-10\n   */\n  or40np910 = (): string | undefined => {\n    return undefined\n  }\n\n  f168 = (): string | undefined => this.or40np910()\n\n  /**\n   * Index 169: or-40-n-p9-11\n   */\n  or40np911 = (): string | undefined => {\n    return undefined\n  }\n\n  f169 = (): string | undefined => this.or40np911()\n\n  /**\n   * Index 170: or-40-n-p9-12\n   */\n  or40np912 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f170 = (): boolean | undefined => this.or40np912()\n\n  /**\n   * Index 171: or-40-n-p9-15\n   */\n  or40np915 = (): string | undefined => {\n    return undefined\n  }\n\n  f171 = (): string | undefined => this.or40np915()\n\n  /**\n   * Index 172: or-40-n-p9-16\n   */\n  or40np916 = (): string | undefined => {\n    return undefined\n  }\n\n  f172 = (): string | undefined => this.or40np916()\n\n  /**\n   * Index 173: or-40-n-p9-17\n   */\n  or40np917 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f173 = (): boolean | undefined => this.or40np917()\n\n  /**\n   * Index 174: or-40-n-p9-18\n   */\n  or40np918 = (): string | undefined => {\n    return undefined\n  }\n\n  f174 = (): string | undefined => this.or40np918()\n\n  /**\n   * Index 175: or-40-n-p10-1\n   */\n  or40np101 = (): string | undefined => {\n    return undefined\n  }\n\n  f175 = (): string | undefined => this.or40np101()\n\n  /**\n   * Index 176: or-40-n-p10-2\n   */\n  or40np102 = (): string | undefined => {\n    return undefined\n  }\n\n  f176 = (): string | undefined => this.or40np102()\n\n  /**\n   * Index 177: or-40-n-p10-3\n   */\n  or40np103 = (): string | undefined => {\n    return undefined\n  }\n\n  f177 = (): string | undefined => this.or40np103()\n\n  /**\n   * Index 178: or-40-n-p10-4\n   */\n  or40np104 = (): string | undefined => {\n    return undefined\n  }\n\n  f178 = (): string | undefined => this.or40np104()\n\n  /**\n   * Index 179: or-40-n-p10-5\n   */\n  or40np105 = (): string | undefined => {\n    return undefined\n  }\n\n  f179 = (): string | undefined => this.or40np105()\n\n  /**\n   * Index 180: or-40-n-p10-6\n   */\n  or40np106 = (): string | undefined => {\n    return undefined\n  }\n\n  f180 = (): string | undefined => this.or40np106()\n\n  /**\n   * Index 181: or-40-n-p10-7\n   */\n  or40np107 = (): string | undefined => {\n    return undefined\n  }\n\n  f181 = (): string | undefined => this.or40np107()\n\n  /**\n   * Index 182: or-40-n-p10-8\n   */\n  or40np108 = (): string | undefined => {\n    return undefined\n  }\n\n  f182 = (): string | undefined => this.or40np108()\n\n  /**\n   * Index 183: or-40-n-p10-9\n   */\n  or40np109 = (): string | undefined => {\n    return undefined\n  }\n\n  f183 = (): string | undefined => this.or40np109()\n\n  /**\n   * Index 184: or-40-n-p10-10\n   */\n  or40np1010 = (): string | undefined => {\n    return undefined\n  }\n\n  f184 = (): string | undefined => this.or40np1010()\n\n  /**\n   * Index 185: or-40-n-p10-11\n   */\n  or40np1011 = (): string | undefined => {\n    return undefined\n  }\n\n  f185 = (): string | undefined => this.or40np1011()\n\n  /**\n   * Index 186: or-40-n-p11-1\n   */\n  or40np11_1 = (): string | undefined => {\n    return undefined\n  }\n\n  f186 = (): string | undefined => this.or40np11_1()\n\n  /**\n   * Index 187: or-40_n_p1_35\n   */\n  or40np135 = (): string | undefined => {\n    return undefined\n  }\n\n  f187 = (): string | undefined => this.or40np135()\n\n  /**\n   * Index 188: or-40-n-p1-31\n   */\n  or40np131 = (): string | undefined => {\n    return undefined\n  }\n\n  f188 = (): string | undefined => this.or40np131()\n\n  /**\n   * Index 189: or-40-n-p2-15\n   */\n  or40np215 = (): string | undefined => {\n    return undefined\n  }\n\n  f189 = (): string | undefined => this.or40np215()\n\n  /**\n   * Index 190: or-40-n-p2-22\n   */\n  or40np222 = (): string | undefined => {\n    return undefined\n  }\n\n  f190 = (): string | undefined => this.or40np222()\n\n  /**\n   * Index 191: or-40-n-p2-29\n   */\n  or40np229 = (): string | undefined => {\n    return undefined\n  }\n\n  f191 = (): string | undefined => this.or40np229()\n\n  /**\n   * Index 192: or-40_n_p9_14\n   */\n  or40np914 = (): string | undefined => {\n    return undefined\n  }\n\n  f192 = (): string | undefined => this.or40np914()\n\n  /**\n   * Index 193: or-40-n-p1-32a\n   */\n  or40np132a = (): string | undefined => {\n    return undefined\n  }\n\n  f193 = (): string | undefined => this.or40np132a()\n\n  /**\n   * Index 194: or-40-n-p1-32b\n   */\n  or40np132b = (): string | undefined => {\n    return undefined\n  }\n\n  f194 = (): string | undefined => this.or40np132b()\n\n  /**\n   * Index 195: or-40-n-p10-12a\n   */\n  or40np1012a = (): string | undefined => {\n    return undefined\n  }\n\n  f195 = (): string | undefined => this.or40np1012a()\n\n  /**\n   * Index 196: or-40-n-p10-12b\n   */\n  or40np1012b = (): string | undefined => {\n    return undefined\n  }\n\n  f196 = (): string | undefined => this.or40np1012b()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.f85(),\n    this.f86(),\n    this.f87(),\n    this.f88(),\n    this.f89(),\n    this.f90(),\n    this.f91(),\n    this.f92(),\n    this.f93(),\n    this.f94(),\n    this.f95(),\n    this.f96(),\n    this.f97(),\n    this.f98(),\n    this.f99(),\n    this.f100(),\n    this.f101(),\n    this.f102(),\n    this.f103(),\n    this.f104(),\n    this.f105(),\n    this.f106(),\n    this.f107(),\n    this.f108(),\n    this.f109(),\n    this.f110(),\n    this.f111(),\n    this.f112(),\n    this.f113(),\n    this.f114(),\n    this.f115(),\n    this.f116(),\n    this.f117(),\n    this.f118(),\n    this.f119(),\n    this.f120(),\n    this.f121(),\n    this.f122(),\n    this.f123(),\n    this.f124(),\n    this.f125(),\n    this.f126(),\n    this.f127(),\n    this.f128(),\n    this.f129(),\n    this.f130(),\n    this.f131(),\n    this.f132(),\n    this.f133(),\n    this.f134(),\n    this.f135(),\n    this.f136(),\n    this.f137(),\n    this.f138(),\n    this.f139(),\n    this.f140(),\n    this.f141(),\n    this.f142(),\n    this.f143(),\n    this.f144(),\n    this.f145(),\n    this.f146(),\n    this.f147(),\n    this.f148(),\n    this.f149(),\n    this.f150(),\n    this.f151(),\n    this.f152(),\n    this.f153(),\n    this.f154(),\n    this.f155(),\n    this.f156(),\n    this.f157(),\n    this.f158(),\n    this.f159(),\n    this.f160(),\n    this.f161(),\n    this.f162(),\n    this.f163(),\n    this.f164(),\n    this.f165(),\n    this.f166(),\n    this.f167(),\n    this.f168(),\n    this.f169(),\n    this.f170(),\n    this.f171(),\n    this.f172(),\n    this.f173(),\n    this.f174(),\n    this.f175(),\n    this.f176(),\n    this.f177(),\n    this.f178(),\n    this.f179(),\n    this.f180(),\n    this.f181(),\n    this.f182(),\n    this.f183(),\n    this.f184(),\n    this.f185(),\n    this.f186(),\n    this.f187(),\n    this.f188(),\n    this.f189(),\n    this.f190(),\n    this.f191(),\n    this.f192(),\n    this.f193(),\n    this.f194(),\n    this.f195(),\n    this.f196()\n  ]\n}\n\nconst makeOR40N = (f1040: F1040): OR40N => new OR40N(f1040)\n\nexport default makeOR40N\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/OR40P.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class OR40P extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-40-P'\n    this.state = 'OR'\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    // const pmt = this.payment()\n    const result: Form[] = []\n    // if ((pmt ?? 0) > 0) {\n    //   result.push(this.il1040V)\n    // }\n    // if (this.scheduleEIC.isRequired()) {\n    //   result.push(this.scheduleEIC)\n    // }\n    // if (this.methods.stateWithholding() > 0) {\n    //   const ilwit = new ILWIT(this.info, this.f1040)\n    //   result.push(ilwit)\n    //   ilwit.attachments().forEach((f) => result.push(f))\n    // }\n\n    return result\n  }\n\n  /**\n   * Index 0: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 1: or-40-n-p9-1\n   */\n  or40np91 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.or40np91()\n\n  /**\n   * Index 2: or-40-n-p9-2\n   */\n  or40np92 = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.or40np92()\n\n  /**\n   * Index 3: or-40-n-p9-3\n   */\n  or40np93 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f3 = (): boolean | undefined => this.or40np93()\n\n  /**\n   * Index 4: or-40-n-p9-4\n   */\n  or40np94 = (): string | undefined => {\n    return undefined\n  }\n\n  f4 = (): string | undefined => this.or40np94()\n\n  /**\n   * Index 5: or-40-n-p9-5\n   */\n  or40np95 = (): string | undefined => {\n    return undefined\n  }\n\n  f5 = (): string | undefined => this.or40np95()\n\n  /**\n   * Index 6: or-40-n-p9-6\n   */\n  or40np96 = (): string | undefined => {\n    return undefined\n  }\n\n  f6 = (): string | undefined => this.or40np96()\n\n  /**\n   * Index 7: or-40-n-p9-7\n   */\n  or40np97 = (): string | undefined => {\n    return undefined\n  }\n\n  f7 = (): string | undefined => this.or40np97()\n\n  /**\n   * Index 8: or-40-n-p9-8\n   */\n  or40np98 = (): string | undefined => {\n    return undefined\n  }\n\n  f8 = (): string | undefined => this.or40np98()\n\n  /**\n   * Index 9: or-40-n-p9-9\n   */\n  or40np99 = (): string | undefined => {\n    return undefined\n  }\n\n  f9 = (): string | undefined => this.or40np99()\n\n  /**\n   * Index 10: or-40-n-p9-10\n   */\n  or40np910 = (): string | undefined => {\n    return undefined\n  }\n\n  f10 = (): string | undefined => this.or40np910()\n\n  /**\n   * Index 11: or-40-n-p9-11\n   */\n  or40np911 = (): string | undefined => {\n    return undefined\n  }\n\n  f11 = (): string | undefined => this.or40np911()\n\n  /**\n   * Index 12: or-40-n-p9-12\n   */\n  or40np912 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f12 = (): boolean | undefined => this.or40np912()\n\n  /**\n   * Index 13: or-40-n-p9-15\n   */\n  or40np915 = (): string | undefined => {\n    return undefined\n  }\n\n  f13 = (): string | undefined => this.or40np915()\n\n  /**\n   * Index 14: or-40-n-p9-16\n   */\n  or40np916 = (): string | undefined => {\n    return undefined\n  }\n\n  f14 = (): string | undefined => this.or40np916()\n\n  /**\n   * Index 15: or-40-n-p9-17\n   */\n  or40np917 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f15 = (): boolean | undefined => this.or40np917()\n\n  /**\n   * Index 16: or-40-n-p9-18\n   */\n  or40np918 = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.or40np918()\n\n  /**\n   * Index 17: or-40-n-p10-1\n   */\n  or40np101 = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.or40np101()\n\n  /**\n   * Index 18: or-40-n-p10-2\n   */\n  or40np102 = (): string | undefined => {\n    return undefined\n  }\n\n  f18 = (): string | undefined => this.or40np102()\n\n  /**\n   * Index 19: or-40-n-p10-3\n   */\n  or40np103 = (): string | undefined => {\n    return undefined\n  }\n\n  f19 = (): string | undefined => this.or40np103()\n\n  /**\n   * Index 20: or-40-n-p10-4\n   */\n  or40np104 = (): string | undefined => {\n    return undefined\n  }\n\n  f20 = (): string | undefined => this.or40np104()\n\n  /**\n   * Index 21: or-40-n-p10-5\n   */\n  or40np105 = (): string | undefined => {\n    return undefined\n  }\n\n  f21 = (): string | undefined => this.or40np105()\n\n  /**\n   * Index 22: or-40-n-p10-6\n   */\n  or40np106 = (): string | undefined => {\n    return undefined\n  }\n\n  f22 = (): string | undefined => this.or40np106()\n\n  /**\n   * Index 23: or-40-n-p10-7\n   */\n  or40np107 = (): string | undefined => {\n    return undefined\n  }\n\n  f23 = (): string | undefined => this.or40np107()\n\n  /**\n   * Index 24: or-40-n-p10-8\n   */\n  or40np108 = (): string | undefined => {\n    return undefined\n  }\n\n  f24 = (): string | undefined => this.or40np108()\n\n  /**\n   * Index 25: or-40-n-p10-9\n   */\n  or40np109 = (): string | undefined => {\n    return undefined\n  }\n\n  f25 = (): string | undefined => this.or40np109()\n\n  /**\n   * Index 26: or-40-n-p10-10\n   */\n  or40np1010 = (): string | undefined => {\n    return undefined\n  }\n\n  f26 = (): string | undefined => this.or40np1010()\n\n  /**\n   * Index 27: or-40-n-p10-11\n   */\n  or40np1011 = (): string | undefined => {\n    return undefined\n  }\n\n  f27 = (): string | undefined => this.or40np1011()\n\n  /**\n   * Index 28: or-40-n-p11-1\n   */\n  or40np111 = (): string | undefined => {\n    return undefined\n  }\n\n  f28 = (): string | undefined => this.or40np111()\n\n  /**\n   * Index 29: or-40-p1-1\n   */\n  or40p11 = (): string | undefined => {\n    return undefined\n  }\n\n  f29 = (): string | undefined => this.or40p11()\n\n  /**\n   * Index 30: or-40-p1-2\n   */\n  or40p12 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f30 = (): boolean | undefined => this.or40p12()\n\n  /**\n   * Index 31: or-40-p1-3\n   */\n  or40p13 = (): string | undefined => {\n    return undefined\n  }\n\n  f31 = (): string | undefined => this.or40p13()\n\n  /**\n   * Index 32: or-40-p1-4\n   */\n  or40p14 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f32 = (): boolean | undefined => this.or40p14()\n\n  /**\n   * Index 33: or-40-p1-5\n   */\n  or40p15 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f33 = (): boolean | undefined => this.or40p15()\n\n  /**\n   * Index 34: or-40-p1-6\n   */\n  or40p16 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f34 = (): boolean | undefined => this.or40p16()\n\n  /**\n   * Index 35: or-40-p1-7\n   */\n  or40p17 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f35 = (): boolean | undefined => this.or40p17()\n\n  /**\n   * Index 36: or-40-p1-8\n   */\n  or40p18 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f36 = (): boolean | undefined => this.or40p18()\n\n  /**\n   * Index 37: or-40-p1-9\n   */\n  or40p19 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f37 = (): boolean | undefined => this.or40p19()\n\n  /**\n   * Index 38: or-40-p1-10\n   */\n  or40p110 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f38 = (): boolean | undefined => this.or40p110()\n\n  /**\n   * Index 39: or-40-p1-11\n   */\n  or40p111 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f39 = (): boolean | undefined => this.or40p111()\n\n  /**\n   * Index 40: or-40-p1-12\n   */\n  or40p112 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f40 = (): boolean | undefined => this.or40p112()\n\n  /**\n   * Index 41: or-40-p1-13\n   */\n  or40p113 = (): string | undefined => {\n    return undefined\n  }\n\n  f41 = (): string | undefined => this.or40p113()\n\n  /**\n   * Index 42: or-40-p1-14\n   */\n  or40p114 = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.or40p114()\n\n  /**\n   * Index 43: or-40-p1-15\n   */\n  or40p115 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.or40p115()\n\n  /**\n   * Index 44: or-40-p1-16\n   */\n  or40p116 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.or40p116()\n\n  /**\n   * Index 45: or-40-p1-17\n   */\n  or40p117 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.or40p117()\n\n  /**\n   * Index 46: or-40-p1-22\n   */\n  or40p122 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f46 = (): boolean | undefined => this.or40p122()\n\n  /**\n   * Index 47: or-40-p1-23\n   */\n  or40p123 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.or40p123()\n\n  /**\n   * Index 48: or-40-p1-24\n   */\n  or40p124 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.or40p124()\n\n  /**\n   * Index 49: or-40-p1-25\n   */\n  or40p125 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.or40p125()\n\n  /**\n   * Index 50: or-40-p1-26\n   */\n  or40p126 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.or40p126()\n\n  /**\n   * Index 51: or-40-p1-27\n   */\n  or40p127 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.or40p127()\n\n  /**\n   * Index 52: or-40-p1-28\n   */\n  or40p128 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f52 = (): boolean | undefined => this.or40p128()\n\n  /**\n   * Index 53: or-40-p1-29\n   */\n  or40p129 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f53 = (): boolean | undefined => this.or40p129()\n\n  /**\n   * Index 54: or-40-p1-30\n   */\n  or40p130 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f54 = (): boolean | undefined => this.or40p130()\n\n  /**\n   * Index 55: or-40-p1-31\n   */\n  or40p131 = (): string | undefined => {\n    return undefined\n  }\n\n  f55 = (): string | undefined => this.or40p131()\n\n  /**\n   * Index 56: or-40-p1-32\n   */\n  or40p132 = (): string | undefined => {\n    return undefined\n  }\n\n  f56 = (): string | undefined => this.or40p132()\n\n  /**\n   * Index 57: or-40-p1-35\n   */\n  or40p135 = (): string | undefined => {\n    return undefined\n  }\n\n  f57 = (): string | undefined => this.or40p135()\n\n  /**\n   * Index 58: or-40-p1-36\n   */\n  or40p136 = (): string | undefined => {\n    return undefined\n  }\n\n  f58 = (): string | undefined => this.or40p136()\n\n  /**\n   * Index 59: or-40-p2-6\n   */\n  or40p26 = (): string | undefined => {\n    return undefined\n  }\n\n  f59 = (): string | undefined => this.or40p26()\n\n  /**\n   * Index 60: or-40-p2-7\n   */\n  or40p27 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f60 = (): boolean | undefined => this.or40p27()\n\n  /**\n   * Index 61: or-40-p2-8\n   */\n  or40p28 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f61 = (): boolean | undefined => this.or40p28()\n\n  /**\n   * Index 62: or-40-p2-9\n   */\n  or40p29 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f62 = (): boolean | undefined => this.or40p29()\n\n  /**\n   * Index 63: or-40-p2-10\n   */\n  or40p210 = (): string | undefined => {\n    return undefined\n  }\n\n  f63 = (): string | undefined => this.or40p210()\n\n  /**\n   * Index 64: or-40-p2-11\n   */\n  or40p211 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f64 = (): boolean | undefined => this.or40p211()\n\n  /**\n   * Index 65: or-40-p2-12\n   */\n  or40p212 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f65 = (): boolean | undefined => this.or40p212()\n\n  /**\n   * Index 66: or-40-p2-13\n   */\n  or40p213 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f66 = (): boolean | undefined => this.or40p213()\n\n  /**\n   * Index 67: or-40-p2-14\n   */\n  or40p214 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f67 = (): boolean | undefined => this.or40p214()\n\n  /**\n   * Index 68: or-40-p2-15\n   */\n  or40p215 = (): string | undefined => {\n    return undefined\n  }\n\n  f68 = (): string | undefined => this.or40p215()\n\n  /**\n   * Index 69: or-40-p2-16\n   */\n  or40p216 = (): string | undefined => {\n    return undefined\n  }\n\n  f69 = (): string | undefined => this.or40p216()\n\n  /**\n   * Index 70: or-40-p2-17\n   */\n  or40p217 = (): string | undefined => {\n    return undefined\n  }\n\n  f70 = (): string | undefined => this.or40p217()\n\n  /**\n   * Index 71: or-40-p2-18\n   */\n  or40p218 = (): string | undefined => {\n    return undefined\n  }\n\n  f71 = (): string | undefined => this.or40p218()\n\n  /**\n   * Index 72: or-40-p2-19\n   */\n  or40p219 = (): string | undefined => {\n    return undefined\n  }\n\n  f72 = (): string | undefined => this.or40p219()\n\n  /**\n   * Index 73: or-40-p2-21\n   */\n  or40p221 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f73 = (): boolean | undefined => this.or40p221()\n\n  /**\n   * Index 74: or-40-p2-22\n   */\n  or40p222 = (): string | undefined => {\n    return undefined\n  }\n\n  f74 = (): string | undefined => this.or40p222()\n\n  /**\n   * Index 75: or-40-p2-23\n   */\n  or40p223 = (): string | undefined => {\n    return undefined\n  }\n\n  f75 = (): string | undefined => this.or40p223()\n\n  /**\n   * Index 76: or-40-p2-24\n   */\n  or40p224 = (): string | undefined => {\n    return undefined\n  }\n\n  f76 = (): string | undefined => this.or40p224()\n\n  /**\n   * Index 77: or-40-p2-25\n   */\n  or40p225 = (): string | undefined => {\n    return undefined\n  }\n\n  f77 = (): string | undefined => this.or40p225()\n\n  /**\n   * Index 78: or-40-p2-26\n   */\n  or40p226 = (): string | undefined => {\n    return undefined\n  }\n\n  f78 = (): string | undefined => this.or40p226()\n\n  /**\n   * Index 79: or-40-p2-28\n   */\n  or40p228 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f79 = (): boolean | undefined => this.or40p228()\n\n  /**\n   * Index 80: or-40-p2-29\n   */\n  or40p229 = (): string | undefined => {\n    return undefined\n  }\n\n  f80 = (): string | undefined => this.or40p229()\n\n  /**\n   * Index 81: or-40-p2-30\n   */\n  or40p230 = (): string | undefined => {\n    return undefined\n  }\n\n  f81 = (): string | undefined => this.or40p230()\n\n  /**\n   * Index 82: or-40-p2-31\n   */\n  or40p231 = (): string | undefined => {\n    return undefined\n  }\n\n  f82 = (): string | undefined => this.or40p231()\n\n  /**\n   * Index 83: or-40-p2-32\n   */\n  or40p232 = (): string | undefined => {\n    return undefined\n  }\n\n  f83 = (): string | undefined => this.or40p232()\n\n  /**\n   * Index 84: or-40-p2-33\n   */\n  or40p233 = (): string | undefined => {\n    return undefined\n  }\n\n  f84 = (): string | undefined => this.or40p233()\n\n  /**\n   * Index 85: or-40-p2-35\n   */\n  or40p235 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f85 = (): boolean | undefined => this.or40p235()\n\n  /**\n   * Index 86: or-40-p2-36\n   */\n  or40p236 = (): string | undefined => {\n    return undefined\n  }\n\n  f86 = (): string | undefined => this.or40p236()\n\n  /**\n   * Index 87: or-40-p2-37\n   */\n  or40p237 = (): string | undefined => {\n    return undefined\n  }\n\n  f87 = (): string | undefined => this.or40p237()\n\n  /**\n   * Index 88: or-40-p3-1\n   */\n  or40p31 = (): string | undefined => {\n    return undefined\n  }\n\n  f88 = (): string | undefined => this.or40p31()\n\n  /**\n   * Index 89: or-40-p3-2\n   */\n  or40p32 = (): string | undefined => {\n    return undefined\n  }\n\n  f89 = (): string | undefined => this.or40p32()\n\n  /**\n   * Index 90: or-40-p3-3\n   */\n  or40p33 = (): string | undefined => {\n    return undefined\n  }\n\n  f90 = (): string | undefined => this.or40p33()\n\n  /**\n   * Index 91: or-40-p3-4\n   */\n  or40p34 = (): string | undefined => {\n    return undefined\n  }\n\n  f91 = (): string | undefined => this.or40p34()\n\n  /**\n   * Index 92: or-40-p3-5\n   */\n  or40p35 = (): string | undefined => {\n    return undefined\n  }\n\n  f92 = (): string | undefined => this.or40p35()\n\n  /**\n   * Index 93: or-40-p3-6\n   */\n  or40p36 = (): string | undefined => {\n    return undefined\n  }\n\n  f93 = (): string | undefined => this.or40p36()\n\n  /**\n   * Index 94: or-40-p3-7\n   */\n  or40p37 = (): string | undefined => {\n    return undefined\n  }\n\n  f94 = (): string | undefined => this.or40p37()\n\n  /**\n   * Index 95: or-40-p3-8\n   */\n  or40p38 = (): string | undefined => {\n    return undefined\n  }\n\n  f95 = (): string | undefined => this.or40p38()\n\n  /**\n   * Index 96: or-40-p3-9\n   */\n  or40p39 = (): string | undefined => {\n    return undefined\n  }\n\n  f96 = (): string | undefined => this.or40p39()\n\n  /**\n   * Index 97: or-40-p3-10\n   */\n  or40p310 = (): string | undefined => {\n    return undefined\n  }\n\n  f97 = (): string | undefined => this.or40p310()\n\n  /**\n   * Index 98: or-40-p3-11\n   */\n  or40p311 = (): string | undefined => {\n    return undefined\n  }\n\n  f98 = (): string | undefined => this.or40p311()\n\n  /**\n   * Index 99: or-40-p3-12\n   */\n  or40p312 = (): string | undefined => {\n    return undefined\n  }\n\n  f99 = (): string | undefined => this.or40p312()\n\n  /**\n   * Index 100: or-40-p3-13\n   */\n  or40p313 = (): string | undefined => {\n    return undefined\n  }\n\n  f100 = (): string | undefined => this.or40p313()\n\n  /**\n   * Index 101: or-40-p3-14\n   */\n  or40p314 = (): string | undefined => {\n    return undefined\n  }\n\n  f101 = (): string | undefined => this.or40p314()\n\n  /**\n   * Index 102: or-40-p3-15\n   */\n  or40p315 = (): string | undefined => {\n    return undefined\n  }\n\n  f102 = (): string | undefined => this.or40p315()\n\n  /**\n   * Index 103: or-40-p3-16\n   */\n  or40p316 = (): string | undefined => {\n    return undefined\n  }\n\n  f103 = (): string | undefined => this.or40p316()\n\n  /**\n   * Index 104: or-40-p3-17\n   */\n  or40p317 = (): string | undefined => {\n    return undefined\n  }\n\n  f104 = (): string | undefined => this.or40p317()\n\n  /**\n   * Index 105: or-40-p4-4\n   */\n  or40p44 = (): string | undefined => {\n    return undefined\n  }\n\n  f105 = (): string | undefined => this.or40p44()\n\n  /**\n   * Index 106: or-40-p4-5\n   */\n  or40p45 = (): string | undefined => {\n    return undefined\n  }\n\n  f106 = (): string | undefined => this.or40p45()\n\n  /**\n   * Index 107: or-40-p4-6\n   */\n  or40p46 = (): string | undefined => {\n    return undefined\n  }\n\n  f107 = (): string | undefined => this.or40p46()\n\n  /**\n   * Index 108: or-40-p4-7\n   */\n  or40p47 = (): string | undefined => {\n    return undefined\n  }\n\n  f108 = (): string | undefined => this.or40p47()\n\n  /**\n   * Index 109: or-40-p4-8\n   */\n  or40p48 = (): string | undefined => {\n    return undefined\n  }\n\n  f109 = (): string | undefined => this.or40p48()\n\n  /**\n   * Index 110: or-40-p4-9\n   */\n  or40p49 = (): string | undefined => {\n    return undefined\n  }\n\n  f110 = (): string | undefined => this.or40p49()\n\n  /**\n   * Index 111: or-40-p4-10\n   */\n  or40p410 = (): string | undefined => {\n    return undefined\n  }\n\n  f111 = (): string | undefined => this.or40p410()\n\n  /**\n   * Index 112: or-40-p4-11\n   */\n  or40p411 = (): string | undefined => {\n    return undefined\n  }\n\n  f112 = (): string | undefined => this.or40p411()\n\n  /**\n   * Index 113: or-40-p4-12\n   */\n  or40p412 = (): string | undefined => {\n    return undefined\n  }\n\n  f113 = (): string | undefined => this.or40p412()\n\n  /**\n   * Index 114: or-40-p4-13\n   */\n  or40p413 = (): string | undefined => {\n    return undefined\n  }\n\n  f114 = (): string | undefined => this.or40p413()\n\n  /**\n   * Index 115: or-40-p4-14\n   */\n  or40p414 = (): string | undefined => {\n    return undefined\n  }\n\n  f115 = (): string | undefined => this.or40p414()\n\n  /**\n   * Index 116: or-40-p4-15\n   */\n  or40p415 = (): string | undefined => {\n    return undefined\n  }\n\n  f116 = (): string | undefined => this.or40p415()\n\n  /**\n   * Index 117: or-40-p4-16\n   */\n  or40p416 = (): string | undefined => {\n    return undefined\n  }\n\n  f117 = (): string | undefined => this.or40p416()\n\n  /**\n   * Index 118: or-40-p4-1\n   */\n  or40p41 = (): string | undefined => {\n    return undefined\n  }\n\n  f118 = (): string | undefined => this.or40p41()\n\n  /**\n   * Index 119: or-40-p4-2\n   */\n  or40p42 = (): string | undefined => {\n    return undefined\n  }\n\n  f119 = (): string | undefined => this.or40p42()\n\n  /**\n   * Index 120: or-40-p4-3\n   */\n  or40p43 = (): string | undefined => {\n    return undefined\n  }\n\n  f120 = (): string | undefined => this.or40p43()\n\n  /**\n   * Index 121: or-40-p5-1\n   */\n  or40p51 = (): string | undefined => {\n    return undefined\n  }\n\n  f121 = (): string | undefined => this.or40p51()\n\n  /**\n   * Index 122: or-40-p5-2\n   */\n  or40p52 = (): string | undefined => {\n    return undefined\n  }\n\n  f122 = (): string | undefined => this.or40p52()\n\n  /**\n   * Index 123: or-40-p5-3\n   */\n  or40p53 = (): string | undefined => {\n    return undefined\n  }\n\n  f123 = (): string | undefined => this.or40p53()\n\n  /**\n   * Index 124: or-40-p5-4\n   */\n  or40p54 = (): string | undefined => {\n    return undefined\n  }\n\n  f124 = (): string | undefined => this.or40p54()\n\n  /**\n   * Index 125: or-40-p5-5\n   */\n  or40p55 = (): string | undefined => {\n    return undefined\n  }\n\n  f125 = (): string | undefined => this.or40p55()\n\n  /**\n   * Index 126: or-40-p5-6\n   */\n  or40p56 = (): string | undefined => {\n    return undefined\n  }\n\n  f126 = (): string | undefined => this.or40p56()\n\n  /**\n   * Index 127: or-40-p5-7\n   */\n  or40p57 = (): string | undefined => {\n    return undefined\n  }\n\n  f127 = (): string | undefined => this.or40p57()\n\n  /**\n   * Index 128: or-40-p5-8\n   */\n  or40p58 = (): string | undefined => {\n    return undefined\n  }\n\n  f128 = (): string | undefined => this.or40p58()\n\n  /**\n   * Index 129: or-40-p5-9\n   */\n  or40p59 = (): string | undefined => {\n    return undefined\n  }\n\n  f129 = (): string | undefined => this.or40p59()\n\n  /**\n   * Index 130: or-40-p5-10\n   */\n  or40p510 = (): string | undefined => {\n    return undefined\n  }\n\n  f130 = (): string | undefined => this.or40p510()\n\n  /**\n   * Index 131: or-40-p5-11\n   */\n  or40p511 = (): string | undefined => {\n    return undefined\n  }\n\n  f131 = (): string | undefined => this.or40p511()\n\n  /**\n   * Index 132: or-40-p5-12\n   */\n  or40p512 = (): string | undefined => {\n    return undefined\n  }\n\n  f132 = (): string | undefined => this.or40p512()\n\n  /**\n   * Index 133: or-40-p5-13\n   */\n  or40p513 = (): string | undefined => {\n    return undefined\n  }\n\n  f133 = (): string | undefined => this.or40p513()\n\n  /**\n   * Index 134: or-40-p5-14\n   */\n  or40p514 = (): string | undefined => {\n    return undefined\n  }\n\n  f134 = (): string | undefined => this.or40p514()\n\n  /**\n   * Index 135: or-40-p5-15\n   */\n  or40p515 = (): string | undefined => {\n    return undefined\n  }\n\n  f135 = (): string | undefined => this.or40p515()\n\n  /**\n   * Index 136: or-40-p5-16\n   */\n  or40p516 = (): string | undefined => {\n    return undefined\n  }\n\n  f136 = (): string | undefined => this.or40p516()\n\n  /**\n   * Index 137: or-40-p6-1\n   */\n  or40p61 = (): string | undefined => {\n    return undefined\n  }\n\n  f137 = (): string | undefined => this.or40p61()\n\n  /**\n   * Index 138: or-40-p6-2\n   */\n  or40p62 = (): string | undefined => {\n    return undefined\n  }\n\n  f138 = (): string | undefined => this.or40p62()\n\n  /**\n   * Index 139: or-40-p6-3\n   */\n  or40p63 = (): string | undefined => {\n    return undefined\n  }\n\n  f139 = (): string | undefined => this.or40p63()\n\n  /**\n   * Index 140: or-40-p6-4\n   */\n  or40p64 = (): string | undefined => {\n    return undefined\n  }\n\n  f140 = (): string | undefined => this.or40p64()\n\n  /**\n   * Index 141: or-40-p6-5\n   */\n  or40p65 = (): string | undefined => {\n    return undefined\n  }\n\n  f141 = (): string | undefined => this.or40p65()\n\n  /**\n   * Index 142: or-40-p6-6\n   */\n  or40p66 = (): string | undefined => {\n    return undefined\n  }\n\n  f142 = (): string | undefined => this.or40p66()\n\n  /**\n   * Index 143: or-40-p6-7\n   */\n  or40p67 = (): string | undefined => {\n    return undefined\n  }\n\n  f143 = (): string | undefined => this.or40p67()\n\n  /**\n   * Index 144: or-40-p6-8\n   */\n  or40p68 = (): string | undefined => {\n    return undefined\n  }\n\n  f144 = (): string | undefined => this.or40p68()\n\n  /**\n   * Index 145: or-40-p6-9\n   */\n  or40p69 = (): string | undefined => {\n    return undefined\n  }\n\n  f145 = (): string | undefined => this.or40p69()\n\n  /**\n   * Index 146: or-40-p6-10\n   */\n  or40p610 = (): string | undefined => {\n    return undefined\n  }\n\n  f146 = (): string | undefined => this.or40p610()\n\n  /**\n   * Index 147: or-40-p6-11\n   */\n  or40p611 = (): string | undefined => {\n    return undefined\n  }\n\n  f147 = (): string | undefined => this.or40p611()\n\n  /**\n   * Index 148: or-40-p6-12\n   */\n  or40p612 = (): string | undefined => {\n    return undefined\n  }\n\n  f148 = (): string | undefined => this.or40p612()\n\n  /**\n   * Index 149: or-40-p6-13\n   */\n  or40p613 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f149 = (): boolean | undefined => this.or40p613()\n\n  /**\n   * Index 150: or-40-p6-14\n   */\n  or40p614 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f150 = (): boolean | undefined => this.or40p614()\n\n  /**\n   * Index 151: or-40-p6-15\n   */\n  or40p615 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f151 = (): boolean | undefined => this.or40p615()\n\n  /**\n   * Index 152: or-40-p6-16\n   */\n  or40p616 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f152 = (): boolean | undefined => this.or40p616()\n\n  /**\n   * Index 153: or-40-p6-17\n   */\n  or40p617 = (): string | undefined => {\n    return undefined\n  }\n\n  f153 = (): string | undefined => this.or40p617()\n\n  /**\n   * Index 154: or-40-p6-18\n   */\n  or40p618 = (): string | undefined => {\n    return undefined\n  }\n\n  f154 = (): string | undefined => this.or40p618()\n\n  /**\n   * Index 155: or-40-p7-1\n   */\n  or40p71 = (): string | undefined => {\n    return undefined\n  }\n\n  f155 = (): string | undefined => this.or40p71()\n\n  /**\n   * Index 156: or-40-p7-2\n   */\n  or40p72 = (): string | undefined => {\n    return undefined\n  }\n\n  f156 = (): string | undefined => this.or40p72()\n\n  /**\n   * Index 157: or-40-p7-3\n   */\n  or40p73 = (): string | undefined => {\n    return undefined\n  }\n\n  f157 = (): string | undefined => this.or40p73()\n\n  /**\n   * Index 158: or-40-p7-4\n   */\n  or40p74 = (): string | undefined => {\n    return undefined\n  }\n\n  f158 = (): string | undefined => this.or40p74()\n\n  /**\n   * Index 159: or-40-p7-5\n   */\n  or40p75 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f159 = (): boolean | undefined => this.or40p75()\n\n  /**\n   * Index 160: or-40-p7-7\n   */\n  or40p77 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f160 = (): boolean | undefined => this.or40p77()\n\n  /**\n   * Index 161: or-40-p7-8\n   */\n  or40p78 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f161 = (): boolean | undefined => this.or40p78()\n\n  /**\n   * Index 162: or-40-p7-9\n   */\n  or40p79 = (): string | undefined => {\n    return undefined\n  }\n\n  f162 = (): string | undefined => this.or40p79()\n\n  /**\n   * Index 163: or-40-p7-10\n   */\n  or40p710 = (): string | undefined => {\n    return undefined\n  }\n\n  f163 = (): string | undefined => this.or40p710()\n\n  /**\n   * Index 164: or-40-p7-11\n   */\n  or40p711 = (): string | undefined => {\n    return undefined\n  }\n\n  f164 = (): string | undefined => this.or40p711()\n\n  /**\n   * Index 165: or-40-p7-12\n   */\n  or40p712 = (): string | undefined => {\n    return undefined\n  }\n\n  f165 = (): string | undefined => this.or40p712()\n\n  /**\n   * Index 166: or-40-p7-16\n   */\n  or40p716 = (): string | undefined => {\n    return undefined\n  }\n\n  f166 = (): string | undefined => this.or40p716()\n\n  /**\n   * Index 167: or-40-p7-17\n   */\n  or40p717 = (): string | undefined => {\n    return undefined\n  }\n\n  f167 = (): string | undefined => this.or40p717()\n\n  /**\n   * Index 168: or-40-p9-1\n   */\n  or40p91 = (): string | undefined => {\n    return undefined\n  }\n\n  f168 = (): string | undefined => this.or40p91()\n\n  /**\n   * Index 169: or-40-p9-2\n   */\n  or40p92 = (): string | undefined => {\n    return undefined\n  }\n\n  f169 = (): string | undefined => this.or40p92()\n\n  /**\n   * Index 170: or-40-p9-3\n   */\n  or40p93 = (): string | undefined => {\n    return undefined\n  }\n\n  f170 = (): string | undefined => this.or40p93()\n\n  /**\n   * Index 171: or-40-p9-4\n   */\n  or40p94 = (): string | undefined => {\n    return undefined\n  }\n\n  f171 = (): string | undefined => this.or40p94()\n\n  /**\n   * Index 172: or-40-p9-5\n   */\n  or40p95 = (): string | undefined => {\n    return undefined\n  }\n\n  f172 = (): string | undefined => this.or40p95()\n\n  /**\n   * Index 173: or-40-p9-6\n   */\n  or40p96 = (): string | undefined => {\n    return undefined\n  }\n\n  f173 = (): string | undefined => this.or40p96()\n\n  /**\n   * Index 174: or-40-p9-7\n   */\n  or40p97 = (): string | undefined => {\n    return undefined\n  }\n\n  f174 = (): string | undefined => this.or40p97()\n\n  /**\n   * Index 175: or-40-p9-8\n   */\n  or40p98 = (): string | undefined => {\n    return undefined\n  }\n\n  f175 = (): string | undefined => this.or40p98()\n\n  /**\n   * Index 176: or-40-p9-9\n   */\n  or40p99 = (): string | undefined => {\n    return undefined\n  }\n\n  f176 = (): string | undefined => this.or40p99()\n\n  /**\n   * Index 177: or-40-p9-10\n   */\n  or40p910 = (): string | undefined => {\n    return undefined\n  }\n\n  f177 = (): string | undefined => this.or40p910()\n\n  /**\n   * Index 178: or-40-p9-11\n   */\n  or40p911 = (): string | undefined => {\n    return undefined\n  }\n\n  f178 = (): string | undefined => this.or40p911()\n\n  /**\n   * Index 179: or-40-p9-12\n   */\n  or40p912 = (): string | undefined => {\n    return undefined\n  }\n\n  f179 = (): string | undefined => this.or40p912()\n\n  /**\n   * Index 180: or-40-p9-13\n   */\n  or40p913 = (): string | undefined => {\n    return undefined\n  }\n\n  f180 = (): string | undefined => this.or40p913()\n\n  /**\n   * Index 181: or-40-p1-18\n   */\n  or40p118 = (): string | undefined => {\n    return undefined\n  }\n\n  f181 = (): string | undefined => this.or40p118()\n\n  /**\n   * Index 182: or-40-p1-19\n   */\n  or40p119 = (): string | undefined => {\n    return undefined\n  }\n\n  f182 = (): string | undefined => this.or40p119()\n\n  /**\n   * Index 183: or-40-p1-20\n   */\n  or40p120 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f183 = (): boolean | undefined => this.or40p120()\n\n  /**\n   * Index 184: or-40-p1-21\n   */\n  or40p121 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f184 = (): boolean | undefined => this.or40p121()\n\n  /**\n   * Index 185: or-40_p2_1\n   */\n  or40p21 = (): string | undefined => {\n    return undefined\n  }\n\n  f185 = (): string | undefined => this.or40p21()\n\n  /**\n   * Index 186: or-40-p1-33\n   */\n  or40p133 = (): string | undefined => {\n    return undefined\n  }\n\n  f186 = (): string | undefined => this.or40p133()\n\n  /**\n   * Index 187: or-40-p2-20\n   */\n  or40p220 = (): string | undefined => {\n    return undefined\n  }\n\n  f187 = (): string | undefined => this.or40p220()\n\n  /**\n   * Index 188: or-40-p2-27\n   */\n  or40p227 = (): string | undefined => {\n    return undefined\n  }\n\n  f188 = (): string | undefined => this.or40p227()\n\n  /**\n   * Index 189: or-40-p2-34\n   */\n  or40p234 = (): string | undefined => {\n    return undefined\n  }\n\n  f189 = (): string | undefined => this.or40p234()\n\n  /**\n   * Index 190: or-40_n_p9_14\n   */\n  or40np914 = (): string | undefined => {\n    return undefined\n  }\n\n  f190 = (): string | undefined => this.or40np914()\n\n  /**\n   * Index 191: or-40-p7-15\n   */\n  or40p715 = (): string | undefined => {\n    return undefined\n  }\n\n  f191 = (): string | undefined => this.or40p715()\n\n  /**\n   * Index 192: or-40-p1-34a\n   */\n  or40p134a = (): string | undefined => {\n    return undefined\n  }\n\n  f192 = (): string | undefined => this.or40p134a()\n\n  /**\n   * Index 193: or-40-p1-34b\n   */\n  or40p134b = (): string | undefined => {\n    return undefined\n  }\n\n  f193 = (): string | undefined => this.or40p134b()\n\n  /**\n   * Index 194: or-40-n-p10-12a\n   */\n  or40np1012a = (): string | undefined => {\n    return undefined\n  }\n\n  f194 = (): string | undefined => this.or40np1012a()\n\n  /**\n   * Index 195: or-40-n-p10-12b\n   */\n  or40np1012b = (): string | undefined => {\n    return undefined\n  }\n\n  f195 = (): string | undefined => this.or40np1012b()\n\n  /**\n   * Index 196: or-40-p7-13\n   */\n  or40p713 = (): string | undefined => {\n    return undefined\n  }\n\n  f196 = (): string | undefined => this.or40p713()\n\n  /**\n   * Index 197: or-40-p7-14\n   */\n  or40p714 = (): string | undefined => {\n    return undefined\n  }\n\n  f197 = (): string | undefined => this.or40p714()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.f85(),\n    this.f86(),\n    this.f87(),\n    this.f88(),\n    this.f89(),\n    this.f90(),\n    this.f91(),\n    this.f92(),\n    this.f93(),\n    this.f94(),\n    this.f95(),\n    this.f96(),\n    this.f97(),\n    this.f98(),\n    this.f99(),\n    this.f100(),\n    this.f101(),\n    this.f102(),\n    this.f103(),\n    this.f104(),\n    this.f105(),\n    this.f106(),\n    this.f107(),\n    this.f108(),\n    this.f109(),\n    this.f110(),\n    this.f111(),\n    this.f112(),\n    this.f113(),\n    this.f114(),\n    this.f115(),\n    this.f116(),\n    this.f117(),\n    this.f118(),\n    this.f119(),\n    this.f120(),\n    this.f121(),\n    this.f122(),\n    this.f123(),\n    this.f124(),\n    this.f125(),\n    this.f126(),\n    this.f127(),\n    this.f128(),\n    this.f129(),\n    this.f130(),\n    this.f131(),\n    this.f132(),\n    this.f133(),\n    this.f134(),\n    this.f135(),\n    this.f136(),\n    this.f137(),\n    this.f138(),\n    this.f139(),\n    this.f140(),\n    this.f141(),\n    this.f142(),\n    this.f143(),\n    this.f144(),\n    this.f145(),\n    this.f146(),\n    this.f147(),\n    this.f148(),\n    this.f149(),\n    this.f150(),\n    this.f151(),\n    this.f152(),\n    this.f153(),\n    this.f154(),\n    this.f155(),\n    this.f156(),\n    this.f157(),\n    this.f158(),\n    this.f159(),\n    this.f160(),\n    this.f161(),\n    this.f162(),\n    this.f163(),\n    this.f164(),\n    this.f165(),\n    this.f166(),\n    this.f167(),\n    this.f168(),\n    this.f169(),\n    this.f170(),\n    this.f171(),\n    this.f172(),\n    this.f173(),\n    this.f174(),\n    this.f175(),\n    this.f176(),\n    this.f177(),\n    this.f178(),\n    this.f179(),\n    this.f180(),\n    this.f181(),\n    this.f182(),\n    this.f183(),\n    this.f184(),\n    this.f185(),\n    this.f186(),\n    this.f187(),\n    this.f188(),\n    this.f189(),\n    this.f190(),\n    this.f191(),\n    this.f192(),\n    this.f193(),\n    this.f194(),\n    this.f195(),\n    this.f196(),\n    this.f197()\n  ]\n}\n\nconst makeOR40P = (f1040: F1040): OR40P => new OR40P(f1040)\n\nexport default makeOR40P\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/OR40V.ts",
    "content": "import Form from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { OR40 } from './OR40'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport default class OR40V extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  or40: OR40\n  formOrder = -1\n  attachments: () => Form[] = () => []\n\n  constructor(f1040: F1040, or40: OR40) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-40-V'\n    this.state = 'OR'\n    this.or40 = or40\n  }\n\n  /**\n   * Index 0: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 1: or-40-v-p1-1\n   */\n  or40vp11 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.or40vp11()\n\n  /**\n   * Index 2: or-40-v-p1-2\n   */\n  or40vp12 = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.or40vp12()\n\n  /**\n   * Index 3: or-40-v-p1-3\n   */\n  or40vp13 = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.or40vp13()\n\n  /**\n   * Index 4: or-40-v-p1-4\n   */\n  or40vp14 = (): string | undefined => {\n    return undefined\n  }\n\n  f4 = (): string | undefined => this.or40vp14()\n\n  /**\n   * Index 5: or-40-v-p1-5\n   */\n  or40vp15 = (): string | undefined => {\n    return undefined\n  }\n\n  f5 = (): string | undefined => this.or40vp15()\n\n  /**\n   * Index 6: or-40-v-p1-6\n   */\n  or40vp16 = (): string | undefined => {\n    return undefined\n  }\n\n  f6 = (): string | undefined => this.or40vp16()\n\n  /**\n   * Index 7: or-40-v-p1-7\n   */\n  or40vp17 = (): string | undefined => {\n    return undefined\n  }\n\n  f7 = (): string | undefined => this.or40vp17()\n\n  /**\n   * Index 8: or-40-v-p1-8\n   */\n  or40vp18 = (): string | undefined => {\n    return undefined\n  }\n\n  f8 = (): string | undefined => this.or40vp18()\n\n  /**\n   * Index 9: or-40-v-p1-9\n   */\n  or40vp19 = (): string | undefined => {\n    return undefined\n  }\n\n  f9 = (): string | undefined => this.or40vp19()\n\n  /**\n   * Index 10: or-40-v-p1-10\n   */\n  or40vp110 = (): string | undefined => {\n    return undefined\n  }\n\n  f10 = (): string | undefined => this.or40vp110()\n\n  /**\n   * Index 11: or-40-v-p1-11\n   */\n  or40vp111 = (): string | undefined => {\n    return undefined\n  }\n\n  f11 = (): string | undefined => this.or40vp111()\n\n  /**\n   * Index 12: or-40-v-p1-12\n   */\n  or40vp112 = (): string | undefined => {\n    return undefined\n  }\n\n  f12 = (): string | undefined => this.or40vp112()\n\n  /**\n   * Index 13: or-40-v-p1-13\n   */\n  or40vp113 = (): string | undefined => {\n    return undefined\n  }\n\n  f13 = (): string | undefined => this.or40vp113()\n\n  /**\n   * Index 14: or-40-v-p1-14\n   */\n  or40vp114 = (): string | undefined => {\n    return undefined\n  }\n\n  f14 = (): string | undefined => this.or40vp114()\n\n  /**\n   * Index 15: or-40-v-p1-15\n   */\n  or40vp115 = (): string | undefined => {\n    return undefined\n  }\n\n  f15 = (): string | undefined => this.or40vp115()\n\n  /**\n   * Index 16: or-40-v-p1-group1\n   */\n  or40vp1group1 = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.or40vp1group1()\n\n  /**\n   * Index 17: or-40-v-p1-16\n   */\n  or40vp116 = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.or40vp116()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17()\n  ]\n}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/ORASC.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class ORASC extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-ASC'\n    this.state = 'OR'\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    // const pmt = this.payment()\n    const result: Form[] = []\n    // if ((pmt ?? 0) > 0) {\n    //   result.push(this.il1040V)\n    // }\n    // if (this.scheduleEIC.isRequired()) {\n    //   result.push(this.scheduleEIC)\n    // }\n    // if (this.methods.stateWithholding() > 0) {\n    //   const ilwit = new ILWIT(this.info, this.f1040)\n    //   result.push(ilwit)\n    //   ilwit.attachments().forEach((f) => result.push(f))\n    // }\n\n    return result\n  }\n\n  /**\n   * Index 0: or-asc-p1-2\n   */\n  orascp12 = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.orascp12()\n\n  /**\n   * Index 1: or-asc-p1-3\n   */\n  orascp13 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.orascp13()\n\n  /**\n   * Index 2: or-asc-p1-4\n   */\n  orascp14 = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.orascp14()\n\n  /**\n   * Index 3: or-asc-p1-5\n   */\n  orascp15 = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.orascp15()\n\n  /**\n   * Index 4: or-asc-p1-6\n   */\n  orascp16 = (): string | undefined => {\n    return undefined\n  }\n\n  f4 = (): string | undefined => this.orascp16()\n\n  /**\n   * Index 5: or-asc-p1-7\n   */\n  orascp17 = (): string | undefined => {\n    return undefined\n  }\n\n  f5 = (): string | undefined => this.orascp17()\n\n  /**\n   * Index 6: or-asc-p1-8\n   */\n  orascp18 = (): string | undefined => {\n    return undefined\n  }\n\n  f6 = (): string | undefined => this.orascp18()\n\n  /**\n   * Index 7: or-asc-p1-12\n   */\n  orascp112 = (): string | undefined => {\n    return undefined\n  }\n\n  f7 = (): string | undefined => this.orascp112()\n\n  /**\n   * Index 8: or-asc-p1-11\n   */\n  orascp111 = (): string | undefined => {\n    return undefined\n  }\n\n  f8 = (): string | undefined => this.orascp111()\n\n  /**\n   * Index 9: or-asc-p1-1\n   */\n  orascp11 = (): string | undefined => {\n    return undefined\n  }\n\n  f9 = (): string | undefined => this.orascp11()\n\n  /**\n   * Index 10: or-asc-p2-1\n   */\n  orascp21 = (): string | undefined => {\n    return undefined\n  }\n\n  f10 = (): string | undefined => this.orascp21()\n\n  /**\n   * Index 11: or-asc-p2-3\n   */\n  orascp23 = (): string | undefined => {\n    return undefined\n  }\n\n  f11 = (): string | undefined => this.orascp23()\n\n  /**\n   * Index 12: or-asc-p2-4\n   */\n  orascp24 = (): string | undefined => {\n    return undefined\n  }\n\n  f12 = (): string | undefined => this.orascp24()\n\n  /**\n   * Index 13: or-asc-p2-6\n   */\n  orascp26 = (): string | undefined => {\n    return undefined\n  }\n\n  f13 = (): string | undefined => this.orascp26()\n\n  /**\n   * Index 14: or-asc-p2-7\n   */\n  orascp27 = (): string | undefined => {\n    return undefined\n  }\n\n  f14 = (): string | undefined => this.orascp27()\n\n  /**\n   * Index 15: or-asc-p1-1a\n   */\n  orascp11a = (): string | undefined => {\n    return undefined\n  }\n\n  f15 = (): string | undefined => this.orascp11a()\n\n  /**\n   * Index 16: or-asc-p1-1b\n   */\n  orascp11b = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.orascp11b()\n\n  /**\n   * Index 17: or-asc-p1-9\n   */\n  orascp19 = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.orascp19()\n\n  /**\n   * Index 18: or-asc-p1-10\n   */\n  orascp110 = (): string | undefined => {\n    return undefined\n  }\n\n  f18 = (): string | undefined => this.orascp110()\n\n  /**\n   * Index 19: or-asc-p2-9\n   */\n  orascp29 = (): string | undefined => {\n    return undefined\n  }\n\n  f19 = (): string | undefined => this.orascp29()\n\n  /**\n   * Index 20: or-asc-p2-10\n   */\n  orascp210 = (): string | undefined => {\n    return undefined\n  }\n\n  f20 = (): string | undefined => this.orascp210()\n\n  /**\n   * Index 21: or-asc-p2-12\n   */\n  orascp212 = (): string | undefined => {\n    return undefined\n  }\n\n  f21 = (): string | undefined => this.orascp212()\n\n  /**\n   * Index 22: or-asc-p2-13\n   */\n  orascp213 = (): string | undefined => {\n    return undefined\n  }\n\n  f22 = (): string | undefined => this.orascp213()\n\n  /**\n   * Index 23: or-asc-p2-15\n   */\n  orascp215 = (): string | undefined => {\n    return undefined\n  }\n\n  f23 = (): string | undefined => this.orascp215()\n\n  /**\n   * Index 24: or-asc-p2-16\n   */\n  orascp216 = (): string | undefined => {\n    return undefined\n  }\n\n  f24 = (): string | undefined => this.orascp216()\n\n  /**\n   * Index 25: or-asc-p2-17\n   */\n  orascp217 = (): string | undefined => {\n    return undefined\n  }\n\n  f25 = (): string | undefined => this.orascp217()\n\n  /**\n   * Index 26: or-asc-p2-18\n   */\n  orascp218 = (): string | undefined => {\n    return undefined\n  }\n\n  f26 = (): string | undefined => this.orascp218()\n\n  /**\n   * Index 27: or-asc-p2-19\n   */\n  orascp219 = (): string | undefined => {\n    return undefined\n  }\n\n  f27 = (): string | undefined => this.orascp219()\n\n  /**\n   * Index 28: or-asc-p2-20\n   */\n  orascp220 = (): string | undefined => {\n    return undefined\n  }\n\n  f28 = (): string | undefined => this.orascp220()\n\n  /**\n   * Index 29: or-asc-p2-21\n   */\n  orascp221 = (): string | undefined => {\n    return undefined\n  }\n\n  f29 = (): string | undefined => this.orascp221()\n\n  /**\n   * Index 30: or-asc-p2-22\n   */\n  orascp222 = (): string | undefined => {\n    return undefined\n  }\n\n  f30 = (): string | undefined => this.orascp222()\n\n  /**\n   * Index 31: or-asc-p2-23\n   */\n  orascp223 = (): string | undefined => {\n    return undefined\n  }\n\n  f31 = (): string | undefined => this.orascp223()\n\n  /**\n   * Index 32: or-asc-p2-24\n   */\n  orascp224 = (): string | undefined => {\n    return undefined\n  }\n\n  f32 = (): string | undefined => this.orascp224()\n\n  /**\n   * Index 33: or-asc-p2-25\n   */\n  orascp225 = (): string | undefined => {\n    return undefined\n  }\n\n  f33 = (): string | undefined => this.orascp225()\n\n  /**\n   * Index 34: or-asc-p3-1\n   */\n  orascp31 = (): string | undefined => {\n    return undefined\n  }\n\n  f34 = (): string | undefined => this.orascp31()\n\n  /**\n   * Index 35: or-asc-p3-2\n   */\n  orascp32 = (): string | undefined => {\n    return undefined\n  }\n\n  f35 = (): string | undefined => this.orascp32()\n\n  /**\n   * Index 36: or-asc-p3-3\n   */\n  orascp33 = (): string | undefined => {\n    return undefined\n  }\n\n  f36 = (): string | undefined => this.orascp33()\n\n  /**\n   * Index 37: or-asc-p3-4\n   */\n  orascp34 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.orascp34()\n\n  /**\n   * Index 38: or-asc-p3-5\n   */\n  orascp35 = (): string | undefined => {\n    return undefined\n  }\n\n  f38 = (): string | undefined => this.orascp35()\n\n  /**\n   * Index 39: or-asc-p3-6\n   */\n  orascp36 = (): string | undefined => {\n    return undefined\n  }\n\n  f39 = (): string | undefined => this.orascp36()\n\n  /**\n   * Index 40: or-asc-p3-8\n   */\n  orascp38 = (): string | undefined => {\n    return undefined\n  }\n\n  f40 = (): string | undefined => this.orascp38()\n\n  /**\n   * Index 41: or-asc-p3-10\n   */\n  orascp310 = (): string | undefined => {\n    return undefined\n  }\n\n  f41 = (): string | undefined => this.orascp310()\n\n  /**\n   * Index 42: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 43: or-asc-p2-2\n   */\n  orascp22 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.orascp22()\n\n  /**\n   * Index 44: or-asc-p2-5\n   */\n  orascp25 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.orascp25()\n\n  /**\n   * Index 45: or-asc-p2-8\n   */\n  orascp28 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.orascp28()\n\n  /**\n   * Index 46: or-asc-p2-11\n   */\n  orascp211 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.orascp211()\n\n  /**\n   * Index 47: or-asc-p2-14\n   */\n  orascp214 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.orascp214()\n\n  /**\n   * Index 48: or-asc-p3-7\n   */\n  orascp37 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.orascp37()\n\n  /**\n   * Index 49: or-asc-p3-9\n   */\n  orascp39 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.orascp39()\n\n  /**\n   * Index 50: or-asc-p3-11\n   */\n  orascp311 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.orascp311()\n\n  /**\n   * Index 51: or-asc-p3-12\n   */\n  orascp312 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.orascp312()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51()\n  ]\n}\n\nconst makeORASC = (f1040: F1040): ORASC => new ORASC(f1040)\n\nexport default makeORASC\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/ORASCNP.ts",
    "content": "import Form, { FormMethods } from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class ORASCNP extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  formOrder = 0\n  methods: FormMethods\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-ASC-NP'\n    this.state = 'OR'\n    this.methods = new FormMethods(this)\n  }\n\n  attachments = (): Form[] => {\n    // const pmt = this.payment()\n    const result: Form[] = []\n    // if ((pmt ?? 0) > 0) {\n    //   result.push(this.il1040V)\n    // }\n    // if (this.scheduleEIC.isRequired()) {\n    //   result.push(this.scheduleEIC)\n    // }\n    // if (this.methods.stateWithholding() > 0) {\n    //   const ilwit = new ILWIT(this.info, this.f1040)\n    //   result.push(ilwit)\n    //   ilwit.attachments().forEach((f) => result.push(f))\n    // }\n\n    return result\n  }\n\n  /**\n   * Index 0: or-asc-p1-1\n   */\n  orascp11 = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.orascp11()\n\n  /**\n   * Index 1: or-asc-p1-1a\n   */\n  orascp11a = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.orascp11a()\n\n  /**\n   * Index 2: or-asc-p1-1b\n   */\n  orascp11b = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.orascp11b()\n\n  /**\n   * Index 3: or-asc-p1-10\n   */\n  orascp110 = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.orascp110()\n\n  /**\n   * Index 4: or-asc-p3-1\n   */\n  orascp31 = (): string | undefined => {\n    return undefined\n  }\n\n  f4 = (): string | undefined => this.orascp31()\n\n  /**\n   * Index 5: or-asc-p3-2\n   */\n  orascp32 = (): string | undefined => {\n    return undefined\n  }\n\n  f5 = (): string | undefined => this.orascp32()\n\n  /**\n   * Index 6: or-asc-p3-3\n   */\n  orascp33 = (): string | undefined => {\n    return undefined\n  }\n\n  f6 = (): string | undefined => this.orascp33()\n\n  /**\n   * Index 7: or-asc-p3-4\n   */\n  orascp34 = (): string | undefined => {\n    return undefined\n  }\n\n  f7 = (): string | undefined => this.orascp34()\n\n  /**\n   * Index 8: or-asc-p3-5\n   */\n  orascp35 = (): string | undefined => {\n    return undefined\n  }\n\n  f8 = (): string | undefined => this.orascp35()\n\n  /**\n   * Index 9: or-asc-p3-6\n   */\n  orascp36 = (): string | undefined => {\n    return undefined\n  }\n\n  f9 = (): string | undefined => this.orascp36()\n\n  /**\n   * Index 10: or-asc-p3-7\n   */\n  orascp37 = (): string | undefined => {\n    return undefined\n  }\n\n  f10 = (): string | undefined => this.orascp37()\n\n  /**\n   * Index 11: or-asc-p1-4\n   */\n  orascp14 = (): string | undefined => {\n    return undefined\n  }\n\n  f11 = (): string | undefined => this.orascp14()\n\n  /**\n   * Index 12: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f12 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 13: or-asc-p3-8\n   */\n  orascp38 = (): string | undefined => {\n    return undefined\n  }\n\n  f13 = (): string | undefined => this.orascp38()\n\n  /**\n   * Index 14: or-asc-p3-10\n   */\n  orascp310 = (): string | undefined => {\n    return undefined\n  }\n\n  f14 = (): string | undefined => this.orascp310()\n\n  /**\n   * Index 15: or-asc-p3-11\n   */\n  orascp311 = (): string | undefined => {\n    return undefined\n  }\n\n  f15 = (): string | undefined => this.orascp311()\n\n  /**\n   * Index 16: or-asc-p3-13\n   */\n  orascp313 = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.orascp313()\n\n  /**\n   * Index 17: or-asc-p3-14\n   */\n  orascp314 = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.orascp314()\n\n  /**\n   * Index 18: or-asc-p3-17\n   */\n  orascp317 = (): string | undefined => {\n    return undefined\n  }\n\n  f18 = (): string | undefined => this.orascp317()\n\n  /**\n   * Index 19: or-asc-p3-20\n   */\n  orascp320 = (): string | undefined => {\n    return undefined\n  }\n\n  f19 = (): string | undefined => this.orascp320()\n\n  /**\n   * Index 20: or-asc-p3-9\n   */\n  orascp39 = (): string | undefined => {\n    return undefined\n  }\n\n  f20 = (): string | undefined => this.orascp39()\n\n  /**\n   * Index 21: or-asc-p3-12\n   */\n  orascp312 = (): string | undefined => {\n    return undefined\n  }\n\n  f21 = (): string | undefined => this.orascp312()\n\n  /**\n   * Index 22: or-asc-p3-15\n   */\n  orascp315 = (): string | undefined => {\n    return undefined\n  }\n\n  f22 = (): string | undefined => this.orascp315()\n\n  /**\n   * Index 23: or-asc-p3-18\n   */\n  orascp318 = (): string | undefined => {\n    return undefined\n  }\n\n  f23 = (): string | undefined => this.orascp318()\n\n  /**\n   * Index 24: or-asc-p3-21\n   */\n  orascp321 = (): string | undefined => {\n    return undefined\n  }\n\n  f24 = (): string | undefined => this.orascp321()\n\n  /**\n   * Index 25: or-asc-p1-2\n   */\n  orascp12 = (): string | undefined => {\n    return undefined\n  }\n\n  f25 = (): string | undefined => this.orascp12()\n\n  /**\n   * Index 26: or-asc-p1-3\n   */\n  orascp13 = (): string | undefined => {\n    return undefined\n  }\n\n  f26 = (): string | undefined => this.orascp13()\n\n  /**\n   * Index 27: or-asc-p1-11\n   */\n  orascp111 = (): string | undefined => {\n    return undefined\n  }\n\n  f27 = (): string | undefined => this.orascp111()\n\n  /**\n   * Index 28: or-asc-p1-12\n   */\n  orascp112 = (): string | undefined => {\n    return undefined\n  }\n\n  f28 = (): string | undefined => this.orascp112()\n\n  /**\n   * Index 29: or-asc-p1-5\n   */\n  orascp15 = (): string | undefined => {\n    return undefined\n  }\n\n  f29 = (): string | undefined => this.orascp15()\n\n  /**\n   * Index 30: or-asc-p1-6\n   */\n  orascp16 = (): string | undefined => {\n    return undefined\n  }\n\n  f30 = (): string | undefined => this.orascp16()\n\n  /**\n   * Index 31: or-asc-p1-7\n   */\n  orascp17 = (): string | undefined => {\n    return undefined\n  }\n\n  f31 = (): string | undefined => this.orascp17()\n\n  /**\n   * Index 32: or-asc-p1-8\n   */\n  orascp18 = (): string | undefined => {\n    return undefined\n  }\n\n  f32 = (): string | undefined => this.orascp18()\n\n  /**\n   * Index 33: or-asc-p2-13\n   */\n  orascp213 = (): string | undefined => {\n    return undefined\n  }\n\n  f33 = (): string | undefined => this.orascp213()\n\n  /**\n   * Index 34: or-asc-p2-1\n   */\n  orascp21 = (): string | undefined => {\n    return undefined\n  }\n\n  f34 = (): string | undefined => this.orascp21()\n\n  /**\n   * Index 35: or-asc-p2-2\n   */\n  orascp22 = (): string | undefined => {\n    return undefined\n  }\n\n  f35 = (): string | undefined => this.orascp22()\n\n  /**\n   * Index 36: or-asc-p2-3\n   */\n  orascp23 = (): string | undefined => {\n    return undefined\n  }\n\n  f36 = (): string | undefined => this.orascp23()\n\n  /**\n   * Index 37: or-asc-p2-4\n   */\n  orascp24 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.orascp24()\n\n  /**\n   * Index 38: or-asc-p2-5\n   */\n  orascp25 = (): string | undefined => {\n    return undefined\n  }\n\n  f38 = (): string | undefined => this.orascp25()\n\n  /**\n   * Index 39: or-asc-p2-6\n   */\n  orascp26 = (): string | undefined => {\n    return undefined\n  }\n\n  f39 = (): string | undefined => this.orascp26()\n\n  /**\n   * Index 40: or-asc-p2-7\n   */\n  orascp27 = (): string | undefined => {\n    return undefined\n  }\n\n  f40 = (): string | undefined => this.orascp27()\n\n  /**\n   * Index 41: or-asc-p2-8\n   */\n  orascp28 = (): string | undefined => {\n    return undefined\n  }\n\n  f41 = (): string | undefined => this.orascp28()\n\n  /**\n   * Index 42: or-asc-p2-9\n   */\n  orascp29 = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.orascp29()\n\n  /**\n   * Index 43: or-asc-p2-10\n   */\n  orascp210 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.orascp210()\n\n  /**\n   * Index 44: or-asc-p2-11\n   */\n  orascp211 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.orascp211()\n\n  /**\n   * Index 45: or-asc-p2-12\n   */\n  orascp212 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.orascp212()\n\n  /**\n   * Index 46: or-asc-p4-1\n   */\n  orascp41 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.orascp41()\n\n  /**\n   * Index 47: or-asc-p4-2\n   */\n  orascp42 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.orascp42()\n\n  /**\n   * Index 48: or-asc-p4-3\n   */\n  orascp43 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.orascp43()\n\n  /**\n   * Index 49: or-asc-p4-4\n   */\n  orascp44 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.orascp44()\n\n  /**\n   * Index 50: or-asc-p4-5\n   */\n  orascp45 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.orascp45()\n\n  /**\n   * Index 51: or-asc-p4-6\n   */\n  orascp46 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.orascp46()\n\n  /**\n   * Index 52: or-asc-p4-7\n   */\n  orascp47 = (): string | undefined => {\n    return undefined\n  }\n\n  f52 = (): string | undefined => this.orascp47()\n\n  /**\n   * Index 53: or-asc-p4-8\n   */\n  orascp48 = (): string | undefined => {\n    return undefined\n  }\n\n  f53 = (): string | undefined => this.orascp48()\n\n  /**\n   * Index 54: or-asc-p4-9\n   */\n  orascp49 = (): string | undefined => {\n    return undefined\n  }\n\n  f54 = (): string | undefined => this.orascp49()\n\n  /**\n   * Index 55: or-asc-p4-10\n   */\n  orascp410 = (): string | undefined => {\n    return undefined\n  }\n\n  f55 = (): string | undefined => this.orascp410()\n\n  /**\n   * Index 56: or-asc-p4-11\n   */\n  orascp411 = (): string | undefined => {\n    return undefined\n  }\n\n  f56 = (): string | undefined => this.orascp411()\n\n  /**\n   * Index 57: or-asc-p4-12\n   */\n  orascp412 = (): string | undefined => {\n    return undefined\n  }\n\n  f57 = (): string | undefined => this.orascp412()\n\n  /**\n   * Index 58: or-asc-p4-13\n   */\n  orascp413 = (): string | undefined => {\n    return undefined\n  }\n\n  f58 = (): string | undefined => this.orascp413()\n\n  /**\n   * Index 59: or-asc-p4-14\n   */\n  orascp414 = (): string | undefined => {\n    return undefined\n  }\n\n  f59 = (): string | undefined => this.orascp414()\n\n  /**\n   * Index 60: or-asc-p5-1\n   */\n  orascp51 = (): string | undefined => {\n    return undefined\n  }\n\n  f60 = (): string | undefined => this.orascp51()\n\n  /**\n   * Index 61: or-asc-p5-3\n   */\n  orascp53 = (): string | undefined => {\n    return undefined\n  }\n\n  f61 = (): string | undefined => this.orascp53()\n\n  /**\n   * Index 62: or-asc-p5-5\n   */\n  orascp55 = (): string | undefined => {\n    return undefined\n  }\n\n  f62 = (): string | undefined => this.orascp55()\n\n  /**\n   * Index 63: or-asc-p3-16\n   */\n  orascp316 = (): string | undefined => {\n    return undefined\n  }\n\n  f63 = (): string | undefined => this.orascp316()\n\n  /**\n   * Index 64: or-asc-p3-19\n   */\n  orascp319 = (): string | undefined => {\n    return undefined\n  }\n\n  f64 = (): string | undefined => this.orascp319()\n\n  /**\n   * Index 65: or-asc-p3-22\n   */\n  orascp322 = (): string | undefined => {\n    return undefined\n  }\n\n  f65 = (): string | undefined => this.orascp322()\n\n  /**\n   * Index 66: or-asc-p3-23\n   */\n  orascp323 = (): string | undefined => {\n    return undefined\n  }\n\n  f66 = (): string | undefined => this.orascp323()\n\n  /**\n   * Index 67: or-asc-p5-2\n   */\n  orascp52 = (): string | undefined => {\n    return undefined\n  }\n\n  f67 = (): string | undefined => this.orascp52()\n\n  /**\n   * Index 68: or-asc-p5-4\n   */\n  orascp54 = (): string | undefined => {\n    return undefined\n  }\n\n  f68 = (): string | undefined => this.orascp54()\n\n  /**\n   * Index 69: or-asc-p5-6\n   */\n  orascp56 = (): string | undefined => {\n    return undefined\n  }\n\n  f69 = (): string | undefined => this.orascp56()\n\n  /**\n   * Index 70: or-asc-p5-7\n   */\n  orascp57 = (): string | undefined => {\n    return undefined\n  }\n\n  f70 = (): string | undefined => this.orascp57()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70()\n  ]\n}\n\nconst makeORASCNP = (f1040: F1040): ORASCNP => new ORASCNP(f1040)\n\nexport default makeORASCNP\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/ORWFHDC.ts",
    "content": "import Form from 'ustaxes/core/stateForms/Form'\nimport F1040 from '../../irsForms/F1040'\nimport { Field } from 'ustaxes/core/pdfFiller'\nimport { State } from 'ustaxes/core/data'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nexport class ORWFHDC extends Form {\n  info: ValidatedInformation\n  f1040: F1040\n  formName: string\n  state: State\n  formOrder = 1\n  attachments: () => Form[] = () => []\n\n  constructor(f1040: F1040) {\n    super()\n    this.info = f1040.info\n    this.f1040 = f1040\n    this.formName = 'OR-WFHDC'\n    this.state = 'OR'\n  }\n\n  /**\n   * Index 0: or-wfhdc-p1_1\n   */\n  orwfhdcp11 = (): string | undefined => {\n    return undefined\n  }\n\n  f0 = (): string | undefined => this.orwfhdcp11()\n\n  /**\n   * Index 1: or-wfhdc-p1_2\n   */\n  orwfhdcp12 = (): string | undefined => {\n    return undefined\n  }\n\n  f1 = (): string | undefined => this.orwfhdcp12()\n\n  /**\n   * Index 2: or-wfhdc-p1_3\n   */\n  orwfhdcp13 = (): string | undefined => {\n    return undefined\n  }\n\n  f2 = (): string | undefined => this.orwfhdcp13()\n\n  /**\n   * Index 3: or-wfhdc-p1_4\n   */\n  orwfhdcp14 = (): string | undefined => {\n    return undefined\n  }\n\n  f3 = (): string | undefined => this.orwfhdcp14()\n\n  /**\n   * Index 4: or-wfhdc-p1_5\n   */\n  orwfhdcp15 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f4 = (): boolean | undefined => this.orwfhdcp15()\n\n  /**\n   * Index 5: or-wfhdc-p1_6\n   */\n  orwfhdcp16 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f5 = (): boolean | undefined => this.orwfhdcp16()\n\n  /**\n   * Index 6: or-wfhdc-p1_7\n   */\n  orwfhdcp17 = (): string | undefined => {\n    return undefined\n  }\n\n  f6 = (): string | undefined => this.orwfhdcp17()\n\n  /**\n   * Index 7: or-wfhdc-p1_8\n   */\n  orwfhdcp18 = (): string | undefined => {\n    return undefined\n  }\n\n  f7 = (): string | undefined => this.orwfhdcp18()\n\n  /**\n   * Index 8: or-wfhdc-p1_9\n   */\n  orwfhdcp19 = (): string | undefined => {\n    return undefined\n  }\n\n  f8 = (): string | undefined => this.orwfhdcp19()\n\n  /**\n   * Index 9: or-wfhdc-p1_10\n   */\n  orwfhdcp110 = (): string | undefined => {\n    return undefined\n  }\n\n  f9 = (): string | undefined => this.orwfhdcp110()\n\n  /**\n   * Index 10: or-wfhdc-p1_11\n   */\n  orwfhdcp111 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f10 = (): boolean | undefined => this.orwfhdcp111()\n\n  /**\n   * Index 11: or-wfhdc-p1_12\n   */\n  orwfhdcp112 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f11 = (): boolean | undefined => this.orwfhdcp112()\n\n  /**\n   * Index 12: or-wfhdc-p1_13\n   */\n  orwfhdcp113 = (): string | undefined => {\n    return undefined\n  }\n\n  f12 = (): string | undefined => this.orwfhdcp113()\n\n  /**\n   * Index 13: or-wfhdc-p1_14\n   */\n  orwfhdcp114 = (): string | undefined => {\n    return undefined\n  }\n\n  f13 = (): string | undefined => this.orwfhdcp114()\n\n  /**\n   * Index 14: or-wfhdc-p1_15\n   */\n  orwfhdcp115 = (): string | undefined => {\n    return undefined\n  }\n\n  f14 = (): string | undefined => this.orwfhdcp115()\n\n  /**\n   * Index 15: or-wfhdc-p1_16\n   */\n  orwfhdcp116 = (): string | undefined => {\n    return undefined\n  }\n\n  f15 = (): string | undefined => this.orwfhdcp116()\n\n  /**\n   * Index 16: or-wfhdc-p1_17\n   */\n  orwfhdcp117 = (): string | undefined => {\n    return undefined\n  }\n\n  f16 = (): string | undefined => this.orwfhdcp117()\n\n  /**\n   * Index 17: or-wfhdc-p1_18\n   */\n  orwfhdcp118 = (): string | undefined => {\n    return undefined\n  }\n\n  f17 = (): string | undefined => this.orwfhdcp118()\n\n  /**\n   * Index 18: or-wfhdc-p1_21\n   */\n  orwfhdcp121 = (): string | undefined => {\n    return undefined\n  }\n\n  f18 = (): string | undefined => this.orwfhdcp121()\n\n  /**\n   * Index 19: or-wfhdc-p1_22\n   */\n  orwfhdcp122 = (): string | undefined => {\n    return undefined\n  }\n\n  f19 = (): string | undefined => this.orwfhdcp122()\n\n  /**\n   * Index 20: or-wfhdc-p1_23\n   */\n  orwfhdcp123 = (): string | undefined => {\n    return undefined\n  }\n\n  f20 = (): string | undefined => this.orwfhdcp123()\n\n  /**\n   * Index 21: or-wfhdc-p1_24\n   */\n  orwfhdcp124 = (): string | undefined => {\n    return undefined\n  }\n\n  f21 = (): string | undefined => this.orwfhdcp124()\n\n  /**\n   * Index 22: or-wfhdc-p1_26\n   */\n  orwfhdcp126 = (): string | undefined => {\n    return undefined\n  }\n\n  f22 = (): string | undefined => this.orwfhdcp126()\n\n  /**\n   * Index 23: or-wfhdc-p2_1\n   */\n  orwfhdcp21 = (): string | undefined => {\n    return undefined\n  }\n\n  f23 = (): string | undefined => this.orwfhdcp21()\n\n  /**\n   * Index 24: or-wfhdc-p2_2\n   */\n  orwfhdcp22 = (): string | undefined => {\n    return undefined\n  }\n\n  f24 = (): string | undefined => this.orwfhdcp22()\n\n  /**\n   * Index 25: or-wfhdc-p2_3\n   */\n  orwfhdcp23 = (): string | undefined => {\n    return undefined\n  }\n\n  f25 = (): string | undefined => this.orwfhdcp23()\n\n  /**\n   * Index 26: or-wfhdc-p2_4\n   */\n  orwfhdcp24 = (): string | undefined => {\n    return undefined\n  }\n\n  f26 = (): string | undefined => this.orwfhdcp24()\n\n  /**\n   * Index 27: or-wfhdc-p2_5\n   */\n  orwfhdcp25 = (): string | undefined => {\n    return undefined\n  }\n\n  f27 = (): string | undefined => this.orwfhdcp25()\n\n  /**\n   * Index 28: or-wfhdc-p2_6\n   */\n  orwfhdcp26 = (): string | undefined => {\n    return undefined\n  }\n\n  f28 = (): string | undefined => this.orwfhdcp26()\n\n  /**\n   * Index 29: or-wfhdc-p2_9\n   */\n  orwfhdcp29 = (): string | undefined => {\n    return undefined\n  }\n\n  f29 = (): string | undefined => this.orwfhdcp29()\n\n  /**\n   * Index 30: or-wfhdc-p2_10\n   */\n  orwfhdcp210 = (): string | undefined => {\n    return undefined\n  }\n\n  f30 = (): string | undefined => this.orwfhdcp210()\n\n  /**\n   * Index 31: or-wfhdc-p2_11\n   */\n  orwfhdcp211 = (): string | undefined => {\n    return undefined\n  }\n\n  f31 = (): string | undefined => this.orwfhdcp211()\n\n  /**\n   * Index 32: or-wfhdc-p2_12\n   */\n  orwfhdcp212 = (): string | undefined => {\n    return undefined\n  }\n\n  f32 = (): string | undefined => this.orwfhdcp212()\n\n  /**\n   * Index 33: or-wfhdc-p2_14\n   */\n  orwfhdcp214 = (): string | undefined => {\n    return undefined\n  }\n\n  f33 = (): string | undefined => this.orwfhdcp214()\n\n  /**\n   * Index 34: or-wfhdc-p2_15\n   */\n  orwfhdcp215 = (): string | undefined => {\n    return undefined\n  }\n\n  f34 = (): string | undefined => this.orwfhdcp215()\n\n  /**\n   * Index 35: or-wfhdc-p2_16\n   */\n  orwfhdcp216 = (): string | undefined => {\n    return undefined\n  }\n\n  f35 = (): string | undefined => this.orwfhdcp216()\n\n  /**\n   * Index 36: or-wfhdc-p2_17\n   */\n  orwfhdcp217 = (): string | undefined => {\n    return undefined\n  }\n\n  f36 = (): string | undefined => this.orwfhdcp217()\n\n  /**\n   * Index 37: or-wfhdc-p2_18\n   */\n  orwfhdcp218 = (): string | undefined => {\n    return undefined\n  }\n\n  f37 = (): string | undefined => this.orwfhdcp218()\n\n  /**\n   * Index 38: or-wfhdc-p2_19\n   */\n  orwfhdcp219 = (): string | undefined => {\n    return undefined\n  }\n\n  f38 = (): string | undefined => this.orwfhdcp219()\n\n  /**\n   * Index 39: or-wfhdc-p2_20\n   */\n  orwfhdcp220 = (): string | undefined => {\n    return undefined\n  }\n\n  f39 = (): string | undefined => this.orwfhdcp220()\n\n  /**\n   * Index 40: or-wfhdc-p2_21\n   */\n  orwfhdcp221 = (): string | undefined => {\n    return undefined\n  }\n\n  f40 = (): string | undefined => this.orwfhdcp221()\n\n  /**\n   * Index 41: or-wfhdc-p2_23\n   */\n  orwfhdcp223 = (): string | undefined => {\n    return undefined\n  }\n\n  f41 = (): string | undefined => this.orwfhdcp223()\n\n  /**\n   * Index 42: or-wfhdc-p2_24\n   */\n  orwfhdcp224 = (): string | undefined => {\n    return undefined\n  }\n\n  f42 = (): string | undefined => this.orwfhdcp224()\n\n  /**\n   * Index 43: or-wfhdc-p2_25\n   */\n  orwfhdcp225 = (): string | undefined => {\n    return undefined\n  }\n\n  f43 = (): string | undefined => this.orwfhdcp225()\n\n  /**\n   * Index 44: or-wfhdc-p2_26\n   */\n  orwfhdcp226 = (): string | undefined => {\n    return undefined\n  }\n\n  f44 = (): string | undefined => this.orwfhdcp226()\n\n  /**\n   * Index 45: or-wfhdc-p2_28\n   */\n  orwfhdcp228 = (): string | undefined => {\n    return undefined\n  }\n\n  f45 = (): string | undefined => this.orwfhdcp228()\n\n  /**\n   * Index 46: or-wfhdc-p2_29\n   */\n  orwfhdcp229 = (): string | undefined => {\n    return undefined\n  }\n\n  f46 = (): string | undefined => this.orwfhdcp229()\n\n  /**\n   * Index 47: or-wfhdc-p4_1\n   */\n  orwfhdcp41 = (): string | undefined => {\n    return undefined\n  }\n\n  f47 = (): string | undefined => this.orwfhdcp41()\n\n  /**\n   * Index 48: or-wfhdc-p4_2\n   */\n  orwfhdcp42 = (): string | undefined => {\n    return undefined\n  }\n\n  f48 = (): string | undefined => this.orwfhdcp42()\n\n  /**\n   * Index 49: or-wfhdc-p4_3\n   */\n  orwfhdcp43 = (): string | undefined => {\n    return undefined\n  }\n\n  f49 = (): string | undefined => this.orwfhdcp43()\n\n  /**\n   * Index 50: or-wfhdc-p4_4\n   */\n  orwfhdcp44 = (): string | undefined => {\n    return undefined\n  }\n\n  f50 = (): string | undefined => this.orwfhdcp44()\n\n  /**\n   * Index 51: or-wfhdc-p4_5\n   */\n  orwfhdcp45 = (): string | undefined => {\n    return undefined\n  }\n\n  f51 = (): string | undefined => this.orwfhdcp45()\n\n  /**\n   * Index 52: or-wfhdc-p4_6\n   */\n  orwfhdcp46 = (): string | undefined => {\n    return undefined\n  }\n\n  f52 = (): string | undefined => this.orwfhdcp46()\n\n  /**\n   * Index 53: or-wfhdc-p4_7\n   */\n  orwfhdcp47 = (): string | undefined => {\n    return undefined\n  }\n\n  f53 = (): string | undefined => this.orwfhdcp47()\n\n  /**\n   * Index 54: or-wfhdc-p4_8\n   */\n  orwfhdcp48 = (): string | undefined => {\n    return undefined\n  }\n\n  f54 = (): string | undefined => this.orwfhdcp48()\n\n  /**\n   * Index 55: or-wfhdc-p5_1\n   */\n  orwfhdcp51 = (): string | undefined => {\n    return undefined\n  }\n\n  f55 = (): string | undefined => this.orwfhdcp51()\n\n  /**\n   * Index 56: or-wfhdc-p5_2\n   */\n  orwfhdcp52 = (): string | undefined => {\n    return undefined\n  }\n\n  f56 = (): string | undefined => this.orwfhdcp52()\n\n  /**\n   * Index 57: or-wfhdc-p5_3\n   */\n  orwfhdcp53 = (): string | undefined => {\n    return undefined\n  }\n\n  f57 = (): string | undefined => this.orwfhdcp53()\n\n  /**\n   * Index 58: or-wfhdc-p5_4\n   */\n  orwfhdcp54 = (): string | undefined => {\n    return undefined\n  }\n\n  f58 = (): string | undefined => this.orwfhdcp54()\n\n  /**\n   * Index 59: or-wfhdc-p5_5\n   */\n  orwfhdcp55 = (): string | undefined => {\n    return undefined\n  }\n\n  f59 = (): string | undefined => this.orwfhdcp55()\n\n  /**\n   * Index 60: or-wfhdc-p5_6\n   */\n  orwfhdcp56 = (): string | undefined => {\n    return undefined\n  }\n\n  f60 = (): string | undefined => this.orwfhdcp56()\n\n  /**\n   * Index 61: or-wfhdc-p5_7\n   */\n  orwfhdcp57 = (): string | undefined => {\n    return undefined\n  }\n\n  f61 = (): string | undefined => this.orwfhdcp57()\n\n  /**\n   * Index 62: or-wfhdc-p5_8\n   */\n  orwfhdcp58 = (): string | undefined => {\n    return undefined\n  }\n\n  f62 = (): string | undefined => this.orwfhdcp58()\n\n  /**\n   * Index 63: or-wfhdc-p5_9\n   */\n  orwfhdcp59 = (): string | undefined => {\n    return undefined\n  }\n\n  f63 = (): string | undefined => this.orwfhdcp59()\n\n  /**\n   * Index 64: or-wfhdc-p5_10\n   */\n  orwfhdcp510 = (): string | undefined => {\n    return undefined\n  }\n\n  f64 = (): string | undefined => this.orwfhdcp510()\n\n  /**\n   * Index 65: or-wfhdc-p5_11\n   */\n  orwfhdcp511 = (): string | undefined => {\n    return undefined\n  }\n\n  f65 = (): string | undefined => this.orwfhdcp511()\n\n  /**\n   * Index 66: or-wfhdc-p5_12\n   */\n  orwfhdcp512 = (): string | undefined => {\n    return undefined\n  }\n\n  f66 = (): string | undefined => this.orwfhdcp512()\n\n  /**\n   * Index 67: or-wfhdc-p5_13\n   */\n  orwfhdcp513 = (): string | undefined => {\n    return undefined\n  }\n\n  f67 = (): string | undefined => this.orwfhdcp513()\n\n  /**\n   * Index 68: Button - Clear form\n   */\n  ButtonClearform = (): string | undefined => {\n    return undefined\n  }\n\n  f68 = (): string | undefined => this.ButtonClearform()\n\n  /**\n   * Index 69: or-wfhdc-p1_19\n   */\n  orwfhdcp119 = (): string | undefined => {\n    return undefined\n  }\n\n  f69 = (): string | undefined => this.orwfhdcp119()\n\n  /**\n   * Index 70: or-wfhdc-p1_25\n   */\n  orwfhdcp125 = (): string | undefined => {\n    return undefined\n  }\n\n  f70 = (): string | undefined => this.orwfhdcp125()\n\n  /**\n   * Index 71: or-wfhdc-p2_13\n   */\n  orwfhdcp213 = (): string | undefined => {\n    return undefined\n  }\n\n  f71 = (): string | undefined => this.orwfhdcp213()\n\n  /**\n   * Index 72: or-wfhdc-p2_27\n   */\n  orwfhdcp227 = (): string | undefined => {\n    return undefined\n  }\n\n  f72 = (): string | undefined => this.orwfhdcp227()\n\n  /**\n   * Index 73: or-wfhdc-p2_7\n   */\n  orwfhdcp27 = (): string | undefined => {\n    return undefined\n  }\n\n  f73 = (): string | undefined => this.orwfhdcp27()\n\n  /**\n   * Index 74: or-wfhdc-p3_1\n   */\n  orwfhdcp31 = (): string | undefined => {\n    return undefined\n  }\n\n  f74 = (): string | undefined => this.orwfhdcp31()\n\n  /**\n   * Index 75: or-wfhdc-p3_2\n   */\n  orwfhdcp32 = (): string | undefined => {\n    return undefined\n  }\n\n  f75 = (): string | undefined => this.orwfhdcp32()\n\n  /**\n   * Index 76: or-wfhdc-p3_3\n   */\n  orwfhdcp33 = (): string | undefined => {\n    return undefined\n  }\n\n  f76 = (): string | undefined => this.orwfhdcp33()\n\n  /**\n   * Index 77: or-wfhdc-p3_4\n   */\n  orwfhdcp34 = (): string | undefined => {\n    return undefined\n  }\n\n  f77 = (): string | undefined => this.orwfhdcp34()\n\n  /**\n   * Index 78: or-wfhdc-p3_5\n   */\n  orwfhdcp35 = (): string | undefined => {\n    return undefined\n  }\n\n  f78 = (): string | undefined => this.orwfhdcp35()\n\n  /**\n   * Index 79: or-wfhdc-p3_6\n   */\n  orwfhdcp36 = (): string | undefined => {\n    return undefined\n  }\n\n  f79 = (): string | undefined => this.orwfhdcp36()\n\n  /**\n   * Index 80: or-wfhdc-p3_7\n   */\n  orwfhdcp37 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f80 = (): boolean | undefined => this.orwfhdcp37()\n\n  /**\n   * Index 81: or-wfhdc-p3_8\n   */\n  orwfhdcp38 = (): string | undefined => {\n    return undefined\n  }\n\n  f81 = (): string | undefined => this.orwfhdcp38()\n\n  /**\n   * Index 82: or-wfhdc-p3_9\n   */\n  orwfhdcp39 = (): string | undefined => {\n    return undefined\n  }\n\n  f82 = (): string | undefined => this.orwfhdcp39()\n\n  /**\n   * Index 83: or-wfhdc-p3_10\n   */\n  orwfhdcp310 = (): string | undefined => {\n    return undefined\n  }\n\n  f83 = (): string | undefined => this.orwfhdcp310()\n\n  /**\n   * Index 84: or-wfhdc-p3_11\n   */\n  orwfhdcp311 = (): string | undefined => {\n    return undefined\n  }\n\n  f84 = (): string | undefined => this.orwfhdcp311()\n\n  /**\n   * Index 85: or-wfhdc-p3_12\n   */\n  orwfhdcp312 = (): string | undefined => {\n    return undefined\n  }\n\n  f85 = (): string | undefined => this.orwfhdcp312()\n\n  /**\n   * Index 86: or-wfhdc-p3_13\n   */\n  orwfhdcp313 = (): string | undefined => {\n    return undefined\n  }\n\n  f86 = (): string | undefined => this.orwfhdcp313()\n\n  /**\n   * Index 87: or-wfhdc-p3_14\n   */\n  orwfhdcp314 = (): string | undefined => {\n    return undefined\n  }\n\n  f87 = (): string | undefined => this.orwfhdcp314()\n\n  /**\n   * Index 88: or-wfhdc-p3_16\n   */\n  orwfhdcp316 = (): string | undefined => {\n    return undefined\n  }\n\n  f88 = (): string | undefined => this.orwfhdcp316()\n\n  /**\n   * Index 89: or-wfhdc-p3_17\n   */\n  orwfhdcp317 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f89 = (): boolean | undefined => this.orwfhdcp317()\n\n  /**\n   * Index 90: or-wfhdc-p3_18\n   */\n  orwfhdcp318 = (): string | undefined => {\n    return undefined\n  }\n\n  f90 = (): string | undefined => this.orwfhdcp318()\n\n  /**\n   * Index 91: or-wfhdc-p3_19\n   */\n  orwfhdcp319 = (): string | undefined => {\n    return undefined\n  }\n\n  f91 = (): string | undefined => this.orwfhdcp319()\n\n  /**\n   * Index 92: or-wfhdc-p3_20\n   */\n  orwfhdcp320 = (): string | undefined => {\n    return undefined\n  }\n\n  f92 = (): string | undefined => this.orwfhdcp320()\n\n  /**\n   * Index 93: or-wfhdc-p3_21\n   */\n  orwfhdcp321 = (): string | undefined => {\n    return undefined\n  }\n\n  f93 = (): string | undefined => this.orwfhdcp321()\n\n  /**\n   * Index 94: or-wfhdc-p3_22\n   */\n  orwfhdcp322 = (): string | undefined => {\n    return undefined\n  }\n\n  f94 = (): string | undefined => this.orwfhdcp322()\n\n  /**\n   * Index 95: or-wfhdc-p3_23\n   */\n  orwfhdcp323 = (): string | undefined => {\n    return undefined\n  }\n\n  f95 = (): string | undefined => this.orwfhdcp323()\n\n  /**\n   * Index 96: or-wfhdc-p3_24\n   */\n  orwfhdcp324 = (): string | undefined => {\n    return undefined\n  }\n\n  f96 = (): string | undefined => this.orwfhdcp324()\n\n  /**\n   * Index 97: or-wfhdc-p3_26\n   */\n  orwfhdcp326 = (): string | undefined => {\n    return undefined\n  }\n\n  f97 = (): string | undefined => this.orwfhdcp326()\n\n  /**\n   * Index 98: or-wfhdc-p3_27\n   */\n  orwfhdcp327 = (): boolean | undefined => {\n    return undefined\n  }\n\n  f98 = (): boolean | undefined => this.orwfhdcp327()\n\n  /**\n   * Index 99: or-wfhdc-p3_28\n   */\n  orwfhdcp328 = (): string | undefined => {\n    return undefined\n  }\n\n  f99 = (): string | undefined => this.orwfhdcp328()\n\n  /**\n   * Index 100: or-wfhdc-p3_29\n   */\n  orwfhdcp329 = (): string | undefined => {\n    return undefined\n  }\n\n  f100 = (): string | undefined => this.orwfhdcp329()\n\n  /**\n   * Index 101: or-wfhdc-p3_30\n   */\n  orwfhdcp330 = (): string | undefined => {\n    return undefined\n  }\n\n  f101 = (): string | undefined => this.orwfhdcp330()\n\n  /**\n   * Index 102: or-wfhdc-p3_15\n   */\n  orwfhdcp315 = (): string | undefined => {\n    return undefined\n  }\n\n  f102 = (): string | undefined => this.orwfhdcp315()\n\n  /**\n   * Index 103: or-wfhdc-p3_25\n   */\n  orwfhdcp325 = (): string | undefined => {\n    return undefined\n  }\n\n  f103 = (): string | undefined => this.orwfhdcp325()\n\n  /**\n   * Index 104: or-wfhdc-p1_20a\n   */\n  orwfhdcp120a = (): string | undefined => {\n    return undefined\n  }\n\n  f104 = (): string | undefined => this.orwfhdcp120a()\n\n  /**\n   * Index 105: or-wfhdc-p1_20b\n   */\n  orwfhdcp120b = (): string | undefined => {\n    return undefined\n  }\n\n  f105 = (): string | undefined => this.orwfhdcp120b()\n\n  /**\n   * Index 106: or-wfhdc-p2_8a\n   */\n  orwfhdcp28a = (): string | undefined => {\n    return undefined\n  }\n\n  f106 = (): string | undefined => this.orwfhdcp28a()\n\n  /**\n   * Index 107: or-wfhdc-p2_8b\n   */\n  orwfhdcp28b = (): string | undefined => {\n    return undefined\n  }\n\n  f107 = (): string | undefined => this.orwfhdcp28b()\n\n  /**\n   * Index 108: or-wfhdc-p2_22a\n   */\n  orwfhdcp222a = (): string | undefined => {\n    return undefined\n  }\n\n  f108 = (): string | undefined => this.orwfhdcp222a()\n\n  /**\n   * Index 109: or-wfhdc-p2_22b\n   */\n  orwfhdcp222b = (): string | undefined => {\n    return undefined\n  }\n\n  f109 = (): string | undefined => this.orwfhdcp222b()\n\n  fields = (): Field[] => [\n    this.f0(),\n    this.f1(),\n    this.f2(),\n    this.f3(),\n    this.f4(),\n    this.f5(),\n    this.f6(),\n    this.f7(),\n    this.f8(),\n    this.f9(),\n    this.f10(),\n    this.f11(),\n    this.f12(),\n    this.f13(),\n    this.f14(),\n    this.f15(),\n    this.f16(),\n    this.f17(),\n    this.f18(),\n    this.f19(),\n    this.f20(),\n    this.f21(),\n    this.f22(),\n    this.f23(),\n    this.f24(),\n    this.f25(),\n    this.f26(),\n    this.f27(),\n    this.f28(),\n    this.f29(),\n    this.f30(),\n    this.f31(),\n    this.f32(),\n    this.f33(),\n    this.f34(),\n    this.f35(),\n    this.f36(),\n    this.f37(),\n    this.f38(),\n    this.f39(),\n    this.f40(),\n    this.f41(),\n    this.f42(),\n    this.f43(),\n    this.f44(),\n    this.f45(),\n    this.f46(),\n    this.f47(),\n    this.f48(),\n    this.f49(),\n    this.f50(),\n    this.f51(),\n    this.f52(),\n    this.f53(),\n    this.f54(),\n    this.f55(),\n    this.f56(),\n    this.f57(),\n    this.f58(),\n    this.f59(),\n    this.f60(),\n    this.f61(),\n    this.f62(),\n    this.f63(),\n    this.f64(),\n    this.f65(),\n    this.f66(),\n    this.f67(),\n    this.f68(),\n    this.f69(),\n    this.f70(),\n    this.f71(),\n    this.f72(),\n    this.f73(),\n    this.f74(),\n    this.f75(),\n    this.f76(),\n    this.f77(),\n    this.f78(),\n    this.f79(),\n    this.f80(),\n    this.f81(),\n    this.f82(),\n    this.f83(),\n    this.f84(),\n    this.f85(),\n    this.f86(),\n    this.f87(),\n    this.f88(),\n    this.f89(),\n    this.f90(),\n    this.f91(),\n    this.f92(),\n    this.f93(),\n    this.f94(),\n    this.f95(),\n    this.f96(),\n    this.f97(),\n    this.f98(),\n    this.f99(),\n    this.f100(),\n    this.f101(),\n    this.f102(),\n    this.f103(),\n    this.f104(),\n    this.f105(),\n    this.f106(),\n    this.f107(),\n    this.f108(),\n    this.f109()\n  ]\n}\n\nconst makeORWFHDC = (f1040: F1040): ORWFHDC => new ORWFHDC(f1040)\n\nexport default makeORWFHDC\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/OR/Parameters.ts",
    "content": "// import { FilingStatus } from 'ustaxes/core/data'\n\nconst parameters = {\n  // exemptions: {\n  //   [FilingStatus.S]: {\n  //     incomeLowerLimit: 2325,\n  //     incomeUpperLimit: 250000,\n  //     exemptionAmount: 2325\n  //   },\n  //   [FilingStatus.MFJ]: {\n  //     incomeLowerLimit: 4650,\n  //     incomeUpperLimit: 500000,\n  //     exemptionAmount: 4650\n  //   }\n  // },\n  // taxRate: 0.0495,\n  // seniorExemption: 1000,\n  // blindExemption: 1000,\n  // earnedIncomeCreditFactor: 0.18,\n  // eicDependentCredit: 2325\n}\n\nexport default parameters\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/PA/Form.ts",
    "content": "export default class PAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/RI/Form.ts",
    "content": "export default class RIForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/SC/Form.ts",
    "content": "export default class SCForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/SD/Form.ts",
    "content": "export default class SDForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/TN/Form.ts",
    "content": "export default class TNForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/TX/Form.ts",
    "content": "export default class TXForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/UT/Form.ts",
    "content": "export default class UTForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/VA/Form.ts",
    "content": "export default class VAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/VT/Form.ts",
    "content": "export default class VTForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/WA/Form.ts",
    "content": "export default class WAForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/WI/Form.ts",
    "content": "export default class WIForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/WV/Form.ts",
    "content": "export default class WVForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/WY/Form.ts",
    "content": "export default class WYForm {}\n"
  },
  {
    "path": "src/forms/Y2021/stateForms/index.ts",
    "content": "import F1040 from '../irsForms/F1040'\nimport { State } from 'ustaxes/core/data'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport il1040 from './IL/IL1040'\nimport { Either } from 'ustaxes/core/util'\nimport { createStateReturn as createStateReturnF } from '../../StateForms'\nimport { StateFormError } from '../../StateForms'\n\nexport const noFilingRequirementStates: State[] = [\n  'AK',\n  'TN',\n  'WY',\n  'FL',\n  'NH',\n  'SD',\n  'TX',\n  'WA',\n  'NV'\n]\n\nexport const stateForms: {\n  [K in State]?: (f1040: F1040) => StateForm\n} = {\n  IL: il1040\n}\n\nexport const createStateReturn = (\n  f1040: F1040\n): Either<StateFormError[], StateForm[]> =>\n  createStateReturnF<F1040>(noFilingRequirementStates, stateForms)(f1040)\n"
  },
  {
    "path": "src/forms/Y2021/tests/Schedule8812.test.ts",
    "content": "import { commonTests } from '.'\nimport Schedule8812 from '../irsForms/Schedule8812'\nimport F1040 from '../irsForms/F1040'\n\nconst withSchedule8812 = async (\n  f: (f1040: F1040, s8812: Schedule8812) => void\n): Promise<void> =>\n  await commonTests.withValid1040(\n    (f1040: F1040): void => {\n      if (f1040.schedule8812.isNeeded()) {\n        f(f1040, f1040.schedule8812)\n      }\n    },\n    // Add filter to info property so we're only testing in the domain\n    // we care about.\n    (info) => info.taxPayer.dependents.length > 0\n  )\n\ndescribe('Schedule 8812', () => {\n  it('should be attached with qualifiying dependents', async () => {\n    await commonTests.withValid1040((f1040) => {\n      // If there are qualifying dependents, we must have a schedule 8812\n      if (f1040.qualifyingDependents.qualifyingChildren().length > 0) {\n        expect(f1040.schedule8812).not.toBe(undefined)\n      }\n    })\n  })\n\n  it('should not produce line 5 with no dependents', async () => {\n    await withSchedule8812((f1040, s8812) => {\n      // If Schedule A is attached, the deduction should be greater than the standard deduction\n      if (s8812.l4a() === 0) {\n        expect(s8812.l5()).toEqual(0)\n      }\n    })\n  })\n\n  it('should show a multiple of 1000 at l10', async () => {\n    await withSchedule8812((f1040, s8812) => {\n      expect(s8812.l10() % 1000).toEqual(0)\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/ScheduleA.test.ts",
    "content": "import { commonTests } from '.'\nimport * as fc from 'fast-check'\n\ndescribe('ScheduleA', () => {\n  it('should make deduction > standard deduction if Schedule A is attached', async () => {\n    await commonTests.withValid1040((f1040) => {\n      // If Schedule A is attached, the deduction should be greater than the standard deduction\n      // Cancel test if Schedule A is not attached\n      fc.pre(f1040.scheduleA.isNeeded())\n\n      expect(f1040.l12a() ?? 0).toBeGreaterThan(f1040.standardDeduction() ?? 0)\n    })\n  })\n\n  it('should be attached if deduction is more than standard', async () => {\n    await commonTests.withValid1040((f1040) => {\n      const standardDeduction = f1040.standardDeduction() ?? 0\n\n      // If the deduction is more than standard, we must have a schedule A\n      // Note dependents of other taxpayers may still itemize.\n      if ((f1040.l12a() ?? 0) > standardDeduction) {\n        expect(f1040.scheduleA).not.toBe(undefined)\n      }\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/ScheduleD.test.ts",
    "content": "import * as fc from 'fast-check'\nimport { testKit, commonTests } from '.'\n\ndescribe('ScheduleD', () => {\n  it('should never pass through more than allowed losses', async () => {\n    await fc.assert(\n      testKit.with1040Property((forms): Promise<void> => {\n        const f1040 = commonTests.findF1040OrFail(forms)\n        if (f1040.scheduleD.isNeeded()) {\n          expect(Math.round(f1040.l7() ?? 0)).toBeGreaterThanOrEqual(\n            -f1040.scheduleD.l21Min()\n          )\n        }\n        return Promise.resolve()\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/ScheduleEIC.test.ts",
    "content": "/* eslint @typescript-eslint/no-empty-function: \"off\" */\n\nimport * as federal from '../data/federal'\nimport { testKit, commonTests } from '.'\n\nbeforeAll(() => jest.spyOn(console, 'warn').mockImplementation(() => {}))\n\ndescribe('ScheduleEIC', () => {\n  it('should disallow EIC for income below threshold', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      const formula = federal.EIC.formulas[f1040.info.taxPayer.filingStatus]\n      if (formula !== undefined && f1040.wages() < formula[0][1].lowerBound) {\n        expect(f1040.scheduleEIC.allowed()).toBe(false)\n        expect(f1040.scheduleEIC.credit()).toBe(0)\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/f1040.test.ts",
    "content": "import { displayRound } from 'ustaxes/core/irsForms/util'\nimport { commonTests, testKit } from '.'\n\njest.setTimeout(40000)\n\nbeforeAll(() => {\n  jest.spyOn(console, 'warn').mockImplementation((x: string) => {\n    if (!x.includes('Removing XFA form data as pdf-lib')) {\n      console.warn(x)\n    }\n  })\n})\n\ndescribe('f1040', () => {\n  commonTests.run()\n\n  it('should never have higher AGI than total income', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040(forms)\n      expect(f1040).not.toBeUndefined()\n      if (f1040 !== undefined) {\n        expect(displayRound(f1040.l11()) ?? 0).toBeLessThanOrEqual(\n          // It is possible for losses to create negative income.\n          displayRound(Math.max(0, f1040.l9())) ?? 0\n        )\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should never produce higher tax than total income', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040(forms)\n      expect(f1040).not.toBeUndefined()\n      if (f1040 !== undefined) {\n        // Remove line 7 for AMT\n        expect(\n          displayRound(f1040.l24() - (f1040.l17() ?? 0)) ?? 0\n        ).toBeLessThanOrEqual(displayRound(Math.max(0, f1040.l9())) ?? 0)\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should never produce tax on taxable income higher than income', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040(forms)\n      expect(f1040).not.toBeUndefined()\n      if (f1040 !== undefined) {\n        // tax on taxable income should be less than taxable income\n        if (f1040.l15() > 0) {\n          expect(f1040.l16() ?? 0).toBeLessThan(f1040.l15())\n        } else {\n          expect(f1040.l16() ?? 0).toEqual(0)\n        }\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/f6251.test.ts",
    "content": "/* eslint @typescript-eslint/no-empty-function: \"off\" */\n\nimport { FilingStatus, PersonRole } from 'ustaxes/core/data'\nimport F1040 from '../irsForms/F1040'\nimport F6251 from '../irsForms/F6251'\nimport { cloneDeep } from 'lodash'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\n\nconst baseInformation: ValidatedInformation = {\n  f1099s: [],\n  f3921s: [\n    {\n      name: 'Stock Option',\n      personRole: PersonRole.PRIMARY,\n      exercisePricePerShare: 1,\n      fmv: 101,\n      numShares: 1000\n    }\n  ],\n  credits: [],\n  scheduleK1Form1065s: [],\n  itemizedDeductions: undefined,\n  w2s: [\n    {\n      employer: { EIN: '111111111', employerName: 'w2s employer name' },\n      personRole: PersonRole.PRIMARY,\n      occupation: 'w2s-occupation',\n      state: 'AL',\n      income: 100000,\n      medicareIncome: 0,\n      fedWithholding: 0,\n      ssWages: 100000,\n      ssWithholding: 0,\n      medicareWithholding: 0,\n      stateWages: 100000,\n      stateWithholding: 0\n    }\n  ],\n  estimatedTaxes: [],\n  realEstate: [],\n  taxPayer: {\n    primaryPerson: {\n      address: {\n        address: '0001',\n        aptNo: '',\n        city: 'AR city',\n        state: 'AR',\n        zip: '1234567'\n      },\n      firstName: 'payer-first-name',\n      lastName: 'payer-last-name',\n      isTaxpayerDependent: false,\n      role: PersonRole.PRIMARY,\n      ssid: '111111111'\n    },\n    spouse: undefined,\n    dependents: [],\n    filingStatus: FilingStatus.S\n  },\n  questions: {},\n  f1098es: [],\n  stateResidencies: [{ state: 'AL' }],\n  healthSavingsAccounts: [],\n  individualRetirementArrangements: []\n}\n\ndescribe('AMT', () => {\n  it('stock options should trigger AMT', () => {\n    const information = cloneDeep(baseInformation)\n    const f1040 = new F1040(information, [])\n    const f6251 = new F6251(f1040)\n    expect(f6251.isNeeded()).toEqual(true)\n    expect(Math.round(f6251.l1() ?? 0)).toEqual(87450)\n    expect(Math.round(f6251.l7() ?? 0)).toEqual(32864)\n    expect(Math.round(f6251.l10())).toEqual(15015)\n    expect(Math.round(f6251.l11())).toEqual(17849)\n  })\n\n  it('small stock options should NOT trigger AMT', () => {\n    const information = cloneDeep(baseInformation)\n    information.f3921s[0].exercisePricePerShare = 100\n\n    const f1040 = new F1040(information, [])\n    const f6251 = new F6251(f1040)\n    expect(f6251.isNeeded()).toEqual(false)\n    expect(Math.round(f6251.l1() ?? 0)).toEqual(87450)\n    expect(Math.round(f6251.l7() ?? 0)).toEqual(7124)\n    expect(Math.round(f6251.l10())).toEqual(15015)\n    expect(Math.round(f6251.l11())).toEqual(0)\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/fica.test.ts",
    "content": "import { fica } from '../data/federal'\nimport F1040 from '../irsForms/F1040'\nimport F8959 from '../irsForms/F8959'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport Schedule2 from '../irsForms/Schedule2'\nimport Schedule3 from '../irsForms/Schedule3'\nimport { displayRound } from 'ustaxes/core/irsForms/util'\nimport { testKit, commonTests } from '.'\nimport { FilingStatus, IncomeW2, PersonRole } from 'ustaxes/core/data'\nimport { run } from 'ustaxes/core/util'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport { ValidatedInformation } from 'ustaxes/forms/F1040Base'\nimport * as fc from 'fast-check'\n\njest.setTimeout(10000)\n\nbeforeAll(() => {\n  jest.spyOn(console, 'warn').mockImplementation(() => {\n    // do nothing\n  })\n})\n\nconst sampleW2: IncomeW2 = {\n  employer: { EIN: '111111111', employerName: 'w2s employer name' },\n  personRole: PersonRole.PRIMARY,\n  occupation: 'w2s-occupation',\n  state: 'AL',\n  income: 111,\n  medicareIncome: 222,\n  fedWithholding: 333,\n  ssWages: 111,\n  ssWithholding: fica.maxSSTax,\n  medicareWithholding: 555,\n  stateWages: 666,\n  stateWithholding: 777\n}\n\nconst sampleInfo: ValidatedInformation = {\n  ...blankState,\n  taxPayer: {\n    dependents: [],\n    filingStatus: FilingStatus.MFJ,\n    primaryPerson: {\n      address: {\n        address: '',\n        city: ''\n      },\n      firstName: '',\n      isTaxpayerDependent: false,\n      lastName: '',\n      role: PersonRole.PRIMARY,\n      ssid: '',\n      isBlind: false,\n      dateOfBirth: new Date('2000-01-01')\n    },\n    spouse: {\n      firstName: '',\n      isTaxpayerDependent: false,\n      lastName: '',\n      role: PersonRole.SPOUSE,\n      ssid: '',\n      isBlind: false,\n      dateOfBirth: new Date('2000-01-01')\n    }\n  }\n}\n\nconst hasSSRefund = (f1040: F1040): boolean => f1040.schedule3.l11() > 0\n\nfunction hasAdditionalMedicareTax(f1040: F1040): boolean {\n  const medicareTax = f1040.f8959.l18()\n  return medicareTax > 0\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype Constructor<T> = new (...args: any[]) => T\nfunction hasAttachment<FormType>(\n  attachments: Form[],\n  formType: Constructor<FormType>\n): boolean {\n  return (\n    attachments.find((f) => {\n      return f instanceof formType\n    }) !== undefined\n  )\n}\n\ndescribe('fica', () => {\n  it('should give refund SS tax overpayment only in some conditions', async () => {\n    await testKit.with1040Assert((forms) => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      if (f1040.validW2s().length <= 1) {\n        // Should never give SS refund with 1 or fewer W2s\n        expect(hasSSRefund(f1040)).toEqual(false)\n      } else {\n        const ssWithheld = f1040\n          .validW2s()\n          .map((w2) => w2.ssWithholding)\n          .reduce((l, r) => l + r, 0)\n        if (\n          f1040.wages() <= fica.maxIncomeSSTaxApplies ||\n          f1040.validW2s().some((w2) => w2.ssWithholding > fica.maxSSTax) ||\n          ssWithheld < fica.maxSSTax\n        ) {\n          // Should never give SS refund if W2 income below max threshold, some W2 has\n          // withheld over the max, or there is no SS withholding to refund.\n          expect(hasSSRefund(f1040)).toEqual(false)\n        } else {\n          // Otherwise, should always give SS refund, and attach schedule 3\n          expect(hasSSRefund(f1040)).toEqual(true)\n          expect(hasAttachment(forms, Schedule3)).toEqual(true)\n        }\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should give SS refund based on filing status', async () => {\n    await testKit.with1040Assert((forms) => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      if (hasSSRefund(f1040)) {\n        const ssRefund = f1040.schedule3.l11()\n        expect(displayRound(ssRefund)).not.toBeUndefined()\n        expect(ssRefund).toBeGreaterThan(0)\n\n        const ssWithheld =\n          f1040\n            .validW2s()\n            .filter((w2) => w2.personRole == PersonRole.PRIMARY)\n            .map((w2) => w2.ssWithholding)\n            .reduce((l, r) => l + r, 0) +\n          f1040\n            .validW2s()\n            .filter((w2) => w2.personRole == PersonRole.SPOUSE)\n            .map((w2) => w2.ssWithholding)\n            .reduce((l, r) => l + r, 0)\n\n        expect(ssRefund).toEqual(ssWithheld - fica.maxSSTax)\n      } else {\n        fc.pre(false)\n      }\n\n      return Promise.resolve()\n    })\n  })\n\n  it('should not give a refund if each person has less than the max', () => {\n    const testInfo: ValidatedInformation = {\n      ...sampleInfo,\n      w2s: [\n        {\n          ...sampleW2,\n          personRole: PersonRole.SPOUSE,\n          ssWithholding: fica.maxSSTax\n        },\n        {\n          ...sampleW2,\n          personRole: PersonRole.PRIMARY,\n          ssWithholding: fica.maxSSTax\n        }\n      ]\n    }\n\n    const f1040 = run(testKit.builder.build(testInfo, []).f1040())\n      .map(commonTests.findF1040OrFail)\n      .orThrow()\n\n    expect(f1040.schedule3.claimableExcessSSTaxWithholding()).toEqual(0)\n  })\n\n  it('should give a refund if a person has more than the max if they have two w2s', () => {\n    const testInfo: ValidatedInformation = {\n      ...sampleInfo,\n      w2s: [\n        {\n          ...sampleW2,\n          personRole: PersonRole.SPOUSE,\n          ssWithholding: fica.maxSSTax\n        },\n        {\n          ...sampleW2,\n          personRole: PersonRole.SPOUSE,\n          // This person has already contributed to the max for their other w2 so the refund should equal this amount\n          ssWithholding: 1000\n        },\n        {\n          ...sampleW2,\n          personRole: PersonRole.PRIMARY,\n          ssWithholding: fica.maxSSTax\n        }\n      ]\n    }\n\n    const f1040 = run(testKit.builder.build(testInfo, []).f1040())\n      .map(commonTests.findF1040OrFail)\n      .orThrow()\n    expect(f1040.schedule3.claimableExcessSSTaxWithholding()).toEqual(1000)\n  })\n\n  it('should add Additional Medicare Tax form 8959', async () => {\n    await testKit.with1040Assert((forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      const filingStatus = f1040.info.taxPayer.filingStatus\n      // Should add Additional Medicare Tax if medicare wages over threshold\n      if (\n        f1040.medicareWages() >\n        fica.additionalMedicareTaxThreshold(filingStatus)\n      ) {\n        expect(hasAdditionalMedicareTax(f1040)).toEqual(true)\n\n        // Should attach both S2 and F8959 to return\n        expect(hasAttachment(forms, Schedule2)).toEqual(true)\n        expect(hasAttachment(forms, F8959)).toEqual(true)\n      } else {\n        const selfEmploymentWages = f1040.scheduleSE.l6() ?? 0\n        const hasTax =\n          f1040.medicareWages() + selfEmploymentWages >\n          fica.additionalMedicareTaxThreshold(filingStatus)\n        expect(hasAdditionalMedicareTax(f1040)).toEqual(hasTax)\n        expect(hasAttachment(forms, F8959)).toEqual(hasTax)\n      }\n      return Promise.resolve()\n    })\n  })\n\n  it('should add Additional Medicare Tax based on filing status', async () => {\n    await testKit.with1040Assert(async (forms): Promise<void> => {\n      const f1040 = commonTests.findF1040OrFail(forms)\n      if (hasAdditionalMedicareTax(f1040)) {\n        const filingStatus = f1040.info.taxPayer.filingStatus\n        const selfEmploymentWages = f1040.scheduleSE.l6() ?? 0\n        const incomeOverThreshold =\n          f1040.medicareWages() +\n          selfEmploymentWages -\n          fica.additionalMedicareTaxThreshold(filingStatus)\n        expect(incomeOverThreshold).toBeGreaterThan(0)\n\n        // Adds the right amount of additional tax\n        const s2l8 = f1040.f8959.l18()\n        expect(s2l8).not.toBeUndefined()\n        expect(Math.round(s2l8)).toEqual(\n          Math.round(incomeOverThreshold * fica.additionalMedicareTaxRate)\n        )\n\n        // Also adds in the extra Medicare tax withheld to 1040 taxes already paid\n        const medicareWithheld = f1040\n          .validW2s()\n          .map((w2) => w2.medicareWithholding)\n          .reduce((l, r) => l + r, 0)\n\n        const regularWithholding =\n          fica.regularMedicareTaxRate * f1040.medicareWages()\n\n        if (medicareWithheld > regularWithholding) {\n          const f1040l25c = f1040.l25c()\n          expect(f1040l25c).not.toBeUndefined()\n          const additionalWithheld = medicareWithheld - regularWithholding\n          expect(displayRound(f1040l25c)).toEqual(\n            displayRound(additionalWithheld)\n          )\n        } else {\n          expect(displayRound(f1040.l25c()) ?? 0).toEqual(0)\n        }\n      }\n      return Promise.resolve()\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/index.ts",
    "content": "import CommonTests, { FormTestInfo } from 'ustaxes/forms/tests/CommonTests'\nimport TestKit from 'ustaxes/forms/tests/TestKit'\nimport F1040 from '../irsForms/F1040'\n\nexport const testKit = new TestKit('Y2021')\n\nclass FormTestInfo2021 extends FormTestInfo<F1040> {\n  getAssets = (f1040: F1040) => f1040.assets\n  getInfo = (f1040: F1040) => f1040.info\n}\n\nexport const commonTests = new CommonTests<F1040>(\n  testKit,\n  new FormTestInfo2021()\n)\n"
  },
  {
    "path": "src/forms/Y2021/tests/states/il.test.ts",
    "content": "import * as fc from 'fast-check'\nimport F1040 from '../../irsForms/F1040'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { create1040 } from '../../irsForms/Main'\nimport { Information, PersonRole } from 'ustaxes/core/data'\nimport { createStateReturn } from '../../stateForms'\nimport { ILWIT } from '../../stateForms/IL/ILWit'\nimport { isLeft } from 'ustaxes/core/util'\nimport StateForm from 'ustaxes/core/stateForms/Form'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport { fail } from 'assert'\n\nconst withStateReturn = (\n  info: Information,\n  logContext: fc.ContextValue,\n  test: (f1040Forms: [F1040, Form[]], stateForms: StateForm[]) => void\n): void => {\n  const f1040Result = create1040(info, [])\n\n  if (isLeft(f1040Result)) {\n    // ignore error infos with no 1040\n    logContext.log(f1040Result.left.join(';'))\n    return\n  }\n\n  const [f1040] = f1040Result.right\n  const stateReturn = createStateReturn(f1040)\n  if (isLeft(stateReturn)) {\n    fail(stateReturn.left.join(';'))\n  }\n\n  test(f1040Result.right, stateReturn.right)\n}\n\nconst A = new arbitraries.Arbitraries(2020)\n\ndescribe('il year 2020', () => {\n  it('should produce correct withholding attachments in', () => {\n    fc.assert(\n      fc.property(A.information(), fc.context(), (info, ctx) => {\n        info.stateResidencies = [{ state: 'IL' }]\n        info.w2s.forEach((w2) => {\n          w2.state = 'IL'\n        })\n        withStateReturn(info, ctx, (_, stateForms) => {\n          ctx.log(stateForms.map((f) => f.formName).join(';'))\n          expect(stateForms.filter((f) => f.formName === 'IL-WIT').length).toBe(\n            Math.ceil(\n              Math.max(\n                ...[PersonRole.PRIMARY, PersonRole.SPOUSE].map(\n                  (r) =>\n                    info.w2s.filter(\n                      (w2) =>\n                        w2.personRole === r && (w2.stateWithholding ?? 0) > 0\n                    ).length\n                )\n              ) / ILWIT.WITHHOLDING_FORMS_PER_PAGE\n            )\n          )\n        })\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/taxRates.test.ts",
    "content": "import { FilingStatus } from 'ustaxes/core/data'\nimport { CURRENT_YEAR } from '../data/federal'\nimport { computeOrdinaryTax } from '../irsForms/TaxTable'\nimport fs from 'fs/promises'\nimport { parseCsvOrThrow } from 'ustaxes/data/csvImport'\n\nconst getTaxTable = async (): Promise<number[][]> => {\n  const path = './src/forms/Y2021/tests/taxTable.csv'\n  const taxTableCsv = (await fs.readFile(path)).toString('utf-8')\n  return parseCsvOrThrow(taxTableCsv, (r: string[], rowNum) =>\n    // ignore heading row.\n    rowNum > 0 ? [r.map((s) => Number(s))] : []\n  )\n}\n\nconst expectTax = (status: FilingStatus, amount: number, tax: number) => {\n  const computedTax = Math.round(computeOrdinaryTax(status, amount))\n  expect(computedTax).toEqual(tax)\n}\n\nconst expectTaxUnder100KRange = (\n  status: FilingStatus,\n  min: number,\n  max: number,\n  tax: number\n) => {\n  const diff = max - min\n  const quarter = Math.round((diff / 4) * 100) / 100\n  expectTax(status, min, tax)\n  expectTax(status, min + quarter, tax)\n  expectTax(status, min + 2 * quarter, tax)\n  expectTax(status, min + 3 * quarter, tax)\n  expectTax(status, max, tax)\n}\n\ndescribe('Tax rates', () => {\n  it('test should be updated for new year', () => {\n    // WARNING! Do not just change the year. Also update the CSV and expected tax amounts below!\n    expect(CURRENT_YEAR).toEqual(2021)\n  })\n  it('ordinary taxes for single status should be correct', async () => {\n    const rows = await getTaxTable()\n    rows.forEach(([min, lessThan, tax]) => {\n      expectTaxUnder100KRange(FilingStatus.S, min, lessThan - 0.01, tax)\n    })\n\n    // Over $100,000\n    const amounts = [\n      [100000, 18021],\n      [164925, 33603],\n      [164926, 33603],\n      [209425, 47843],\n      [209426, 47843],\n      [523600, 157804],\n      [523601, 157805]\n    ]\n    amounts.forEach(([amount, tax]) => {\n      expectTax(FilingStatus.S, amount, tax)\n    })\n  })\n\n  it('ordinary taxes for married filing jointly status should be correct', async () => {\n    const rows = await getTaxTable()\n    rows.forEach(([min, lessThan, , tax]) => {\n      expectTaxUnder100KRange(FilingStatus.MFJ, min, lessThan - 0.01, tax)\n    })\n\n    // Over $100,000\n    const amounts = [\n      [100000, 13497],\n      [172750, 29502],\n      [172751, 29502],\n      [329850, 67206],\n      [329851, 67206],\n      [418850, 95686],\n      [418851, 95686],\n      [628300, 168994],\n      [628301, 168994]\n    ]\n    amounts.forEach(([amount, tax]) => {\n      expectTax(FilingStatus.MFJ, amount, tax)\n    })\n  })\n\n  it('ordinary taxes for married filing separately status should be correct', async () => {\n    const rows = await getTaxTable()\n    rows.forEach(([min, lessThan, , , tax]) => {\n      expectTaxUnder100KRange(FilingStatus.MFS, min, lessThan - 0.01, tax)\n    })\n\n    // Over $100,000\n    const amounts = [\n      [100000, 18021],\n      [164925, 33603],\n      [164926, 33603],\n      [209425, 47843],\n      [209426, 47843],\n      [314150, 84497],\n      [314151, 84497]\n    ]\n    amounts.forEach(([amount, tax]) => {\n      expectTax(FilingStatus.MFS, amount, tax)\n    })\n  })\n\n  it('ordinary taxes for head of household status should be correct', async () => {\n    const rows = await getTaxTable()\n    rows.forEach(([min, lessThan, , , , tax]) => {\n      expectTaxUnder100KRange(FilingStatus.HOH, min, lessThan - 0.01, tax)\n    })\n\n    // Over $100,000\n    const amounts = [\n      [100000, 16569],\n      [164900, 32145],\n      [164901, 32145],\n      [209400, 46385],\n      [209401, 46385],\n      [523600, 156355],\n      [523601, 156355]\n    ]\n    amounts.forEach(([amount, tax]) => {\n      expectTax(FilingStatus.HOH, amount, tax)\n    })\n  })\n})\n"
  },
  {
    "path": "src/forms/Y2021/tests/taxTable.csv",
    "content": "At Least,Less than,Single,Married Filing Jointly,Married Filing Separately,Head of Household\n0,5,0,0,0,0\n5,15,1,1,1,1\n15,25,2,2,2,2\n25,50,4,4,4,4\n50,75,6,6,6,6\n75,100,9,9,9,9\n100,125,11,11,11,11\n125,150,14,14,14,14\n150,175,16,16,16,16\n175,200,19,19,19,19\n200,225,21,21,21,21\n225,250,24,24,24,24\n250,275,26,26,26,26\n275,300,29,29,29,29\n300,325,31,31,31,31\n325,350,34,34,34,34\n350,375,36,36,36,36\n375,400,39,39,39,39\n400,425,41,41,41,41\n425,450,44,44,44,44\n450,475,46,46,46,46\n475,500,49,49,49,49\n500,525,51,51,51,51\n525,550,54,54,54,54\n550,575,56,56,56,56\n575,600,59,59,59,59\n600,625,61,61,61,61\n625,650,64,64,64,64\n650,675,66,66,66,66\n675,700,69,69,69,69\n700,725,71,71,71,71\n725,750,74,74,74,74\n750,775,76,76,76,76\n775,800,79,79,79,79\n800,825,81,81,81,81\n825,850,84,84,84,84\n850,875,86,86,86,86\n875,900,89,89,89,89\n900,925,91,91,91,91\n925,950,94,94,94,94\n950,975,96,96,96,96\n975,1000,99,99,99,99\n1000,1025,101,101,101,101\n1025,1050,104,104,104,104\n1050,1075,106,106,106,106\n1075,1100,109,109,109,109\n1100,1125,111,111,111,111\n1125,1150,114,114,114,114\n1150,1175,116,116,116,116\n1175,1200,119,119,119,119\n1200,1225,121,121,121,121\n1225,1250,124,124,124,124\n1250,1275,126,126,126,126\n1275,1300,129,129,129,129\n1300,1325,131,131,131,131\n1325,1350,134,134,134,134\n1350,1375,136,136,136,136\n1375,1400,139,139,139,139\n1400,1425,141,141,141,141\n1425,1450,144,144,144,144\n1450,1475,146,146,146,146\n1475,1500,149,149,149,149\n1500,1525,151,151,151,151\n1525,1550,154,154,154,154\n1550,1575,156,156,156,156\n1575,1600,159,159,159,159\n1600,1625,161,161,161,161\n1625,1650,164,164,164,164\n1650,1675,166,166,166,166\n1675,1700,169,169,169,169\n1700,1725,171,171,171,171\n1725,1750,174,174,174,174\n1750,1775,176,176,176,176\n1775,1800,179,179,179,179\n1800,1825,181,181,181,181\n1825,1850,184,184,184,184\n1850,1875,186,186,186,186\n1875,1900,189,189,189,189\n1900,1925,191,191,191,191\n1925,1950,194,194,194,194\n1950,1975,196,196,196,196\n1975,2000,199,199,199,199\n2000,2025,201,201,201,201\n2025,2050,204,204,204,204\n2050,2075,206,206,206,206\n2075,2100,209,209,209,209\n2100,2125,211,211,211,211\n2125,2150,214,214,214,214\n2150,2175,216,216,216,216\n2175,2200,219,219,219,219\n2200,2225,221,221,221,221\n2225,2250,224,224,224,224\n2250,2275,226,226,226,226\n2275,2300,229,229,229,229\n2300,2325,231,231,231,231\n2325,2350,234,234,234,234\n2350,2375,236,236,236,236\n2375,2400,239,239,239,239\n2400,2425,241,241,241,241\n2425,2450,244,244,244,244\n2450,2475,246,246,246,246\n2475,2500,249,249,249,249\n2500,2525,251,251,251,251\n2525,2550,254,254,254,254\n2550,2575,256,256,256,256\n2575,2600,259,259,259,259\n2600,2625,261,261,261,261\n2625,2650,264,264,264,264\n2650,2675,266,266,266,266\n2675,2700,269,269,269,269\n2700,2725,271,271,271,271\n2725,2750,274,274,274,274\n2750,2775,276,276,276,276\n2775,2800,279,279,279,279\n2800,2825,281,281,281,281\n2825,2850,284,284,284,284\n2850,2875,286,286,286,286\n2875,2900,289,289,289,289\n2900,2925,291,291,291,291\n2925,2950,294,294,294,294\n2950,2975,296,296,296,296\n2975,3000,299,299,299,299\n3000,3050,303,303,303,303\n3050,3100,308,308,308,308\n3100,3150,313,313,313,313\n3150,3200,318,318,318,318\n3200,3250,323,323,323,323\n3250,3300,328,328,328,328\n3300,3350,333,333,333,333\n3350,3400,338,338,338,338\n3400,3450,343,343,343,343\n3450,3500,348,348,348,348\n3500,3550,353,353,353,353\n3550,3600,358,358,358,358\n3600,3650,363,363,363,363\n3650,3700,368,368,368,368\n3700,3750,373,373,373,373\n3750,3800,378,378,378,378\n3800,3850,383,383,383,383\n3850,3900,388,388,388,388\n3900,3950,393,393,393,393\n3950,4000,398,398,398,398\n4000,4050,403,403,403,403\n4050,4100,408,408,408,408\n4100,4150,413,413,413,413\n4150,4200,418,418,418,418\n4200,4250,423,423,423,423\n4250,4300,428,428,428,428\n4300,4350,433,433,433,433\n4350,4400,438,438,438,438\n4400,4450,443,443,443,443\n4450,4500,448,448,448,448\n4500,4550,453,453,453,453\n4550,4600,458,458,458,458\n4600,4650,463,463,463,463\n4650,4700,468,468,468,468\n4700,4750,473,473,473,473\n4750,4800,478,478,478,478\n4800,4850,483,483,483,483\n4850,4900,488,488,488,488\n4900,4950,493,493,493,493\n4950,5000,498,498,498,498\n5000,5050,503,503,503,503\n5050,5100,508,508,508,508\n5100,5150,513,513,513,513\n5150,5200,518,518,518,518\n5200,5250,523,523,523,523\n5250,5300,528,528,528,528\n5300,5350,533,533,533,533\n5350,5400,538,538,538,538\n5400,5450,543,543,543,543\n5450,5500,548,548,548,548\n5500,5550,553,553,553,553\n5550,5600,558,558,558,558\n5600,5650,563,563,563,563\n5650,5700,568,568,568,568\n5700,5750,573,573,573,573\n5750,5800,578,578,578,578\n5800,5850,583,583,583,583\n5850,5900,588,588,588,588\n5900,5950,593,593,593,593\n5950,6000,598,598,598,598\n6000,6050,603,603,603,603\n6050,6100,608,608,608,608\n6100,6150,613,613,613,613\n6150,6200,618,618,618,618\n6200,6250,623,623,623,623\n6250,6300,628,628,628,628\n6300,6350,633,633,633,633\n6350,6400,638,638,638,638\n6400,6450,643,643,643,643\n6450,6500,648,648,648,648\n6500,6550,653,653,653,653\n6550,6600,658,658,658,658\n6600,6650,663,663,663,663\n6650,6700,668,668,668,668\n6700,6750,673,673,673,673\n6750,6800,678,678,678,678\n6800,6850,683,683,683,683\n6850,6900,688,688,688,688\n6900,6950,693,693,693,693\n6950,7000,698,698,698,698\n7000,7050,703,703,703,703\n7050,7100,708,708,708,708\n7100,7150,713,713,713,713\n7150,7200,718,718,718,718\n7200,7250,723,723,723,723\n7250,7300,728,728,728,728\n7300,7350,733,733,733,733\n7350,7400,738,738,738,738\n7400,7450,743,743,743,743\n7450,7500,748,748,748,748\n7500,7550,753,753,753,753\n7550,7600,758,758,758,758\n7600,7650,763,763,763,763\n7650,7700,768,768,768,768\n7700,7750,773,773,773,773\n7750,7800,778,778,778,778\n7800,7850,783,783,783,783\n7850,7900,788,788,788,788\n7900,7950,793,793,793,793\n7950,8000,798,798,798,798\n8000,8050,803,803,803,803\n8050,8100,808,808,808,808\n8100,8150,813,813,813,813\n8150,8200,818,818,818,818\n8200,8250,823,823,823,823\n8250,8300,828,828,828,828\n8300,8350,833,833,833,833\n8350,8400,838,838,838,838\n8400,8450,843,843,843,843\n8450,8500,848,848,848,848\n8500,8550,853,853,853,853\n8550,8600,858,858,858,858\n8600,8650,863,863,863,863\n8650,8700,868,868,868,868\n8700,8750,873,873,873,873\n8750,8800,878,878,878,878\n8800,8850,883,883,883,883\n8850,8900,888,888,888,888\n8900,8950,893,893,893,893\n8950,9000,898,898,898,898\n9000,9050,903,903,903,903\n9050,9100,908,908,908,908\n9100,9150,913,913,913,913\n9150,9200,918,918,918,918\n9200,9250,923,923,923,923\n9250,9300,928,928,928,928\n9300,9350,933,933,933,933\n9350,9400,938,938,938,938\n9400,9450,943,943,943,943\n9450,9500,948,948,948,948\n9500,9550,953,953,953,953\n9550,9600,958,958,958,958\n9600,9650,963,963,963,963\n9650,9700,968,968,968,968\n9700,9750,973,973,973,973\n9750,9800,978,978,978,978\n9800,9850,983,983,983,983\n9850,9900,988,988,988,988\n9900,9950,993,993,993,993\n9950,10000,998,998,998,998\n10000,10050,1004,1003,1004,1003\n10050,10100,1010,1008,1010,1008\n10100,10150,1016,1013,1016,1013\n10150,10200,1022,1018,1022,1018\n10200,10250,1028,1023,1028,1023\n10250,10300,1034,1028,1034,1028\n10300,10350,1040,1033,1040,1033\n10350,10400,1046,1038,1046,1038\n10400,10450,1052,1043,1052,1043\n10450,10500,1058,1048,1058,1048\n10500,10550,1064,1053,1064,1053\n10550,10600,1070,1058,1070,1058\n10600,10650,1076,1063,1076,1063\n10650,10700,1082,1068,1082,1068\n10700,10750,1088,1073,1088,1073\n10750,10800,1094,1078,1094,1078\n10800,10850,1100,1083,1100,1083\n10850,10900,1106,1088,1106,1088\n10900,10950,1112,1093,1112,1093\n10950,11000,1118,1098,1118,1098\n11000,11050,1124,1103,1124,1103\n11050,11100,1130,1108,1130,1108\n11100,11150,1136,1113,1136,1113\n11150,11200,1142,1118,1142,1118\n11200,11250,1148,1123,1148,1123\n11250,11300,1154,1128,1154,1128\n11300,11350,1160,1133,1160,1133\n11350,11400,1166,1138,1166,1138\n11400,11450,1172,1143,1172,1143\n11450,11500,1178,1148,1178,1148\n11500,11550,1184,1153,1184,1153\n11550,11600,1190,1158,1190,1158\n11600,11650,1196,1163,1196,1163\n11650,11700,1202,1168,1202,1168\n11700,11750,1208,1173,1208,1173\n11750,11800,1214,1178,1214,1178\n11800,11850,1220,1183,1220,1183\n11850,11900,1226,1188,1226,1188\n11900,11950,1232,1193,1232,1193\n11950,12000,1238,1198,1238,1198\n12000,12050,1244,1203,1244,1203\n12050,12100,1250,1208,1250,1208\n12100,12150,1256,1213,1256,1213\n12150,12200,1262,1218,1262,1218\n12200,12250,1268,1223,1268,1223\n12250,12300,1274,1228,1274,1228\n12300,12350,1280,1233,1280,1233\n12350,12400,1286,1238,1286,1238\n12400,12450,1292,1243,1292,1243\n12450,12500,1298,1248,1298,1248\n12500,12550,1304,1253,1304,1253\n12550,12600,1310,1258,1310,1258\n12600,12650,1316,1263,1316,1263\n12650,12700,1322,1268,1322,1268\n12700,12750,1328,1273,1328,1273\n12750,12800,1334,1278,1334,1278\n12800,12850,1340,1283,1340,1283\n12850,12900,1346,1288,1346,1288\n12900,12950,1352,1293,1352,1293\n12950,13000,1358,1298,1358,1298\n13000,13050,1364,1303,1364,1303\n13050,13100,1370,1308,1370,1308\n13100,13150,1376,1313,1376,1313\n13150,13200,1382,1318,1382,1318\n13200,13250,1388,1323,1388,1323\n13250,13300,1394,1328,1394,1328\n13300,13350,1400,1333,1400,1333\n13350,13400,1406,1338,1406,1338\n13400,13450,1412,1343,1412,1343\n13450,13500,1418,1348,1418,1348\n13500,13550,1424,1353,1424,1353\n13550,13600,1430,1358,1430,1358\n13600,13650,1436,1363,1436,1363\n13650,13700,1442,1368,1442,1368\n13700,13750,1448,1373,1448,1373\n13750,13800,1454,1378,1454,1378\n13800,13850,1460,1383,1460,1383\n13850,13900,1466,1388,1466,1388\n13900,13950,1472,1393,1472,1393\n13950,14000,1478,1398,1478,1398\n14000,14050,1484,1403,1484,1403\n14050,14100,1490,1408,1490,1408\n14100,14150,1496,1413,1496,1413\n14150,14200,1502,1418,1502,1418\n14200,14250,1508,1423,1508,1423\n14250,14300,1514,1428,1514,1429\n14300,14350,1520,1433,1520,1435\n14350,14400,1526,1438,1526,1441\n14400,14450,1532,1443,1532,1447\n14450,14500,1538,1448,1538,1453\n14500,14550,1544,1453,1544,1459\n14550,14600,1550,1458,1550,1465\n14600,14650,1556,1463,1556,1471\n14650,14700,1562,1468,1562,1477\n14700,14750,1568,1473,1568,1483\n14750,14800,1574,1478,1574,1489\n14800,14850,1580,1483,1580,1495\n14850,14900,1586,1488,1586,1501\n14900,14950,1592,1493,1592,1507\n14950,15000,1598,1498,1598,1513\n15000,15050,1604,1503,1604,1519\n15050,15100,1610,1508,1610,1525\n15100,15150,1616,1513,1616,1531\n15150,15200,1622,1518,1622,1537\n15200,15250,1628,1523,1628,1543\n15250,15300,1634,1528,1634,1549\n15300,15350,1640,1533,1640,1555\n15350,15400,1646,1538,1646,1561\n15400,15450,1652,1543,1652,1567\n15450,15500,1658,1548,1658,1573\n15500,15550,1664,1553,1664,1579\n15550,15600,1670,1558,1670,1585\n15600,15650,1676,1563,1676,1591\n15650,15700,1682,1568,1682,1597\n15700,15750,1688,1573,1688,1603\n15750,15800,1694,1578,1694,1609\n15800,15850,1700,1583,1700,1615\n15850,15900,1706,1588,1706,1621\n15900,15950,1712,1593,1712,1627\n15950,16000,1718,1598,1718,1633\n16000,16050,1724,1603,1724,1639\n16050,16100,1730,1608,1730,1645\n16100,16150,1736,1613,1736,1651\n16150,16200,1742,1618,1742,1657\n16200,16250,1748,1623,1748,1663\n16250,16300,1754,1628,1754,1669\n16300,16350,1760,1633,1760,1675\n16350,16400,1766,1638,1766,1681\n16400,16450,1772,1643,1772,1687\n16450,16500,1778,1648,1778,1693\n16500,16550,1784,1653,1784,1699\n16550,16600,1790,1658,1790,1705\n16600,16650,1796,1663,1796,1711\n16650,16700,1802,1668,1802,1717\n16700,16750,1808,1673,1808,1723\n16750,16800,1814,1678,1814,1729\n16800,16850,1820,1683,1820,1735\n16850,16900,1826,1688,1826,1741\n16900,16950,1832,1693,1832,1747\n16950,17000,1838,1698,1838,1753\n17000,17050,1844,1703,1844,1759\n17050,17100,1850,1708,1850,1765\n17100,17150,1856,1713,1856,1771\n17150,17200,1862,1718,1862,1777\n17200,17250,1868,1723,1868,1783\n17250,17300,1874,1728,1874,1789\n17300,17350,1880,1733,1880,1795\n17350,17400,1886,1738,1886,1801\n17400,17450,1892,1743,1892,1807\n17450,17500,1898,1748,1898,1813\n17500,17550,1904,1753,1904,1819\n17550,17600,1910,1758,1910,1825\n17600,17650,1916,1763,1916,1831\n17650,17700,1922,1768,1922,1837\n17700,17750,1928,1773,1928,1843\n17750,17800,1934,1778,1934,1849\n17800,17850,1940,1783,1940,1855\n17850,17900,1946,1788,1946,1861\n17900,17950,1952,1793,1952,1867\n17950,18000,1958,1798,1958,1873\n18000,18050,1964,1803,1964,1879\n18050,18100,1970,1808,1970,1885\n18100,18150,1976,1813,1976,1891\n18150,18200,1982,1818,1982,1897\n18200,18250,1988,1823,1988,1903\n18250,18300,1994,1828,1994,1909\n18300,18350,2000,1833,2000,1915\n18350,18400,2006,1838,2006,1921\n18400,18450,2012,1843,2012,1927\n18450,18500,2018,1848,2018,1933\n18500,18550,2024,1853,2024,1939\n18550,18600,2030,1858,2030,1945\n18600,18650,2036,1863,2036,1951\n18650,18700,2042,1868,2042,1957\n18700,18750,2048,1873,2048,1963\n18750,18800,2054,1878,2054,1969\n18800,18850,2060,1883,2060,1975\n18850,18900,2066,1888,2066,1981\n18900,18950,2072,1893,2072,1987\n18950,19000,2078,1898,2078,1993\n19000,19050,2084,1903,2084,1999\n19050,19100,2090,1908,2090,2005\n19100,19150,2096,1913,2096,2011\n19150,19200,2102,1918,2102,2017\n19200,19250,2108,1923,2108,2023\n19250,19300,2114,1928,2114,2029\n19300,19350,2120,1933,2120,2035\n19350,19400,2126,1938,2126,2041\n19400,19450,2132,1943,2132,2047\n19450,19500,2138,1948,2138,2053\n19500,19550,2144,1953,2144,2059\n19550,19600,2150,1958,2150,2065\n19600,19650,2156,1963,2156,2071\n19650,19700,2162,1968,2162,2077\n19700,19750,2168,1973,2168,2083\n19750,19800,2174,1978,2174,2089\n19800,19850,2180,1983,2180,2095\n19850,19900,2186,1988,2186,2101\n19900,19950,2192,1993,2192,2107\n19950,20000,2198,1999,2198,2113\n20000,20050,2204,2005,2204,2119\n20050,20100,2210,2011,2210,2125\n20100,20150,2216,2017,2216,2131\n20150,20200,2222,2023,2222,2137\n20200,20250,2228,2029,2228,2143\n20250,20300,2234,2035,2234,2149\n20300,20350,2240,2041,2240,2155\n20350,20400,2246,2047,2246,2161\n20400,20450,2252,2053,2252,2167\n20450,20500,2258,2059,2258,2173\n20500,20550,2264,2065,2264,2179\n20550,20600,2270,2071,2270,2185\n20600,20650,2276,2077,2276,2191\n20650,20700,2282,2083,2282,2197\n20700,20750,2288,2089,2288,2203\n20750,20800,2294,2095,2294,2209\n20800,20850,2300,2101,2300,2215\n20850,20900,2306,2107,2306,2221\n20900,20950,2312,2113,2312,2227\n20950,21000,2318,2119,2318,2233\n21000,21050,2324,2125,2324,2239\n21050,21100,2330,2131,2330,2245\n21100,21150,2336,2137,2336,2251\n21150,21200,2342,2143,2342,2257\n21200,21250,2348,2149,2348,2263\n21250,21300,2354,2155,2354,2269\n21300,21350,2360,2161,2360,2275\n21350,21400,2366,2167,2366,2281\n21400,21450,2372,2173,2372,2287\n21450,21500,2378,2179,2378,2293\n21500,21550,2384,2185,2384,2299\n21550,21600,2390,2191,2390,2305\n21600,21650,2396,2197,2396,2311\n21650,21700,2402,2203,2402,2317\n21700,21750,2408,2209,2408,2323\n21750,21800,2414,2215,2414,2329\n21800,21850,2420,2221,2420,2335\n21850,21900,2426,2227,2426,2341\n21900,21950,2432,2233,2432,2347\n21950,22000,2438,2239,2438,2353\n22000,22050,2444,2245,2444,2359\n22050,22100,2450,2251,2450,2365\n22100,22150,2456,2257,2456,2371\n22150,22200,2462,2263,2462,2377\n22200,22250,2468,2269,2468,2383\n22250,22300,2474,2275,2474,2389\n22300,22350,2480,2281,2480,2395\n22350,22400,2486,2287,2486,2401\n22400,22450,2492,2293,2492,2407\n22450,22500,2498,2299,2498,2413\n22500,22550,2504,2305,2504,2419\n22550,22600,2510,2311,2510,2425\n22600,22650,2516,2317,2516,2431\n22650,22700,2522,2323,2522,2437\n22700,22750,2528,2329,2528,2443\n22750,22800,2534,2335,2534,2449\n22800,22850,2540,2341,2540,2455\n22850,22900,2546,2347,2546,2461\n22900,22950,2552,2353,2552,2467\n22950,23000,2558,2359,2558,2473\n23000,23050,2564,2365,2564,2479\n23050,23100,2570,2371,2570,2485\n23100,23150,2576,2377,2576,2491\n23150,23200,2582,2383,2582,2497\n23200,23250,2588,2389,2588,2503\n23250,23300,2594,2395,2594,2509\n23300,23350,2600,2401,2600,2515\n23350,23400,2606,2407,2606,2521\n23400,23450,2612,2413,2612,2527\n23450,23500,2618,2419,2618,2533\n23500,23550,2624,2425,2624,2539\n23550,23600,2630,2431,2630,2545\n23600,23650,2636,2437,2636,2551\n23650,23700,2642,2443,2642,2557\n23700,23750,2648,2449,2648,2563\n23750,23800,2654,2455,2654,2569\n23800,23850,2660,2461,2660,2575\n23850,23900,2666,2467,2666,2581\n23900,23950,2672,2473,2672,2587\n23950,24000,2678,2479,2678,2593\n24000,24050,2684,2485,2684,2599\n24050,24100,2690,2491,2690,2605\n24100,24150,2696,2497,2696,2611\n24150,24200,2702,2503,2702,2617\n24200,24250,2708,2509,2708,2623\n24250,24300,2714,2515,2714,2629\n24300,24350,2720,2521,2720,2635\n24350,24400,2726,2527,2726,2641\n24400,24450,2732,2533,2732,2647\n24450,24500,2738,2539,2738,2653\n24500,24550,2744,2545,2744,2659\n24550,24600,2750,2551,2750,2665\n24600,24650,2756,2557,2756,2671\n24650,24700,2762,2563,2762,2677\n24700,24750,2768,2569,2768,2683\n24750,24800,2774,2575,2774,2689\n24800,24850,2780,2581,2780,2695\n24850,24900,2786,2587,2786,2701\n24900,24950,2792,2593,2792,2707\n24950,25000,2798,2599,2798,2713\n25000,25050,2804,2605,2804,2719\n25050,25100,2810,2611,2810,2725\n25100,25150,2816,2617,2816,2731\n25150,25200,2822,2623,2822,2737\n25200,25250,2828,2629,2828,2743\n25250,25300,2834,2635,2834,2749\n25300,25350,2840,2641,2840,2755\n25350,25400,2846,2647,2846,2761\n25400,25450,2852,2653,2852,2767\n25450,25500,2858,2659,2858,2773\n25500,25550,2864,2665,2864,2779\n25550,25600,2870,2671,2870,2785\n25600,25650,2876,2677,2876,2791\n25650,25700,2882,2683,2882,2797\n25700,25750,2888,2689,2888,2803\n25750,25800,2894,2695,2894,2809\n25800,25850,2900,2701,2900,2815\n25850,25900,2906,2707,2906,2821\n25900,25950,2912,2713,2912,2827\n25950,26000,2918,2719,2918,2833\n26000,26050,2924,2725,2924,2839\n26050,26100,2930,2731,2930,2845\n26100,26150,2936,2737,2936,2851\n26150,26200,2942,2743,2942,2857\n26200,26250,2948,2749,2948,2863\n26250,26300,2954,2755,2954,2869\n26300,26350,2960,2761,2960,2875\n26350,26400,2966,2767,2966,2881\n26400,26450,2972,2773,2972,2887\n26450,26500,2978,2779,2978,2893\n26500,26550,2984,2785,2984,2899\n26550,26600,2990,2791,2990,2905\n26600,26650,2996,2797,2996,2911\n26650,26700,3002,2803,3002,2917\n26700,26750,3008,2809,3008,2923\n26750,26800,3014,2815,3014,2929\n26800,26850,3020,2821,3020,2935\n26850,26900,3026,2827,3026,2941\n26900,26950,3032,2833,3032,2947\n26950,27000,3038,2839,3038,2953\n27000,27050,3044,2845,3044,2959\n27050,27100,3050,2851,3050,2965\n27100,27150,3056,2857,3056,2971\n27150,27200,3062,2863,3062,2977\n27200,27250,3068,2869,3068,2983\n27250,27300,3074,2875,3074,2989\n27300,27350,3080,2881,3080,2995\n27350,27400,3086,2887,3086,3001\n27400,27450,3092,2893,3092,3007\n27450,27500,3098,2899,3098,3013\n27500,27550,3104,2905,3104,3019\n27550,27600,3110,2911,3110,3025\n27600,27650,3116,2917,3116,3031\n27650,27700,3122,2923,3122,3037\n27700,27750,3128,2929,3128,3043\n27750,27800,3134,2935,3134,3049\n27800,27850,3140,2941,3140,3055\n27850,27900,3146,2947,3146,3061\n27900,27950,3152,2953,3152,3067\n27950,28000,3158,2959,3158,3073\n28000,28050,3164,2965,3164,3079\n28050,28100,3170,2971,3170,3085\n28100,28150,3176,2977,3176,3091\n28150,28200,3182,2983,3182,3097\n28200,28250,3188,2989,3188,3103\n28250,28300,3194,2995,3194,3109\n28300,28350,3200,3001,3200,3115\n28350,28400,3206,3007,3206,3121\n28400,28450,3212,3013,3212,3127\n28450,28500,3218,3019,3218,3133\n28500,28550,3224,3025,3224,3139\n28550,28600,3230,3031,3230,3145\n28600,28650,3236,3037,3236,3151\n28650,28700,3242,3043,3242,3157\n28700,28750,3248,3049,3248,3163\n28750,28800,3254,3055,3254,3169\n28800,28850,3260,3061,3260,3175\n28850,28900,3266,3067,3266,3181\n28900,28950,3272,3073,3272,3187\n28950,29000,3278,3079,3278,3193\n29000,29050,3284,3085,3284,3199\n29050,29100,3290,3091,3290,3205\n29100,29150,3296,3097,3296,3211\n29150,29200,3302,3103,3302,3217\n29200,29250,3308,3109,3308,3223\n29250,29300,3314,3115,3314,3229\n29300,29350,3320,3121,3320,3235\n29350,29400,3326,3127,3326,3241\n29400,29450,3332,3133,3332,3247\n29450,29500,3338,3139,3338,3253\n29500,29550,3344,3145,3344,3259\n29550,29600,3350,3151,3350,3265\n29600,29650,3356,3157,3356,3271\n29650,29700,3362,3163,3362,3277\n29700,29750,3368,3169,3368,3283\n29750,29800,3374,3175,3374,3289\n29800,29850,3380,3181,3380,3295\n29850,29900,3386,3187,3386,3301\n29900,29950,3392,3193,3392,3307\n29950,30000,3398,3199,3398,3313\n30000,30050,3404,3205,3404,3319\n30050,30100,3410,3211,3410,3325\n30100,30150,3416,3217,3416,3331\n30150,30200,3422,3223,3422,3337\n30200,30250,3428,3229,3428,3343\n30250,30300,3434,3235,3434,3349\n30300,30350,3440,3241,3440,3355\n30350,30400,3446,3247,3446,3361\n30400,30450,3452,3253,3452,3367\n30450,30500,3458,3259,3458,3373\n30500,30550,3464,3265,3464,3379\n30550,30600,3470,3271,3470,3385\n30600,30650,3476,3277,3476,3391\n30650,30700,3482,3283,3482,3397\n30700,30750,3488,3289,3488,3403\n30750,30800,3494,3295,3494,3409\n30800,30850,3500,3301,3500,3415\n30850,30900,3506,3307,3506,3421\n30900,30950,3512,3313,3512,3427\n30950,31000,3518,3319,3518,3433\n31000,31050,3524,3325,3524,3439\n31050,31100,3530,3331,3530,3445\n31100,31150,3536,3337,3536,3451\n31150,31200,3542,3343,3542,3457\n31200,31250,3548,3349,3548,3463\n31250,31300,3554,3355,3554,3469\n31300,31350,3560,3361,3560,3475\n31350,31400,3566,3367,3566,3481\n31400,31450,3572,3373,3572,3487\n31450,31500,3578,3379,3578,3493\n31500,31550,3584,3385,3584,3499\n31550,31600,3590,3391,3590,3505\n31600,31650,3596,3397,3596,3511\n31650,31700,3602,3403,3602,3517\n31700,31750,3608,3409,3608,3523\n31750,31800,3614,3415,3614,3529\n31800,31850,3620,3421,3620,3535\n31850,31900,3626,3427,3626,3541\n31900,31950,3632,3433,3632,3547\n31950,32000,3638,3439,3638,3553\n32000,32050,3644,3445,3644,3559\n32050,32100,3650,3451,3650,3565\n32100,32150,3656,3457,3656,3571\n32150,32200,3662,3463,3662,3577\n32200,32250,3668,3469,3668,3583\n32250,32300,3674,3475,3674,3589\n32300,32350,3680,3481,3680,3595\n32350,32400,3686,3487,3686,3601\n32400,32450,3692,3493,3692,3607\n32450,32500,3698,3499,3698,3613\n32500,32550,3704,3505,3704,3619\n32550,32600,3710,3511,3710,3625\n32600,32650,3716,3517,3716,3631\n32650,32700,3722,3523,3722,3637\n32700,32750,3728,3529,3728,3643\n32750,32800,3734,3535,3734,3649\n32800,32850,3740,3541,3740,3655\n32850,32900,3746,3547,3746,3661\n32900,32950,3752,3553,3752,3667\n32950,33000,3758,3559,3758,3673\n33000,33050,3764,3565,3764,3679\n33050,33100,3770,3571,3770,3685\n33100,33150,3776,3577,3776,3691\n33150,33200,3782,3583,3782,3697\n33200,33250,3788,3589,3788,3703\n33250,33300,3794,3595,3794,3709\n33300,33350,3800,3601,3800,3715\n33350,33400,3806,3607,3806,3721\n33400,33450,3812,3613,3812,3727\n33450,33500,3818,3619,3818,3733\n33500,33550,3824,3625,3824,3739\n33550,33600,3830,3631,3830,3745\n33600,33650,3836,3637,3836,3751\n33650,33700,3842,3643,3842,3757\n33700,33750,3848,3649,3848,3763\n33750,33800,3854,3655,3854,3769\n33800,33850,3860,3661,3860,3775\n33850,33900,3866,3667,3866,3781\n33900,33950,3872,3673,3872,3787\n33950,34000,3878,3679,3878,3793\n34000,34050,3884,3685,3884,3799\n34050,34100,3890,3691,3890,3805\n34100,34150,3896,3697,3896,3811\n34150,34200,3902,3703,3902,3817\n34200,34250,3908,3709,3908,3823\n34250,34300,3914,3715,3914,3829\n34300,34350,3920,3721,3920,3835\n34350,34400,3926,3727,3926,3841\n34400,34450,3932,3733,3932,3847\n34450,34500,3938,3739,3938,3853\n34500,34550,3944,3745,3944,3859\n34550,34600,3950,3751,3950,3865\n34600,34650,3956,3757,3956,3871\n34650,34700,3962,3763,3962,3877\n34700,34750,3968,3769,3968,3883\n34750,34800,3974,3775,3974,3889\n34800,34850,3980,3781,3980,3895\n34850,34900,3986,3787,3986,3901\n34900,34950,3992,3793,3992,3907\n34950,35000,3998,3799,3998,3913\n35000,35050,4004,3805,4004,3919\n35050,35100,4010,3811,4010,3925\n35100,35150,4016,3817,4016,3931\n35150,35200,4022,3823,4022,3937\n35200,35250,4028,3829,4028,3943\n35250,35300,4034,3835,4034,3949\n35300,35350,4040,3841,4040,3955\n35350,35400,4046,3847,4046,3961\n35400,35450,4052,3853,4052,3967\n35450,35500,4058,3859,4058,3973\n35500,35550,4064,3865,4064,3979\n35550,35600,4070,3871,4070,3985\n35600,35650,4076,3877,4076,3991\n35650,35700,4082,3883,4082,3997\n35700,35750,4088,3889,4088,4003\n35750,35800,4094,3895,4094,4009\n35800,35850,4100,3901,4100,4015\n35850,35900,4106,3907,4106,4021\n35900,35950,4112,3913,4112,4027\n35950,36000,4118,3919,4118,4033\n36000,36050,4124,3925,4124,4039\n36050,36100,4130,3931,4130,4045\n36100,36150,4136,3937,4136,4051\n36150,36200,4142,3943,4142,4057\n36200,36250,4148,3949,4148,4063\n36250,36300,4154,3955,4154,4069\n36300,36350,4160,3961,4160,4075\n36350,36400,4166,3967,4166,4081\n36400,36450,4172,3973,4172,4087\n36450,36500,4178,3979,4178,4093\n36500,36550,4184,3985,4184,4099\n36550,36600,4190,3991,4190,4105\n36600,36650,4196,3997,4196,4111\n36650,36700,4202,4003,4202,4117\n36700,36750,4208,4009,4208,4123\n36750,36800,4214,4015,4214,4129\n36800,36850,4220,4021,4220,4135\n36850,36900,4226,4027,4226,4141\n36900,36950,4232,4033,4232,4147\n36950,37000,4238,4039,4238,4153\n37000,37050,4244,4045,4244,4159\n37050,37100,4250,4051,4250,4165\n37100,37150,4256,4057,4256,4171\n37150,37200,4262,4063,4262,4177\n37200,37250,4268,4069,4268,4183\n37250,37300,4274,4075,4274,4189\n37300,37350,4280,4081,4280,4195\n37350,37400,4286,4087,4286,4201\n37400,37450,4292,4093,4292,4207\n37450,37500,4298,4099,4298,4213\n37500,37550,4304,4105,4304,4219\n37550,37600,4310,4111,4310,4225\n37600,37650,4316,4117,4316,4231\n37650,37700,4322,4123,4322,4237\n37700,37750,4328,4129,4328,4243\n37750,37800,4334,4135,4334,4249\n37800,37850,4340,4141,4340,4255\n37850,37900,4346,4147,4346,4261\n37900,37950,4352,4153,4352,4267\n37950,38000,4358,4159,4358,4273\n38000,38050,4364,4165,4364,4279\n38050,38100,4370,4171,4370,4285\n38100,38150,4376,4177,4376,4291\n38150,38200,4382,4183,4382,4297\n38200,38250,4388,4189,4388,4303\n38250,38300,4394,4195,4394,4309\n38300,38350,4400,4201,4400,4315\n38350,38400,4406,4207,4406,4321\n38400,38450,4412,4213,4412,4327\n38450,38500,4418,4219,4418,4333\n38500,38550,4424,4225,4424,4339\n38550,38600,4430,4231,4430,4345\n38600,38650,4436,4237,4436,4351\n38650,38700,4442,4243,4442,4357\n38700,38750,4448,4249,4448,4363\n38750,38800,4454,4255,4454,4369\n38800,38850,4460,4261,4460,4375\n38850,38900,4466,4267,4466,4381\n38900,38950,4472,4273,4472,4387\n38950,39000,4478,4279,4478,4393\n39000,39050,4484,4285,4484,4399\n39050,39100,4490,4291,4490,4405\n39100,39150,4496,4297,4496,4411\n39150,39200,4502,4303,4502,4417\n39200,39250,4508,4309,4508,4423\n39250,39300,4514,4315,4514,4429\n39300,39350,4520,4321,4520,4435\n39350,39400,4526,4327,4526,4441\n39400,39450,4532,4333,4532,4447\n39450,39500,4538,4339,4538,4453\n39500,39550,4544,4345,4544,4459\n39550,39600,4550,4351,4550,4465\n39600,39650,4556,4357,4556,4471\n39650,39700,4562,4363,4562,4477\n39700,39750,4568,4369,4568,4483\n39750,39800,4574,4375,4574,4489\n39800,39850,4580,4381,4580,4495\n39850,39900,4586,4387,4586,4501\n39900,39950,4592,4393,4592,4507\n39950,40000,4598,4399,4598,4513\n40000,40050,4604,4405,4604,4519\n40050,40100,4610,4411,4610,4525\n40100,40150,4616,4417,4616,4531\n40150,40200,4622,4423,4622,4537\n40200,40250,4628,4429,4628,4543\n40250,40300,4634,4435,4634,4549\n40300,40350,4640,4441,4640,4555\n40350,40400,4646,4447,4646,4561\n40400,40450,4652,4453,4652,4567\n40450,40500,4658,4459,4658,4573\n40500,40550,4664,4465,4664,4579\n40550,40600,4675,4471,4675,4585\n40600,40650,4686,4477,4686,4591\n40650,40700,4697,4483,4697,4597\n40700,40750,4708,4489,4708,4603\n40750,40800,4719,4495,4719,4609\n40800,40850,4730,4501,4730,4615\n40850,40900,4741,4507,4741,4621\n40900,40950,4752,4513,4752,4627\n40950,41000,4763,4519,4763,4633\n41000,41050,4774,4525,4774,4639\n41050,41100,4785,4531,4785,4645\n41100,41150,4796,4537,4796,4651\n41150,41200,4807,4543,4807,4657\n41200,41250,4818,4549,4818,4663\n41250,41300,4829,4555,4829,4669\n41300,41350,4840,4561,4840,4675\n41350,41400,4851,4567,4851,4681\n41400,41450,4862,4573,4862,4687\n41450,41500,4873,4579,4873,4693\n41500,41550,4884,4585,4884,4699\n41550,41600,4895,4591,4895,4705\n41600,41650,4906,4597,4906,4711\n41650,41700,4917,4603,4917,4717\n41700,41750,4928,4609,4928,4723\n41750,41800,4939,4615,4939,4729\n41800,41850,4950,4621,4950,4735\n41850,41900,4961,4627,4961,4741\n41900,41950,4972,4633,4972,4747\n41950,42000,4983,4639,4983,4753\n42000,42050,4994,4645,4994,4759\n42050,42100,5005,4651,5005,4765\n42100,42150,5016,4657,5016,4771\n42150,42200,5027,4663,5027,4777\n42200,42250,5038,4669,5038,4783\n42250,42300,5049,4675,5049,4789\n42300,42350,5060,4681,5060,4795\n42350,42400,5071,4687,5071,4801\n42400,42450,5082,4693,5082,4807\n42450,42500,5093,4699,5093,4813\n42500,42550,5104,4705,5104,4819\n42550,42600,5115,4711,5115,4825\n42600,42650,5126,4717,5126,4831\n42650,42700,5137,4723,5137,4837\n42700,42750,5148,4729,5148,4843\n42750,42800,5159,4735,5159,4849\n42800,42850,5170,4741,5170,4855\n42850,42900,5181,4747,5181,4861\n42900,42950,5192,4753,5192,4867\n42950,43000,5203,4759,5203,4873\n43000,43050,5214,4765,5214,4879\n43050,43100,5225,4771,5225,4885\n43100,43150,5236,4777,5236,4891\n43150,43200,5247,4783,5247,4897\n43200,43250,5258,4789,5258,4903\n43250,43300,5269,4795,5269,4909\n43300,43350,5280,4801,5280,4915\n43350,43400,5291,4807,5291,4921\n43400,43450,5302,4813,5302,4927\n43450,43500,5313,4819,5313,4933\n43500,43550,5324,4825,5324,4939\n43550,43600,5335,4831,5335,4945\n43600,43650,5346,4837,5346,4951\n43650,43700,5357,4843,5357,4957\n43700,43750,5368,4849,5368,4963\n43750,43800,5379,4855,5379,4969\n43800,43850,5390,4861,5390,4975\n43850,43900,5401,4867,5401,4981\n43900,43950,5412,4873,5412,4987\n43950,44000,5423,4879,5423,4993\n44000,44050,5434,4885,5434,4999\n44050,44100,5445,4891,5445,5005\n44100,44150,5456,4897,5456,5011\n44150,44200,5467,4903,5467,5017\n44200,44250,5478,4909,5478,5023\n44250,44300,5489,4915,5489,5029\n44300,44350,5500,4921,5500,5035\n44350,44400,5511,4927,5511,5041\n44400,44450,5522,4933,5522,5047\n44450,44500,5533,4939,5533,5053\n44500,44550,5544,4945,5544,5059\n44550,44600,5555,4951,5555,5065\n44600,44650,5566,4957,5566,5071\n44650,44700,5577,4963,5577,5077\n44700,44750,5588,4969,5588,5083\n44750,44800,5599,4975,5599,5089\n44800,44850,5610,4981,5610,5095\n44850,44900,5621,4987,5621,5101\n44900,44950,5632,4993,5632,5107\n44950,45000,5643,4999,5643,5113\n45000,45050,5654,5005,5654,5119\n45050,45100,5665,5011,5665,5125\n45100,45150,5676,5017,5676,5131\n45150,45200,5687,5023,5687,5137\n45200,45250,5698,5029,5698,5143\n45250,45300,5709,5035,5709,5149\n45300,45350,5720,5041,5720,5155\n45350,45400,5731,5047,5731,5161\n45400,45450,5742,5053,5742,5167\n45450,45500,5753,5059,5753,5173\n45500,45550,5764,5065,5764,5179\n45550,45600,5775,5071,5775,5185\n45600,45650,5786,5077,5786,5191\n45650,45700,5797,5083,5797,5197\n45700,45750,5808,5089,5808,5203\n45750,45800,5819,5095,5819,5209\n45800,45850,5830,5101,5830,5215\n45850,45900,5841,5107,5841,5221\n45900,45950,5852,5113,5852,5227\n45950,46000,5863,5119,5863,5233\n46000,46050,5874,5125,5874,5239\n46050,46100,5885,5131,5885,5245\n46100,46150,5896,5137,5896,5251\n46150,46200,5907,5143,5907,5257\n46200,46250,5918,5149,5918,5263\n46250,46300,5929,5155,5929,5269\n46300,46350,5940,5161,5940,5275\n46350,46400,5951,5167,5951,5281\n46400,46450,5962,5173,5962,5287\n46450,46500,5973,5179,5973,5293\n46500,46550,5984,5185,5984,5299\n46550,46600,5995,5191,5995,5305\n46600,46650,6006,5197,6006,5311\n46650,46700,6017,5203,6017,5317\n46700,46750,6028,5209,6028,5323\n46750,46800,6039,5215,6039,5329\n46800,46850,6050,5221,6050,5335\n46850,46900,6061,5227,6061,5341\n46900,46950,6072,5233,6072,5347\n46950,47000,6083,5239,6083,5353\n47000,47050,6094,5245,6094,5359\n47050,47100,6105,5251,6105,5365\n47100,47150,6116,5257,6116,5371\n47150,47200,6127,5263,6127,5377\n47200,47250,6138,5269,6138,5383\n47250,47300,6149,5275,6149,5389\n47300,47350,6160,5281,6160,5395\n47350,47400,6171,5287,6171,5401\n47400,47450,6182,5293,6182,5407\n47450,47500,6193,5299,6193,5413\n47500,47550,6204,5305,6204,5419\n47550,47600,6215,5311,6215,5425\n47600,47650,6226,5317,6226,5431\n47650,47700,6237,5323,6237,5437\n47700,47750,6248,5329,6248,5443\n47750,47800,6259,5335,6259,5449\n47800,47850,6270,5341,6270,5455\n47850,47900,6281,5347,6281,5461\n47900,47950,6292,5353,6292,5467\n47950,48000,6303,5359,6303,5473\n48000,48050,6314,5365,6314,5479\n48050,48100,6325,5371,6325,5485\n48100,48150,6336,5377,6336,5491\n48150,48200,6347,5383,6347,5497\n48200,48250,6358,5389,6358,5503\n48250,48300,6369,5395,6369,5509\n48300,48350,6380,5401,6380,5515\n48350,48400,6391,5407,6391,5521\n48400,48450,6402,5413,6402,5527\n48450,48500,6413,5419,6413,5533\n48500,48550,6424,5425,6424,5539\n48550,48600,6435,5431,6435,5545\n48600,48650,6446,5437,6446,5551\n48650,48700,6457,5443,6457,5557\n48700,48750,6468,5449,6468,5563\n48750,48800,6479,5455,6479,5569\n48800,48850,6490,5461,6490,5575\n48850,48900,6501,5467,6501,5581\n48900,48950,6512,5473,6512,5587\n48950,49000,6523,5479,6523,5593\n49000,49050,6534,5485,6534,5599\n49050,49100,6545,5491,6545,5605\n49100,49150,6556,5497,6556,5611\n49150,49200,6567,5503,6567,5617\n49200,49250,6578,5509,6578,5623\n49250,49300,6589,5515,6589,5629\n49300,49350,6600,5521,6600,5635\n49350,49400,6611,5527,6611,5641\n49400,49450,6622,5533,6622,5647\n49450,49500,6633,5539,6633,5653\n49500,49550,6644,5545,6644,5659\n49550,49600,6655,5551,6655,5665\n49600,49650,6666,5557,6666,5671\n49650,49700,6677,5563,6677,5677\n49700,49750,6688,5569,6688,5683\n49750,49800,6699,5575,6699,5689\n49800,49850,6710,5581,6710,5695\n49850,49900,6721,5587,6721,5701\n49900,49950,6732,5593,6732,5707\n49950,50000,6743,5599,6743,5713\n50000,50050,6754,5605,6754,5719\n50050,50100,6765,5611,6765,5725\n50100,50150,6776,5617,6776,5731\n50150,50200,6787,5623,6787,5737\n50200,50250,6798,5629,6798,5743\n50250,50300,6809,5635,6809,5749\n50300,50350,6820,5641,6820,5755\n50350,50400,6831,5647,6831,5761\n50400,50450,6842,5653,6842,5767\n50450,50500,6853,5659,6853,5773\n50500,50550,6864,5665,6864,5779\n50550,50600,6875,5671,6875,5785\n50600,50650,6886,5677,6886,5791\n50650,50700,6897,5683,6897,5797\n50700,50750,6908,5689,6908,5803\n50750,50800,6919,5695,6919,5809\n50800,50850,6930,5701,6930,5815\n50850,50900,6941,5707,6941,5821\n50900,50950,6952,5713,6952,5827\n50950,51000,6963,5719,6963,5833\n51000,51050,6974,5725,6974,5839\n51050,51100,6985,5731,6985,5845\n51100,51150,6996,5737,6996,5851\n51150,51200,7007,5743,7007,5857\n51200,51250,7018,5749,7018,5863\n51250,51300,7029,5755,7029,5869\n51300,51350,7040,5761,7040,5875\n51350,51400,7051,5767,7051,5881\n51400,51450,7062,5773,7062,5887\n51450,51500,7073,5779,7073,5893\n51500,51550,7084,5785,7084,5899\n51550,51600,7095,5791,7095,5905\n51600,51650,7106,5797,7106,5911\n51650,51700,7117,5803,7117,5917\n51700,51750,7128,5809,7128,5923\n51750,51800,7139,5815,7139,5929\n51800,51850,7150,5821,7150,5935\n51850,51900,7161,5827,7161,5941\n51900,51950,7172,5833,7172,5947\n51950,52000,7183,5839,7183,5953\n52000,52050,7194,5845,7194,5959\n52050,52100,7205,5851,7205,5965\n52100,52150,7216,5857,7216,5971\n52150,52200,7227,5863,7227,5977\n52200,52250,7238,5869,7238,5983\n52250,52300,7249,5875,7249,5989\n52300,52350,7260,5881,7260,5995\n52350,52400,7271,5887,7271,6001\n52400,52450,7282,5893,7282,6007\n52450,52500,7293,5899,7293,6013\n52500,52550,7304,5905,7304,6019\n52550,52600,7315,5911,7315,6025\n52600,52650,7326,5917,7326,6031\n52650,52700,7337,5923,7337,6037\n52700,52750,7348,5929,7348,6043\n52750,52800,7359,5935,7359,6049\n52800,52850,7370,5941,7370,6055\n52850,52900,7381,5947,7381,6061\n52900,52950,7392,5953,7392,6067\n52950,53000,7403,5959,7403,6073\n53000,53050,7414,5965,7414,6079\n53050,53100,7425,5971,7425,6085\n53100,53150,7436,5977,7436,6091\n53150,53200,7447,5983,7447,6097\n53200,53250,7458,5989,7458,6103\n53250,53300,7469,5995,7469,6109\n53300,53350,7480,6001,7480,6115\n53350,53400,7491,6007,7491,6121\n53400,53450,7502,6013,7502,6127\n53450,53500,7513,6019,7513,6133\n53500,53550,7524,6025,7524,6139\n53550,53600,7535,6031,7535,6145\n53600,53650,7546,6037,7546,6151\n53650,53700,7557,6043,7557,6157\n53700,53750,7568,6049,7568,6163\n53750,53800,7579,6055,7579,6169\n53800,53850,7590,6061,7590,6175\n53850,53900,7601,6067,7601,6181\n53900,53950,7612,6073,7612,6187\n53950,54000,7623,6079,7623,6193\n54000,54050,7634,6085,7634,6199\n54050,54100,7645,6091,7645,6205\n54100,54150,7656,6097,7656,6211\n54150,54200,7667,6103,7667,6217\n54200,54250,7678,6109,7678,6226\n54250,54300,7689,6115,7689,6237\n54300,54350,7700,6121,7700,6248\n54350,54400,7711,6127,7711,6259\n54400,54450,7722,6133,7722,6270\n54450,54500,7733,6139,7733,6281\n54500,54550,7744,6145,7744,6292\n54550,54600,7755,6151,7755,6303\n54600,54650,7766,6157,7766,6314\n54650,54700,7777,6163,7777,6325\n54700,54750,7788,6169,7788,6336\n54750,54800,7799,6175,7799,6347\n54800,54850,7810,6181,7810,6358\n54850,54900,7821,6187,7821,6369\n54900,54950,7832,6193,7832,6380\n54950,55000,7843,6199,7843,6391\n55000,55050,7854,6205,7854,6402\n55050,55100,7865,6211,7865,6413\n55100,55150,7876,6217,7876,6424\n55150,55200,7887,6223,7887,6435\n55200,55250,7898,6229,7898,6446\n55250,55300,7909,6235,7909,6457\n55300,55350,7920,6241,7920,6468\n55350,55400,7931,6247,7931,6479\n55400,55450,7942,6253,7942,6490\n55450,55500,7953,6259,7953,6501\n55500,55550,7964,6265,7964,6512\n55550,55600,7975,6271,7975,6523\n55600,55650,7986,6277,7986,6534\n55650,55700,7997,6283,7997,6545\n55700,55750,8008,6289,8008,6556\n55750,55800,8019,6295,8019,6567\n55800,55850,8030,6301,8030,6578\n55850,55900,8041,6307,8041,6589\n55900,55950,8052,6313,8052,6600\n55950,56000,8063,6319,8063,6611\n56000,56050,8074,6325,8074,6622\n56050,56100,8085,6331,8085,6633\n56100,56150,8096,6337,8096,6644\n56150,56200,8107,6343,8107,6655\n56200,56250,8118,6349,8118,6666\n56250,56300,8129,6355,8129,6677\n56300,56350,8140,6361,8140,6688\n56350,56400,8151,6367,8151,6699\n56400,56450,8162,6373,8162,6710\n56450,56500,8173,6379,8173,6721\n56500,56550,8184,6385,8184,6732\n56550,56600,8195,6391,8195,6743\n56600,56650,8206,6397,8206,6754\n56650,56700,8217,6403,8217,6765\n56700,56750,8228,6409,8228,6776\n56750,56800,8239,6415,8239,6787\n56800,56850,8250,6421,8250,6798\n56850,56900,8261,6427,8261,6809\n56900,56950,8272,6433,8272,6820\n56950,57000,8283,6439,8283,6831\n57000,57050,8294,6445,8294,6842\n57050,57100,8305,6451,8305,6853\n57100,57150,8316,6457,8316,6864\n57150,57200,8327,6463,8327,6875\n57200,57250,8338,6469,8338,6886\n57250,57300,8349,6475,8349,6897\n57300,57350,8360,6481,8360,6908\n57350,57400,8371,6487,8371,6919\n57400,57450,8382,6493,8382,6930\n57450,57500,8393,6499,8393,6941\n57500,57550,8404,6505,8404,6952\n57550,57600,8415,6511,8415,6963\n57600,57650,8426,6517,8426,6974\n57650,57700,8437,6523,8437,6985\n57700,57750,8448,6529,8448,6996\n57750,57800,8459,6535,8459,7007\n57800,57850,8470,6541,8470,7018\n57850,57900,8481,6547,8481,7029\n57900,57950,8492,6553,8492,7040\n57950,58000,8503,6559,8503,7051\n58000,58050,8514,6565,8514,7062\n58050,58100,8525,6571,8525,7073\n58100,58150,8536,6577,8536,7084\n58150,58200,8547,6583,8547,7095\n58200,58250,8558,6589,8558,7106\n58250,58300,8569,6595,8569,7117\n58300,58350,8580,6601,8580,7128\n58350,58400,8591,6607,8591,7139\n58400,58450,8602,6613,8602,7150\n58450,58500,8613,6619,8613,7161\n58500,58550,8624,6625,8624,7172\n58550,58600,8635,6631,8635,7183\n58600,58650,8646,6637,8646,7194\n58650,58700,8657,6643,8657,7205\n58700,58750,8668,6649,8668,7216\n58750,58800,8679,6655,8679,7227\n58800,58850,8690,6661,8690,7238\n58850,58900,8701,6667,8701,7249\n58900,58950,8712,6673,8712,7260\n58950,59000,8723,6679,8723,7271\n59000,59050,8734,6685,8734,7282\n59050,59100,8745,6691,8745,7293\n59100,59150,8756,6697,8756,7304\n59150,59200,8767,6703,8767,7315\n59200,59250,8778,6709,8778,7326\n59250,59300,8789,6715,8789,7337\n59300,59350,8800,6721,8800,7348\n59350,59400,8811,6727,8811,7359\n59400,59450,8822,6733,8822,7370\n59450,59500,8833,6739,8833,7381\n59500,59550,8844,6745,8844,7392\n59550,59600,8855,6751,8855,7403\n59600,59650,8866,6757,8866,7414\n59650,59700,8877,6763,8877,7425\n59700,59750,8888,6769,8888,7436\n59750,59800,8899,6775,8899,7447\n59800,59850,8910,6781,8910,7458\n59850,59900,8921,6787,8921,7469\n59900,59950,8932,6793,8932,7480\n59950,60000,8943,6799,8943,7491\n60000,60050,8954,6805,8954,7502\n60050,60100,8965,6811,8965,7513\n60100,60150,8976,6817,8976,7524\n60150,60200,8987,6823,8987,7535\n60200,60250,8998,6829,8998,7546\n60250,60300,9009,6835,9009,7557\n60300,60350,9020,6841,9020,7568\n60350,60400,9031,6847,9031,7579\n60400,60450,9042,6853,9042,7590\n60450,60500,9053,6859,9053,7601\n60500,60550,9064,6865,9064,7612\n60550,60600,9075,6871,9075,7623\n60600,60650,9086,6877,9086,7634\n60650,60700,9097,6883,9097,7645\n60700,60750,9108,6889,9108,7656\n60750,60800,9119,6895,9119,7667\n60800,60850,9130,6901,9130,7678\n60850,60900,9141,6907,9141,7689\n60900,60950,9152,6913,9152,7700\n60950,61000,9163,6919,9163,7711\n61000,61050,9174,6925,9174,7722\n61050,61100,9185,6931,9185,7733\n61100,61150,9196,6937,9196,7744\n61150,61200,9207,6943,9207,7755\n61200,61250,9218,6949,9218,7766\n61250,61300,9229,6955,9229,7777\n61300,61350,9240,6961,9240,7788\n61350,61400,9251,6967,9251,7799\n61400,61450,9262,6973,9262,7810\n61450,61500,9273,6979,9273,7821\n61500,61550,9284,6985,9284,7832\n61550,61600,9295,6991,9295,7843\n61600,61650,9306,6997,9306,7854\n61650,61700,9317,7003,9317,7865\n61700,61750,9328,7009,9328,7876\n61750,61800,9339,7015,9339,7887\n61800,61850,9350,7021,9350,7898\n61850,61900,9361,7027,9361,7909\n61900,61950,9372,7033,9372,7920\n61950,62000,9383,7039,9383,7931\n62000,62050,9394,7045,9394,7942\n62050,62100,9405,7051,9405,7953\n62100,62150,9416,7057,9416,7964\n62150,62200,9427,7063,9427,7975\n62200,62250,9438,7069,9438,7986\n62250,62300,9449,7075,9449,7997\n62300,62350,9460,7081,9460,8008\n62350,62400,9471,7087,9471,8019\n62400,62450,9482,7093,9482,8030\n62450,62500,9493,7099,9493,8041\n62500,62550,9504,7105,9504,8052\n62550,62600,9515,7111,9515,8063\n62600,62650,9526,7117,9526,8074\n62650,62700,9537,7123,9537,8085\n62700,62750,9548,7129,9548,8096\n62750,62800,9559,7135,9559,8107\n62800,62850,9570,7141,9570,8118\n62850,62900,9581,7147,9581,8129\n62900,62950,9592,7153,9592,8140\n62950,63000,9603,7159,9603,8151\n63000,63050,9614,7165,9614,8162\n63050,63100,9625,7171,9625,8173\n63100,63150,9636,7177,9636,8184\n63150,63200,9647,7183,9647,8195\n63200,63250,9658,7189,9658,8206\n63250,63300,9669,7195,9669,8217\n63300,63350,9680,7201,9680,8228\n63350,63400,9691,7207,9691,8239\n63400,63450,9702,7213,9702,8250\n63450,63500,9713,7219,9713,8261\n63500,63550,9724,7225,9724,8272\n63550,63600,9735,7231,9735,8283\n63600,63650,9746,7237,9746,8294\n63650,63700,9757,7243,9757,8305\n63700,63750,9768,7249,9768,8316\n63750,63800,9779,7255,9779,8327\n63800,63850,9790,7261,9790,8338\n63850,63900,9801,7267,9801,8349\n63900,63950,9812,7273,9812,8360\n63950,64000,9823,7279,9823,8371\n64000,64050,9834,7285,9834,8382\n64050,64100,9845,7291,9845,8393\n64100,64150,9856,7297,9856,8404\n64150,64200,9867,7303,9867,8415\n64200,64250,9878,7309,9878,8426\n64250,64300,9889,7315,9889,8437\n64300,64350,9900,7321,9900,8448\n64350,64400,9911,7327,9911,8459\n64400,64450,9922,7333,9922,8470\n64450,64500,9933,7339,9933,8481\n64500,64550,9944,7345,9944,8492\n64550,64600,9955,7351,9955,8503\n64600,64650,9966,7357,9966,8514\n64650,64700,9977,7363,9977,8525\n64700,64750,9988,7369,9988,8536\n64750,64800,9999,7375,9999,8547\n64800,64850,10010,7381,10010,8558\n64850,64900,10021,7387,10021,8569\n64900,64950,10032,7393,10032,8580\n64950,65000,10043,7399,10043,8591\n65000,65050,10054,7405,10054,8602\n65050,65100,10065,7411,10065,8613\n65100,65150,10076,7417,10076,8624\n65150,65200,10087,7423,10087,8635\n65200,65250,10098,7429,10098,8646\n65250,65300,10109,7435,10109,8657\n65300,65350,10120,7441,10120,8668\n65350,65400,10131,7447,10131,8679\n65400,65450,10142,7453,10142,8690\n65450,65500,10153,7459,10153,8701\n65500,65550,10164,7465,10164,8712\n65550,65600,10175,7471,10175,8723\n65600,65650,10186,7477,10186,8734\n65650,65700,10197,7483,10197,8745\n65700,65750,10208,7489,10208,8756\n65750,65800,10219,7495,10219,8767\n65800,65850,10230,7501,10230,8778\n65850,65900,10241,7507,10241,8789\n65900,65950,10252,7513,10252,8800\n65950,66000,10263,7519,10263,8811\n66000,66050,10274,7525,10274,8822\n66050,66100,10285,7531,10285,8833\n66100,66150,10296,7537,10296,8844\n66150,66200,10307,7543,10307,8855\n66200,66250,10318,7549,10318,8866\n66250,66300,10329,7555,10329,8877\n66300,66350,10340,7561,10340,8888\n66350,66400,10351,7567,10351,8899\n66400,66450,10362,7573,10362,8910\n66450,66500,10373,7579,10373,8921\n66500,66550,10384,7585,10384,8932\n66550,66600,10395,7591,10395,8943\n66600,66650,10406,7597,10406,8954\n66650,66700,10417,7603,10417,8965\n66700,66750,10428,7609,10428,8976\n66750,66800,10439,7615,10439,8987\n66800,66850,10450,7621,10450,8998\n66850,66900,10461,7627,10461,9009\n66900,66950,10472,7633,10472,9020\n66950,67000,10483,7639,10483,9031\n67000,67050,10494,7645,10494,9042\n67050,67100,10505,7651,10505,9053\n67100,67150,10516,7657,10516,9064\n67150,67200,10527,7663,10527,9075\n67200,67250,10538,7669,10538,9086\n67250,67300,10549,7675,10549,9097\n67300,67350,10560,7681,10560,9108\n67350,67400,10571,7687,10571,9119\n67400,67450,10582,7693,10582,9130\n67450,67500,10593,7699,10593,9141\n67500,67550,10604,7705,10604,9152\n67550,67600,10615,7711,10615,9163\n67600,67650,10626,7717,10626,9174\n67650,67700,10637,7723,10637,9185\n67700,67750,10648,7729,10648,9196\n67750,67800,10659,7735,10659,9207\n67800,67850,10670,7741,10670,9218\n67850,67900,10681,7747,10681,9229\n67900,67950,10692,7753,10692,9240\n67950,68000,10703,7759,10703,9251\n68000,68050,10714,7765,10714,9262\n68050,68100,10725,7771,10725,9273\n68100,68150,10736,7777,10736,9284\n68150,68200,10747,7783,10747,9295\n68200,68250,10758,7789,10758,9306\n68250,68300,10769,7795,10769,9317\n68300,68350,10780,7801,10780,9328\n68350,68400,10791,7807,10791,9339\n68400,68450,10802,7813,10802,9350\n68450,68500,10813,7819,10813,9361\n68500,68550,10824,7825,10824,9372\n68550,68600,10835,7831,10835,9383\n68600,68650,10846,7837,10846,9394\n68650,68700,10857,7843,10857,9405\n68700,68750,10868,7849,10868,9416\n68750,68800,10879,7855,10879,9427\n68800,68850,10890,7861,10890,9438\n68850,68900,10901,7867,10901,9449\n68900,68950,10912,7873,10912,9460\n68950,69000,10923,7879,10923,9471\n69000,69050,10934,7885,10934,9482\n69050,69100,10945,7891,10945,9493\n69100,69150,10956,7897,10956,9504\n69150,69200,10967,7903,10967,9515\n69200,69250,10978,7909,10978,9526\n69250,69300,10989,7915,10989,9537\n69300,69350,11000,7921,11000,9548\n69350,69400,11011,7927,11011,9559\n69400,69450,11022,7933,11022,9570\n69450,69500,11033,7939,11033,9581\n69500,69550,11044,7945,11044,9592\n69550,69600,11055,7951,11055,9603\n69600,69650,11066,7957,11066,9614\n69650,69700,11077,7963,11077,9625\n69700,69750,11088,7969,11088,9636\n69750,69800,11099,7975,11099,9647\n69800,69850,11110,7981,11110,9658\n69850,69900,11121,7987,11121,9669\n69900,69950,11132,7993,11132,9680\n69950,70000,11143,7999,11143,9691\n70000,70050,11154,8005,11154,9702\n70050,70100,11165,8011,11165,9713\n70100,70150,11176,8017,11176,9724\n70150,70200,11187,8023,11187,9735\n70200,70250,11198,8029,11198,9746\n70250,70300,11209,8035,11209,9757\n70300,70350,11220,8041,11220,9768\n70350,70400,11231,8047,11231,9779\n70400,70450,11242,8053,11242,9790\n70450,70500,11253,8059,11253,9801\n70500,70550,11264,8065,11264,9812\n70550,70600,11275,8071,11275,9823\n70600,70650,11286,8077,11286,9834\n70650,70700,11297,8083,11297,9845\n70700,70750,11308,8089,11308,9856\n70750,70800,11319,8095,11319,9867\n70800,70850,11330,8101,11330,9878\n70850,70900,11341,8107,11341,9889\n70900,70950,11352,8113,11352,9900\n70950,71000,11363,8119,11363,9911\n71000,71050,11374,8125,11374,9922\n71050,71100,11385,8131,11385,9933\n71100,71150,11396,8137,11396,9944\n71150,71200,11407,8143,11407,9955\n71200,71250,11418,8149,11418,9966\n71250,71300,11429,8155,11429,9977\n71300,71350,11440,8161,11440,9988\n71350,71400,11451,8167,11451,9999\n71400,71450,11462,8173,11462,10010\n71450,71500,11473,8179,11473,10021\n71500,71550,11484,8185,11484,10032\n71550,71600,11495,8191,11495,10043\n71600,71650,11506,8197,11506,10054\n71650,71700,11517,8203,11517,10065\n71700,71750,11528,8209,11528,10076\n71750,71800,11539,8215,11539,10087\n71800,71850,11550,8221,11550,10098\n71850,71900,11561,8227,11561,10109\n71900,71950,11572,8233,11572,10120\n71950,72000,11583,8239,11583,10131\n72000,72050,11594,8245,11594,10142\n72050,72100,11605,8251,11605,10153\n72100,72150,11616,8257,11616,10164\n72150,72200,11627,8263,11627,10175\n72200,72250,11638,8269,11638,10186\n72250,72300,11649,8275,11649,10197\n72300,72350,11660,8281,11660,10208\n72350,72400,11671,8287,11671,10219\n72400,72450,11682,8293,11682,10230\n72450,72500,11693,8299,11693,10241\n72500,72550,11704,8305,11704,10252\n72550,72600,11715,8311,11715,10263\n72600,72650,11726,8317,11726,10274\n72650,72700,11737,8323,11737,10285\n72700,72750,11748,8329,11748,10296\n72750,72800,11759,8335,11759,10307\n72800,72850,11770,8341,11770,10318\n72850,72900,11781,8347,11781,10329\n72900,72950,11792,8353,11792,10340\n72950,73000,11803,8359,11803,10351\n73000,73050,11814,8365,11814,10362\n73050,73100,11825,8371,11825,10373\n73100,73150,11836,8377,11836,10384\n73150,73200,11847,8383,11847,10395\n73200,73250,11858,8389,11858,10406\n73250,73300,11869,8395,11869,10417\n73300,73350,11880,8401,11880,10428\n73350,73400,11891,8407,11891,10439\n73400,73450,11902,8413,11902,10450\n73450,73500,11913,8419,11913,10461\n73500,73550,11924,8425,11924,10472\n73550,73600,11935,8431,11935,10483\n73600,73650,11946,8437,11946,10494\n73650,73700,11957,8443,11957,10505\n73700,73750,11968,8449,11968,10516\n73750,73800,11979,8455,11979,10527\n73800,73850,11990,8461,11990,10538\n73850,73900,12001,8467,12001,10549\n73900,73950,12012,8473,12012,10560\n73950,74000,12023,8479,12023,10571\n74000,74050,12034,8485,12034,10582\n74050,74100,12045,8491,12045,10593\n74100,74150,12056,8497,12056,10604\n74150,74200,12067,8503,12067,10615\n74200,74250,12078,8509,12078,10626\n74250,74300,12089,8515,12089,10637\n74300,74350,12100,8521,12100,10648\n74350,74400,12111,8527,12111,10659\n74400,74450,12122,8533,12122,10670\n74450,74500,12133,8539,12133,10681\n74500,74550,12144,8545,12144,10692\n74550,74600,12155,8551,12155,10703\n74600,74650,12166,8557,12166,10714\n74650,74700,12177,8563,12177,10725\n74700,74750,12188,8569,12188,10736\n74750,74800,12199,8575,12199,10747\n74800,74850,12210,8581,12210,10758\n74850,74900,12221,8587,12221,10769\n74900,74950,12232,8593,12232,10780\n74950,75000,12243,8599,12243,10791\n75000,75050,12254,8605,12254,10802\n75050,75100,12265,8611,12265,10813\n75100,75150,12276,8617,12276,10824\n75150,75200,12287,8623,12287,10835\n75200,75250,12298,8629,12298,10846\n75250,75300,12309,8635,12309,10857\n75300,75350,12320,8641,12320,10868\n75350,75400,12331,8647,12331,10879\n75400,75450,12342,8653,12342,10890\n75450,75500,12353,8659,12353,10901\n75500,75550,12364,8665,12364,10912\n75550,75600,12375,8671,12375,10923\n75600,75650,12386,8677,12386,10934\n75650,75700,12397,8683,12397,10945\n75700,75750,12408,8689,12408,10956\n75750,75800,12419,8695,12419,10967\n75800,75850,12430,8701,12430,10978\n75850,75900,12441,8707,12441,10989\n75900,75950,12452,8713,12452,11000\n75950,76000,12463,8719,12463,11011\n76000,76050,12474,8725,12474,11022\n76050,76100,12485,8731,12485,11033\n76100,76150,12496,8737,12496,11044\n76150,76200,12507,8743,12507,11055\n76200,76250,12518,8749,12518,11066\n76250,76300,12529,8755,12529,11077\n76300,76350,12540,8761,12540,11088\n76350,76400,12551,8767,12551,11099\n76400,76450,12562,8773,12562,11110\n76450,76500,12573,8779,12573,11121\n76500,76550,12584,8785,12584,11132\n76550,76600,12595,8791,12595,11143\n76600,76650,12606,8797,12606,11154\n76650,76700,12617,8803,12617,11165\n76700,76750,12628,8809,12628,11176\n76750,76800,12639,8815,12639,11187\n76800,76850,12650,8821,12650,11198\n76850,76900,12661,8827,12661,11209\n76900,76950,12672,8833,12672,11220\n76950,77000,12683,8839,12683,11231\n77000,77050,12694,8845,12694,11242\n77050,77100,12705,8851,12705,11253\n77100,77150,12716,8857,12716,11264\n77150,77200,12727,8863,12727,11275\n77200,77250,12738,8869,12738,11286\n77250,77300,12749,8875,12749,11297\n77300,77350,12760,8881,12760,11308\n77350,77400,12771,8887,12771,11319\n77400,77450,12782,8893,12782,11330\n77450,77500,12793,8899,12793,11341\n77500,77550,12804,8905,12804,11352\n77550,77600,12815,8911,12815,11363\n77600,77650,12826,8917,12826,11374\n77650,77700,12837,8923,12837,11385\n77700,77750,12848,8929,12848,11396\n77750,77800,12859,8935,12859,11407\n77800,77850,12870,8941,12870,11418\n77850,77900,12881,8947,12881,11429\n77900,77950,12892,8953,12892,11440\n77950,78000,12903,8959,12903,11451\n78000,78050,12914,8965,12914,11462\n78050,78100,12925,8971,12925,11473\n78100,78150,12936,8977,12936,11484\n78150,78200,12947,8983,12947,11495\n78200,78250,12958,8989,12958,11506\n78250,78300,12969,8995,12969,11517\n78300,78350,12980,9001,12980,11528\n78350,78400,12991,9007,12991,11539\n78400,78450,13002,9013,13002,11550\n78450,78500,13013,9019,13013,11561\n78500,78550,13024,9025,13024,11572\n78550,78600,13035,9031,13035,11583\n78600,78650,13046,9037,13046,11594\n78650,78700,13057,9043,13057,11605\n78700,78750,13068,9049,13068,11616\n78750,78800,13079,9055,13079,11627\n78800,78850,13090,9061,13090,11638\n78850,78900,13101,9067,13101,11649\n78900,78950,13112,9073,13112,11660\n78950,79000,13123,9079,13123,11671\n79000,79050,13134,9085,13134,11682\n79050,79100,13145,9091,13145,11693\n79100,79150,13156,9097,13156,11704\n79150,79200,13167,9103,13167,11715\n79200,79250,13178,9109,13178,11726\n79250,79300,13189,9115,13189,11737\n79300,79350,13200,9121,13200,11748\n79350,79400,13211,9127,13211,11759\n79400,79450,13222,9133,13222,11770\n79450,79500,13233,9139,13233,11781\n79500,79550,13244,9145,13244,11792\n79550,79600,13255,9151,13255,11803\n79600,79650,13266,9157,13266,11814\n79650,79700,13277,9163,13277,11825\n79700,79750,13288,9169,13288,11836\n79750,79800,13299,9175,13299,11847\n79800,79850,13310,9181,13310,11858\n79850,79900,13321,9187,13321,11869\n79900,79950,13332,9193,13332,11880\n79950,80000,13343,9199,13343,11891\n80000,80050,13354,9205,13354,11902\n80050,80100,13365,9211,13365,11913\n80100,80150,13376,9217,13376,11924\n80150,80200,13387,9223,13387,11935\n80200,80250,13398,9229,13398,11946\n80250,80300,13409,9235,13409,11957\n80300,80350,13420,9241,13420,11968\n80350,80400,13431,9247,13431,11979\n80400,80450,13442,9253,13442,11990\n80450,80500,13453,9259,13453,12001\n80500,80550,13464,9265,13464,12012\n80550,80600,13475,9271,13475,12023\n80600,80650,13486,9277,13486,12034\n80650,80700,13497,9283,13497,12045\n80700,80750,13508,9289,13508,12056\n80750,80800,13519,9295,13519,12067\n80800,80850,13530,9301,13530,12078\n80850,80900,13541,9307,13541,12089\n80900,80950,13552,9313,13552,12100\n80950,81000,13563,9319,13563,12111\n81000,81050,13574,9325,13574,12122\n81050,81100,13585,9334,13585,12133\n81100,81150,13596,9345,13596,12144\n81150,81200,13607,9356,13607,12155\n81200,81250,13618,9367,13618,12166\n81250,81300,13629,9378,13629,12177\n81300,81350,13640,9389,13640,12188\n81350,81400,13651,9400,13651,12199\n81400,81450,13662,9411,13662,12210\n81450,81500,13673,9422,13673,12221\n81500,81550,13684,9433,13684,12232\n81550,81600,13695,9444,13695,12243\n81600,81650,13706,9455,13706,12254\n81650,81700,13717,9466,13717,12265\n81700,81750,13728,9477,13728,12276\n81750,81800,13739,9488,13739,12287\n81800,81850,13750,9499,13750,12298\n81850,81900,13761,9510,13761,12309\n81900,81950,13772,9521,13772,12320\n81950,82000,13783,9532,13783,12331\n82000,82050,13794,9543,13794,12342\n82050,82100,13805,9554,13805,12353\n82100,82150,13816,9565,13816,12364\n82150,82200,13827,9576,13827,12375\n82200,82250,13838,9587,13838,12386\n82250,82300,13849,9598,13849,12397\n82300,82350,13860,9609,13860,12408\n82350,82400,13871,9620,13871,12419\n82400,82450,13882,9631,13882,12430\n82450,82500,13893,9642,13893,12441\n82500,82550,13904,9653,13904,12452\n82550,82600,13915,9664,13915,12463\n82600,82650,13926,9675,13926,12474\n82650,82700,13937,9686,13937,12485\n82700,82750,13948,9697,13948,12496\n82750,82800,13959,9708,13959,12507\n82800,82850,13970,9719,13970,12518\n82850,82900,13981,9730,13981,12529\n82900,82950,13992,9741,13992,12540\n82950,83000,14003,9752,14003,12551\n83000,83050,14014,9763,14014,12562\n83050,83100,14025,9774,14025,12573\n83100,83150,14036,9785,14036,12584\n83150,83200,14047,9796,14047,12595\n83200,83250,14058,9807,14058,12606\n83250,83300,14069,9818,14069,12617\n83300,83350,14080,9829,14080,12628\n83350,83400,14091,9840,14091,12639\n83400,83450,14102,9851,14102,12650\n83450,83500,14113,9862,14113,12661\n83500,83550,14124,9873,14124,12672\n83550,83600,14135,9884,14135,12683\n83600,83650,14146,9895,14146,12694\n83650,83700,14157,9906,14157,12705\n83700,83750,14168,9917,14168,12716\n83750,83800,14179,9928,14179,12727\n83800,83850,14190,9939,14190,12738\n83850,83900,14201,9950,14201,12749\n83900,83950,14212,9961,14212,12760\n83950,84000,14223,9972,14223,12771\n84000,84050,14234,9983,14234,12782\n84050,84100,14245,9994,14245,12793\n84100,84150,14256,10005,14256,12804\n84150,84200,14267,10016,14267,12815\n84200,84250,14278,10027,14278,12826\n84250,84300,14289,10038,14289,12837\n84300,84350,14300,10049,14300,12848\n84350,84400,14311,10060,14311,12859\n84400,84450,14322,10071,14322,12870\n84450,84500,14333,10082,14333,12881\n84500,84550,14344,10093,14344,12892\n84550,84600,14355,10104,14355,12903\n84600,84650,14366,10115,14366,12914\n84650,84700,14377,10126,14377,12925\n84700,84750,14388,10137,14388,12936\n84750,84800,14399,10148,14399,12947\n84800,84850,14410,10159,14410,12958\n84850,84900,14421,10170,14421,12969\n84900,84950,14432,10181,14432,12980\n84950,85000,14443,10192,14443,12991\n85000,85050,14454,10203,14454,13002\n85050,85100,14465,10214,14465,13013\n85100,85150,14476,10225,14476,13024\n85150,85200,14487,10236,14487,13035\n85200,85250,14498,10247,14498,13046\n85250,85300,14509,10258,14509,13057\n85300,85350,14520,10269,14520,13068\n85350,85400,14531,10280,14531,13079\n85400,85450,14542,10291,14542,13090\n85450,85500,14553,10302,14553,13101\n85500,85550,14564,10313,14564,13112\n85550,85600,14575,10324,14575,13123\n85600,85650,14586,10335,14586,13134\n85650,85700,14597,10346,14597,13145\n85700,85750,14608,10357,14608,13156\n85750,85800,14619,10368,14619,13167\n85800,85850,14630,10379,14630,13178\n85850,85900,14641,10390,14641,13189\n85900,85950,14652,10401,14652,13200\n85950,86000,14663,10412,14663,13211\n86000,86050,14674,10423,14674,13222\n86050,86100,14685,10434,14685,13233\n86100,86150,14696,10445,14696,13244\n86150,86200,14707,10456,14707,13255\n86200,86250,14718,10467,14718,13266\n86250,86300,14729,10478,14729,13277\n86300,86350,14740,10489,14740,13288\n86350,86400,14751,10500,14751,13299\n86400,86450,14763,10511,14763,13311\n86450,86500,14775,10522,14775,13323\n86500,86550,14787,10533,14787,13335\n86550,86600,14799,10544,14799,13347\n86600,86650,14811,10555,14811,13359\n86650,86700,14823,10566,14823,13371\n86700,86750,14835,10577,14835,13383\n86750,86800,14847,10588,14847,13395\n86800,86850,14859,10599,14859,13407\n86850,86900,14871,10610,14871,13419\n86900,86950,14883,10621,14883,13431\n86950,87000,14895,10632,14895,13443\n87000,87050,14907,10643,14907,13455\n87050,87100,14919,10654,14919,13467\n87100,87150,14931,10665,14931,13479\n87150,87200,14943,10676,14943,13491\n87200,87250,14955,10687,14955,13503\n87250,87300,14967,10698,14967,13515\n87300,87350,14979,10709,14979,13527\n87350,87400,14991,10720,14991,13539\n87400,87450,15003,10731,15003,13551\n87450,87500,15015,10742,15015,13563\n87500,87550,15027,10753,15027,13575\n87550,87600,15039,10764,15039,13587\n87600,87650,15051,10775,15051,13599\n87650,87700,15063,10786,15063,13611\n87700,87750,15075,10797,15075,13623\n87750,87800,15087,10808,15087,13635\n87800,87850,15099,10819,15099,13647\n87850,87900,15111,10830,15111,13659\n87900,87950,15123,10841,15123,13671\n87950,88000,15135,10852,15135,13683\n88000,88050,15147,10863,15147,13695\n88050,88100,15159,10874,15159,13707\n88100,88150,15171,10885,15171,13719\n88150,88200,15183,10896,15183,13731\n88200,88250,15195,10907,15195,13743\n88250,88300,15207,10918,15207,13755\n88300,88350,15219,10929,15219,13767\n88350,88400,15231,10940,15231,13779\n88400,88450,15243,10951,15243,13791\n88450,88500,15255,10962,15255,13803\n88500,88550,15267,10973,15267,13815\n88550,88600,15279,10984,15279,13827\n88600,88650,15291,10995,15291,13839\n88650,88700,15303,11006,15303,13851\n88700,88750,15315,11017,15315,13863\n88750,88800,15327,11028,15327,13875\n88800,88850,15339,11039,15339,13887\n88850,88900,15351,11050,15351,13899\n88900,88950,15363,11061,15363,13911\n88950,89000,15375,11072,15375,13923\n89000,89050,15387,11083,15387,13935\n89050,89100,15399,11094,15399,13947\n89100,89150,15411,11105,15411,13959\n89150,89200,15423,11116,15423,13971\n89200,89250,15435,11127,15435,13983\n89250,89300,15447,11138,15447,13995\n89300,89350,15459,11149,15459,14007\n89350,89400,15471,11160,15471,14019\n89400,89450,15483,11171,15483,14031\n89450,89500,15495,11182,15495,14043\n89500,89550,15507,11193,15507,14055\n89550,89600,15519,11204,15519,14067\n89600,89650,15531,11215,15531,14079\n89650,89700,15543,11226,15543,14091\n89700,89750,15555,11237,15555,14103\n89750,89800,15567,11248,15567,14115\n89800,89850,15579,11259,15579,14127\n89850,89900,15591,11270,15591,14139\n89900,89950,15603,11281,15603,14151\n89950,90000,15615,11292,15615,14163\n90000,90050,15627,11303,15627,14175\n90050,90100,15639,11314,15639,14187\n90100,90150,15651,11325,15651,14199\n90150,90200,15663,11336,15663,14211\n90200,90250,15675,11347,15675,14223\n90250,90300,15687,11358,15687,14235\n90300,90350,15699,11369,15699,14247\n90350,90400,15711,11380,15711,14259\n90400,90450,15723,11391,15723,14271\n90450,90500,15735,11402,15735,14283\n90500,90550,15747,11413,15747,14295\n90550,90600,15759,11424,15759,14307\n90600,90650,15771,11435,15771,14319\n90650,90700,15783,11446,15783,14331\n90700,90750,15795,11457,15795,14343\n90750,90800,15807,11468,15807,14355\n90800,90850,15819,11479,15819,14367\n90850,90900,15831,11490,15831,14379\n90900,90950,15843,11501,15843,14391\n90950,91000,15855,11512,15855,14403\n91000,91050,15867,11523,15867,14415\n91050,91100,15879,11534,15879,14427\n91100,91150,15891,11545,15891,14439\n91150,91200,15903,11556,15903,14451\n91200,91250,15915,11567,15915,14463\n91250,91300,15927,11578,15927,14475\n91300,91350,15939,11589,15939,14487\n91350,91400,15951,11600,15951,14499\n91400,91450,15963,11611,15963,14511\n91450,91500,15975,11622,15975,14523\n91500,91550,15987,11633,15987,14535\n91550,91600,15999,11644,15999,14547\n91600,91650,16011,11655,16011,14559\n91650,91700,16023,11666,16023,14571\n91700,91750,16035,11677,16035,14583\n91750,91800,16047,11688,16047,14595\n91800,91850,16059,11699,16059,14607\n91850,91900,16071,11710,16071,14619\n91900,91950,16083,11721,16083,14631\n91950,92000,16095,11732,16095,14643\n92000,92050,16107,11743,16107,14655\n92050,92100,16119,11754,16119,14667\n92100,92150,16131,11765,16131,14679\n92150,92200,16143,11776,16143,14691\n92200,92250,16155,11787,16155,14703\n92250,92300,16167,11798,16167,14715\n92300,92350,16179,11809,16179,14727\n92350,92400,16191,11820,16191,14739\n92400,92450,16203,11831,16203,14751\n92450,92500,16215,11842,16215,14763\n92500,92550,16227,11853,16227,14775\n92550,92600,16239,11864,16239,14787\n92600,92650,16251,11875,16251,14799\n92650,92700,16263,11886,16263,14811\n92700,92750,16275,11897,16275,14823\n92750,92800,16287,11908,16287,14835\n92800,92850,16299,11919,16299,14847\n92850,92900,16311,11930,16311,14859\n92900,92950,16323,11941,16323,14871\n92950,93000,16335,11952,16335,14883\n93000,93050,16347,11963,16347,14895\n93050,93100,16359,11974,16359,14907\n93100,93150,16371,11985,16371,14919\n93150,93200,16383,11996,16383,14931\n93200,93250,16395,12007,16395,14943\n93250,93300,16407,12018,16407,14955\n93300,93350,16419,12029,16419,14967\n93350,93400,16431,12040,16431,14979\n93400,93450,16443,12051,16443,14991\n93450,93500,16455,12062,16455,15003\n93500,93550,16467,12073,16467,15015\n93550,93600,16479,12084,16479,15027\n93600,93650,16491,12095,16491,15039\n93650,93700,16503,12106,16503,15051\n93700,93750,16515,12117,16515,15063\n93750,93800,16527,12128,16527,15075\n93800,93850,16539,12139,16539,15087\n93850,93900,16551,12150,16551,15099\n93900,93950,16563,12161,16563,15111\n93950,94000,16575,12172,16575,15123\n94000,94050,16587,12183,16587,15135\n94050,94100,16599,12194,16599,15147\n94100,94150,16611,12205,16611,15159\n94150,94200,16623,12216,16623,15171\n94200,94250,16635,12227,16635,15183\n94250,94300,16647,12238,16647,15195\n94300,94350,16659,12249,16659,15207\n94350,94400,16671,12260,16671,15219\n94400,94450,16683,12271,16683,15231\n94450,94500,16695,12282,16695,15243\n94500,94550,16707,12293,16707,15255\n94550,94600,16719,12304,16719,15267\n94600,94650,16731,12315,16731,15279\n94650,94700,16743,12326,16743,15291\n94700,94750,16755,12337,16755,15303\n94750,94800,16767,12348,16767,15315\n94800,94850,16779,12359,16779,15327\n94850,94900,16791,12370,16791,15339\n94900,94950,16803,12381,16803,15351\n94950,95000,16815,12392,16815,15363\n95000,95050,16827,12403,16827,15375\n95050,95100,16839,12414,16839,15387\n95100,95150,16851,12425,16851,15399\n95150,95200,16863,12436,16863,15411\n95200,95250,16875,12447,16875,15423\n95250,95300,16887,12458,16887,15435\n95300,95350,16899,12469,16899,15447\n95350,95400,16911,12480,16911,15459\n95400,95450,16923,12491,16923,15471\n95450,95500,16935,12502,16935,15483\n95500,95550,16947,12513,16947,15495\n95550,95600,16959,12524,16959,15507\n95600,95650,16971,12535,16971,15519\n95650,95700,16983,12546,16983,15531\n95700,95750,16995,12557,16995,15543\n95750,95800,17007,12568,17007,15555\n95800,95850,17019,12579,17019,15567\n95850,95900,17031,12590,17031,15579\n95900,95950,17043,12601,17043,15591\n95950,96000,17055,12612,17055,15603\n96000,96050,17067,12623,17067,15615\n96050,96100,17079,12634,17079,15627\n96100,96150,17091,12645,17091,15639\n96150,96200,17103,12656,17103,15651\n96200,96250,17115,12667,17115,15663\n96250,96300,17127,12678,17127,15675\n96300,96350,17139,12689,17139,15687\n96350,96400,17151,12700,17151,15699\n96400,96450,17163,12711,17163,15711\n96450,96500,17175,12722,17175,15723\n96500,96550,17187,12733,17187,15735\n96550,96600,17199,12744,17199,15747\n96600,96650,17211,12755,17211,15759\n96650,96700,17223,12766,17223,15771\n96700,96750,17235,12777,17235,15783\n96750,96800,17247,12788,17247,15795\n96800,96850,17259,12799,17259,15807\n96850,96900,17271,12810,17271,15819\n96900,96950,17283,12821,17283,15831\n96950,97000,17295,12832,17295,15843\n97000,97050,17307,12843,17307,15855\n97050,97100,17319,12854,17319,15867\n97100,97150,17331,12865,17331,15879\n97150,97200,17343,12876,17343,15891\n97200,97250,17355,12887,17355,15903\n97250,97300,17367,12898,17367,15915\n97300,97350,17379,12909,17379,15927\n97350,97400,17391,12920,17391,15939\n97400,97450,17403,12931,17403,15951\n97450,97500,17415,12942,17415,15963\n97500,97550,17427,12953,17427,15975\n97550,97600,17439,12964,17439,15987\n97600,97650,17451,12975,17451,15999\n97650,97700,17463,12986,17463,16011\n97700,97750,17475,12997,17475,16023\n97750,97800,17487,13008,17487,16035\n97800,97850,17499,13019,17499,16047\n97850,97900,17511,13030,17511,16059\n97900,97950,17523,13041,17523,16071\n97950,98000,17535,13052,17535,16083\n98000,98050,17547,13063,17547,16095\n98050,98100,17559,13074,17559,16107\n98100,98150,17571,13085,17571,16119\n98150,98200,17583,13096,17583,16131\n98200,98250,17595,13107,17595,16143\n98250,98300,17607,13118,17607,16155\n98300,98350,17619,13129,17619,16167\n98350,98400,17631,13140,17631,16179\n98400,98450,17643,13151,17643,16191\n98450,98500,17655,13162,17655,16203\n98500,98550,17667,13173,17667,16215\n98550,98600,17679,13184,17679,16227\n98600,98650,17691,13195,17691,16239\n98650,98700,17703,13206,17703,16251\n98700,98750,17715,13217,17715,16263\n98750,98800,17727,13228,17727,16275\n98800,98850,17739,13239,17739,16287\n98850,98900,17751,13250,17751,16299\n98900,98950,17763,13261,17763,16311\n98950,99000,17775,13272,17775,16323\n99000,99050,17787,13283,17787,16335\n99050,99100,17799,13294,17799,16347\n99100,99150,17811,13305,17811,16359\n99150,99200,17823,13316,17823,16371\n99200,99250,17835,13327,17835,16383\n99250,99300,17847,13338,17847,16395\n99300,99350,17859,13349,17859,16407\n99350,99400,17871,13360,17871,16419\n99400,99450,17883,13371,17883,16431\n99450,99500,17895,13382,17895,16443\n99500,99550,17907,13393,17907,16455\n99550,99600,17919,13404,17919,16467\n99600,99650,17931,13415,17931,16479\n99650,99700,17943,13426,17943,16491\n99700,99750,17955,13437,17955,16503\n99750,99800,17967,13448,17967,16515\n99800,99850,17979,13459,17979,16527\n99850,99900,17991,13470,17991,16539\n99900,99950,18003,13481,18003,16551\n99950,100000,18015,13492,18015,16563\n"
  },
  {
    "path": "src/forms/YearForms.ts",
    "content": "import { Information, Asset } from 'ustaxes/core/data'\nimport { Either, isLeft, isRight, left, run, runAsync } from 'ustaxes/core/util'\nimport { TaxYear } from 'ustaxes/core/data'\nimport { create1040 as create1040For2020 } from 'ustaxes/forms/Y2020/irsForms/Main'\nimport { create1040 as create1040For2021 } from 'ustaxes/forms/Y2021/irsForms/Main'\n\nimport F1040For2020 from 'ustaxes/forms/Y2020/irsForms/F1040'\nimport F1040For2021 from 'ustaxes/forms/Y2021/irsForms/F1040'\n\nimport Form from 'ustaxes/core/irsForms/Form'\nimport StateForm from 'ustaxes/core/stateForms/Form'\n\nimport { createStateReturn as createStateReturn2020 } from 'ustaxes/forms/Y2020/stateForms'\nimport { createStateReturn as createStateReturn2021 } from 'ustaxes/forms/Y2021/stateForms'\nimport { PDFDocument } from 'pdf-lib'\nimport { fillPDF } from 'ustaxes/core/pdfFiller/fillPdf'\nimport {\n  combinePdfs,\n  downloadPDF,\n  PDFDownloader\n} from 'ustaxes/core/pdfFiller/pdfHandler'\nimport { F1040Error } from './errors'\nimport { StateFormError } from './StateForms'\nimport { validate } from './F1040Base'\n\ninterface CreateFormConfig {\n  createF1040: (\n    info: Information,\n    assets: Asset[]\n  ) => Either<F1040Error[], Form[]>\n  getPDF: (f: Form) => Promise<PDFDocument>\n  getStatePDF: (f: StateForm) => Promise<PDFDocument>\n  createStateReturn: (\n    f1040: Form\n  ) => Either<Array<F1040Error | StateFormError>, StateForm[]>\n}\n\nexport class YearCreateForm {\n  year: TaxYear\n  unvalidatedInfo: Information\n  assets: Asset[]\n  config: CreateFormConfig\n\n  constructor(\n    year: TaxYear,\n    info: Information,\n    assets: Asset[],\n    config: CreateFormConfig\n  ) {\n    this.year = year\n    this.unvalidatedInfo = info\n    this.assets = assets\n\n    this.config = config\n  }\n\n  errors = (): F1040Error[] => {\n    const errors = validate(this.unvalidatedInfo)\n    return isLeft(errors) ? errors.left : []\n  }\n\n  f1040 = (): Either<F1040Error[], Form[]> =>\n    run(validate(this.unvalidatedInfo))\n      .chain((info) => this.config.createF1040(info, this.assets))\n      .value()\n\n  f1040Pdfs = async (): Promise<Either<string[], PDFDocument[]>> => {\n    const r1 = await run(this.f1040()).mapAsync((forms) =>\n      Promise.all(\n        forms.map(async (form) =>\n          fillPDF(await this.config.getPDF(form), form.renderedFields())\n        )\n      )\n    )\n    return r1.value()\n  }\n\n  f1040Pdf = async (): Promise<Either<string[], PDFDocument>> => {\n    const r1 = await runAsync(this.f1040Pdfs())\n    const r2 = await r1.mapAsync(combinePdfs)\n    return r2.value()\n  }\n\n  f1040Bytes = async (): Promise<Either<string[], Uint8Array>> => {\n    const r1 = await runAsync(this.f1040Pdf())\n    const r2 = await r1.mapAsync((pdf) => pdf.save())\n    return r2.value()\n  }\n\n  makeStateReturn = (): Either<(F1040Error | StateFormError)[], StateForm[]> =>\n    run(this.f1040())\n      .mapLeft<Array<F1040Error | StateFormError>>((e) => e)\n      .chain((forms) => {\n        if (forms.length < 1) {\n          throw new Error('No forms to create state return')\n        }\n        const f1040 = forms.find((f) => f.tag === 'f1040')\n        if (f1040 === undefined) {\n          throw new Error('Fed forms sent to state creator without 1040')\n        }\n        return this.config.createStateReturn(f1040)\n      })\n      .value()\n\n  stateReturnPDFs = async (): Promise<Either<string[], PDFDocument[]>> => {\n    const r1 = run(this.makeStateReturn())\n    const r2 = await r1.mapAsync((forms) =>\n      Promise.all(\n        forms.map(async (form) =>\n          fillPDF(await this.config.getStatePDF(form), form.renderedFields())\n        )\n      )\n    )\n    return r2.value()\n  }\n\n  stateReturnPDF = async (): Promise<Either<string[], PDFDocument>> => {\n    const r1 = await runAsync(this.stateReturnPDFs())\n    const r2 = await r1.mapAsync(combinePdfs)\n    return r2.value()\n  }\n\n  stateReturnBytes = async (): Promise<Either<string[], Uint8Array>> => {\n    const r1 = await runAsync(this.stateReturnPDF())\n    const r2 = await r1.mapAsync((pdf) => pdf.save())\n    return r2.value()\n  }\n\n  canCreateFederal = (): boolean => isRight(this.f1040())\n\n  canCreateState = (): boolean => isRight(this.makeStateReturn())\n}\n\nexport class CreateForms {\n  readonly year: TaxYear\n  downloader: PDFDownloader\n\n  constructor(year: TaxYear) {\n    this.year = year\n    this.downloader = (url: string) => downloadPDF(`/forms/${year}/${url}`)\n  }\n\n  setDownloader = (downloader: PDFDownloader): CreateForms => {\n    this.downloader = downloader\n    return this\n  }\n\n  build = (info: Information, assets: Asset<Date>[]): YearCreateForm => {\n    const takeSecond =\n      <A, AA, E, B, C>(\n        f: (a: A, aa: AA) => Either<E, [B, C]>\n      ): ((a: A, aa: AA) => Either<E, C>) =>\n      (a: A, aa: AA): Either<E, C> =>\n        run(f(a, aa))\n          .map(([, c]) => c)\n          .value()\n\n    const baseConfig = {\n      getPDF: (form: Form): Promise<PDFDocument> =>\n        this.downloader(`irs/${form.tag}.pdf`),\n\n      getStatePDF: (form: StateForm): Promise<PDFDocument> =>\n        this.downloader(`states/${form.state}/${form.formName}.pdf`)\n    }\n\n    const configs: { [K in TaxYear]: CreateFormConfig } = {\n      Y2019: {\n        ...baseConfig,\n        createF1040: () => left([F1040Error.unsupportedTaxYear]),\n        createStateReturn: () => left([StateFormError.unsupportedTaxYear])\n      },\n      Y2020: {\n        ...baseConfig,\n        createF1040: takeSecond(create1040For2020),\n        createStateReturn: (f: Form) => createStateReturn2020(f as F1040For2020)\n      },\n      Y2021: {\n        ...baseConfig,\n        createF1040: takeSecond(create1040For2021),\n        createStateReturn: (f: Form) => createStateReturn2021(f as F1040For2021)\n      }\n    }\n\n    return new YearCreateForm(this.year, info, assets, configs[this.year])\n  }\n}\n\nexport const yearFormBuilder = (year: TaxYear): CreateForms =>\n  new CreateForms(year)\n\nexport default (\n  year: TaxYear,\n  info: Information,\n  assets: Asset<Date>[]\n): YearCreateForm => yearFormBuilder(year).build(info, assets)\n"
  },
  {
    "path": "src/forms/errors.ts",
    "content": "export enum F1040Error {\n  unsupportedTaxYear = 'Tax year not supported',\n  incompletePrimaryTaxpayer = 'Taxpayer information not completed',\n  filingStatusUndefined = 'Select a filing status',\n  filingStatusRequirementsNotMet = 'Filing status does not match dependents or spouse requirements',\n  unknown = 'Unknown error'\n}\n"
  },
  {
    "path": "src/forms/tests/CommonTests.ts",
    "content": "import { Information, Asset, FilingStatus } from 'ustaxes/core/data'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { run } from 'ustaxes/core/util'\nimport { F1040Error } from '../errors'\nimport F1040Base, { validate } from '../F1040Base'\nimport TestKit from './TestKit'\nexport abstract class FormTestInfo<A> {\n  abstract getAssets: (a: A) => Asset<Date>[]\n  abstract getInfo: (a: A) => Information\n\n  getErrors: (info: Information) => F1040Error[] = (info) =>\n    run(validate(info)).fold(\n      (errors) => errors,\n      () => []\n    )\n}\n\nbeforeAll(() => {\n  jest.spyOn(console, 'warn').mockImplementation((x: string) => {\n    if (!x.includes('Removing XFA form data as pdf-lib')) {\n      console.warn(x)\n    }\n  })\n})\n\nexport default class CommonTests<F1040 extends F1040Base> {\n  testKit: TestKit\n  formTestInfo: FormTestInfo<F1040>\n\n  constructor(testKit: TestKit, formTestInfo: FormTestInfo<F1040>) {\n    this.testKit = testKit\n    this.formTestInfo = formTestInfo\n  }\n\n  findF1040 = (forms: Form[]): F1040 | undefined =>\n    forms.find((v) => v.tag === 'f1040') as F1040 | undefined\n\n  findF1040OrFail = (forms: Form[]): F1040 => {\n    const res = this.findF1040(forms)\n    if (res === undefined) {\n      throw new Error(\n        `Looked for F1040 in ${forms.map((f) => f.tag).join(',')}, not found`\n      )\n    }\n    return res\n  }\n\n  withValid1040 = async (\n    f: (f1040: F1040, fs: FilingStatus) => void,\n    filter: (info: Information) => boolean = () => true\n  ): Promise<void> =>\n    this.testKit.with1040Assert(\n      async (forms): Promise<void> => {\n        const f1040 = this.findF1040OrFail(forms)\n\n        const fs = f1040.info.taxPayer.filingStatus\n\n        await Promise.resolve(f(f1040, fs))\n      },\n      {},\n      filter\n    )\n\n  run = (): void => {\n    it('should be created in', async () => {\n      await this.testKit.with1040Assert((forms) => {\n        const f1040 = this.findF1040(forms)\n        expect(f1040).not.toBeUndefined()\n\n        return Promise.resolve()\n      })\n    })\n\n    it('should arrange attachments according to sequence order', async () => {\n      await this.testKit.with1040Assert((forms) => {\n        expect(forms.sort((a, b) => a.sequenceIndex - b.sequenceIndex)).toEqual(\n          forms\n        )\n        return Promise.resolve()\n      })\n    })\n\n    it('should create a PDF without failing', async () => {\n      await this.testKit.with1040Assert(async (forms) => {\n        const f1040 = this.findF1040(forms)\n        expect(f1040).not.toBeUndefined()\n        if (f1040 !== undefined) {\n          const builder = this.testKit.builder.build(\n            this.formTestInfo.getInfo(f1040),\n            this.formTestInfo.getAssets(f1040)\n          )\n          const pdfs = await builder.f1040Pdfs()\n          run(pdfs).fold(\n            (e) => fail(e),\n            (pdfs) => {\n              expect(pdfs).not.toHaveLength(0)\n            }\n          )\n        }\n      })\n    })\n  }\n}\n"
  },
  {
    "path": "src/forms/tests/TestKit.ts",
    "content": "/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n\nimport fc, { Parameters } from 'fast-check'\nimport { Information, Asset, TaxYear, TaxYears } from 'ustaxes/core/data'\nimport Form from 'ustaxes/core/irsForms/Form'\nimport { run } from 'ustaxes/core/util'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport * as ustarbitraries from 'ustaxes/tests/arbitraries'\nimport { localPDFs } from 'ustaxes/core/tests/LocalForms'\nimport fs from 'fs/promises'\nimport path from 'path'\nimport { PDFDocument } from 'pdf-lib'\nimport { insertFormDataToPdfs } from 'ustaxes/core/irsForms'\nimport { CreateForms, yearFormBuilder } from '../YearForms'\nimport { PDFDownloader } from 'ustaxes/core/pdfFiller/pdfHandler'\nimport { ValidatedInformation } from '../F1040Base'\n\nconst logsDir = path.resolve(__dirname, '../../../logs/errors')\n\nexport default class TestKit {\n  year: TaxYear\n  downloader: PDFDownloader\n  arbitaries: arbitraries.Arbitraries\n  builder: CreateForms\n  constructor(year: TaxYear) {\n    this.year = year\n    this.downloader = localPDFs(year)\n    this.arbitaries = new arbitraries.Arbitraries(TaxYears[year])\n    this.builder = yearFormBuilder(year).setDownloader(this.downloader)\n  }\n\n  /**\n   * This is used when there is some error generated in a test\n   * The calculated forms will be used to generate a return and\n   * saved to the /logs directory in the project root.\n   */\n  log1040 = async (\n    info: Information,\n    assets: Asset<Date>[],\n    logstr?: string\n  ): Promise<void> => {\n    try {\n      const builder = this.builder.build(info, assets)\n      const pdfs = await builder.f1040Pdfs()\n      const today = new Date()\n      const dateStr = `${today.getFullYear()}-${\n        today.getMonth() + 1\n      }-${today.getDate()}`\n      const saveDirName = `Errors ${dateStr} ${today.toLocaleTimeString()}`\n      const saveDir = path.resolve(logsDir, saveDirName)\n      await fs.mkdir(saveDir, { recursive: true })\n      await run(pdfs).fold(\n        (e: string[]) =>\n          fs.writeFile(path.resolve(saveDir, 'failure.txt'), e.join('\\n')),\n        (pdfs) =>\n          Promise.all(\n            pdfs.map(async (pdf, i) => {\n              await fs.writeFile(\n                path.resolve(saveDir, pdf.getTitle() ?? `Form ${i}`),\n                await pdf.save()\n              )\n            })\n          )\n      )\n      await fs.writeFile(\n        path.resolve(saveDir, 'info.json'),\n        JSON.stringify(info, null, 2)\n      )\n      if (logstr !== undefined) {\n        await fs.writeFile(\n          path.resolve(saveDir, 'error.txt'),\n          logstr.toString()\n        )\n      }\n    } catch (e) {\n      console.info('Got another error trying to log testing error')\n      console.error(e)\n      console.error('Giving up!')\n      throw e\n    }\n  }\n\n  /**\n   * Run a property test on generated PDFs\n   * **Must** be awaited\n   */\n  with1040Pdfs = async (\n    f: (pdfs: PDFDocument[], info: Information, assets: Asset<Date>[]) => void,\n    params: Parameters<[Information, Asset<Date>[]]> = {\n      // This might take a long time as many pdfs have to be rendered\n      // So by default just run for 1 minute max and hope\n      interruptAfterTimeLimit: 60 * 1000\n    }\n  ): Promise<void> =>\n    await this.with1040Assert(async (forms, info, assets) => {\n      const pdfs = await insertFormDataToPdfs(forms, this.downloader)\n      f(pdfs, info, assets)\n    }, params)\n\n  with1040Property = (\n    f: (\n      forms: Form[],\n      info: ValidatedInformation,\n      assets: Asset<Date>[]\n    ) => Promise<void>,\n    filter: (info: ValidatedInformation) => boolean = () => true\n  ): fc.IAsyncPropertyWithHooks<[ValidatedInformation, Asset<Date>[]]> =>\n    fc.asyncProperty(\n      this.arbitaries.information().filter(filter),\n      fc.array(ustarbitraries.positionDate),\n      async (information, assets): Promise<void> => {\n        const builder = this.builder.build(information, assets)\n        await run(builder.f1040()).fold(\n          async (e: string[]): Promise<void> => {\n            await Promise.resolve(expect(e).not.toEqual([]))\n          },\n          async (forms: Form[]): Promise<void> => {\n            return await f(forms, information, assets)\n          }\n        )\n      }\n    )\n\n  /**\n   * Run a property test on 1040 data.\n   * Must** be awaited.\n   */\n  with1040Assert = async (\n    f: (\n      forms: Form[],\n      info: ValidatedInformation,\n      assets: Asset<Date>[]\n    ) => Promise<void>,\n    params: Parameters<[Information, Asset<Date>[]]> = {},\n    filter: (info: ValidatedInformation) => boolean = () => true\n  ): Promise<void> => {\n    let lastCallWithInfo: [ValidatedInformation, Asset<Date>[]] | undefined\n    await fc\n      .assert(\n        this.with1040Property(async (forms, info, assets) => {\n          await f(forms, info, assets).catch((e) => {\n            // Save the last failing test info for logging\n            lastCallWithInfo = [info, assets]\n            // Hand it back to fc's assert.\n            // We're only saving the last form data after\n            // fast-check has done its shrinking. So we need\n            // fast-check to catch this exception and decide\n            // whether to run it again.\n            throw e\n          })\n        }, filter),\n        params\n      )\n      .catch(async (e: Error) => {\n        console.error('Logging 1040 errors.')\n        if (lastCallWithInfo !== undefined) {\n          await this.log1040(...lastCallWithInfo, e.message)\n        } else {\n          console.error('trying to log error but no info is available')\n        }\n        throw e\n      })\n  }\n}\n\ninterface Access<A, B> {\n  [k: string]: A | (() => B)\n}\n\nexport const showForm = (f: Access<unknown, number>): string => {\n  return Object.keys(f)\n    .filter((k) => k.startsWith('l'))\n    .map((k) => {\n      if (typeof f[k] === 'function') {\n        return `${k}=${(f[k] as () => number)()}`\n      }\n    })\n    .join('\\n')\n}\n"
  },
  {
    "path": "src/index.css",
    "content": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n    monospace;\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import { StrictMode } from 'react'\nimport ReactDOM from 'react-dom'\nimport { Provider } from 'react-redux'\nimport App from './App'\nimport * as serviceWorker from './serviceWorker'\nimport { BrowserRouter as Router } from 'react-router-dom'\n\nimport { store, persistor } from './redux/store'\nimport { PersistGate } from 'redux-persist/integration/react'\n\nimport './index.css'\n\nReactDOM.render(\n  <StrictMode>\n    <Provider store={store}>\n      <PersistGate\n        loading={<h1>Loading from Local Storage</h1>}\n        persistor={persistor}\n      >\n        <Router>\n          <App />\n        </Router>\n      </PersistGate>\n    </Provider>\n  </StrictMode>,\n  document.getElementById('root')\n)\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister()\n"
  },
  {
    "path": "src/log.ts",
    "content": "import log from 'loglevel'\n\nconst { TRACE, ERROR } = log.levels\n\nlog.setDefaultLevel(process.env.NODE_ENV === 'development' ? TRACE : ERROR)\n\nexport default log\n"
  },
  {
    "path": "src/pdfHandler.ts",
    "content": "import { save } from '@tauri-apps/api/dialog'\nimport { writeBinaryFile } from '@tauri-apps/api/fs'\n\nexport async function savePDF(\n  contents: Uint8Array,\n  defaultFilename: string\n): Promise<void> {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access\n  if ((window as any).__TAURI__ === undefined) {\n    // To set the download file name, we create a temporary link element,\n    // use download property of an anchor tag, supported for most people\n    const blob = new Blob([contents], { type: 'application/pdf' })\n    const url = URL.createObjectURL(blob)\n    const a = document.createElement('a')\n    a.href = url\n    a.download = defaultFilename\n    document.body.appendChild(a)\n    a.click()\n    URL.revokeObjectURL(url)\n    a.remove()\n    return await Promise.resolve()\n  } else {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call\n    const defaultPath = await (window as any).__TAURI__.path.documentDir()\n\n    // path can be null if user cancels save.\n    const path: string | null = (await save({\n      filters: [{ name: 'PDF Documents (.pdf)', extensions: ['pdf'] }],\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      defaultPath\n    })) as string | null\n\n    if (path !== null) {\n      return await writeBinaryFile({ contents, path }, {})\n    }\n\n    // user canceled save.\n    return await Promise.resolve()\n  }\n}\n"
  },
  {
    "path": "src/react-app-env.d.ts",
    "content": "import 'react-scripts'\n"
  },
  {
    "path": "src/redux/TaxesState.ts",
    "content": "import { Information } from 'ustaxes/core/data'\nimport { YearsTaxesState } from './data'\n\nexport default class TaxesStateMethods {\n  ts: YearsTaxesState\n\n  constructor(ts: YearsTaxesState) {\n    this.ts = ts\n  }\n\n  info = (): Information => this.ts[this.ts.activeYear]\n}\n"
  },
  {
    "path": "src/redux/actions.ts",
    "content": "import {\n  Person,\n  IncomeW2,\n  Refund,\n  DependentDateString,\n  FilingStatus,\n  PrimaryPersonDateString,\n  ContactInfo,\n  Supported1099,\n  F1098e,\n  SpouseDateString,\n  Property,\n  StateResidency,\n  Information,\n  EstimatedTaxPayments,\n  Responses,\n  Ira,\n  Asset,\n  ItemizedDeductions,\n  F3921,\n  ScheduleK1Form1065,\n  TaxYear,\n  HealthSavingsAccountDateString,\n  InformationDateString,\n  Credit,\n  EditCreditAction\n} from 'ustaxes/core/data'\n\nimport {\n  EditDependentAction,\n  EditPropertyAction,\n  Edit1099Action,\n  EditW2Action,\n  EditEstimatedTaxesAction,\n  Edit1098eAction,\n  EditHSAAction,\n  EditIraAction,\n  EditAssetAction,\n  EditF3921Action,\n  EditScheduleK1Form1065Action\n} from 'ustaxes/core/data'\nimport * as validators from 'ustaxes/core/data/validate'\nimport { index as indexValidator } from 'ustaxes/core/data/validate'\nimport { ValidateFunction } from 'ajv'\nimport { infoToStringInfo } from './data'\n\nexport enum ActionName {\n  SAVE_REFUND_INFO = 'SAVE_REFUND_INFO',\n  SAVE_PRIMARY_PERSON_INFO = 'SAVE_TAXPAYER_INFO',\n  SAVE_CONTACT_INFO = 'SAVE_CONTACT_INFO',\n  SAVE_STATE_RESIDENCY = 'SAVE_STATE_RESIDENCY',\n  SAVE_FILING_STATUS_INFO = 'SAFE_FILING_STATUS_INFO',\n  ADD_DEPENDENT = 'TAXPAYER/ADD_DEPENDENT',\n  EDIT_DEPENDENT = 'TAXPAYER/EDIT_DEPENDENT',\n  REMOVE_DEPENDENT = 'TAXPAYER/REMOVE_DEPENDENT',\n  ADD_SPOUSE = 'TAXPAYER/ADD_SPOUSE',\n  REMOVE_SPOUSE = 'TAXPAYER/REMOVE_SPOUSE',\n  ADD_W2 = 'ADD_W2',\n  EDIT_W2 = 'EDIT_W2',\n  REMOVE_W2 = 'REMOVE_W2',\n  ADD_ESTIMATED_TAX = 'ADD_ESTIMATED_TAX',\n  EDIT_ESTIMATED_TAX = 'EDIT_ESTIMATED_TAX',\n  REMOVE_ESTIMATED_TAX = 'REMOVE_ESTIMATED_TAX',\n  ADD_1099 = 'ADD_1099',\n  EDIT_1099 = 'EDIT_1099',\n  REMOVE_1099 = 'REMOVE_1099',\n  ADD_PROPERTY = 'ADD_PROPERTY',\n  EDIT_PROPERTY = 'EDIT_PROPERTY',\n  REMOVE_PROPERTY = 'REMOVE_PROPERTY',\n  ANSWER_QUESTION = 'ANSWER_QUESTION',\n  ADD_1098e = 'ADD_1098e',\n  EDIT_1098e = 'EDIT_1098e',\n  REMOVE_1098e = 'REMOVE_1098e',\n  SET_ITEMIZED_DEDUCTIONS = 'SET_ITEMIZED_DEDUCTIONS',\n  ADD_HSA = 'ADD_HSA',\n  EDIT_HSA = 'EDIT_HSA',\n  REMOVE_HSA = 'REMOVE_HSA',\n  SET_INFO = 'SET_INFO',\n  SET_ACTIVE_YEAR = 'SET_ACTIVE_YEAR',\n  PROPAGATE_YEAR_DATA = 'PROPAGATE_YEAR_DATA',\n  ADD_IRA = 'ADD_IRA',\n  EDIT_IRA = 'EDIT_IRA',\n  REMOVE_IRA = 'REMOVE_IRA',\n  ADD_ASSET = 'ASSETS/ADD',\n  ADD_ASSETS = 'ASSETS/ADD_MANY',\n  EDIT_ASSET = 'ASSETS/EDIT',\n  REMOVE_ASSET = 'ASSETS/REMOVE',\n  REMOVE_ASSETS = 'ASSETS/REMOVE_MANY',\n  ADD_F3921 = 'F3921/ADD',\n  EDIT_F3921 = 'F3921/EDIT',\n  REMOVE_F3921 = 'F3921/REMOVE',\n  ADD_SCHEDULE_K1_F1065 = 'SCHEDULE_K1_F1065/ADD',\n  EDIT_SCHEDULE_K1_F1065 = 'SCHEDULE_K1_F1065/EDIT',\n  REMOVE_SCHEDULE_K1_F1065 = 'SCHEDULE_K1_F1065/REMOVE',\n  ADD_CREDIT = 'CREDIT/ADD',\n  EDIT_CREDIT = 'CREDIT/EDIT',\n  REMOVE_CREDIT = 'CREDIT/REMOVE'\n}\n\ninterface Save<T, R> {\n  type: T\n  year: TaxYear\n  formData: R\n}\n\ntype SaveRefundInfo = Save<typeof ActionName.SAVE_REFUND_INFO, Refund>\ntype SavePrimaryPersonInfo = Save<\n  typeof ActionName.SAVE_PRIMARY_PERSON_INFO,\n  PrimaryPersonDateString\n>\ntype SaveFilingStatusInfo = Save<\n  typeof ActionName.SAVE_FILING_STATUS_INFO,\n  FilingStatus\n>\ntype SaveContactInfo = Save<typeof ActionName.SAVE_CONTACT_INFO, ContactInfo>\ntype SaveStateResidencyInfo = Save<\n  typeof ActionName.SAVE_STATE_RESIDENCY,\n  StateResidency\n>\ntype AddDependent = Save<typeof ActionName.ADD_DEPENDENT, DependentDateString>\ntype EditDependent = Save<typeof ActionName.EDIT_DEPENDENT, EditDependentAction>\ntype RemoveDependent = Save<typeof ActionName.REMOVE_DEPENDENT, number>\ntype AddSpouse = Save<typeof ActionName.ADD_SPOUSE, SpouseDateString>\ntype RemoveSpouse = Save<typeof ActionName.REMOVE_SPOUSE, Record<string, never>>\ntype AddW2 = Save<typeof ActionName.ADD_W2, IncomeW2>\ntype EditW2 = Save<typeof ActionName.EDIT_W2, EditW2Action>\ntype RemoveW2 = Save<typeof ActionName.REMOVE_W2, number>\ntype AddEstimatedTaxes = Save<\n  typeof ActionName.ADD_ESTIMATED_TAX,\n  EstimatedTaxPayments\n>\ntype EditEstimatedTaxes = Save<\n  typeof ActionName.EDIT_ESTIMATED_TAX,\n  EditEstimatedTaxesAction\n>\ntype RemoveEstimatedTaxes = Save<typeof ActionName.REMOVE_ESTIMATED_TAX, number>\ntype AddHSA = Save<typeof ActionName.ADD_HSA, HealthSavingsAccountDateString>\ntype EditHSA = Save<typeof ActionName.EDIT_HSA, EditHSAAction>\ntype RemoveHSA = Save<typeof ActionName.REMOVE_HSA, number>\ntype Add1099 = Save<typeof ActionName.ADD_1099, Supported1099>\ntype Edit1099 = Save<typeof ActionName.EDIT_1099, Edit1099Action>\ntype Remove1099 = Save<typeof ActionName.REMOVE_1099, number>\ntype AddProperty = Save<typeof ActionName.ADD_PROPERTY, Property>\ntype EditProperty = Save<typeof ActionName.EDIT_PROPERTY, EditPropertyAction>\ntype RemoveProperty = Save<typeof ActionName.REMOVE_PROPERTY, number>\ntype AnswerQuestion = Save<typeof ActionName.ANSWER_QUESTION, Responses>\ntype Add1098e = Save<typeof ActionName.ADD_1098e, F1098e>\ntype Edit1098e = Save<typeof ActionName.EDIT_1098e, Edit1098eAction>\ntype Remove1098e = Save<typeof ActionName.REMOVE_1098e, number>\ntype SetItemizedDeductions = Save<\n  typeof ActionName.SET_ITEMIZED_DEDUCTIONS,\n  ItemizedDeductions\n>\ntype SetInfo = Save<typeof ActionName.SET_INFO, InformationDateString>\ntype SetActiveYear = Save<typeof ActionName.SET_ACTIVE_YEAR, TaxYear>\ntype AddIRA = Save<typeof ActionName.ADD_IRA, Ira>\ntype EditIRA = Save<typeof ActionName.EDIT_IRA, EditIraAction>\ntype RemoveIRA = Save<typeof ActionName.REMOVE_IRA, number>\ntype AddAsset = Save<typeof ActionName.ADD_ASSET, Asset<Date>>\ntype AddAssets = Save<typeof ActionName.ADD_ASSETS, Asset<Date>[]>\ntype EditAsset = Save<typeof ActionName.EDIT_ASSET, EditAssetAction>\ntype RemoveAsset = Save<typeof ActionName.REMOVE_ASSET, number>\ntype RemoveAssets = Save<typeof ActionName.REMOVE_ASSETS, number[]>\ntype AddF3921 = Save<typeof ActionName.ADD_F3921, F3921>\ntype EditF3921 = Save<typeof ActionName.EDIT_F3921, EditF3921Action>\ntype RemoveF3921 = Save<typeof ActionName.REMOVE_F3921, number>\ntype AddScheduleK1Form1065 = Save<\n  typeof ActionName.ADD_SCHEDULE_K1_F1065,\n  ScheduleK1Form1065\n>\ntype EditScheduleK1Form1065 = Save<\n  typeof ActionName.EDIT_SCHEDULE_K1_F1065,\n  EditScheduleK1Form1065Action\n>\ntype RemoveScheduleK1Form1065 = Save<\n  typeof ActionName.REMOVE_SCHEDULE_K1_F1065,\n  number\n>\ntype AddCredit = Save<typeof ActionName.ADD_CREDIT, Credit>\ntype EditCredit = Save<typeof ActionName.EDIT_CREDIT, EditCreditAction>\ntype RemoveCredit = Save<typeof ActionName.REMOVE_CREDIT, number>\n\nexport type Actions =\n  | SaveRefundInfo\n  | SavePrimaryPersonInfo\n  | SaveFilingStatusInfo\n  | SaveContactInfo\n  | SaveStateResidencyInfo\n  | AddDependent\n  | EditDependent\n  | RemoveDependent\n  | AddSpouse\n  | RemoveSpouse\n  | AddW2\n  | EditW2\n  | RemoveW2\n  | AddEstimatedTaxes\n  | EditEstimatedTaxes\n  | RemoveEstimatedTaxes\n  | Add1099\n  | Edit1099\n  | Remove1099\n  | AddProperty\n  | EditProperty\n  | RemoveProperty\n  | AnswerQuestion\n  | Add1098e\n  | Edit1098e\n  | Remove1098e\n  | SetItemizedDeductions\n  | AddHSA\n  | EditHSA\n  | RemoveHSA\n  | SetInfo\n  | SetActiveYear\n  | AddIRA\n  | EditIRA\n  | RemoveIRA\n  | AddAsset\n  | AddAssets\n  | EditAsset\n  | RemoveAsset\n  | RemoveAssets\n  | AddF3921\n  | EditF3921\n  | RemoveF3921\n  | AddScheduleK1Form1065\n  | EditScheduleK1Form1065\n  | RemoveScheduleK1Form1065\n  | AddCredit\n  | EditCredit\n  | RemoveCredit\n\nexport type SignalAction = (year: TaxYear) => Actions\nexport type ActionCreator<A> = (formData: A) => SignalAction\n\nfunction signalAction<T extends ActionName>(\n  t: T\n): (year: TaxYear) => Save<T, Record<string, never>> {\n  return (year: TaxYear) => ({\n    type: t,\n    year,\n    formData: {}\n  })\n}\n\n/**\n *  Create an action constructor given an action name and a validator\n *  for the action's payload. The validator checks the payload against\n *  the schema at runtime so we can see errors if data of the wrong types\n *  about to be inserted into the model\n */\nconst makeActionCreator =\n  <A, T extends ActionName>(t: T, validate?: ValidateFunction<A>) =>\n  (formData: A) =>\n  (year: TaxYear): Save<T, A> => ({\n    type: t,\n    year,\n    formData:\n      validate !== undefined\n        ? validators.checkType<A>(formData, validate)\n        : formData\n  })\n\n/**\n * This variant includes a preprocessor function that can be used to\n * apply formatting changes to provided data, for example.\n */\nconst makePreprocessActionCreator =\n  <A, AA, T extends ActionName>(\n    t: T,\n    validate: ValidateFunction<AA> | undefined,\n    clean: (d: A) => AA\n  ) =>\n  (formData: A) =>\n  (year: TaxYear): Save<T, AA> => ({\n    type: t,\n    year,\n    formData:\n      validate !== undefined\n        ? validators.checkType(clean(formData), validate)\n        : { ...formData, ...clean(formData) }\n  })\n\nexport const saveRefundInfo: ActionCreator<Refund> = makeActionCreator(\n  ActionName.SAVE_REFUND_INFO,\n  validators.refund\n)\n\nconst cleanPerson = <P extends Person<string>>(p: P): P => ({\n  ...p,\n  ssid: p.ssid.replace(/-/g, '')\n})\n\nexport const savePrimaryPersonInfo: ActionCreator<PrimaryPersonDateString> =\n  makePreprocessActionCreator(\n    ActionName.SAVE_PRIMARY_PERSON_INFO,\n    validators.primaryPerson,\n    cleanPerson\n  )\n\nexport const saveStateResidencyInfo: ActionCreator<StateResidency> =\n  makeActionCreator(ActionName.SAVE_STATE_RESIDENCY, validators.stateResidency)\n\nexport const saveFilingStatusInfo: ActionCreator<FilingStatus> =\n  makeActionCreator(ActionName.SAVE_FILING_STATUS_INFO, validators.filingStatus)\n\nexport const saveContactInfo: ActionCreator<ContactInfo> =\n  makePreprocessActionCreator(\n    ActionName.SAVE_CONTACT_INFO,\n    validators.contactInfo,\n    (t) => ({\n      ...t,\n      contactPhoneNumber: t.contactPhoneNumber?.replace(/-/g, '')\n    })\n  )\n\nexport const addDependent: ActionCreator<DependentDateString> =\n  makePreprocessActionCreator(\n    ActionName.ADD_DEPENDENT,\n    validators.dependent,\n    (t: DependentDateString) => cleanPerson(t)\n  )\n\nexport const editDependent: ActionCreator<EditDependentAction> =\n  makePreprocessActionCreator(\n    ActionName.EDIT_DEPENDENT,\n    undefined,\n    ({ index, value }: EditDependentAction) => ({\n      index,\n      value: cleanPerson(value)\n    })\n  )\n\nexport const removeDependent: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_DEPENDENT,\n  indexValidator\n)\n\nexport const addSpouse: ActionCreator<SpouseDateString> =\n  makePreprocessActionCreator(\n    ActionName.ADD_SPOUSE,\n    validators.spouse,\n    cleanPerson\n  )\n\nexport const removeSpouse: SignalAction = signalAction(ActionName.REMOVE_SPOUSE)\n\nexport const addW2: ActionCreator<IncomeW2> = makeActionCreator(\n  ActionName.ADD_W2,\n  validators.incomeW2\n)\n\nexport const editW2: ActionCreator<EditW2Action> = makeActionCreator(\n  ActionName.EDIT_W2\n)\n\nexport const removeW2: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_W2,\n  indexValidator\n)\n\nexport const addEstimatedPayment: ActionCreator<EstimatedTaxPayments> =\n  makeActionCreator(\n    ActionName.ADD_ESTIMATED_TAX,\n    validators.estimatedTaxPayments\n  )\n\nexport const editEstimatedPayment: ActionCreator<EditEstimatedTaxesAction> =\n  makeActionCreator(ActionName.EDIT_ESTIMATED_TAX)\n\nexport const removeEstimatedPayment: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_ESTIMATED_TAX,\n  indexValidator\n)\n\nexport const addHSA: ActionCreator<HealthSavingsAccountDateString> =\n  makeActionCreator(ActionName.ADD_HSA, validators.healthSavingsAccount)\n\nexport const editHSA: ActionCreator<EditHSAAction> = makeActionCreator(\n  ActionName.EDIT_HSA,\n  validators.editHSAAction\n)\n\nexport const removeHSA: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_HSA,\n  indexValidator\n)\n\nexport const add1099: ActionCreator<Supported1099> = makeActionCreator(\n  ActionName.ADD_1099,\n  validators.supported1099\n)\n\nexport const edit1099: ActionCreator<Edit1099Action> = makeActionCreator(\n  ActionName.EDIT_1099\n)\n\nexport const remove1099: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_1099,\n  indexValidator\n)\n\nexport const addProperty: ActionCreator<Property> = makeActionCreator(\n  ActionName.ADD_PROPERTY,\n  validators.property\n)\n\nexport const editProperty: ActionCreator<EditPropertyAction> =\n  makeActionCreator(ActionName.EDIT_PROPERTY)\n\nexport const removeProperty: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_PROPERTY,\n  indexValidator\n)\n\nexport const answerQuestion: ActionCreator<Responses> = makeActionCreator(\n  ActionName.ANSWER_QUESTION,\n  validators.responses\n)\n\nexport const add1098e: ActionCreator<F1098e> = makeActionCreator(\n  ActionName.ADD_1098e,\n  validators.f1098e\n)\n\nexport const edit1098e: ActionCreator<Edit1098eAction> = makeActionCreator(\n  ActionName.EDIT_1098e\n)\n\nexport const remove1098e: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_1098e,\n  indexValidator\n)\n\nexport const setItemizedDeductions: ActionCreator<ItemizedDeductions> =\n  makeActionCreator(\n    ActionName.SET_ITEMIZED_DEDUCTIONS,\n    validators.itemizedDeductions\n  )\n\n// debugging purposes only, leaving unchecked.\nexport const setInfo = makePreprocessActionCreator<\n  Information,\n  InformationDateString,\n  ActionName.SET_INFO\n>(ActionName.SET_INFO, validators.information, (info) => infoToStringInfo(info))\n\nexport const setActiveYear: ActionCreator<TaxYear> = makeActionCreator(\n  ActionName.SET_ACTIVE_YEAR,\n  validators.taxYear\n)\n\nexport const addIRA: ActionCreator<Ira> = makeActionCreator(\n  ActionName.ADD_IRA,\n  validators.ira\n)\n\nexport const editIRA: ActionCreator<EditIraAction> = makeActionCreator(\n  ActionName.EDIT_IRA,\n  validators.editIraAction\n)\n\nexport const removeIRA: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_IRA,\n  indexValidator\n)\n\nexport const addAsset: ActionCreator<Asset<Date>> = makeActionCreator(\n  ActionName.ADD_ASSET\n)\n\nexport const addAssets: ActionCreator<Asset<Date>[]> = makeActionCreator(\n  ActionName.ADD_ASSETS\n)\n\nexport const editAsset: ActionCreator<EditAssetAction> = makeActionCreator(\n  ActionName.EDIT_ASSET\n)\n\nexport const removeAsset: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_ASSET,\n  indexValidator\n)\n\nexport const removeAssets: ActionCreator<number[]> = makeActionCreator(\n  ActionName.REMOVE_ASSETS\n)\n\nexport const addF3921: ActionCreator<F3921> = makeActionCreator(\n  ActionName.ADD_F3921\n)\n\nexport const editF3921: ActionCreator<EditF3921Action> = makeActionCreator(\n  ActionName.EDIT_F3921\n)\n\nexport const removeF3921: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_F3921,\n  indexValidator\n)\n\nexport const addScheduleK1Form1065: ActionCreator<ScheduleK1Form1065> =\n  makeActionCreator(ActionName.ADD_SCHEDULE_K1_F1065)\n\nexport const editScheduleK1Form1065: ActionCreator<EditScheduleK1Form1065Action> =\n  makeActionCreator(ActionName.EDIT_SCHEDULE_K1_F1065)\n\nexport const removeScheduleK1Form1065: ActionCreator<number> =\n  makeActionCreator(ActionName.REMOVE_SCHEDULE_K1_F1065, indexValidator)\n\nexport const addCredit: ActionCreator<Credit> = makeActionCreator(\n  ActionName.ADD_CREDIT,\n  validators.credit\n)\n\nexport const editCredit: ActionCreator<EditCreditAction> = makeActionCreator(\n  ActionName.EDIT_CREDIT,\n  validators.editCreditAction\n)\n\nexport const removeCredit: ActionCreator<number> = makeActionCreator(\n  ActionName.REMOVE_CREDIT,\n  indexValidator\n)\n"
  },
  {
    "path": "src/redux/data.ts",
    "content": "import { Asset, Information, Person, TaxYear } from 'ustaxes/core/data'\nimport { blankState } from './reducer'\n\n/**\n * This is a simplified form of our global TaxesState\n * which allows TaxesState to be viewed as if if contained\n * data for a single year.\n */\nexport type TaxesState = { information: Information }\n\nexport type YearsTaxesState<D = Date> = { [K in TaxYear]: Information<D> } & {\n  assets: Asset<D>[]\n  activeYear: TaxYear\n}\n\nexport const blankYearTaxesState: YearsTaxesState = {\n  assets: [],\n  Y2019: blankState,\n  Y2020: blankState,\n  Y2021: blankState,\n  activeYear: 'Y2020'\n}\n\nexport const dateToStringPerson = <P extends Person<Date>>(\n  p: P\n): Omit<P, 'dateOfBirth'> & { dateOfBirth: string } => ({\n  ...p,\n  dateOfBirth: p.dateOfBirth.toISOString()\n})\n\nexport const stringToDatePerson = <P extends Person<string>>(\n  p: P\n): Omit<P, 'dateOfBirth'> & { dateOfBirth: Date } => ({\n  ...p,\n  dateOfBirth: new Date(p.dateOfBirth)\n})\n\nexport const stringToDateInfo = <I extends Information<string>>(\n  info: I\n): Information<Date> => ({\n  ...info,\n  healthSavingsAccounts: info.healthSavingsAccounts.map((h) => ({\n    ...h,\n    startDate: new Date(h.startDate),\n    endDate: new Date(h.endDate)\n  })),\n  taxPayer: {\n    ...info.taxPayer,\n    primaryPerson: info.taxPayer.primaryPerson\n      ? stringToDatePerson(info.taxPayer.primaryPerson)\n      : undefined,\n    dependents: info.taxPayer.dependents.map((d) => stringToDatePerson(d)),\n    spouse: info.taxPayer.spouse\n      ? stringToDatePerson(info.taxPayer.spouse)\n      : undefined\n  }\n})\n\nexport const infoToStringInfo = <I extends Information<Date>>(\n  info: I\n): Information<string> => ({\n  ...info,\n  healthSavingsAccounts: info.healthSavingsAccounts.map((h) => ({\n    ...h,\n    startDate: h.startDate.toISOString(),\n    endDate: h.endDate.toISOString()\n  })),\n  taxPayer: {\n    ...info.taxPayer,\n    primaryPerson: info.taxPayer.primaryPerson\n      ? dateToStringPerson(info.taxPayer.primaryPerson)\n      : undefined,\n    dependents: info.taxPayer.dependents.map((d) => dateToStringPerson(d)),\n    spouse: info.taxPayer.spouse\n      ? dateToStringPerson(info.taxPayer.spouse)\n      : undefined\n  }\n})\n"
  },
  {
    "path": "src/redux/fs/Actions.ts",
    "content": "type FSActionName = 'fs/persist' | 'fs/recover'\n\nexport interface FSAction {\n  readonly type: FSActionName\n}\n\nexport interface FSPersist extends FSAction {\n  readonly type: 'fs/persist'\n}\n\nexport interface FSRecover extends FSAction {\n  readonly type: 'fs/recover'\n  data: string\n}\n\nexport const fsPersist = (): FSPersist => ({\n  type: 'fs/persist'\n})\n\nexport const fsRecover = (data: string): FSRecover => ({\n  type: 'fs/recover',\n  data\n})\n"
  },
  {
    "path": "src/redux/fs/FSReducer.ts",
    "content": "import { AnyAction, Reducer } from 'redux'\nimport { migrateEachYear, migrateAgeAndBlindness } from '../migration'\nimport { download, stateToString, stringToState } from '.'\nimport { USTState } from '../store'\nimport { FSPersist, FSRecover } from './Actions'\n\ntype PersistActions = FSPersist | FSRecover\n\n/**\n * Extends a reducer to persist and load data\n * to/from an external JSON file.\n * This behaves like a Redux \"Middleware\", which\n * is basically just a function from reducer to reducer.\n * It will overwrite whatever state exists with whatever\n * state it finds, but needs none of its own state.\n */\nexport const fsReducer = <S extends USTState, A extends AnyAction>(\n  filename: string,\n  reducer: Reducer<S, A>\n): Reducer<S, A & PersistActions> => {\n  return (state: S | undefined, action: A & PersistActions): S => {\n    const newState = reducer(state, action)\n\n    switch (action.type) {\n      case 'fs/recover': {\n        // we know now that the action is a FSRecover,\n        // so we can safely cast it to a FSRecover<USTSerializedState>.\n        return {\n          ...newState,\n          ...migrateAgeAndBlindness(\n            migrateEachYear(\n              // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n              stringToState(action.data)\n            )\n          )\n        } as S // migrations return any, must coerce.\n      }\n      case 'fs/persist': {\n        download(filename, stateToString(newState))\n        return newState\n      }\n      default: {\n        return newState\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/redux/fs/Load.tsx",
    "content": "import { Button, ButtonProps } from '@material-ui/core'\nimport { ChangeEvent, PropsWithChildren, ReactElement } from 'react'\nimport { intentionallyFloat } from 'ustaxes/core/util'\nimport { loadFile } from '.'\n\ninterface LoadProps<S> {\n  handleData: (s: S) => void\n}\n\ninterface Accept {\n  accept?: string\n}\n\nexport const LoadRaw = (\n  props: PropsWithChildren<LoadProps<string> & Accept & ButtonProps>\n): ReactElement => {\n  const { children, handleData, accept = '.*,text', ...rest } = props\n\n  const onClick = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {\n    e.preventDefault()\n    const files = e.target.files\n    if (files === null || files.length < 1) {\n      return\n    }\n    const file = files[0]\n\n    handleData(await loadFile(file))\n  }\n\n  return (\n    <Button {...{ ...rest, component: 'label' }}>\n      {children}\n      <input\n        type=\"file\"\n        hidden\n        accept={accept}\n        onChange={intentionallyFloat(onClick)}\n      />\n    </Button>\n  )\n}\n\nconst Load = <S,>(\n  props: PropsWithChildren<LoadProps<S> & ButtonProps & Accept>\n): ReactElement => {\n  const { children, handleData, ...rest } = props\n\n  return (\n    <LoadRaw\n      {...rest}\n      handleData={(contents: string) => handleData(JSON.parse(contents) as S)}\n    >\n      {children}\n    </LoadRaw>\n  )\n}\n\nexport default Load\n"
  },
  {
    "path": "src/redux/fs/index.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { deserializeTransform, serializeTransform, USTState } from '../store'\nimport Load from './Load'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types\nexport const stateToString = (state: any): string =>\n  JSON.stringify(serializeTransform(state))\n\n/**\n * Reuse the same functionality as reloading the state from redux-persist,\n * to reload state from a file\n */\nexport const stringToState = (str: string): USTState =>\n  deserializeTransform(JSON.parse(str)) as USTState\n\nexport const download = (filename: string, text: string): void => {\n  const element = document.createElement('a')\n  element.setAttribute(\n    'href',\n    'data:text/json;charset=utf-8,' + encodeURIComponent(text)\n  )\n  element.setAttribute('download', filename)\n\n  element.style.display = 'none'\n  document.body.appendChild(element)\n\n  element.click()\n\n  document.body.removeChild(element)\n}\n\nexport const loadFile = async (file: File): Promise<string> => {\n  const fileReader: FileReader = new FileReader()\n\n  return new Promise((resolve, reject) => {\n    fileReader.onload = function (\n      this: FileReader,\n      e: ProgressEvent<FileReader>\n    ): any {\n      e.preventDefault()\n      // type known here because of readAsText\n      const contents: string | null = fileReader.result as string | null\n      if (contents === null) {\n        reject('file contents were null')\n      } else {\n        resolve(contents)\n      }\n    }\n    fileReader.readAsText(file)\n  })\n}\n\nexport { Load }\n"
  },
  {
    "path": "src/redux/index.ts",
    "content": "// override default useDispatch with our\n// version that lets us curry the tax year\nimport {\n  useYearDispatch as useDispatch,\n  useYearSelector as useSelector\n} from './yearDispatch'\n\nexport * from './data'\nexport * from './TaxesState'\n\nexport { useDispatch, useSelector }\n"
  },
  {
    "path": "src/redux/migration.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { enumKeys } from 'ustaxes/core/util'\nimport {\n  Person,\n  Dependent,\n  Spouse,\n  PrimaryPerson,\n  TaxYears,\n  FilingStatus\n} from 'ustaxes/core/data'\nimport { blankState } from './reducer'\nimport { USTState } from './store'\n\nexport interface QualifyingInformationV0 {\n  numberOfMonths: number\n  isStudent: boolean\n  birthYear: number\n}\n\nexport interface DependentV0 extends Omit<Person, 'isBlind' | 'dateOfBirth'> {\n  relationship: string\n  qualifyingInfo?: QualifyingInformationV0\n}\n\nexport type PrimaryPersonV0 = Omit<PrimaryPerson, 'isBlind' | 'dateOfBirth'>\n\nexport type SpouseV0 = Omit<Spouse, 'isBlind' | 'dateOfBirth'>\n\nexport type USTStateV0 = {\n  [P in keyof Omit<USTState, 'taxPayer'>]: USTState[P]\n} & {\n  taxPayer: {\n    primaryPerson?: PrimaryPersonV0\n    dependents: DependentV0[]\n    filingStatus?: FilingStatus\n    spouse?: SpouseV0\n  }\n}\n\nfunction migrateDependent(p: DependentV0): Dependent {\n  const birthYear = p.qualifyingInfo?.birthYear\n  const q: Dependent = {\n    ...p,\n    qualifyingInfo: {\n      numberOfMonths: p.qualifyingInfo?.numberOfMonths ?? 0,\n      isStudent: p.qualifyingInfo?.isStudent ?? false\n    },\n    dateOfBirth:\n      birthYear !== undefined ? new Date(birthYear, 0, 1) : new Date(),\n    isBlind: false\n  }\n  return q\n}\n\nfunction migratePrimaryOrSpouse(p: Spouse | PrimaryPerson) {\n  if (p.isBlind === undefined) {\n    p.isBlind = false\n  }\n\n  if (p.dateOfBirth === undefined) {\n    p.dateOfBirth = new Date()\n  }\n  return p\n}\n\nexport const migrateAgeAndBlindness = <S extends USTState>(state: S): S =>\n  enumKeys(TaxYears).reduce((acc, year) => {\n    if (acc[year].taxPayer !== undefined) {\n      const primaryPerson = acc[year].taxPayer.primaryPerson\n\n      if (primaryPerson !== undefined) {\n        acc[year].taxPayer.primaryPerson = migratePrimaryOrSpouse(\n          primaryPerson\n        ) as PrimaryPerson\n      }\n\n      const spouse = acc[year].taxPayer.spouse\n      if (spouse !== undefined) {\n        acc[year].taxPayer.spouse = migratePrimaryOrSpouse(spouse) as Spouse\n      }\n      acc[year].taxPayer.dependents = acc[year].taxPayer.dependents.map((d) =>\n        migrateDependent(d as DependentV0)\n      )\n    }\n    return {\n      ...acc,\n      [year]: {\n        ...blankState,\n        ...acc[year]\n      }\n    }\n  }, state)\n\n/**\n * Ensures all default fields are present on each year's data\n * @returns state\n */\nexport const migrateEachYear = <S extends USTState>(state: S): S =>\n  enumKeys(TaxYears).reduce((acc, year) => {\n    // Make sure SS wages are set on W2s\n    acc[year].w2s.forEach((w2) => {\n      if (w2.ssWages === undefined) {\n        w2.ssWages = 0\n      }\n    })\n\n    // Ensure interestIncome on K1s\n    acc[year].scheduleK1Form1065s.forEach((k1) => {\n      if (k1.interestIncome === undefined) {\n        k1.interestIncome = 0\n      }\n    })\n\n    return {\n      ...acc,\n      [year]: {\n        ...blankState,\n        ...acc[year]\n      }\n    }\n  }, state)\n"
  },
  {
    "path": "src/redux/reducer.ts",
    "content": "/* eslint-disable indent */\nimport { CombinedState, combineReducers, Reducer } from 'redux'\nimport { Asset, FilingStatus, Information, TaxYear } from 'ustaxes/core/data'\nimport { YearsTaxesState } from '.'\nimport { ActionName, Actions } from './actions'\nimport { stringToDateInfo } from './data'\n\nconst DEFAULT_TAX_YEAR: TaxYear = 'Y2021'\n\nexport const blankState: Information = {\n  f1099s: [],\n  w2s: [],\n  estimatedTaxes: [],\n  realEstate: [],\n  taxPayer: { dependents: [] },\n  questions: {},\n  f1098es: [],\n  f3921s: [],\n  scheduleK1Form1065s: [],\n  itemizedDeductions: undefined,\n  stateResidencies: [],\n  healthSavingsAccounts: [],\n  credits: [],\n  individualRetirementArrangements: []\n}\n\nconst formReducer = (\n  state: Information | undefined,\n  action: Actions\n): Information => {\n  const newState: Information = state ?? blankState\n\n  switch (action.type) {\n    case ActionName.SAVE_PRIMARY_PERSON_INFO: {\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          primaryPerson: {\n            ...action.formData,\n            dateOfBirth: new Date(action.formData.dateOfBirth)\n          }\n        }\n      }\n    }\n    case ActionName.SAVE_CONTACT_INFO: {\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          ...action.formData\n        }\n      }\n    }\n    case ActionName.SAVE_STATE_RESIDENCY: {\n      return {\n        ...newState,\n        stateResidencies: [action.formData]\n      }\n    }\n    case ActionName.SAVE_FILING_STATUS_INFO: {\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          filingStatus: action.formData\n        }\n      }\n    }\n    case ActionName.ADD_DEPENDENT: {\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          dependents: [\n            ...newState.taxPayer.dependents,\n            {\n              ...action.formData,\n              dateOfBirth: new Date(action.formData.dateOfBirth)\n            }\n          ]\n        }\n      }\n    }\n\n    // Replace dependent by index with a new object.\n    case ActionName.EDIT_DEPENDENT: {\n      const newDependents = [...newState.taxPayer.dependents]\n      newDependents.splice(action.formData.index, 1, {\n        ...action.formData.value,\n        dateOfBirth: new Date(action.formData.value.dateOfBirth)\n      })\n\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          dependents: newDependents\n        }\n      }\n    }\n\n    case ActionName.REMOVE_DEPENDENT: {\n      const newDependents = [...newState.taxPayer.dependents]\n      newDependents.splice(action.formData, 1)\n\n      const filingStatus = (() => {\n        if (\n          newDependents.length === 0 &&\n          newState.taxPayer.filingStatus === FilingStatus.HOH\n        ) {\n          return undefined\n        }\n        return newState.taxPayer.filingStatus\n      })()\n\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          filingStatus,\n          dependents: newDependents\n        }\n      }\n    }\n    case ActionName.SAVE_REFUND_INFO: {\n      return {\n        ...newState,\n        refund: action.formData\n      }\n    }\n    case ActionName.ADD_W2: {\n      return {\n        ...newState,\n        w2s: [...newState.w2s, action.formData]\n      }\n    }\n    case ActionName.EDIT_W2: {\n      const newW2s = [...newState.w2s]\n      newW2s.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        w2s: newW2s\n      }\n    }\n    case ActionName.REMOVE_W2: {\n      const newW2s = [...newState.w2s]\n      newW2s.splice(action.formData, 1)\n      return {\n        ...newState,\n        w2s: newW2s\n      }\n    }\n    case ActionName.ADD_ESTIMATED_TAX: {\n      return {\n        ...newState,\n        estimatedTaxes: [...newState.estimatedTaxes, action.formData]\n      }\n    }\n    case ActionName.EDIT_ESTIMATED_TAX: {\n      const newEstimatedTaxes = [...newState.estimatedTaxes]\n      newEstimatedTaxes.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        estimatedTaxes: newEstimatedTaxes\n      }\n    }\n    case ActionName.REMOVE_ESTIMATED_TAX: {\n      const newEstimatedTaxes = [...newState.estimatedTaxes]\n      newEstimatedTaxes.splice(action.formData, 1)\n      return {\n        ...newState,\n        estimatedTaxes: newEstimatedTaxes\n      }\n    }\n    case ActionName.ADD_1099: {\n      return {\n        ...newState,\n        f1099s: [...newState.f1099s, action.formData]\n      }\n    }\n    case ActionName.EDIT_1099: {\n      const new1099s = [...newState.f1099s]\n      new1099s.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        f1099s: new1099s\n      }\n    }\n    case ActionName.REMOVE_1099: {\n      const new1099s = [...newState.f1099s]\n      new1099s.splice(action.formData, 1)\n      return {\n        ...newState,\n        f1099s: new1099s\n      }\n    }\n    case ActionName.ADD_SPOUSE: {\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          spouse: {\n            ...action.formData,\n            dateOfBirth: new Date(action.formData.dateOfBirth)\n          }\n        }\n      }\n    }\n    case ActionName.REMOVE_SPOUSE: {\n      const filingStatus = (() => {\n        const fs = newState.taxPayer.filingStatus\n        if ([FilingStatus.MFS, FilingStatus.MFJ, undefined].includes(fs)) {\n          return undefined\n        }\n        return fs\n      })()\n\n      return {\n        ...newState,\n        taxPayer: {\n          ...newState.taxPayer,\n          filingStatus,\n          spouse: undefined\n        }\n      }\n    }\n    case ActionName.ADD_PROPERTY: {\n      return {\n        ...newState,\n        realEstate: [...newState.realEstate, action.formData]\n      }\n    }\n    case ActionName.EDIT_PROPERTY: {\n      const newProperties = [...newState.realEstate]\n      newProperties.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        realEstate: newProperties\n      }\n    }\n    case ActionName.REMOVE_PROPERTY: {\n      const newProperties = [...newState.realEstate]\n      newProperties.splice(action.formData, 1)\n      return {\n        ...newState,\n        realEstate: newProperties\n      }\n    }\n    case ActionName.ANSWER_QUESTION: {\n      // must reset all questions\n      return {\n        ...newState,\n        questions: action.formData\n      }\n    }\n    case ActionName.ADD_1098e: {\n      return {\n        ...newState,\n        f1098es: [...newState.f1098es, action.formData]\n      }\n    }\n    case ActionName.EDIT_1098e: {\n      const new1098es = [...newState.f1098es]\n      new1098es.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        f1098es: new1098es\n      }\n    }\n    case ActionName.REMOVE_1098e: {\n      const new1098es = [...newState.f1098es]\n      new1098es.splice(action.formData, 1)\n      return {\n        ...newState,\n        f1098es: new1098es\n      }\n    }\n    case ActionName.ADD_F3921: {\n      return {\n        ...newState,\n        f3921s: [...newState.f3921s, action.formData]\n      }\n    }\n    case ActionName.EDIT_F3921: {\n      const newf3921s = [...newState.f3921s]\n      newf3921s.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        f3921s: newf3921s\n      }\n    }\n    case ActionName.REMOVE_F3921: {\n      const newf3921s = [...newState.f3921s]\n      newf3921s.splice(action.formData, 1)\n      return {\n        ...newState,\n        f3921s: newf3921s\n      }\n    }\n    case ActionName.ADD_SCHEDULE_K1_F1065: {\n      return {\n        ...newState,\n        scheduleK1Form1065s: [...newState.scheduleK1Form1065s, action.formData]\n      }\n    }\n    case ActionName.EDIT_SCHEDULE_K1_F1065: {\n      const newK1s = [...newState.scheduleK1Form1065s]\n      newK1s.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        scheduleK1Form1065s: newK1s\n      }\n    }\n    case ActionName.REMOVE_SCHEDULE_K1_F1065: {\n      const newK1s = [...newState.scheduleK1Form1065s]\n      newK1s.splice(action.formData, 1)\n      return {\n        ...newState,\n        scheduleK1Form1065s: newK1s\n      }\n    }\n    case ActionName.SET_ITEMIZED_DEDUCTIONS: {\n      return {\n        ...newState,\n        itemizedDeductions: action.formData\n      }\n    }\n    case ActionName.SET_INFO: {\n      return {\n        ...newState,\n        ...stringToDateInfo(action.formData)\n      }\n    }\n    case ActionName.ADD_HSA: {\n      return {\n        ...newState,\n        healthSavingsAccounts: [\n          ...newState.healthSavingsAccounts,\n          {\n            ...action.formData,\n            endDate: new Date(action.formData.endDate),\n            startDate: new Date(action.formData.startDate)\n          }\n        ]\n      }\n    }\n    case ActionName.EDIT_HSA: {\n      const newHsa = [...newState.healthSavingsAccounts]\n      newHsa.splice(action.formData.index, 1, {\n        ...action.formData.value,\n        endDate: new Date(action.formData.value.endDate),\n        startDate: new Date(action.formData.value.startDate)\n      })\n      return {\n        ...newState,\n        healthSavingsAccounts: newHsa\n      }\n    }\n    case ActionName.REMOVE_HSA: {\n      const newHsa = [...newState.healthSavingsAccounts]\n      newHsa.splice(action.formData, 1)\n      return {\n        ...newState,\n        healthSavingsAccounts: newHsa\n      }\n    }\n    case ActionName.ADD_IRA: {\n      return {\n        ...newState,\n        individualRetirementArrangements: [\n          ...newState.individualRetirementArrangements,\n          action.formData\n        ]\n      }\n    }\n    case ActionName.EDIT_IRA: {\n      const newIra = [...newState.individualRetirementArrangements]\n      newIra.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        individualRetirementArrangements: newIra\n      }\n    }\n    case ActionName.REMOVE_IRA: {\n      const newIra = [...newState.individualRetirementArrangements]\n      newIra.splice(action.formData, 1)\n      return {\n        ...newState,\n        individualRetirementArrangements: newIra\n      }\n    }\n    case ActionName.ADD_CREDIT: {\n      return {\n        ...newState,\n        credits: [...newState.credits, action.formData]\n      }\n    }\n    case ActionName.EDIT_CREDIT: {\n      const newCredits = [...newState.credits]\n      newCredits.splice(action.formData.index, 1, action.formData.value)\n      return {\n        ...newState,\n        credits: newCredits\n      }\n    }\n    case ActionName.REMOVE_CREDIT: {\n      const newCredits = [...newState.credits]\n      newCredits.splice(action.formData, 1)\n      return {\n        ...newState,\n        credits: newCredits\n      }\n    }\n\n    default: {\n      return newState\n    }\n  }\n}\n\nconst guardByYear =\n  (year: TaxYear) =>\n  (state: Information | undefined, action: Actions): Information => {\n    const newState: Information = state ?? blankState\n\n    if (action.year !== year) {\n      return newState\n    }\n\n    return formReducer(newState, action)\n  }\n\nconst activeYear = (state: TaxYear | undefined, action: Actions): TaxYear => {\n  const newState = state ?? DEFAULT_TAX_YEAR\n\n  switch (action.type) {\n    case ActionName.SET_ACTIVE_YEAR: {\n      return action.formData\n    }\n    default: {\n      return newState\n    }\n  }\n}\n\nconst assetReducer = (\n  state: Asset<Date>[] | undefined,\n  action: Actions\n): Asset<Date>[] => {\n  const newState = state ?? []\n\n  switch (action.type) {\n    case ActionName.ADD_ASSET: {\n      return [...newState, action.formData]\n    }\n    case ActionName.ADD_ASSETS: {\n      return [...newState, ...action.formData]\n    }\n    case ActionName.EDIT_ASSET: {\n      const newAssets = [...newState]\n      newAssets.splice(action.formData.index, 1, action.formData.value)\n      return newAssets\n    }\n    case ActionName.REMOVE_ASSET: {\n      const newAssets = [...newState]\n      newAssets.splice(action.formData, 1)\n      return newAssets\n    }\n    case ActionName.REMOVE_ASSETS: {\n      return newState.filter((_, i) => !action.formData.includes(i))\n    }\n    default: {\n      return newState\n    }\n  }\n}\n\nconst rootReducer: Reducer<\n  CombinedState<YearsTaxesState>,\n  Actions\n> = combineReducers({\n  assets: assetReducer,\n  Y2019: guardByYear('Y2019'),\n  Y2020: guardByYear('Y2020'),\n  Y2021: guardByYear('Y2021'),\n  activeYear\n}) as Reducer<CombinedState<YearsTaxesState>, Actions>\n\nexport default rootReducer\n"
  },
  {
    "path": "src/redux/store.ts",
    "content": "import {\n  createStore as reduxCreateStore,\n  applyMiddleware,\n  Store,\n  CombinedState\n} from 'redux'\nimport logger from 'redux-logger'\nimport rootReducer from './reducer'\nimport _ from 'lodash'\nimport {\n  persistStore,\n  persistReducer,\n  PersistedState,\n  createMigrate\n} from 'redux-persist'\nimport storage from 'redux-persist/lib/storage' // defaults to localStorage for web\nimport { Asset, Information, TaxYear } from 'ustaxes/core/data'\nimport { blankYearTaxesState, YearsTaxesState } from '.'\nimport { Actions } from './actions'\nimport { PersistPartial } from 'redux-persist/es/persistReducer'\nimport { createTransform } from 'redux-persist'\nimport { FSAction } from './fs/Actions'\nimport { fsReducer } from './fs/FSReducer'\nimport { migrateEachYear, migrateAgeAndBlindness } from './migration'\n\ntype SerializedState = { [K in TaxYear]: Information } & {\n  assets: Asset<string>[]\n  activeYear: TaxYear\n}\n\nexport type USTSerializedState = NonNullable<PersistedState> & SerializedState\nexport type USTState = NonNullable<PersistedState> & YearsTaxesState\n\n/**\n * Redux-persist calls the transform function not for\n * the entire state, but for each reducer in our state.\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n\n// A key that must indicate a date value.\n// eg: dateOfBirth, or openDate\nconst dateKey = /(^date)|(Date)/\n\nconst serializeDeserialize =\n  (f: (d: Date | string) => Date | string) =>\n  (s: any): any => {\n    const recur = serializeDeserialize(f)\n    if (_.isArray(s)) {\n      return s.map((p) => recur(p))\n    } else if (_.isObject(s)) {\n      const ob = s as { [k: string]: any }\n      return Object.keys(ob).reduce((acc, k) => {\n        const newValue = (() => {\n          if (dateKey.exec(k) !== null) {\n            return f(ob[k] as Date | string)\n          }\n          return recur(ob[k])\n        })()\n\n        return {\n          ...acc,\n          [k]: newValue\n        }\n      }, {})\n    } else {\n      return s\n    }\n  }\n\n/**\n * Look for all the Dates that need to be turned to strings\n */\nexport const serializeTransform: (s: any) => any = serializeDeserialize((d) =>\n  (d as Date).toISOString()\n)\n\n/**\n * Look for all strings that need to be turned to Dates\n */\nexport const deserializeTransform: (s: any) => any = serializeDeserialize(\n  (d) => new Date(d as string)\n)\n\n/* eslint-enable @typescript-eslint/no-unsafe-assignment */\n/* eslint-enable @typescript-eslint/no-unsafe-argument */\n/* eslint-enable @typescript-eslint/no-unsafe-return */\n/* eslint-enable @typescript-eslint/no-unsafe-call */\n\nconst dateStringTransform = createTransform(\n  serializeTransform,\n  deserializeTransform\n)\n\n//const migrate = async (state: USTState): Promise<USTState> =>\n// migrateEachYear(state)\n\n// Keys are the version numbers. They must be integers.\n// Each version takes a state and applies a function that\n// generates the state for that version from the previous\n// version.\n\n// The below migrations deal with types that don't exist in this\n// project anymore, and the hope is that after applying the\n// migrations to the user's data, the resulting data will match\n// the YearsTaxesState<Date> type. But without maintaining\n// type definititions for every possible version, we can't\n// really say anything about the type of the incoming data.\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\nconst migrations = {\n  0: (state: any) => migrateEachYear(state),\n  1: (state: any) => migrateAgeAndBlindness(state)\n}\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nconst persistedReducer = fsReducer(\n  'ustaxes_save.json',\n  persistReducer<CombinedState<YearsTaxesState>, Actions>(\n    {\n      key: 'root',\n      // Changing the version here will set the version used\n      // in the app. When the data is rehydrated the version\n      // number will be compared and all migrations between\n      // the persisted version and the version here will be\n      // applied in order\n      version: 1,\n      storage,\n      migrate: createMigrate(migrations, { debug: false }),\n      transforms: [dateStringTransform]\n    },\n    rootReducer\n  )\n)\n\nexport type InfoStore = Store<YearsTaxesState, FSAction & Actions> & {\n  dispatch: unknown\n}\n\nexport type PersistedStore = Store<\n  YearsTaxesState & PersistPartial,\n  FSAction & Actions\n> & {\n  dispatch: unknown\n}\n\nexport const createWholeStoreUnpersisted = (\n  state: YearsTaxesState\n): InfoStore => reduxCreateStore(rootReducer, state, undefined)\n\nexport const createStoreUnpersisted = (information: Information): InfoStore =>\n  createWholeStoreUnpersisted({\n    ...blankYearTaxesState,\n    Y2020: information\n  })\n\nexport const createStore = (): PersistedStore =>\n  reduxCreateStore(persistedReducer, applyMiddleware(logger))\n\nexport const store = createStore()\n\nexport const persistor = persistStore(store)\n"
  },
  {
    "path": "src/redux/yearDispatch.ts",
    "content": "import { Dispatch } from 'react'\nimport { useDispatch, useSelector } from 'react-redux'\nimport { SignalAction } from './actions'\nimport { YearsTaxesState } from '.'\nimport { TaxYear } from 'ustaxes/core/data'\nimport { TaxesState } from '.'\n\n/**\n * Provides an override over the default redux dispatch\n * so that the user can send events and watch state\n * ignoring the current active year. Modifications\n * are posted to the current selected year.\n */\nconst useYearDispatch = (): Dispatch<SignalAction> => {\n  const dispatch = useDispatch()\n  const year: TaxYear = useSelector(\n    (state: YearsTaxesState) => state.activeYear\n  )\n\n  return (v: SignalAction) => dispatch(v(year))\n}\n\n/**\n * Provides an override of the useSelector hook for\n * UI that doesn't care which year's data is currently\n * being accessed.\n */\nconst useYearSelector = <R>(f: (t: TaxesState) => R): R =>\n  f(\n    useSelector((state: YearsTaxesState) => ({\n      information: state[state.activeYear]\n    }))\n  )\n\nexport { useYearDispatch, useYearSelector }\n"
  },
  {
    "path": "src/serviceWorker.js",
    "content": "// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n  window.location.hostname === 'localhost' ||\n    // [::1] is the IPv6 localhost address.\n    window.location.hostname === '[::1]' ||\n    // 127.0.0.0/8 are considered localhost for IPv4.\n    window.location.hostname.match(\n      /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n    )\n)\n\nfunction registerValidSW(swUrl, config) {\n  navigator.serviceWorker\n    .register(swUrl)\n    .then((registration) => {\n      registration.onupdatefound = () => {\n        const installingWorker = registration.installing\n        if (installingWorker == null) {\n          return\n        }\n        installingWorker.onstatechange = () => {\n          if (installingWorker.state === 'installed') {\n            if (navigator.serviceWorker.controller) {\n              // At this point, the updated precached content has been fetched,\n              // but the previous service worker will still serve the older\n              // content until all client tabs are closed.\n              console.log(\n                'New content is available and will be used when all ' +\n                  'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n              )\n\n              // Execute callback\n              if (config && config.onUpdate) {\n                config.onUpdate(registration)\n              }\n            } else {\n              // At this point, everything has been precached.\n              // It's the perfect time to display a\n              // \"Content is cached for offline use.\" message.\n              console.log('Content is cached for offline use.')\n\n              // Execute callback\n              if (config && config.onSuccess) {\n                config.onSuccess(registration)\n              }\n            }\n          }\n        }\n      }\n    })\n    .catch((error) => {\n      console.error('Error during service worker registration:', error)\n    })\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n  // Check if the service worker can be found. If it can't reload the page.\n  fetch(swUrl, {\n    headers: { 'Service-Worker': 'script' }\n  })\n    .then((response) => {\n      // Ensure service worker exists, and that we really are getting a JS file.\n      const contentType = response.headers.get('content-type')\n      if (\n        response.status === 404 ||\n        (contentType != null && contentType.indexOf('javascript') === -1)\n      ) {\n        // No service worker found. Probably a different app. Reload the page.\n        navigator.serviceWorker.ready.then((registration) => {\n          registration.unregister().then(() => {\n            window.location.reload()\n          })\n        })\n      } else {\n        // Service worker found. Proceed as normal.\n        registerValidSW(swUrl, config)\n      }\n    })\n    .catch(() => {\n      console.log(\n        'No internet connection found. App is running in offline mode.'\n      )\n    })\n}\n\nexport function register(config) {\n  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n    // The URL constructor is available in all browsers that support SW.\n    const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)\n    if (publicUrl.origin !== window.location.origin) {\n      // Our service worker won't work if PUBLIC_URL is on a different origin\n      // from what our page is served on. This might happen if a CDN is used to\n      // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n      return\n    }\n\n    window.addEventListener('load', () => {\n      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`\n\n      if (isLocalhost) {\n        // This is running on localhost. Let's check if a service worker still exists or not.\n        checkValidServiceWorker(swUrl, config)\n\n        // Add some additional logging to localhost, pointing developers to the\n        // service worker/PWA documentation.\n        navigator.serviceWorker.ready.then(() => {\n          console.log(\n            'This web app is being served cache-first by a service ' +\n              'worker. To learn more, visit https://bit.ly/CRA-PWA'\n          )\n        })\n      } else {\n        // Is not localhost. Just register service worker\n        registerValidSW(swUrl, config)\n      }\n    })\n  }\n}\n\nexport function unregister() {\n  if ('serviceWorker' in navigator) {\n    navigator.serviceWorker.ready\n      .then((registration) => {\n        registration.unregister()\n      })\n      .catch((error) => {\n        console.error(error.message)\n      })\n  }\n}\n"
  },
  {
    "path": "src/setupTests.js",
    "content": "/* eslint-disable */\n// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom/extend-expect'\n\nconst localStorageMock = {\n  getItem: jest.fn(),\n  setItem: jest.fn(),\n  clear: jest.fn()\n}\nglobal.localStorage = localStorageMock\n\nglobal.console = {\n  log: jest.fn(),\n  error: jest.fn(),\n\n  // Keep native behaviour for other methods, use those to print out things in your own tests\n  warn: console.warn,\n  info: console.info,\n  debug: console.debug\n}\n"
  },
  {
    "path": "src/testUtil.tsx",
    "content": "import { ReactElement } from 'react'\nimport { render, RenderOptions, RenderResult } from '@testing-library/react'\n\nimport { BrowserRouter as Router } from 'react-router-dom'\n\nexport const resizeWindow = (x: number, y: number): void => {\n  global.innerWidth = x\n  global.innerHeight = y\n  window.dispatchEvent(new Event('resize'))\n}\n\nexport const renderWithProviders = (\n  ui: ReactElement,\n  options: RenderOptions = {}\n): RenderResult => render(<Router>{ui}</Router>, options)\n"
  },
  {
    "path": "src/tests/MultipleYears.test.tsx",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport * as fc from 'fast-check'\nimport * as utarbitraries from './arbitraries'\nimport { cleanup, waitFor } from '@testing-library/react'\nimport { blankYearTaxesState, YearsTaxesState } from 'ustaxes/redux'\nimport { ReactElement } from 'react'\nimport TaxPayer from 'ustaxes/components/TaxPayer'\nimport { tests as TaxPayerTests } from './components/Taxpayer.test'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport { FakePagerProvider, PagerMethods } from './common/FakePager'\nimport YearStatusBar from 'ustaxes/components/YearStatusBar'\nimport YearStatusBarMethods from './common/YearsStatusBarMethods'\nimport { PersonMethods } from './common/PersonMethods'\nimport TestPage from './common/Page'\nimport TaxPayerMethods from './common/TaxPayerMethods'\n\n// RTL's cleanup method only after each\n// jest test is done. (Not each property test)\nafterEach(() => {\n  cleanup()\n})\n\njest.setTimeout(40000)\n\nfc.configureGlobal({\n  interruptAfterTimeLimit: 35000,\n  markInterruptAsFailure: false // When set to true, timeout during initial cases (1) will be marked as an error\n  // When set to false, timeout during initial cases (1) will not be considered as a failure\n})\n\nclass TestForm extends TestPage {\n  yearStatus: YearStatusBarMethods\n  person: PersonMethods\n  taxPayer: TaxPayerMethods\n  pager: PagerMethods\n\n  constructor(state: YearsTaxesState) {\n    super(state)\n    this.yearStatus = new YearStatusBarMethods(() =>\n      this.rendered().getByTestId('year-status-bar')\n    )\n    this.person = new PersonMethods(() =>\n      this.rendered().getByTestId('taxpayer')\n    )\n    this.taxPayer = new TaxPayerMethods(() =>\n      this.rendered().getByTestId('taxpayer')\n    )\n    this.pager = new PagerMethods(() => this.rendered().getByTestId('taxpayer'))\n  }\n\n  component: ReactElement = (\n    <FakePagerProvider>\n      <div data-testid=\"year-status-bar\">\n        <YearStatusBar />\n      </div>\n      <div data-testid=\"taxpayer\">\n        <TaxPayer />\n      </div>\n    </FakePagerProvider>\n  )\n}\n\nconst withForm =\n  (state: YearsTaxesState) =>\n  async (\n    f: (form: TestForm) => Promise<boolean | undefined>\n  ): Promise<boolean> => {\n    try {\n      const form = new TestForm(state)\n\n      try {\n        const res = await f(form).catch((e) => {\n          console.info('Error caught in handling promise.')\n          console.info(e)\n          console.info(form.rendered().container.innerHTML)\n          form.cleanup()\n          throw e\n        })\n\n        form.cleanup()\n        return res ?? true\n      } catch (e) {\n        console.info('Error caught in handling outer.')\n        console.info(e)\n        console.info(form.rendered().container.innerHTML)\n        form.cleanup()\n        throw e\n      }\n    } catch (e) {\n      console.error('Caught exception')\n      console.info(state)\n      throw e\n    }\n  }\n\ndescribe('years', () => {\n  it('should have open feature', async () => {\n    const state = utarbitraries.justOneState()\n\n    await withForm(state)(async (form): Promise<boolean> => {\n      await waitFor(() =>\n        expect(form.yearStatus.yearDropdownButton()).toBeInTheDocument()\n      )\n\n      form.yearStatus.openDropdown()\n\n      await waitFor(() =>\n        expect(form.yearStatus.yearDropdownButton()).not.toBeInTheDocument()\n      )\n\n      expect(form.yearStatus.yearSelect()).toBeInTheDocument()\n\n      return true\n    })\n  })\n\n  it('should start with correct selected', async () => {\n    const state = utarbitraries.justOneState()\n\n    await withForm(state)(async (form): Promise<boolean> => {\n      await waitFor(() => {\n        expect(form.store.getState().activeYear).toBe(state.activeYear)\n        expect(form.yearStatus.yearValue()).toEqual(state.activeYear)\n      })\n      return true\n    })\n  })\n\n  it('should set active year in model', async () => {\n    await fc\n      .assert(\n        fc.asyncProperty(\n          utarbitraries.taxYear,\n          utarbitraries.taxYear,\n          async (startYear, year) => {\n            // Generating states can lead to long runtimes as the generator\n            // tries to fiddle with all of state's parameters to induce a failure.\n            // We're just testing the year part of the state now.\n            const state = {\n              ...blankYearTaxesState,\n              [startYear]: blankState,\n              activeYear: startYear\n            }\n            await withForm(state)(async (form): Promise<boolean> => {\n              await form.yearStatus.setYear(year)\n\n              await waitFor(() =>\n                expect(form.store.getState().activeYear).toEqual(year)\n              )\n              form.yearStatus.openDropdown()\n              await waitFor(() =>\n                expect(form.yearStatus.yearValue()).toEqual(year)\n              )\n              return true\n            })\n          }\n        )\n      )\n      .catch((e) => {\n        console.info('exception from property')\n        throw e\n      })\n  })\n\n  it('should update form data on select', async () =>\n    await fc.assert(\n      fc.asyncProperty(utarbitraries.taxYear, async (year) => {\n        const state = utarbitraries.justOneState()\n        await withForm(state)(async (form) => {\n          await form.yearStatus.setYear(year)\n\n          await waitFor(() =>\n            expect(form.person.firstNameField()?.value).toEqual(\n              state[year].taxPayer.primaryPerson?.firstName\n            )\n          )\n\n          return true\n        })\n      })\n    ))\n\n  it('selecting year should not impact taxpayer form error handling after changing year', async () => {\n    const form = new TestForm({\n      ...blankYearTaxesState,\n      Y2020: blankState,\n      activeYear: 'Y2020'\n    })\n\n    await TaxPayerTests.incompleteData(form)\n\n    await form.yearStatus.setYear('Y2021')\n\n    await TaxPayerTests.incompleteData(form)\n\n    form.cleanup()\n  })\n})\n"
  },
  {
    "path": "src/tests/Recover.test.ts",
    "content": "import * as fc from 'fast-check'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport { stateToString, stringToState } from 'ustaxes/redux/fs'\n\ndescribe('FS Recover / Save', () => {\n  it('should restore the same data it created', () => {\n    fc.assert(\n      fc.property(arbitraries.yearsTaxesState, (state) => {\n        expect(stringToState(stateToString(state))).toEqual(state)\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/tests/arbitraries.ts",
    "content": "import * as fc from 'fast-check'\nimport * as util from 'ustaxes/core/util'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport prand from 'pure-rand'\nimport { Asset, AssetType, TaxYear, TaxYears } from 'ustaxes/core/data'\n\nexport const taxYear: fc.Arbitrary<TaxYear> = fc.constantFrom(\n  ...util.enumKeys(TaxYears)\n)\n\nexport const taxYearNumber: fc.Arbitrary<number> = taxYear.map(\n  (y) => TaxYears[y]\n)\n\nconst dateInYear = (year: number) =>\n  fc.date({ min: new Date(year, 0, 1), max: new Date(year, 11, 31) })\nconst taxYearDate = taxYearNumber.chain(dateInYear)\n\nconst orUndefined = <T>(arb: fc.Arbitrary<T>) =>\n  fc.oneof(arb, fc.constant(undefined))\n\nexport const positionDate: fc.Arbitrary<Asset<Date>> = fc\n  .tuple(\n    fc.date(),\n    orUndefined(taxYearDate),\n    fc.oneof(\n      fc.constant<AssetType>('Security'),\n      fc.constant<AssetType>('Real Estate')\n    )\n  )\n  .chain(([openDate, closeDate, positionType]) =>\n    fc\n      .tuple(\n        arbitraries.word,\n        orUndefined(fc.date({ min: openDate })),\n        fc.nat(),\n        fc.nat(),\n        fc.nat(),\n        fc.nat(),\n        fc.nat(),\n        arbitraries.state\n      )\n      .map(\n        ([\n          name,\n          giftedDate,\n          openPrice,\n          closePrice,\n          quantity,\n          openFee,\n          closeFee,\n          state\n        ]) => ({\n          name,\n          openDate,\n          closeDate,\n          giftedDate: closeDate === undefined ? giftedDate : undefined,\n          openPrice,\n          closePrice,\n          openFee,\n          closeFee: closeDate === undefined ? undefined : closeFee,\n          positionType,\n          quantity: positionType === 'Real Estate' ? 1 : quantity,\n          state\n        })\n      )\n  )\n\nexport const position: fc.Arbitrary<Asset<string>> = positionDate.map((p) => ({\n  ...p,\n  openDate: p.openDate.toISOString(),\n  closeDate: p.closeDate?.toISOString(),\n  giftedDate: p.giftedDate?.toISOString()\n}))\n\nexport const taxesState: fc.Arbitrary<YearsTaxesState> = taxYear.chain(\n  (activeYear) => {\n    const information = arbitraries.forYear(TaxYears[activeYear]).information()\n\n    return fc\n      .tuple(fc.array(positionDate), information, information, information)\n      .map(([assets, Y2019, Y2020, Y2021]) => ({\n        assets,\n        Y2019,\n        Y2020,\n        Y2021,\n        activeYear\n      }))\n  }\n)\n\nconst gen = new fc.Random(prand.mersenne(new Date().getMilliseconds()))\n\nexport const justOneState = (): YearsTaxesState =>\n  taxesState.noShrink().generate(gen).value\n"
  },
  {
    "path": "src/tests/common/DomMethods.ts",
    "content": "export default class DomMethods {\n  dom: () => HTMLElement\n\n  constructor(dom: () => HTMLElement) {\n    this.dom = dom\n  }\n}\n"
  },
  {
    "path": "src/tests/common/FakePager.tsx",
    "content": "import { Button } from '@material-ui/core'\nimport { within } from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport { PropsWithChildren, ReactElement } from 'react'\nimport { PagerContext, PagerProps } from 'ustaxes/components/pager'\nimport DomMethods from './DomMethods'\n\nconst constPagerProps: PagerProps = {\n  onAdvance: () => {\n    // not needed\n  },\n  navButtons: (\n    <Button type=\"submit\" name=\"save\">\n      Save and Continue\n    </Button>\n  )\n}\n\nexport class PagerMethods extends DomMethods {\n  saveButton = (): HTMLButtonElement =>\n    within(this.dom()).getByRole('button', {\n      name: /Save/i\n    })\n\n  save = (): void => userEvent.click(this.saveButton())\n}\n\nexport const FakePagerProvider = ({\n  children\n}: PropsWithChildren<Record<never, never>>): ReactElement => (\n  <PagerContext.Provider value={constPagerProps}>\n    {children}\n  </PagerContext.Provider>\n)\n"
  },
  {
    "path": "src/tests/common/Page.tsx",
    "content": "import { YearsTaxesState } from 'ustaxes/redux'\nimport { ReactElement } from 'react'\nimport { createWholeStoreUnpersisted, InfoStore } from 'ustaxes/redux/store'\nimport { Provider } from 'react-redux'\nimport * as Queries from '@testing-library/dom/types/queries'\nimport { RenderResult } from '@testing-library/react'\nimport { renderWithProviders } from 'ustaxes/testUtil'\n\nexport type TestRenderResult = RenderResult<typeof Queries, HTMLElement>\n\nexport abstract class TestPage {\n  private _rendered: TestRenderResult | undefined\n  private _baseElement: HTMLElement | undefined\n  abstract component: ReactElement\n  initialState: YearsTaxesState\n  store: InfoStore\n\n  constructor(state: YearsTaxesState) {\n    this.initialState = state\n    this.store = createWholeStoreUnpersisted(state)\n  }\n\n  renderComponent(): ReactElement {\n    return <Provider store={this.store}>{this.component}</Provider>\n  }\n\n  rendered = (): TestRenderResult => {\n    if (this._rendered === undefined) {\n      // Attempt to fully isolate the rendered component\n      // so that this rendered component may be safely\n      // accessed asynchronously\n      const baseElement: HTMLElement = document.createElement('div')\n      document.getElementsByTagName('body')[0].appendChild(baseElement)\n      const rendered = renderWithProviders(this.renderComponent(), {\n        baseElement\n      })\n      rendered.debug(undefined, Infinity)\n      this._baseElement = baseElement\n      this._rendered = rendered\n    }\n    return this._rendered\n  }\n\n  allFieldNames = (): string[] =>\n    this.rendered()\n      .getAllByRole('textbox')\n      .flatMap((x) => {\n        const name = x.getAttribute('name')\n        return name !== null ? [name] : []\n      })\n\n  cleanup = (): void => {\n    this._rendered?.unmount()\n    this._rendered = undefined\n    this._baseElement?.remove()\n    this._baseElement = undefined\n  }\n}\n\n/**\n * Attempts to help with the cryptic error messages that can be\n * thrown out by `waitFor`.\n * @param makePage\n * @returns\n */\nexport const withPage =\n  <P extends TestPage>(makePage: (state: YearsTaxesState) => P) =>\n  (state: YearsTaxesState) =>\n  async (f: (page: P) => Promise<boolean | undefined>): Promise<boolean> => {\n    try {\n      const page = makePage(state)\n      try {\n        const res = await f(page).catch((e) => {\n          console.info('Error caught in handling promise.')\n          console.info(e)\n          console.info(page.rendered().container.innerHTML)\n          page.cleanup()\n          throw e\n        })\n\n        page.cleanup()\n        return res ?? true\n      } catch (e) {\n        console.info('Error caught in handling outer.')\n        console.info(e)\n        console.info(page.rendered().container.innerHTML)\n        page.cleanup()\n        throw e\n      }\n    } catch (e) {\n      console.error('Caught exception')\n      console.info(state)\n      throw e\n    }\n  }\n\nexport default TestPage\n"
  },
  {
    "path": "src/tests/common/PersonMethods.tsx",
    "content": "import { labels as personLabels } from 'ustaxes/components/TaxPayer/PersonFields'\nimport { within } from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport DomMethods from './DomMethods'\n\nexport class PersonMethods extends DomMethods {\n  firstNameField = (): HTMLInputElement | null =>\n    within(this.dom()).queryByLabelText(personLabels.fname)\n\n  setIfAble = (f: HTMLInputElement | null, v: string): boolean => {\n    if (f !== null) {\n      userEvent.type(f, v)\n      return true\n    }\n    return false\n  }\n\n  setFirstName = (v: string): boolean =>\n    this.setIfAble(this.firstNameField(), v)\n\n  lastNameField = (): HTMLInputElement | null =>\n    within(this.dom()).queryByLabelText(personLabels.lname)\n\n  setLastName = (v: string): boolean => this.setIfAble(this.lastNameField(), v)\n\n  ssnField = (): HTMLInputElement | null =>\n    within(this.dom()).queryByLabelText(personLabels.ssn)\n\n  dateOfBirthField = (): HTMLInputElement | null =>\n    // not sure why querying by label is not working.\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    within(this.dom()).queryByTestId('dateOfBirth')!.children[1]\n      .children[0] as HTMLInputElement | null\n\n  requiredErrors = (): HTMLElement[] =>\n    within(this.dom()).queryAllByText('Input is required')\n\n  dateOfBirthErrors = (): HTMLElement[] =>\n    within(this.dom()).queryAllByText('Invalid Date Format')\n\n  saveButton = (): HTMLButtonElement | null =>\n    within(this.dom()).queryByRole('button', {\n      name: /Save/\n    })\n\n  closeButton = (): HTMLButtonElement | null =>\n    within(this.dom()).queryByRole('button', {\n      name: /Discard/i\n    })\n\n  deleteButtons = (): HTMLButtonElement[] =>\n    within(this.dom()).queryAllByRole('button', {\n      name: /delete/\n    })\n}\n"
  },
  {
    "path": "src/tests/common/TaxPayerMethods.tsx",
    "content": "import { within } from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport { ReactElement } from 'react'\nimport TaxPayer from 'ustaxes/components/TaxPayer'\nimport DomMethods from './DomMethods'\n\nexport default class TaxPayerMethods extends DomMethods {\n  component: ReactElement = (<TaxPayer />)\n\n  g = {\n    foreignCountryBox: (): HTMLInputElement =>\n      within(this.dom()).getByLabelText('Do you have a foreign address?')\n  }\n\n  setIsForeignCountry = (value: boolean): void =>\n    (value ? userEvent.click : userEvent.clear)(this.g.foreignCountryBox())\n}\n"
  },
  {
    "path": "src/tests/common/YearsStatusBarMethods.tsx",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport {\n  waitFor,\n  waitForElementToBeRemoved,\n  within\n} from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport { enumKeys } from 'ustaxes/core/util'\nimport { TaxYear, TaxYears } from 'ustaxes/core/data'\nimport DomMethods from './DomMethods'\n\nexport default class YearStatusBarMethods extends DomMethods {\n  yearDropdownButton = (): HTMLElement | null =>\n    within(this.dom()).queryByTestId('year-dropdown-button')\n\n  openDropdown = (): void => {\n    userEvent.click(this.yearDropdownButton()!)\n  }\n\n  yearSelect = (): HTMLSelectElement => within(this.dom()).getByRole('combobox')\n\n  year = (): HTMLInputElement | null =>\n    within(this.dom()).queryByLabelText('Select Tax Year')\n\n  yearValue = (): TaxYear | undefined => {\n    const y = this.year()\n    if (y !== null) {\n      return y.value as TaxYear\n    } else {\n      const year = this.yearDropdownButton()?.textContent?.trim()\n      if (year !== undefined) {\n        return enumKeys(TaxYears).find((v) => TaxYears[v] === parseInt(year))\n      } else {\n        throw new Error('Cannot read year in form')\n      }\n    }\n  }\n\n  yearSelectConfirm = (): HTMLButtonElement | null =>\n    within(this.dom()).queryByRole('button', {\n      name: /Update/\n    })\n\n  getOption = (y: TaxYear): HTMLOptionElement | null =>\n    (within(this.dom())\n      .getAllByRole('option')\n      .find((x) => x.getAttribute('value') === y) as\n      | HTMLOptionElement\n      | undefined) ?? null\n\n  setYear = async (y: TaxYear): Promise<void> => {\n    this.openDropdown()\n    await waitFor(() => {\n      expect(this.yearSelectConfirm()).toBeInTheDocument()\n    })\n\n    userEvent.selectOptions(this.yearSelect(), [y])\n    userEvent.click(this.yearSelectConfirm()!)\n\n    await waitForElementToBeRemoved(() => this.yearSelectConfirm())\n  }\n}\n"
  },
  {
    "path": "src/tests/components/CreatePdf.test.tsx",
    "content": "import { waitFor } from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport { ReactElement } from 'react'\nimport CreatePDF from 'ustaxes/components/CreatePDF'\nimport { Information } from 'ustaxes/core/data'\nimport { F1040Error } from 'ustaxes/forms/errors'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport { FakePagerProvider, PagerMethods } from '../common/FakePager'\nimport * as arbitraries from 'ustaxes/core/tests/arbitraries'\nimport * as fc from 'fast-check'\nimport TestPage from '../common/Page'\nimport { blankYearTaxesState, YearsTaxesState } from 'ustaxes/redux'\n\nafterEach(async () => {\n  await waitFor(() => localStorage.clear())\n  jest.resetAllMocks()\n})\n\njest.setTimeout(10000)\n\nexport default class CreatePDFTestPage extends TestPage {\n  pager: PagerMethods\n  constructor(state: YearsTaxesState) {\n    super(state)\n    this.pager = new PagerMethods(() => this.rendered().container)\n  }\n\n  component: ReactElement = (\n    <FakePagerProvider>\n      <CreatePDF />\n    </FakePagerProvider>\n  )\n}\n\nexport const tests = {\n  incompleteData: async ({ pager }: CreatePDFTestPage): Promise<void> => {\n    await waitFor(() => expect(pager.saveButton()).toBeInTheDocument())\n\n    userEvent.click(pager.saveButton())\n  }\n}\n\ndescribe('CreatePDF Page', () => {\n  const taxpayerComponent = (information: Information = blankState) =>\n    new CreatePDFTestPage({\n      ...blankYearTaxesState,\n      Y2020: information,\n      activeYear: 'Y2020'\n    })\n\n  it('should show no data error if no data is entered', async () => {\n    const page = taxpayerComponent()\n\n    await waitFor(() =>\n      expect(\n        page.rendered().queryByText(F1040Error.filingStatusUndefined)\n      ).toBeInTheDocument()\n    )\n\n    page.cleanup()\n  })\n\n  it('should show filing status error if some data is entered', async () => {\n    const information = arbitraries.forYear(2020).information()\n    await fc.assert(\n      fc.asyncProperty(information, async (info) => {\n        const newInfo: Information = info\n        newInfo.taxPayer.filingStatus = undefined\n        const page = taxpayerComponent(newInfo)\n\n        await waitFor(() =>\n          expect(\n            page\n              .rendered()\n              .queryByText(F1040Error.filingStatusRequirementsNotMet)\n          ).toBeInTheDocument()\n        )\n\n        page.cleanup()\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/tests/components/Menu.test.tsx",
    "content": "import { screen } from '@testing-library/react'\nimport Menu, { drawerSections } from 'ustaxes/components/Menu'\nimport { renderWithProviders } from 'ustaxes/testUtil'\nimport { Provider } from 'react-redux'\nimport { createWholeStoreUnpersisted } from 'ustaxes/redux/store'\nimport { blankYearTaxesState } from 'ustaxes/redux'\n\nconst heading = drawerSections[0].title\nconst blankStore = createWholeStoreUnpersisted(blankYearTaxesState)\n\nconst component = (\n  <Provider store={blankStore}>\n    <Menu />\n  </Provider>\n)\n\ndescribe('Menu', () => {\n  describe('desktop view', () => {\n    it('renders', () => {\n      renderWithProviders(component)\n      expect(screen.getByText(heading)).toBeInTheDocument()\n    })\n  })\n})\n"
  },
  {
    "path": "src/tests/components/Questions.test.tsx",
    "content": "/* eslint @typescript-eslint/no-empty-function: \"off\" */\n\nimport { ReactElement } from 'react'\nimport { fireEvent, render, waitFor } from '@testing-library/react'\nimport { Provider } from 'react-redux'\nimport Questions from 'ustaxes/components/Questions'\nimport { InfoStore, createStoreUnpersisted } from 'ustaxes/redux/store'\nimport { questions } from 'ustaxes/core/data/questions'\nimport { PagerButtons, PagerContext } from 'ustaxes/components/pager'\nimport { Information } from 'ustaxes/core/data'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport TaxesStateMethods from 'ustaxes/redux/TaxesState'\n\nafterEach(async () => {\n  await waitFor(() => localStorage.clear())\n  jest.resetAllMocks()\n})\n\njest.mock('redux-persist', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const real = jest.requireActual('redux-persist')\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...real,\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    persistReducer: jest.fn().mockImplementation((config, reducers) => reducers)\n  }\n})\n\ndescribe('Questions', () => {\n  const navButtons = <PagerButtons submitText=\"Save\" />\n\n  const testComponent = (\n    info: Information = blankState\n  ): [InfoStore, ReactElement] => {\n    const store = createStoreUnpersisted(info)\n    const component = (\n      <Provider store={store}>\n        <PagerContext.Provider value={{ onAdvance: () => {}, navButtons }}>\n          <Questions />\n        </PagerContext.Provider>\n      </Provider>\n    )\n\n    return [store, component]\n  }\n\n  const cryptoQuestion = questions.find((q) => q.tag === 'CRYPTO')\n\n  if (cryptoQuestion === undefined) {\n    throw new Error('crypto question undefined')\n  }\n\n  it('should always show crypto question', async () => {\n    const [, component] = testComponent()\n    const result = render(component)\n    const questionComponent = await result.findAllByText(cryptoQuestion.text)\n    expect(questionComponent[0]).toBeInTheDocument()\n  })\n\n  it('should propagate to model', async () => {\n    const [store, component] = testComponent()\n    const result = render(component)\n    const checkBoxes = await result.findAllByRole('checkbox')\n    const save = await result.findByRole('button', { name: /Save/ })\n    checkBoxes.forEach((b) => fireEvent.click(b))\n    fireEvent.click(save)\n\n    await waitFor(() => {})\n    expect(\n      new TaxesStateMethods(store.getState()).info().questions.CRYPTO\n    ).toEqual(true)\n  })\n})\n"
  },
  {
    "path": "src/tests/components/SpouseAndDependent/Dependent.test.tsx",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */\n\nimport { waitFor } from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport { store } from 'ustaxes/redux/store'\nimport log from 'ustaxes/core/log'\nimport { SpouseAndDependentTestPage } from './Pages'\n\nafterEach(async () => {\n  await waitFor(() => localStorage.clear())\n  jest.resetAllMocks()\n})\n\nbeforeAll(() => {\n  log.setLevel(log.levels.TRACE)\n})\n\njest.setTimeout(10000)\n\njest.mock('redux-persist', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const real = jest.requireActual('redux-persist')\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...real,\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    persistReducer: jest.fn().mockImplementation((config, reducers) => reducers)\n  }\n})\n\ndescribe('Dependents', () => {\n  it('renders an empty dependent list initially', () => {\n    const spouseAndDependent = new SpouseAndDependentTestPage(store.getState())\n    const { spouse, dependent } = spouseAndDependent\n\n    // Both spouse and dependent add buttons should appear\n    expect(dependent.addButton()).toBeInTheDocument()\n    expect(spouse.addButton()).toBeInTheDocument()\n\n    // initial state does not have forms or labels\n    expect(dependent.firstNameField()).not.toBeInTheDocument()\n    expect(dependent.lastNameField()).not.toBeInTheDocument()\n    expect(dependent.ssnField()).not.toBeInTheDocument()\n\n    spouseAndDependent.cleanup()\n  })\n\n  it('renders dependent form element when add button is clicked', async () => {\n    const spouseAndDependent = new SpouseAndDependentTestPage(store.getState())\n    const { spouse, dependent } = spouseAndDependent\n\n    await waitFor(() => {\n      expect(spouse.addButton()).toBeInTheDocument()\n      expect(dependent.addButton()).toBeInTheDocument()\n    })\n\n    userEvent.click(dependent.addButton()!)\n\n    const dependentFormLabels = [\n      'First Name and Initial',\n      'Last Name',\n      'SSN / TIN',\n      'Relationship to Taxpayer',\n      'Date of Birth',\n      'How many months did you live together this year?',\n      'Is this person a full-time student?'\n    ]\n\n    // Assert all form labels appear\n    await waitFor(() => {\n      dependentFormLabels.forEach((label) =>\n        expect(\n          spouseAndDependent.rendered().getByText(label)\n        ).toBeInTheDocument()\n      )\n    })\n\n    userEvent.click(spouseAndDependent.dependent.closeButton()!)\n\n    // assert all the labels are now gone\n    await waitFor(() => {\n      dependentFormLabels.forEach((label) => {\n        expect(\n          spouseAndDependent.rendered().queryByText(label)\n        ).not.toBeInTheDocument()\n      })\n    })\n\n    spouseAndDependent.cleanup()\n  })\n\n  it('saves multiple dependents', async () => {\n    const spouseAndDependent = new SpouseAndDependentTestPage(store.getState())\n    const dependent = spouseAndDependent.dependent\n\n    await waitFor(() => {\n      expect(dependent.addButton()).toBeInTheDocument()\n    })\n\n    userEvent.click(dependent.addButton()!)\n\n    await waitFor(() => {\n      expect(dependent.firstNameField()).toBeInTheDocument()\n    })\n\n    expect(dependent.isStudent()).toBeInTheDocument()\n\n    // add values for each input\n    userEvent.type(dependent.firstNameField()!, 'Charlie')\n    userEvent.type(dependent.lastNameField()!, 'Brown')\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '222222222')\n    userEvent.type(dependent.relationField()!, 'Son')\n    userEvent.clear(dependent.dateOfBirthField()!)\n    userEvent.type(dependent.dateOfBirthField()!, '01/01/2007')\n    userEvent.type(dependent.durationField()!, '12')\n    userEvent.click(dependent.isStudent()!)\n\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(async () =>\n      expect(\n        await spouseAndDependent.rendered().findByText('Charlie Brown')\n      ).toBeInTheDocument()\n    )\n\n    expect(\n      spouseAndDependent.rendered().getByText('222-22-2222')\n    ).toBeInTheDocument()\n\n    userEvent.click(dependent.addButton()!)\n\n    await waitFor(() => expect(dependent.isStudent()).toBeInTheDocument())\n\n    userEvent.type(dependent.firstNameField()!, 'Sally')\n    userEvent.type(dependent.lastNameField()!, 'Brown')\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '333333333')\n    userEvent.type(dependent.relationField()!, 'Daughter')\n    userEvent.clear(dependent.dateOfBirthField()!)\n    userEvent.type(dependent.dateOfBirthField()!, '03/01/2000')\n    userEvent.type(dependent.durationField()!, '12')\n    userEvent.click(dependent.isStudent()!)\n\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(async () => {\n      expect(\n        await spouseAndDependent.rendered().findByText('Charlie Brown')\n      ).toBeInTheDocument()\n    })\n\n    expect(\n      spouseAndDependent.rendered().getByText('222-22-2222')\n    ).toBeInTheDocument()\n    await waitFor(() => {\n      expect(\n        spouseAndDependent.rendered().getByText('Sally Brown')\n      ).toBeInTheDocument()\n    })\n    expect(\n      spouseAndDependent.rendered().getByText('333-33-3333')\n    ).toBeInTheDocument()\n\n    expect(dependent.deleteButtons()).toHaveLength(2)\n\n    const [deleteCharlie, deleteSally] = dependent.deleteButtons()\n\n    userEvent.click(deleteSally)\n\n    await waitFor(() =>\n      expect(\n        spouseAndDependent.rendered().queryByText('Sally Brown')\n      ).not.toBeInTheDocument()\n    )\n\n    userEvent.click(deleteCharlie)\n    await waitFor(() =>\n      expect(\n        spouseAndDependent.rendered().queryByText('Charlie Brown')\n      ).not.toBeInTheDocument()\n    )\n\n    spouseAndDependent.cleanup()\n  })\n\n  it('saves and edits multiple dependents', async (): Promise<void> => {\n    const spouseAndDependent = new SpouseAndDependentTestPage(store.getState())\n    const dependent = spouseAndDependent.dependent\n\n    await waitFor(() => {\n      expect(dependent.addButton()).toBeInTheDocument()\n    })\n\n    userEvent.click(dependent.addButton()!)\n\n    await waitFor(() => expect(dependent.firstNameField()).toBeInTheDocument())\n\n    userEvent.type(dependent.firstNameField()!, 'Charlie')\n    userEvent.type(dependent.lastNameField()!, 'Brown')\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '222222222')\n    userEvent.type(dependent.relationField()!, 'Son')\n    userEvent.type(dependent.durationField()!, '12')\n    userEvent.clear(dependent.dateOfBirthField()!)\n    userEvent.type(dependent.dateOfBirthField()!, '09/11/2001')\n    userEvent.click(dependent.isStudent()!)\n\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(async () =>\n      expect(\n        await spouseAndDependent.rendered().findByText('Charlie Brown')\n      ).toBeInTheDocument()\n    )\n    expect(\n      spouseAndDependent.rendered().getByText('222-22-2222')\n    ).toBeInTheDocument()\n\n    userEvent.click(dependent.addButton()!)\n\n    await waitFor(() => expect(dependent.firstNameField()).toBeInTheDocument())\n    await waitFor(() =>\n      expect(dependent.dateOfBirthField()).toBeInTheDocument()\n    )\n\n    userEvent.type(dependent.firstNameField()!, 'Sally')\n    userEvent.type(dependent.lastNameField()!, 'Brown')\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '333333333')\n    userEvent.type(dependent.relationField()!, 'Daughter')\n    userEvent.type(dependent.durationField()!, '12')\n    userEvent.clear(dependent.dateOfBirthField()!)\n    userEvent.type(dependent.dateOfBirthField()!, '08/12/1999')\n    userEvent.click(dependent.isStudent()!)\n    userEvent.click(dependent.saveButton()!)\n\n    expect(\n      spouseAndDependent.rendered().queryByText('Input is required')\n    ).not.toBeInTheDocument()\n\n    await waitFor(() => expect(dependent.dateOfBirthErrors()).toHaveLength(0))\n\n    await waitFor(async () => {\n      expect(\n        await spouseAndDependent.rendered().findByText('Charlie Brown')\n      ).toBeInTheDocument()\n      expect(\n        spouseAndDependent.rendered().getByText('222-22-2222')\n      ).toBeInTheDocument()\n      expect(\n        spouseAndDependent.rendered().getByText('Sally Brown')\n      ).toBeInTheDocument()\n      expect(\n        spouseAndDependent.rendered().getByText('333-33-3333')\n      ).toBeInTheDocument()\n    })\n\n    await waitFor(() => {\n      expect(dependent.editButtons()).toHaveLength(2)\n    })\n\n    const editCharlie = dependent.editButtons()[0]\n    userEvent.click(editCharlie)\n\n    expect(dependent.firstNameField()!.value).toBe('Charlie')\n    expect(dependent.lastNameField()!.value).toBe('Brown')\n    expect(dependent.ssnField()!.value).toBe('222-22-2222')\n    expect(dependent.relationField()!.value).toBe('Son')\n    expect(dependent.durationField()!.value).toBe('12')\n    expect(dependent.firstNameField()!.value).toBe('Charlie')\n    expect(dependent.dateOfBirthField()!.value).toBe('09/11/2001')\n\n    userEvent.type(dependent.firstNameField()!, '{selectall}{del}Deebo')\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '777777777')\n\n    userEvent.click(dependent.saveButton()!)\n\n    await spouseAndDependent.rendered().findByText('Deebo Brown')\n    await spouseAndDependent.rendered().findByText('777-77-7777')\n\n    expect(dependent.deleteButtons()).toHaveLength(2)\n\n    const [deleteDeebo, deleteSally] = dependent.deleteButtons()\n\n    userEvent.click(deleteSally)\n    await waitFor(() =>\n      expect(\n        spouseAndDependent.rendered().queryByText('Sally Brown')\n      ).not.toBeInTheDocument()\n    )\n\n    userEvent.click(deleteDeebo)\n    await waitFor(() =>\n      expect(\n        spouseAndDependent.rendered().queryByText('Deebo Brown')\n      ).not.toBeInTheDocument()\n    )\n\n    spouseAndDependent.cleanup()\n  })\n\n  it('renders appropriate input errors', async () => {\n    const spouseAndDependent = new SpouseAndDependentTestPage(store.getState())\n    const dependent = spouseAndDependent.dependent\n\n    await waitFor(() => expect(dependent.addButton()).toBeInTheDocument())\n\n    userEvent.click(dependent.addButton()!)\n\n    const labels = [\n      'First Name and Initial',\n      'Last Name',\n      'SSN / TIN',\n      'Relationship to Taxpayer',\n      'Date of Birth',\n      'How many months did you live together this year?',\n      'Is this person a full-time student?'\n    ]\n    // Assert all form labels appear\n    await waitFor(() => {\n      labels.forEach((label) =>\n        expect(\n          spouseAndDependent.rendered().getByText(label)\n        ).toBeInTheDocument()\n      )\n    })\n\n    // click the save button with empty inputs\n    userEvent.click(dependent.saveButton()!)\n\n    // expect six `Input is required` errors\n    await waitFor(() => expect(dependent.requiredErrors()).toHaveLength(6))\n\n    userEvent.type(dependent.firstNameField()!, '8675309')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() => expect(dependent.requiredErrors()).toHaveLength(5))\n\n    userEvent.clear(dependent.firstNameField()!)\n    userEvent.type(dependent.firstNameField()!, 'Booker T')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() => {\n      expect(dependent.requiredErrors()).toHaveLength(5)\n    })\n\n    userEvent.type(dependent.lastNameField()!, '{selectall}{del}Washington')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() => expect(dependent.requiredErrors()).toHaveLength(4))\n\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '123')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(async () =>\n      expect(\n        await spouseAndDependent\n          .rendered()\n          .findAllByText('Input should be filled with 9 digits')\n      ).toHaveLength(1)\n    )\n\n    expect(dependent.requiredErrors()).toHaveLength(3)\n\n    userEvent.clear(dependent.ssnField()!)\n    userEvent.type(dependent.ssnField()!, '123456789')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() =>\n      expect(\n        spouseAndDependent\n          .rendered()\n          .queryByText('Input should be filled with 9 digits')\n      ).not.toBeInTheDocument()\n    )\n    await waitFor(() => expect(dependent.requiredErrors()).toHaveLength(3))\n\n    userEvent.type(dependent.relationField()!, '1111')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(async () =>\n      expect(\n        await spouseAndDependent\n          .rendered()\n          .findAllByText('Input should only include letters and spaces')\n      ).toHaveLength(1)\n    )\n\n    expect(dependent.requiredErrors()).toHaveLength(2)\n\n    userEvent.type(dependent.relationField()!, '{selectall}{del}stepchild')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() =>\n      expect(\n        spouseAndDependent\n          .rendered()\n          .queryByText('Input should only include letters and spaces')\n      ).not.toBeInTheDocument()\n    )\n\n    expect(dependent.requiredErrors()).toHaveLength(2)\n\n    userEvent.clear(dependent.dateOfBirthField()!)\n    userEvent.type(dependent.dateOfBirthField()!, '31/12/2011')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() => expect(dependent.requiredErrors()).toHaveLength(1))\n\n    await waitFor(() => {\n      const dateErr = spouseAndDependent\n        .rendered()\n        .queryAllByText('Invalid date format')\n      expect(dateErr).toHaveLength(1)\n    })\n\n    userEvent.clear(dependent.dateOfBirthField()!)\n    userEvent.type(dependent.dateOfBirthField()!, '01/01/2000')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() =>\n      expect(spouseAndDependent.rendered().queryByText('Invalid date format'))\n    )\n\n    userEvent.type(dependent.durationField()!, 'abcd')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() => expect(dependent.requiredErrors()).toHaveLength(1))\n\n    userEvent.type(dependent.durationField()!, '{selectall}{del}15')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() =>\n      expect(\n        spouseAndDependent\n          .rendered()\n          .queryAllByText('Input must be less than or equal to 12')\n      ).toHaveLength(1)\n    )\n\n    expect(dependent.requiredErrors()).toHaveLength(0)\n\n    userEvent.type(dependent.durationField()!, '{selectall}{del}10')\n    userEvent.click(dependent.saveButton()!)\n\n    await waitFor(() =>\n      expect(\n        spouseAndDependent\n          .rendered()\n          .queryByText('Input must be less than or equal to 12')\n      ).not.toBeInTheDocument()\n    )\n    expect(dependent.requiredErrors()).toHaveLength(0)\n\n    await spouseAndDependent.rendered().findByText('Booker T Washington')\n    expect(\n      spouseAndDependent.rendered().getByText('123-45-6789')\n    ).toBeInTheDocument()\n\n    const deleteBooker = dependent.deleteButtons()[0]\n    userEvent.click(deleteBooker)\n    await waitFor(() =>\n      expect(\n        spouseAndDependent.rendered().queryByText('Booker T Washington')\n      ).not.toBeInTheDocument()\n    )\n\n    spouseAndDependent.cleanup()\n  })\n})\n"
  },
  {
    "path": "src/tests/components/SpouseAndDependent/FilingStatus.test.tsx",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */\n\nimport log from 'ustaxes/core/log'\n\nimport * as yarbitraries from '../../arbitraries'\nimport { SpouseAndDependentTestPage } from './Pages'\nimport { filingStatuses, TaxPayer, TaxYear } from 'ustaxes/core/data'\nimport { waitFor } from '@testing-library/react'\n\nbeforeEach(() => {\n  log.setLevel(log.levels.TRACE)\n})\n\njest.mock('redux-persist', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const real = jest.requireActual('redux-persist')\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...real,\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    persistReducer: jest.fn().mockImplementation((config, reducers) => reducers)\n  }\n})\n\njest.setTimeout(10000)\n\ndescribe('FilingStatus', () => {\n  jest.setTimeout(20000)\n\n  it('should update on year change', async () => {\n    const state = yarbitraries.justOneState()\n    const y1: TaxYear = 'Y2020'\n    const y2: TaxYear = 'Y2021'\n\n    state.activeYear = y1\n    const page = new SpouseAndDependentTestPage(state)\n\n    expect(page.filingStatus.dropdown()).toBeInTheDocument()\n\n    const checkFs = (tp: TaxPayer) => {\n      if (\n        tp.filingStatus !== undefined &&\n        filingStatuses(tp).includes(tp.filingStatus)\n      ) {\n        expect(page.filingStatus.selected()).toEqual(tp.filingStatus)\n      } else {\n        expect(page.filingStatus.selected()).toEqual('')\n      }\n    }\n\n    expect(state[y1].taxPayer).not.toBeUndefined()\n    expect(state[y2].taxPayer).not.toBeUndefined()\n\n    checkFs(state[y1].taxPayer)\n    await page.yearStatus.setYear(y2)\n\n    await waitFor(() => {\n      expect(page.store.getState().activeYear).toEqual(y2)\n    })\n    await waitFor(() => {\n      expect(page.yearStatus.yearValue()).toEqual(y2)\n    })\n    const tp = state[y2].taxPayer\n    await waitFor(() => {\n      checkFs(tp)\n    })\n\n    return true\n  })\n})\n"
  },
  {
    "path": "src/tests/components/SpouseAndDependent/Methods.ts",
    "content": "import { PersonMethods } from '../../common/PersonMethods'\nimport { within } from '@testing-library/react'\nimport DomMethods from '../../common/DomMethods'\nimport { FilingStatus } from 'ustaxes/core/data'\n\nexport class SpouseMethods extends PersonMethods {\n  addButton = (): HTMLButtonElement | null =>\n    within(this.dom()).queryByRole('button', {\n      name: /Add/\n    })\n\n  editButton = (): HTMLButtonElement | null =>\n    within(this.dom()).queryByLabelText('edit')\n}\n\nexport class DependentMethods extends PersonMethods {\n  relationField = (): HTMLInputElement | null =>\n    within(this.dom()).queryByLabelText('Relationship to Taxpayer')\n\n  durationField = (): HTMLInputElement | null =>\n    within(this.dom()).queryByLabelText(/How many months/)\n\n  isStudent = (): HTMLInputElement | null =>\n    within(this.dom()).queryByText('Is this person a full-time student?')\n\n  addButton = (): HTMLButtonElement | null =>\n    within(this.dom()).queryByRole('button', {\n      name: /Add/\n    })\n\n  editButtons = (): HTMLButtonElement[] =>\n    within(this.dom()).queryAllByLabelText('edit')\n}\n\nexport class FilingStatusMethods extends DomMethods {\n  options = (): FilingStatus[] =>\n    within(this.dom())\n      .getAllByRole('option')\n      .flatMap((x) => {\n        const v = x.getAttribute('value') as FilingStatus | null\n        return v === null ? [] : [v]\n      })\n\n  dropdown = (): HTMLSelectElement | null =>\n    within(this.dom()).queryByRole('combobox')\n\n  selected = (): FilingStatus | undefined =>\n    this.dropdown()?.value as FilingStatus | undefined\n}\n"
  },
  {
    "path": "src/tests/components/SpouseAndDependent/Pages.tsx",
    "content": "import { ReactElement } from 'react'\nimport {\n  AddDependentForm,\n  FilingStatusDropdown,\n  SpouseInfo\n} from 'ustaxes/components/TaxPayer/SpouseAndDependent'\nimport YearStatusBar from 'ustaxes/components/YearStatusBar'\nimport { YearsTaxesState } from 'ustaxes/redux'\nimport TestPage from 'ustaxes/tests/common/Page'\nimport YearStatusBarMethods from 'ustaxes/tests/common/YearsStatusBarMethods'\nimport { DependentMethods, SpouseMethods, FilingStatusMethods } from './Methods'\n\nexport class SpouseTestPage extends TestPage {\n  spouse: SpouseMethods\n\n  constructor(state: YearsTaxesState) {\n    super(state)\n    this.spouse = new SpouseMethods(() =>\n      this.rendered().getByTestId('spouse-info')\n    )\n  }\n\n  component: ReactElement = (\n    <div data-testid=\"spouse-info\">\n      <SpouseInfo />\n    </div>\n  )\n}\n\nexport class SpouseAndDependentTestPage extends TestPage {\n  yearStatus: YearStatusBarMethods\n  spouse: SpouseMethods\n  dependent: DependentMethods\n  filingStatus: FilingStatusMethods\n\n  constructor(state: YearsTaxesState) {\n    super(state)\n\n    const testId = (id: string) => (): HTMLElement =>\n      this.rendered().getByTestId(id)\n\n    this.yearStatus = new YearStatusBarMethods(testId('year-status-bar'))\n    this.spouse = new SpouseMethods(testId('spouse-info'))\n    this.dependent = new DependentMethods(testId('add-dependent-form'))\n    this.filingStatus = new FilingStatusMethods(\n      testId('filing-status-dropdown')\n    )\n  }\n\n  component: ReactElement = (\n    <>\n      <div data-testid=\"year-status-bar\">\n        <YearStatusBar />\n      </div>\n      <div data-testid=\"spouse-info\">\n        <SpouseInfo />\n      </div>\n      <div data-testid=\"add-dependent-form\">\n        <AddDependentForm />\n      </div>\n      <div data-testid=\"filing-status-dropdown\">\n        <FilingStatusDropdown />\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "src/tests/components/SpouseAndDependent/Spouse.test.tsx",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */\n\nimport { waitFor } from '@testing-library/react'\nimport userEvent from '@testing-library/user-event'\nimport { store } from 'ustaxes/redux/store'\nimport log from 'ustaxes/core/log'\nimport { SpouseTestPage } from './Pages'\n\nafterEach(async () => {\n  await waitFor(() => localStorage.clear())\n  jest.resetAllMocks()\n})\n\nbeforeEach(() => {\n  log.setLevel(log.levels.TRACE)\n})\n\njest.setTimeout(30000)\n\njest.mock('redux-persist', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const real = jest.requireActual('redux-persist')\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...real,\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    persistReducer: jest.fn().mockImplementation((config, reducers) => reducers)\n  }\n})\n\ndescribe('SpouseInfo', () => {\n  it('renders an `Add` button when no spouse has been added', () => {\n    const spousePage = new SpouseTestPage(store.getState())\n    const spouseTest = spousePage.spouse\n\n    // initial state has an add button\n    expect(spouseTest.addButton()).toBeInTheDocument()\n\n    // initial state does not have any forms or labels\n    expect(spouseTest.firstNameField()).not.toBeInTheDocument()\n    expect(spouseTest.lastNameField()).not.toBeInTheDocument()\n    expect(spouseTest.ssnField()).not.toBeInTheDocument()\n\n    spousePage.cleanup()\n  })\n\n  it('renders form elements when `Add` button is clicked', async () => {\n    const spousePage = new SpouseTestPage(store.getState())\n    const spouseTest = spousePage.spouse\n    userEvent.click(spouseTest.addButton()!)\n\n    // forms and labels appear after clicking the add button\n    await waitFor(() => {\n      expect(spouseTest.firstNameField()).toBeInTheDocument()\n      expect(spouseTest.lastNameField()).toBeInTheDocument()\n      expect(spouseTest.ssnField()).toBeInTheDocument()\n      expect(spouseTest.saveButton()).toBeInTheDocument()\n      expect(spouseTest.closeButton()).toBeInTheDocument()\n    })\n\n    spousePage.cleanup()\n  })\n\n  it('saves and edits a spouse', async () => {\n    const spousePage = new SpouseTestPage(store.getState())\n    const { spouse } = spousePage\n\n    await waitFor(() => expect(spouse.addButton()).toBeInTheDocument())\n\n    userEvent.click(spouse.addButton()!)\n\n    // add values for each input\n    userEvent.type(spouse.firstNameField()!, 'Sally K')\n    userEvent.type(spouse.lastNameField()!, 'Ride')\n\n    await waitFor(() => expect(spouse.dateOfBirthField()).toBeInTheDocument())\n\n    userEvent.clear(spouse.dateOfBirthField()!)\n    userEvent.type(spouse.dateOfBirthField()!, '12311988')\n\n    userEvent.clear(spouse.ssnField()!)\n    userEvent.type(spouse.ssnField()!, '123456789')\n\n    // click the save button\n    userEvent.click(spouse.saveButton()!)\n\n    // expect first and last name to be concatenated\n    expect(\n      await spousePage.rendered().findByText('Sally K Ride')\n    ).toBeInTheDocument()\n    // expect ssn to appear with hyphens\n    expect(spousePage.rendered().getByText('123-45-6789')).toBeInTheDocument()\n\n    userEvent.click(spouse.editButton()!)\n\n    // expect the edit button to no longer be in the document\n    await waitFor(() => expect(spouse.editButton()).not.toBeInTheDocument())\n\n    // assert that the input values match what was entered\n    expect(spouse.firstNameField()!.value).toBe('Sally K')\n    expect(spouse.lastNameField()!.value).toBe('Ride')\n    expect(spouse.ssnField()!.value).toBe('123-45-6789')\n\n    // delete the old values and add new ones\n    userEvent.type(spouse.firstNameField()!, '{selectall}{del}Fella')\n    userEvent.type(spouse.lastNameField()!, '{selectall}{del}McGee')\n    userEvent.clear(spouse.ssnField()!)\n    userEvent.type(spouse.ssnField()!, '987-65-4321')\n\n    // click the save button to save the new values\n    userEvent.click(spouse.saveButton()!)\n\n    // expect the new names to be concatenated and new ssn to appear with hyphens\n    expect(\n      await spousePage.rendered().findByText('Fella McGee')\n    ).toBeInTheDocument()\n    expect(spousePage.rendered().getByText('987-65-4321')).toBeInTheDocument()\n\n    // click the delete button\n    userEvent.click(spouse.deleteButtons()[0])\n\n    // the add button is back\n    expect(spouse.addButton()).toBeInTheDocument()\n\n    // expect input fields to not be in the document\n    expect(spousePage.rendered().queryAllByRole('textbox')).toHaveLength(0)\n\n    spousePage.cleanup()\n  })\n\n  it('does not save when required fields not completed', async () => {\n    const spousePage = new SpouseTestPage(store.getState())\n    const { spouse } = spousePage\n\n    await waitFor(() => expect(spouse.addButton()).toBeInTheDocument())\n\n    userEvent.click(spouse.addButton()!)\n\n    expect(spouse.saveButton()!).toBeInTheDocument()\n    expect(spouse.closeButton()).toBeInTheDocument()\n\n    // click the save button with empty inputs\n    userEvent.click(spouse.saveButton()!)\n\n    // expect four `Input is required` errors (including date input)\n    await waitFor(() => expect(spouse.requiredErrors()).toHaveLength(4))\n\n    // fill in the first name incorrectly\n    userEvent.type(spouse.firstNameField()!, 'F$LF(#)& ##3')\n    userEvent.click(spouse.saveButton()!)\n\n    await waitFor(() => expect(spouse.requiredErrors()).toHaveLength(3))\n\n    // fill in the first name correctly\n    userEvent.type(spouse.firstNameField()!, '{selectall}{del}Sally K')\n    userEvent.click(spouse.saveButton()!)\n\n    await waitFor(() => expect(spouse.requiredErrors()).toHaveLength(3))\n\n    // add a name with restricted characters\n    userEvent.type(spouse.lastNameField()!, 'R5$%84')\n    userEvent.click(spouse.saveButton()!)\n\n    await waitFor(() => expect(spouse.requiredErrors()).toHaveLength(2))\n\n    // correctly enter a last name\n    userEvent.type(spouse.lastNameField()!, '{selectall}{del}Ride')\n    userEvent.click(spouse.saveButton()!)\n\n    expect(spouse.requiredErrors()).toHaveLength(2)\n\n    userEvent.clear(spouse.dateOfBirthField()!)\n    userEvent.type(spouse.dateOfBirthField()!, '12/31/1989')\n\n    // only ssn error remains\n    expect(spouse.requiredErrors()).toHaveLength(1)\n\n    // incorrectly enter ssn\n    userEvent.clear(spouse.ssnField()!)\n    userEvent.type(spouse.ssnField()!, '123sc')\n    userEvent.click(spouse.saveButton()!)\n\n    expect(\n      await spousePage\n        .rendered()\n        .findByText('Input should be filled with 9 digits')\n    ).toBeInTheDocument()\n\n    // clear ssn and add a valid value\n    userEvent.clear(spouse.ssnField()!)\n    userEvent.type(spouse.ssnField()!, '123456789')\n    userEvent.click(spouse.saveButton()!)\n\n    userEvent.clear(spouse.dateOfBirthField()!)\n    userEvent.type(spouse.dateOfBirthField()!, '03011989')\n\n    // expect saved values to be formatted correctly\n    expect(await spousePage.rendered().findByText('Sally K Ride'))\n    expect(spousePage.rendered().getByText('123-45-6789'))\n\n    // expect ssn error to be gone\n    expect(\n      spousePage.rendered().queryByText('Input should be filled with 9 digits')\n    ).not.toBeInTheDocument()\n\n    // delete the entry\n    userEvent.click(spouse.deleteButtons()[0])\n\n    const inputsAfterDelete = spousePage.rendered().queryAllByRole('textbox')\n\n    expect(inputsAfterDelete).toHaveLength(0)\n\n    spousePage.cleanup()\n  })\n})\n"
  },
  {
    "path": "src/tests/components/Taxpayer.test.tsx",
    "content": "import { waitFor } from '@testing-library/react'\nimport TaxPayer from 'ustaxes/components/TaxPayer'\nimport { Information } from 'ustaxes/core/data'\nimport { blankYearTaxesState, YearsTaxesState } from 'ustaxes/redux'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport { FakePagerProvider, PagerMethods } from '../common/FakePager'\nimport TestPage from '../common/Page'\nimport { PersonMethods } from '../common/PersonMethods'\nimport TaxPayerMethods from '../common/TaxPayerMethods'\n\njest.setTimeout(1000 * 60 * 10)\n\nafterEach(async () => {\n  await waitFor(() => localStorage.clear())\n  jest.resetAllMocks()\n})\n\njest.mock('redux-persist', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const real = jest.requireActual('redux-persist')\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...real,\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    persistReducer: jest.fn().mockImplementation((_, reducers) => reducers)\n  }\n})\n\nclass TaxPayerTestPage extends TestPage {\n  taxPayer: TaxPayerMethods\n  person: PersonMethods\n  pager: PagerMethods\n\n  constructor(state: YearsTaxesState) {\n    super(state)\n    const dom = () => this.rendered().getByTestId('taxpayer')\n\n    this.taxPayer = new TaxPayerMethods(dom)\n    this.person = new PersonMethods(dom)\n    this.pager = new PagerMethods(dom)\n  }\n\n  component = (\n    <FakePagerProvider>\n      <div data-testid=\"taxpayer\">\n        <TaxPayer />\n      </div>\n    </FakePagerProvider>\n  )\n}\n\ninterface Person {\n  person: PersonMethods\n}\ninterface Pager {\n  pager: PagerMethods\n}\n\ninterface TaxPayer {\n  taxPayer: TaxPayerMethods\n}\n\nexport const tests = {\n  incompleteData: async ({ person, pager }: Person & Pager): Promise<void> => {\n    person.setFirstName('Bob')\n    await waitFor(() => expect(pager.saveButton()).toBeInTheDocument())\n\n    pager.save()\n\n    await waitFor(() => expect(person.requiredErrors()).not.toHaveLength(0))\n  },\n  checkboxForeignCountryFields: async (\n    page: TestPage & TaxPayer\n  ): Promise<void> => {\n    expect(page.allFieldNames()).not.toContain('address.province')\n    expect(page.allFieldNames()).toContain('address.zip')\n\n    page.taxPayer.setIsForeignCountry(true)\n    await waitFor(() => {\n      expect(page.allFieldNames()).toContain('address.province')\n      expect(page.allFieldNames()).not.toContain('address.zip')\n    })\n  }\n}\n\ndescribe('Taxpayer', () => {\n  const taxpayerComponent = (information: Information = blankState) =>\n    new TaxPayerTestPage({\n      ...blankYearTaxesState,\n      Y2020: information,\n      activeYear: 'Y2020'\n    })\n\n  it('should show errors if incomplete data is entered', async () => {\n    const page = taxpayerComponent()\n\n    await tests.incompleteData(page)\n\n    page.cleanup()\n  })\n\n  it('checkbox should open foreign country fields', async () => {\n    const page = taxpayerComponent()\n\n    await tests.checkboxForeignCountryFields(page)\n\n    page.cleanup()\n  })\n})\n"
  },
  {
    "path": "src/tests/components/income/F1099Info.test.tsx",
    "content": "import F1099Info from 'ustaxes/components/income/F1099Info'\nimport { fireEvent, screen, waitFor, act } from '@testing-library/react'\nimport { Provider } from 'react-redux'\nimport { InfoStore, createStoreUnpersisted } from 'ustaxes/redux/store'\nimport { PagerButtons, PagerContext } from 'ustaxes/components/pager'\nimport {\n  FilingStatus,\n  Income1099Type,\n  Information,\n  PersonRole,\n  IncomeW2\n} from 'ustaxes/core/data'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport userEvent from '@testing-library/user-event'\nimport { renderWithProviders } from 'ustaxes/testUtil'\n\nconst testW2sSpouse: IncomeW2 = {\n  employer: { EIN: '111111111', employerName: 'w2s employer name' },\n  personRole: PersonRole.SPOUSE,\n  occupation: 'w2s-occupation',\n  state: 'AL',\n  income: 111,\n  medicareIncome: 222,\n  fedWithholding: 333,\n  ssWages: 111,\n  ssWithholding: 444,\n  medicareWithholding: 555,\n  stateWages: 666,\n  stateWithholding: 777\n}\n\nconst testInformationState: Information = {\n  ...blankState,\n  f1099s: [\n    {\n      payer: 'payer-name',\n      type: Income1099Type.INT,\n      form: { income: 1111111 },\n      personRole: PersonRole.PRIMARY\n    }\n  ],\n  w2s: [testW2sSpouse],\n  estimatedTaxes: [],\n  realEstate: [],\n  taxPayer: {\n    primaryPerson: {\n      address: {\n        address: '0001',\n        aptNo: '',\n        city: 'AR city',\n        state: 'AR',\n        zip: '1234567'\n      },\n      firstName: 'payer-first-name',\n      lastName: 'payer-last-name',\n      isTaxpayerDependent: false,\n      role: PersonRole.PRIMARY,\n      ssid: '111111111'\n    },\n    spouse: {\n      firstName: 'spouse-first-name',\n      isTaxpayerDependent: false,\n      lastName: 'spouse-last-name',\n      role: PersonRole.SPOUSE,\n      ssid: '222222222'\n    },\n    dependents: [],\n    filingStatus: FilingStatus.MFS\n  },\n  questions: {},\n  f1098es: [],\n  stateResidencies: [{ state: 'AL' }],\n  healthSavingsAccounts: []\n}\n\ndescribe('F1099Info', () => {\n  afterEach(async () => {\n    await waitFor(() => localStorage.clear())\n    jest.resetAllMocks()\n  })\n\n  const setup = (\n    info: Information | undefined = blankState\n  ): {\n    store: InfoStore\n    labelTextChange: (labelText: string | RegExp, input: string) => void\n    selectOption: (labelText: string | RegExp, input: string) => void\n    buttonClick: (buttonText: string) => void\n  } => {\n    const store = createStoreUnpersisted(info)\n    const navButtons = <PagerButtons submitText=\"Save and Continue\" />\n\n    renderWithProviders(\n      <Provider store={store}>\n        <PagerContext.Provider value={{ onAdvance: jest.fn(), navButtons }}>\n          <F1099Info />\n        </PagerContext.Provider>\n      </Provider>\n    )\n\n    const labelTextChange = (labelText: string | RegExp, input: string) => {\n      act(() => {\n        fireEvent.change(screen.getByLabelText(labelText), {\n          target: { value: input }\n        })\n      })\n    }\n\n    const selectOption = (\n      labelText: string | RegExp,\n      input: string,\n      index = 0\n    ) => {\n      act(() => {\n        fireEvent.change(screen.getAllByLabelText(labelText)[index], {\n          target: { value: input }\n        })\n      })\n    }\n\n    const buttonClick = (buttonText: string, index = 0) => {\n      userEvent.click(screen.getAllByText(buttonText)[index])\n    }\n\n    return { store, labelTextChange, selectOption, buttonClick }\n  }\n\n  describe('validations work', () => {\n    it('shows empty error messages', async () => {\n      const { buttonClick } = setup()\n\n      buttonClick('Add')\n      buttonClick('Save')\n\n      await waitFor(() => {\n        expect(screen.getAllByText('Make a selection')).toHaveLength(2)\n        expect(screen.getAllByText('Input is required')).toHaveLength(1)\n      })\n    })\n\n    it('Payer name', async () => {\n      const { labelTextChange, buttonClick } = setup()\n\n      buttonClick('Add')\n      labelTextChange('Enter name of bank, broker firm, or other payer', '')\n      buttonClick('Save')\n\n      await waitFor(() =>\n        expect(screen.getByText('Input is required')).toBeInTheDocument()\n      )\n    })\n\n    it('Form Type', () => {\n      const { selectOption, buttonClick } = setup()\n\n      buttonClick('Add')\n      selectOption('Form Type', '1099-B')\n      buttonClick('Save')\n    })\n\n    it('Recipient', () => {\n      const { selectOption, buttonClick } = setup()\n\n      buttonClick('Add')\n      selectOption('Recipient', 'John')\n      buttonClick('Save')\n    })\n\n    it('saves information', async () => {\n      const { labelTextChange, selectOption, buttonClick } =\n        setup(testInformationState)\n\n      buttonClick('Add')\n\n      selectOption('Form Type', '1099-B')\n      labelTextChange(\n        'Enter name of bank, broker firm, or other payer',\n        'payer-name'\n      )\n      selectOption(/Recipient/, 'John')\n\n      buttonClick('Save')\n\n      await waitFor(() => {\n        expect(screen.getByText('1099-B')).toBeInTheDocument()\n      })\n    })\n\n    it('updates information', async () => {\n      const { labelTextChange, selectOption, buttonClick } =\n        setup(testInformationState)\n\n      userEvent.click(screen.getAllByRole('button')[0])\n\n      selectOption('Form Type', '1099-B')\n      labelTextChange(\n        'Enter name of bank, broker firm, or other payer',\n        'payer-name'\n      )\n      selectOption(/Recipient/, 'John')\n\n      buttonClick('Save')\n\n      await waitFor(() => {\n        expect(screen.getByText('1099-B')).toBeInTheDocument()\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "src/tests/components/income/W2JobInfo.test.tsx",
    "content": "import { fireEvent, screen, render, waitFor, act } from '@testing-library/react'\nimport { Provider } from 'react-redux'\nimport { InfoStore, createStoreUnpersisted } from 'ustaxes/redux/store'\nimport { PagerButtons, PagerContext } from 'ustaxes/components/pager'\nimport {\n  FilingStatus,\n  Income1099Type,\n  PersonRole,\n  IncomeW2,\n  Information\n} from 'ustaxes/core/data'\nimport { blankState } from 'ustaxes/redux/reducer'\nimport W2JobInfo from 'ustaxes/components/income/W2JobInfo'\nimport userEvent from '@testing-library/user-event'\n\njest.mock('redux-persist', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const real = jest.requireActual('redux-persist')\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...real,\n    persistReducer: jest\n      .fn()\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      .mockImplementation((_config, reducers) => reducers)\n  }\n})\n\nconst testW2sSpouse: IncomeW2 = {\n  employer: { EIN: '111111111', employerName: 'w2s employer name' },\n  personRole: PersonRole.SPOUSE,\n  occupation: 'w2s-occupation',\n  state: 'AL',\n  income: 111,\n  medicareIncome: 222,\n  fedWithholding: 333,\n  ssWages: 111,\n  ssWithholding: 444,\n  medicareWithholding: 555,\n  stateWages: 666,\n  stateWithholding: 777\n}\n\nconst testInfo: Information = {\n  ...blankState,\n  f1099s: [\n    {\n      payer: 'payer-name',\n      type: Income1099Type.INT,\n      form: { income: 1111111 },\n      personRole: PersonRole.PRIMARY\n    }\n  ],\n  w2s: [testW2sSpouse],\n  estimatedTaxes: [],\n  realEstate: [],\n  taxPayer: {\n    primaryPerson: {\n      address: {\n        address: '0001',\n        aptNo: '',\n        city: 'AR city',\n        state: 'AR',\n        zip: '1234567'\n      },\n      firstName: 'payer-first-name',\n      lastName: 'payer-last-name',\n      isTaxpayerDependent: false,\n      role: PersonRole.PRIMARY,\n      ssid: '111111111'\n    },\n    spouse: {\n      firstName: 'spouse-first-name',\n      isTaxpayerDependent: false,\n      lastName: 'spouse-last-name',\n      role: PersonRole.SPOUSE,\n      ssid: '222222222'\n    },\n    dependents: [],\n    filingStatus: FilingStatus.MFS\n  },\n  stateResidencies: [{ state: 'AL' }]\n}\n\nconst errors = {\n  inputRequired: () => screen.queryAllByText('Input is required'),\n  selectionRequired: () => screen.queryAllByText('Make a selection'),\n  inputWordFormat: () =>\n    screen.queryAllByText('Input should only include letters and spaces'),\n  einFormat: () =>\n    screen.queryAllByText('Input should be filled with 9 digits'),\n  all: () => {\n    // just a moment\n  }\n}\nerrors.all = () => [\n  ...errors.inputRequired(),\n  ...errors.selectionRequired(),\n  ...errors.inputWordFormat(),\n  ...errors.einFormat()\n]\n\ndescribe('W2JobInfo', () => {\n  afterEach(async () => {\n    await waitFor(() => localStorage.clear())\n    jest.resetAllMocks()\n  })\n\n  const setup = (\n    info: Information = blankState\n  ): {\n    store: InfoStore\n    changeByLabelText: (labelText: string | RegExp, input: string) => void\n    selectOption: (labelText: string | RegExp, input: string) => void\n    clickButton: (buttonText: string) => void\n  } => {\n    const store = createStoreUnpersisted(info)\n    const navButtons = <PagerButtons submitText=\"Save and Continue\" />\n\n    render(\n      <Provider store={store}>\n        <PagerContext.Provider value={{ onAdvance: jest.fn(), navButtons }}>\n          <W2JobInfo />\n        </PagerContext.Provider>\n      </Provider>\n    )\n\n    const changeByLabelText = (labelText: string | RegExp, input: string) => {\n      act(() => {\n        fireEvent.change(screen.getByLabelText(labelText), {\n          target: { value: input }\n        })\n      })\n    }\n\n    const selectOption = (\n      labelText: string | RegExp,\n      input: string,\n      index = 0\n    ) => {\n      act(() => {\n        fireEvent.change(screen.getAllByLabelText(labelText)[index], {\n          target: { value: input }\n        })\n      })\n    }\n\n    const clickButton = (buttonText: string, index = 0) => {\n      userEvent.click(screen.getAllByText(buttonText)[index])\n    }\n\n    return { store, changeByLabelText, selectOption, clickButton }\n  }\n\n  describe('validations work', () => {\n    it('shows empty error messages', async () => {\n      const { clickButton } = setup()\n\n      clickButton('Add')\n      clickButton('Save')\n\n      await waitFor(() => {\n        expect(errors.inputRequired()).toHaveLength(11)\n        expect(errors.selectionRequired()).toHaveLength(2)\n      })\n    })\n\n    it('Employer name can be any string', async () => {\n      const { changeByLabelText, clickButton } = setup()\n\n      clickButton('Add')\n      changeByLabelText('Employer name', '123')\n      clickButton('Save')\n\n      await waitFor(() => expect(errors.inputWordFormat()).toHaveLength(0))\n    })\n\n    it('Employers Identification Number', async () => {\n      const { changeByLabelText, clickButton } = setup()\n\n      clickButton('Add')\n      changeByLabelText(/Employer's Identification Number/, '123')\n      clickButton('Save')\n\n      await waitFor(() => expect(errors.einFormat()).toHaveLength(1))\n    })\n\n    it('Occupation', async () => {\n      const { changeByLabelText, clickButton } = setup()\n\n      clickButton('Add')\n      changeByLabelText('Occupation', '123')\n      clickButton('Save')\n\n      await waitFor(() => expect(errors.inputWordFormat()).toHaveLength(1))\n    })\n  })\n\n  it('shows spouse W2 message', () => {\n    setup(testInfo)\n\n    expect(\n      screen.getByText(/Filing status is set to Married Filing Separately./)\n    )\n  })\n\n  it('saves information', async () => {\n    const { changeByLabelText, selectOption, clickButton } = setup(testInfo)\n\n    clickButton('Add')\n\n    changeByLabelText('Employer name', 'test employer')\n    changeByLabelText(/Employer's Identification Number/, '111111111')\n    changeByLabelText('Occupation', 'test occupation')\n    changeByLabelText(/Wages, tips, other compensation/, '123456')\n    changeByLabelText(/Federal income tax withheld/, '3333')\n    changeByLabelText(/Social security wages/, '12345')\n    changeByLabelText(/Social security tax withheld/, '4444')\n    changeByLabelText(/Medicare Income/, '5555')\n    changeByLabelText(/Medicare tax withheld/, '6666')\n    changeByLabelText(/State wages, tips, etc/, '7777')\n    changeByLabelText(/State income tax/, '8888')\n    selectOption('Employee', 'PRIMARY')\n    selectOption(/State/, 'AL')\n\n    clickButton('Save')\n\n    await waitFor(() => {\n      expect(screen.getByText('test employer')).toBeInTheDocument()\n      expect(screen.getByText('$123,456')).toBeInTheDocument()\n    })\n  })\n\n  it('removes item of list', async () => {\n    if (testW2sSpouse.employer?.employerName) {\n      setup(testInfo)\n\n      expect(\n        screen.getByText(testW2sSpouse.employer.employerName)\n      ).toBeInTheDocument()\n\n      userEvent.click(screen.getAllByRole('button')[1])\n\n      await waitFor(() =>\n        expect(screen.queryByText('w2s employer name')).not.toBeInTheDocument()\n      )\n    }\n  })\n\n  it('sets current information when editing', () => {\n    setup(testInfo)\n\n    userEvent.click(screen.getAllByRole('button')[0])\n\n    expect(screen.getByLabelText('Employer name')).toHaveValue(\n      testW2sSpouse.employer?.employerName\n    )\n    expect(\n      screen.getByLabelText(/Employer's Identification Number/)\n    ).toHaveValue(\n      (testW2sSpouse.employer?.EIN?.slice(0, 2) ?? '') +\n        '-' +\n        (testW2sSpouse.employer?.EIN?.slice(2) ?? '')\n    )\n    expect(screen.getByLabelText('Occupation')).toHaveValue(\n      testW2sSpouse.occupation\n    )\n    expect(\n      screen.getByLabelText(/Wages, tips, other compensation/)\n    ).toHaveValue(testW2sSpouse.income.toLocaleString('en-US'))\n    expect(screen.getByLabelText(/Social security tax withheld/)).toHaveValue(\n      testW2sSpouse.ssWithholding.toLocaleString('en-US')\n    )\n    expect(screen.getByLabelText(/Medicare Income/)).toHaveValue(\n      testW2sSpouse.medicareIncome.toLocaleString('en-US')\n    )\n    expect(screen.getByLabelText(/Medicare tax withheld/)).toHaveValue(\n      testW2sSpouse.medicareWithholding.toLocaleString('en-US')\n    )\n    expect(screen.getAllByLabelText(/State/)[0]).toHaveValue(\n      testW2sSpouse.state\n    )\n    expect(screen.getByLabelText(/State wages, tips, etc/)).toHaveValue(\n      testW2sSpouse.stateWages?.toLocaleString('en-US')\n    )\n    expect(screen.getByLabelText(/State income tax/)).toHaveValue(\n      testW2sSpouse.stateWithholding?.toLocaleString('en-US')\n    )\n    expect(screen.getByLabelText('Employee')).toHaveValue(\n      testW2sSpouse.personRole\n    )\n  })\n\n  it('updates information', async () => {\n    const { changeByLabelText, selectOption, clickButton } = setup(testInfo)\n\n    userEvent.click(screen.getAllByRole('button')[0])\n\n    changeByLabelText('Employer name', 'updated employer name')\n    changeByLabelText(/Employer's Identification Number/, '999999999')\n    changeByLabelText('Occupation', 'updated occupation')\n    changeByLabelText(/Wages, tips, other compensation/, '8888')\n    changeByLabelText(/Federal income tax withheld/, '7777')\n    changeByLabelText(/Social security tax withheld/, '6666')\n    changeByLabelText(/Medicare Income/, '5555')\n    changeByLabelText(/Medicare tax withheld/, '4444')\n    changeByLabelText(/State wages, tips, etc/, '3333')\n    changeByLabelText(/State income tax/, '2222')\n    selectOption('Employee', 'SPOUSE')\n    selectOption(/State/, 'AR')\n\n    clickButton('Save')\n\n    await waitFor(() => {\n      expect(screen.getByText('updated employer name')).toBeInTheDocument()\n      expect(screen.getByText('$8,888')).toBeInTheDocument()\n    })\n  })\n})\n"
  },
  {
    "path": "src/tests/testdata/transactions_test1.csv",
    "content": "portfolio,trade id,product,side,created at,size,size unit,price,fee,total,price/fee/total unit,,Notes\ndefault,1,DEF,BUY,2016-01-01,21,DEF,10,0,210,USD,,extra data\ndefault,2,ABC,BUY,2018-03-17T07:35:58.772Z,23.053,ABC,49.9,0,1150.3447,USD,,\ndefault,3,ABC,BUY,2018-03-17T07:35:58.772Z,55,ABC,49.9,0,2744.5,USD,,\ndefault,4,DEF,BUY,2018-03-17T07:35:58.772Z,119,DEF,49.9,0,5938.1,USD,,\ndefault,5,ABC,BUY,2018-03-17T07:35:58.772Z,0.32321,ABC,41.5,0,13.413215,USD,,\ndefault,6,ABC,SELL,2018-03-17T07:35:58.772Z,21.2,ABC,52.25,0,1107.7,USD,,\ndefault,7,ABC,BUY,2018-03-17T07:35:58.772Z,88,ABC,48.28,0,4248.64,USD,,\ndefault,8,ABC,BUY,2018-03-17T07:35:58.772Z,48.212,ABC,46.12,0,2223.53744,USD,,\ndefault,9,ABC,BUY,2018-03-17T07:35:58.772Z,201.8,ABC,45.96,0,9274.728,USD,,\ndefault,10,ABC,SELL,2018-03-17T07:35:58.772Z,162.91733152,ABC,51.11,0,8326.7048139872,USD,,\ndefault,11,ABC,BUY,2018-03-17T07:35:58.772Z,101.12323123,ABC,48.09,0,4863.0161898507,USD,,\ndefault,12,ABC,BUY,2018-03-17T07:35:58.772Z,110.7132,ABC,40,0,4428.528,USD,,\ndefault,13,ABC,SELL,2018-03-17T07:35:58.772Z,34.18880027,ABC,30,0,1025.6640081,USD,,\ndefault,14,ABC,SELL,2018-03-17T07:35:58.772Z,0.6012,ABC,80,0,48.096,USD,,\ndefault,15,ABC,SELL,2018-03-17T07:35:58.772Z,33.438906,ABC,88,0,2942.623728,USD,,\ndefault,16,ABC,SELL,2018-03-17T07:35:58.772Z,31.62909373,ABC,90,0,2846.6184357,USD,,\ndefault,17,ABC,SELL,2018-03-17T07:35:58.772Z,13.3389495,ABC,99.993,0,1333.8015773535,USD,,\ndefault,18,ABC,SELL,2018-03-17T07:35:58.772Z,1.888381,ABC,110.21,0,208.11847001,USD,,\ndefault,19,ABC,SELL,2018-03-17T07:35:58.772Z,5.8608,ABC,110.21,0,645.918768,USD,,\ndefault,20,ABC,SELL,2018-03-17T07:35:58.772Z,0.26699,ABC,100.23,0,26.7604077,USD,,\ndefault,21,ABC,SELL,2018-03-17T07:35:58.772Z,49.171473,ABC,90.12,0,4431.33314676,USD,,\ndefault,22,ABC,SELL,2021-01-03,1.0065098,ABC,88.23,0,88.804359654,USD,,\ndefault,23,ABC,SELL,2021-01-04,23.6808967,ABC,83.32,0.24,1973.092313044,USD,,\ndefault,24,ABC,SELL,2021-01-05,0.4884,ABC,89.344,1,43.6356096,USD,,\ndefault,25,ABC,SELL,2021-01-06,200,ABC,80.132,0.3,16026.4,USD,,\ndefault,26,ABC,SELL,2021-01-07,21.5116,ABC,60.34,2,1298.009944,USD,,\ndefault,27,ABC,BUY,2021-01-08,28.91691796,ABC,55.23,0.134,1597.0813789308,USD,,\ndefault,28,ABC,BUY,2021-01-09,54.993,ABC,50.123,0.1234,2756.414139,USD,,\ndefault,29,ABC,BUY,2021-01-10,1.011648,ABC,40.23,0.123,40.69859904,USD,,\ndefault,30,ABC,BUY,2021-01-11,28.20255404,ABC,35.23,1.13,993.5759788292,USD,,\ndefault,31,ABC,BUY,2021-01-12,122.24241,ABC,31.31,0.341,3827.4098571,USD,,\ndefault,32,ABC,BUY,2021-01-13,266.72692021,ABC,29.43,0.2134,7849.7732617803,USD,,\ndefault,33,ABC,BUY,2021-01-14,17.56857139,ABC,26.2314,0.51,460.848223559646,USD,,\ndefault,34,ABC,BUY,2021-01-15,22.62554838,ABC,22.231,0.23,502.98856603578,USD,,\ndefault,35,ABC,BUY,2021-01-16,29.92998023,ABC,19.23,0.43,575.5535198229,USD,,\ndefault,36,ABC,BUY,2021-01-17,45.22658664,ABC,12.1234,0.123,548.300000471376,USD,,\ndefault,24,ABC,SELL,2021-01-15,28.91691796,ABC,89.344,4,2583.55311821824,USD,,\ndefault,25,ABC,SELL,2021-01-16,54.993,ABC,80.132,1.3,4406.699076,USD,,\ndefault,26,DEF,SELL,2021-01-17,1.011648,DEF,60.34,0,61.04284032,USD,,\n"
  },
  {
    "path": "src/tests/testdata/transactions_test2_error.csv",
    "content": "portfolio,trade id,product,side,created at,size,size unit,price,fee,total,price/fee/total unit,,Notes\ndefault,1,DEF,BUY,2016-01-01,21,DEF,10,0,210,USD,,extra data\ndefault,2,ABC,BUY,2018-03-17T07:35:58.772Z,23.053,ABC,49.9,0,1150.3447,USD,,\ndefault,3,ABC,BUY,2018-03-17T07:35:58.772Z,55,ABC,49.9,0,2744.5,USD,,\ndefault,4,DEF,BUY,2018-03-17T07:35:58.772Z,119,DEF,49.9,0,5938.1,USD,,\ndefault,5,ABC,BUY,2018-03-17T07:35:58.772Z,0.32321,ABC,41.5,0,13.413215,USD,,\ndefault,6,ABC,SELL,2018-03-17T07:35:58.772Z,21.2,ABC,52.25,0,1107.7,USD,,\ndefault,7,ABC,BUY,2018-03-17T07:35:58.772Z,88,ABC,48.28,0,4248.64,USD,,\ndefault,8,ABC,BUY,2018-03-17T07:35:58.772Z,48.212,ABC,46.12,0,2223.53744,USD,,\ndefault,9,ABC,BUY,2018-03-17T07:35:58.772Z,201.8,ABC,45.96,0,9274.728,USD,,\ndefault,10,ABC,SELL,2018-03-17T07:35:58.772Z,162.91733152,ABC,51.11,0,8326.7048139872,USD,,\ndefault,11,ABC,BUY,2018-03-17T07:35:58.772Z,101.12323123,ABC,48.09,0,4863.0161898507,USD,,\ndefault,12,ABC,BUY,2018-03-17T07:35:58.772Z,110.7132,ABC,40,0,4428.528,USD,,\ndefault,13,ABC,SELL,2018-03-17T07:35:58.772Z,34.18880027,ABC,30,0,1025.6640081,USD,,\ndefault,14,ABC,SELL,2018-03-17T07:35:58.772Z,0.6012,ABC,80,0,48.096,USD,,\ndefault,15,ABC,SELL,2018-03-17T07:35:58.772Z,33.438906,ABC,88,0,2942.623728,USD,,\ndefault,16,ABC,SELL,2018-03-17T07:35:58.772Z,31.62909373,ABC,90,0,2846.6184357,USD,,\ndefault,17,ABC,SELL,2018-03-17T07:35:58.772Z,13.3389495,ABC,99.993,0,1333.8015773535,USD,,\ndefault,18,ABC,SELL,2018-03-17T07:35:58.772Z,1.888381,ABC,110.21,0,208.11847001,USD,,\ndefault,19,ABC,SELL,2018-03-17T07:35:58.772Z,5.8608,ABC,110.21,0,645.918768,USD,,\ndefault,20,ABC,SELL,2018-03-17T07:35:58.772Z,0.26699,ABC,100.23,0,26.7604077,USD,,\ndefault,21,ABC,SELL,2018-03-17T07:35:58.772Z,49.171473,ABC,90.12,0,4431.33314676,USD,,\ndefault,22,ABC,SELL,2021-01-03,1.0065098,ABC,88.23,0,88.804359654,USD,,\ndefault,23,ABC,SELL,2021-01-04,23.6808967,ABC,83.32,0,1973.092313044,USD,,\ndefault,24,ABC,SELL,2021-01-05,0.4884,ABC,89.344,0,43.6356096,USD,,\ndefault,25,ABC,SELL,2021-01-06,200,ABC,80.132,0,16026.4,USD,,\ndefault,26,Q,SELL,2021-01-07,21.5116,ABC,60.34,0,1298.009944,USD,,\ndefault,27,ABC,BUY,2021-01-08,28.91691796,ABC,55.23,0,1597.0813789308,USD,,\ndefault,28,ABC,BUY,2021-01-09,54.993,ABC,50.123,0,2756.414139,USD,,\ndefault,29,ABC,BUY,2021-01-10,1.011648,ABC,40.23,0,40.69859904,USD,,\ndefault,30,ABC,BUY,2021-01-11,28.20255404,ABC,35.23,0,993.5759788292,USD,,\ndefault,31,ABC,BUY,2021-01-12,122.24241,ABC,31.31,0,3827.4098571,USD,,\ndefault,32,ABC,BUY,2021-01-13,266.72692021,ABC,29.43,0,7849.7732617803,USD,,\ndefault,33,ABC,BUY,2021-01-14,17.56857139,ABC,26.2314,0,460.848223559646,USD,,\ndefault,34,ABC,BUY,2021-01-15,22.62554838,ABC,22.231,0,502.98856603578,USD,,\ndefault,35,ABC,BUY,2021-01-16,29.92998023,ABC,19.23,0,575.5535198229,USD,,\ndefault,36,ABC,BUY,2021-01-17,45.22658664,ABC,12.1234,0,548.300000471376,USD,,\ndefault,24,ABC,SELL,2021-01-15,28.91691796,ABC,89.344,0,2583.55311821824,USD,,\ndefault,25,ABC,SELL,2021-01-16,54.993,ABC,80.132,0,4406.699076,USD,,\ndefault,26,DEF,SELL,2021-01-17,1.011648,DEF,60.34,0,61.04284032,USD,,\n"
  },
  {
    "path": "src/tests/transactions/Transactions.test.tsx",
    "content": "import * as arbitraries from './arbitraries'\nimport fc, { Arbitrary } from 'fast-check'\nimport {\n  Portfolio,\n  Transaction,\n  processTransaction,\n  Security\n} from 'ustaxes/data/transactions'\n\ndescribe('Transactions', () => {\n  test('For any portfolio, selling a security not held throws', () => {\n    const testArb: Arbitrary<[Security, Portfolio]> = arbitraries\n      .securities({ minLength: 2 })\n      .chain((securities) =>\n        arbitraries\n          .portfolio(securities.slice(1))\n          .map((portfolio) => [securities[0], portfolio])\n      )\n\n    fc.assert(\n      fc.property(\n        testArb,\n        arbitraries.transaction(),\n        ([newSecurity, portfolio], transaction) => {\n          const applyTransaction: Transaction = {\n            ...transaction,\n            side: 'SELL',\n            security: newSecurity\n          }\n          expect(() => processTransaction(portfolio, applyTransaction)).toThrow(\n            new Error('Transaction list failed')\n          )\n        }\n      )\n    )\n  })\n\n  test('For any portfolio, buying anything appends one position to the portfolio', () => {\n    fc.assert(\n      fc.property(\n        arbitraries.portfolio(),\n        arbitraries.transaction(),\n        (portfolio, transaction) => {\n          const purchase: Transaction = {\n            ...transaction,\n            side: 'BUY'\n          }\n          const newPortfolio = processTransaction(portfolio, purchase)\n          const dropOne = {\n            ...newPortfolio,\n            positions: newPortfolio.positions.slice(\n              0,\n              newPortfolio.positions.length - 1\n            )\n          }\n          const last = newPortfolio.positions[newPortfolio.positions.length - 1]\n\n          // Portfolio before buy is unaffected\n          expect(portfolio).toEqual(dropOne)\n\n          // Buy adds a position equivalent to buying in an empty portfolio\n          expect(processTransaction({ positions: [] }, purchase)).toEqual({\n            positions: [last]\n          })\n        }\n      )\n    )\n  })\n\n  const buyTransactions: Arbitrary<Transaction[]> = arbitraries\n    .securities()\n    .chain((securities) =>\n      fc.array(\n        arbitraries.transaction(securities).map((t) => ({ ...t, side: 'BUY' }))\n      )\n    )\n\n  // Add a strictly smaller list of the same transactions changed to sells.\n  const buysAndSells: Arbitrary<[Transaction[], Transaction[]]> =\n    buyTransactions.chain((buys) =>\n      fc\n        .subarray(buys.map<Transaction>((buy) => ({ ...buy, side: 'SELL' })))\n        .map((sells) => [buys, sells])\n    )\n\n  const buysAndScaledSells: Arbitrary<[Transaction[], Transaction[]]> =\n    buysAndSells.chain(([buys, sells]) => {\n      return fc\n        .tuple(fc.nat({ max: 1000 }), fc.float({ min: 0.2, max: 1.0 }))\n        .map(([numDays, scale]) => [\n          buys,\n          sells.map((t) => {\n            const newDate = new Date(t.date)\n            newDate.setDate(newDate.getDate() + numDays)\n\n            return {\n              ...t,\n              quantity: Math.floor(t.quantity * scale),\n              date: newDate.toISOString().slice(0, 10)\n            }\n          })\n        ])\n    })\n\n  const transactions: Arbitrary<Transaction[]> = buysAndScaledSells.map(\n    ([buys, sells]) =>\n      [...buys, ...sells].sort(\n        (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()\n      )\n  )\n\n  test('For any (valid) list of transactions, the final portfolio has the same sum of quanities as the transaction list', () => {\n    fc.assert(\n      fc.property(transactions, (transactions) => {\n        const portfolio = transactions.reduce<Portfolio>(\n          (p, t) => processTransaction(p, t),\n          { positions: [] }\n        )\n\n        const transactionCounts = transactions\n          .map<[string, number]>((t) => [\n            t.security.name,\n            t.side === 'BUY' ? t.quantity : -t.quantity\n          ])\n          .reduce<\n            Partial<{\n              [name: string]: number\n            }>\n          >(\n            (acc, [name, quantity]) => ({\n              ...acc,\n              [name]: (acc[name] ?? 0) + quantity\n            }),\n            {}\n          )\n\n        const portfolioCounts = portfolio.positions\n          .filter((p) => p.closeDate === undefined)\n          .reduce<\n            Partial<{\n              [name: string]: number\n            }>\n          >(\n            (acc, p) => ({\n              ...acc,\n              [p.security.name]: (acc[p.security.name] ?? 0) + p.quantity\n            }),\n            {}\n          )\n\n        expect(transactionCounts).toEqual(portfolioCounts)\n      })\n    )\n  })\n\n  test('For any (valid) list of transactions, the final portfolio has the same sum of buys and sells', () => {\n    fc.assert(\n      fc.property(transactions, (transactions) => {\n        const portfolio = transactions.reduce<Portfolio>(\n          (p, t) => processTransaction(p, t),\n          { positions: [] }\n        )\n\n        const transactionCounts = transactions.reduce<\n          Partial<{\n            [name: string]: { basis: number; proceeds: number }\n          }>\n        >(\n          (acc, t) => ({\n            ...acc,\n            [t.security.name]: {\n              basis:\n                (acc[t.security.name]?.basis ?? 0) +\n                (t.side === 'BUY' ? t.quantity * t.price : 0),\n              proceeds:\n                (acc[t.security.name]?.proceeds ?? 0) +\n                (t.side === 'SELL' ? t.quantity * t.price : 0)\n            }\n          }),\n          {}\n        )\n\n        const portfolioCounts = portfolio.positions.reduce<\n          Partial<{\n            [name: string]: { basis: number; proceeds: number }\n          }>\n        >(\n          (acc, p) => ({\n            ...acc,\n            [p.security.name]: {\n              basis: (acc[p.security.name]?.basis ?? 0) + p.price * p.quantity,\n              proceeds:\n                (acc[p.security.name]?.proceeds ?? 0) +\n                (p.closePrice ?? 0) * p.quantity\n            }\n          }),\n          {}\n        )\n\n        expect(transactionCounts).toEqual(portfolioCounts)\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/tests/transactions/arbitraries.ts",
    "content": "import fc, { Arbitrary } from 'fast-check'\nimport {\n  Portfolio,\n  Position,\n  Security,\n  Side,\n  Transaction\n} from 'ustaxes/data/transactions'\n\nexport const security = (): Arbitrary<Security> =>\n  fc.string({ minLength: 1, maxLength: 5 }).map((name) => ({ name }))\n\nexport const securities = (config = { minLength: 1 }): Arbitrary<Security[]> =>\n  fc\n    .set(fc.string({ minLength: 1, maxLength: 5 }), {\n      minLength: config.minLength\n    })\n    .map((names) => names.map((name) => ({ name })))\n\nconst dateStr = (): Arbitrary<string> =>\n  fc\n    .date({\n      min: new Date('2018-01-01'),\n      max: new Date('2022-12-31')\n    })\n    .map((d) => d.toISOString().substring(0, 10))\n\nexport const transaction = (securities?: Security[]): Arbitrary<Transaction> =>\n  fc\n    .tuple(fc.float({ min: 0 }), fc.integer({ min: 1, max: 1000 }))\n    .chain(([price, quantity]) =>\n      fc\n        .tuple(\n          securities === undefined\n            ? security()\n            : fc.constantFrom(...securities),\n          dateStr(),\n          fc.constantFrom<Side>('BUY', 'SELL'),\n          fc.float({ min: 0, max: (quantity * price) / 2 })\n        )\n        .map(([security, date, side, fee]) => ({\n          security,\n          date,\n          side,\n          price,\n          quantity,\n          fee\n        }))\n    )\n\nexport const position = (securities?: Security[]): Arbitrary<Position> =>\n  fc\n    .tuple(\n      fc.nat(),\n      fc.float({ min: 0 }),\n      fc.float({ min: 0 }),\n      fc.oneof(dateStr(), fc.constant(undefined))\n    )\n    .chain(([quantity, price, closePrice, closeDate]) =>\n      fc\n        .tuple(\n          securities === undefined\n            ? security()\n            : fc.constantFrom(...securities),\n          dateStr(),\n          fc.float({ min: 0, max: (quantity * price) / 2 }),\n          fc.float({ min: 0, max: (quantity * closePrice) / 2 })\n        )\n        .map(([security, openDate, openFee, closeFee]) => ({\n          security,\n          quantity,\n          price,\n          openDate,\n          closeDate,\n          closePrice: closeDate === undefined ? undefined : closePrice,\n          openFee,\n          closeFee: closeDate === undefined ? undefined : closeFee\n        }))\n    )\n\nexport const portfolio = (securities?: Security[]): Arbitrary<Portfolio> =>\n  fc\n    .array(position(securities))\n    .map((positions) =>\n      positions.sort(\n        (a, b) =>\n          new Date(a.openDate).getTime() - new Date(b.openDate).getTime()\n      )\n    )\n    .map((positions) => ({ positions }))\n"
  },
  {
    "path": "src-tauri/.gitignore",
    "content": "# Generated by Cargo\n# will have compiled files and executables\n/target/\nWixTools\n\n# These are backup files generated by rustfmt\n**/*.rs.bk\n\nconfig.json\nbundle.json\n"
  },
  {
    "path": "src-tauri/Cargo.toml",
    "content": "[package]\nname = \"us-taxes\"\nversion = \"0.1.21\"\ndescription = \"UsTaxes is an open source webapp for filing US federal income tax. All tax calculations are performed in the browser, so no personal information is stored on external servers!\"\nlicense = \"\"\nrepository = \"\"\ndefault-run = \"us-taxes\"\nedition = \"2018\"\nbuild = \"src/build.rs\"\n\n[build-dependencies]\ntauri-build = { version = \"1.0.0-rc.5\", features = [] }\n\n[dependencies]\nserde_json = \"1.0.85\"\nserde = { version = \"1.0.145\", features = [ \"derive\" ] }\ntauri = { version = \"1.0.0-rc.6\", features = [\"api-all\"] }\n\n[features]\ncustom-protocol = [ \"tauri/custom-protocol\" ]\ndefault = [ \"custom-protocol\" ]\n\n[[bin]]\nname = \"us-taxes\"\npath = \"src/main.rs\"\n"
  },
  {
    "path": "src-tauri/rustfmt.toml",
    "content": "max_width = 100\nhard_tabs = false\ntab_spaces = 2\nnewline_style = \"Auto\"\nuse_small_heuristics = \"Default\"\nreorder_imports = true\nreorder_modules = true\nremove_nested_parens = true\nedition = \"2018\"\nmerge_derives = true\nuse_try_shorthand = false\nuse_field_init_shorthand = false\nforce_explicit_abi = true\n"
  },
  {
    "path": "src-tauri/src/build.rs",
    "content": "use tauri_build::{try_build, Attributes, WindowsAttributes};\n\nfn main() {\n  if let Err(error) = try_build(\n    Attributes::new()\n      .windows_attributes(WindowsAttributes::new().window_icon_path(\"icons/favicon.ico\")),\n  ) {\n    panic!(\"error found during tauri-build: {}\", error);\n  }\n}\n"
  },
  {
    "path": "src-tauri/src/cmd.rs",
    "content": "use serde::Deserialize;\n\n#[derive(Deserialize)]\n#[serde(tag = \"cmd\", rename_all = \"camelCase\")]\npub enum Cmd {\n  // your custom commands\n  // multiple arguments are allowed\n  // note that rename_all = \"camelCase\": you need to use \"myCustomCommand\" on JS\n  LocalLog { log: String },\n}\n"
  },
  {
    "path": "src-tauri/src/main.rs",
    "content": "#![cfg_attr(\n  all(not(debug_assertions), target_os = \"windows\"),\n  windows_subsystem = \"windows\"\n)]\n\nfn main() {\n  let result = tauri::Builder::default()\n    .run(tauri::generate_context!());\n\n  println!(\"{:?}\", result)\n}\n"
  },
  {
    "path": "src-tauri/tauri.conf.json",
    "content": "{\n  \"build\": {\n    \"distDir\": \"../build\",\n    \"devPath\": \"http://localhost:3000\",\n    \"beforeDevCommand\": \"npm run start\",\n    \"beforeBuildCommand\": \"npm run build\",\n    \"withGlobalTauri\": true\n  },\n  \"tauri\": {\n    \"bundle\": {\n      \"active\": true,\n      \"targets\": \"all\",\n      \"identifier\": \"ustaxes\",\n      \"icon\": [\n        \"./icons/favicon.ico\"\n      ],\n      \"resources\": [],\n      \"externalBin\": [],\n      \"copyright\": \"\",\n      \"category\": \"DeveloperTool\",\n      \"shortDescription\": \"\",\n      \"longDescription\": \"\",\n      \"deb\": {\n        \"depends\": []\n      },\n      \"macOS\": {\n        \"frameworks\": [],\n        \"exceptionDomain\": \"\",\n        \"signingIdentity\": null,\n        \"entitlements\": null,\n        \"minimumSystemVersion\": \"\"\n      },\n      \"windows\": {\n        \"certificateThumbprint\": null,\n        \"digestAlgorithm\": \"sha256\",\n        \"timestampUrl\": \"\"\n      }\n    },\n    \"allowlist\": {\n      \"all\": true\n    },\n    \"windows\": [\n      {\n        \"title\": \"US Taxes\",\n        \"width\": 800,\n        \"height\": 600,\n        \"resizable\": true,\n        \"fullscreen\": false\n      }\n    ],\n    \"security\": {\n      \"csp\": \"default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline' 'self'\"\n    }\n  }\n}"
  },
  {
    "path": "tsconfig.json",
    "content": "{\r\n  \"extends\": \"./tsconfig.path.json\",\r\n  \"compilerOptions\": {\r\n    \"target\": \"es5\",\r\n    \"lib\": [\r\n      \"dom\",\r\n      \"dom.iterable\",\r\n      \"esnext\"\r\n    ],\r\n    \"typeRoots\": [\r\n      \"src/customTypes\",\r\n      \"node_modules/@types\"\r\n    ],\r\n    \"allowJs\": true,\r\n    \"skipLibCheck\": true,\r\n    \"esModuleInterop\": true,\r\n    \"allowSyntheticDefaultImports\": true,\r\n    \"strict\": true,\r\n    \"forceConsistentCasingInFileNames\": true,\r\n    \"noFallthroughCasesInSwitch\": true,\r\n    \"module\": \"esnext\",\r\n    \"moduleResolution\": \"node\",\r\n    \"resolveJsonModule\": true,\r\n    \"isolatedModules\": true,\r\n    \"noEmit\": true,\r\n    \"strictNullChecks\": true,\r\n    \"jsx\": \"react-jsx\"\r\n  },\r\n  \"include\": [\r\n    \"src/**/*\",\r\n    \"scripts\"\r\n  ],\r\n  \"exclude\": [\r\n    \"**/node_modules\",\r\n    \"**/.*/\"\r\n  ],\r\n  \"ts-node\": {\r\n    \"compilerOptions\": {\r\n      \"module\": \"commonjs\"\r\n    }\r\n  }\r\n}\r\n"
  },
  {
    "path": "tsconfig.path.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"ustaxes/*\": [\"src/*\"]\n    }\n  }\n}\n"
  }
]