dividendcase 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. {dividendcase-0.2.0 → dividendcase-0.3.0}/CHANGELOG.md +5 -0
  2. {dividendcase-0.2.0 → dividendcase-0.3.0}/PKG-INFO +2 -1
  3. {dividendcase-0.2.0 → dividendcase-0.3.0}/README.md +1 -0
  4. {dividendcase-0.2.0 → dividendcase-0.3.0}/pyproject.toml +1 -1
  5. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/portfolio.py +43 -1
  6. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/router.py +2 -1
  7. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/user.py +8 -0
  8. dividendcase-0.3.0/src/dividendcase/api/v1/withholding.py +73 -0
  9. dividendcase-0.3.0/src/dividendcase/migrations/versions/0004_withholding_overrides.py +27 -0
  10. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/user_preferences.py +2 -0
  11. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/user_investment.py +11 -0
  12. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/user_preferences.py +23 -1
  13. dividendcase-0.3.0/src/dividendcase/services/withholding.py +147 -0
  14. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/404/index.html +1 -1
  15. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/404.html +1 -1
  16. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/__next.__PAGE__.txt +2 -2
  17. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/__next._full.txt +2 -2
  18. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/__next._tree.txt +2 -2
  19. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/0awgjdi9fz2lt.js +1 -0
  20. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/0b2z-at3befil.js +1 -0
  21. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/0n6g6b54gzf5x.js +1 -0
  22. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/1bqpwkv1vyxpj.js +1 -0
  23. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/1hhlyzonxd9i-.js +1 -0
  24. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/0c87cux8r1ss5.js → dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/1v39mvwqbje6r.js +1 -1
  25. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/20i38r94ivt58.css +4 -0
  26. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/24b9a-jv8jte6.js +1 -0
  27. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/262l2h_0-9l6p.js +1 -0
  28. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/2a7ptk2e1-m_w.js +1 -0
  29. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/2jv28ru5lkbdo.js +1 -0
  30. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/3_zz4bh7-d5v3.js +1 -0
  31. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/3ffizu307ndoz.js +1 -0
  32. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/2hixbsi924bp7.js → dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/3gycc_xsviaej.js +2 -2
  33. dividendcase-0.3.0/src/dividendcase/web/_next/static/chunks/3wvr-sx1cadm4.js +1 -0
  34. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_not-found/__next._full.txt +2 -2
  35. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_not-found/__next._not-found.__PAGE__.txt +2 -2
  36. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_not-found/__next._tree.txt +2 -2
  37. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_not-found/index.html +1 -1
  38. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_not-found/index.txt +2 -2
  39. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/__next._full.txt +4 -4
  40. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/__next._tree.txt +2 -2
  41. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/__next.dashboard.__PAGE__.txt +4 -4
  42. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/about/__next._full.txt +4 -4
  43. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/about/__next._tree.txt +2 -2
  44. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/about/__next.dashboard.about.__PAGE__.txt +4 -4
  45. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/about/index.html +1 -1
  46. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/about/index.txt +4 -4
  47. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/calendar/__next._full.txt +4 -4
  48. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/calendar/__next._tree.txt +2 -2
  49. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/calendar/__next.dashboard.calendar.__PAGE__.txt +4 -4
  50. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/calendar/index.html +1 -1
  51. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/calendar/index.txt +4 -4
  52. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/compare/__next._full.txt +4 -4
  53. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/compare/__next._tree.txt +2 -2
  54. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/compare/__next.dashboard.compare.__PAGE__.txt +4 -4
  55. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/compare/index.html +1 -1
  56. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/compare/index.txt +4 -4
  57. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/data/__next._full.txt +4 -4
  58. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/data/__next._tree.txt +2 -2
  59. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/data/__next.dashboard.data.__PAGE__.txt +4 -4
  60. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/data/index.html +1 -1
  61. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/data/index.txt +4 -4
  62. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/drip/__next._full.txt +4 -4
  63. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/drip/__next._tree.txt +2 -2
  64. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/drip/__next.dashboard.drip.__PAGE__.txt +4 -4
  65. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/drip/index.html +1 -1
  66. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/drip/index.txt +4 -4
  67. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/index.html +1 -1
  68. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/index.txt +4 -4
  69. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/__next._full.txt +4 -4
  70. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/__next._tree.txt +2 -2
  71. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/__next.dashboard.investments.__PAGE__.txt +4 -4
  72. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/index.html +1 -1
  73. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/index.txt +4 -4
  74. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/portfolio/__next._full.txt +4 -4
  75. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/portfolio/__next._tree.txt +2 -2
  76. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/portfolio/__next.dashboard.investments.portfolio.__PAGE__.txt +4 -4
  77. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/portfolio/index.html +1 -1
  78. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/investments/portfolio/index.txt +4 -4
  79. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/screener/__next._full.txt +4 -4
  80. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/screener/__next._tree.txt +2 -2
  81. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/screener/__next.dashboard.screener.__PAGE__.txt +4 -4
  82. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/screener/index.html +1 -1
  83. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/screener/index.txt +4 -4
  84. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/settings/__next._full.txt +4 -4
  85. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/settings/__next._tree.txt +2 -2
  86. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/settings/__next.dashboard.settings.__PAGE__.txt +4 -4
  87. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/settings/index.html +1 -1
  88. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/settings/index.txt +4 -4
  89. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/stock/__next._full.txt +4 -4
  90. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/stock/__next._tree.txt +2 -2
  91. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/stock/__next.dashboard.stock.__PAGE__.txt +4 -4
  92. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/stock/index.html +1 -1
  93. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/stock/index.txt +4 -4
  94. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/watchlist/__next._full.txt +4 -4
  95. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/watchlist/__next._tree.txt +2 -2
  96. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/watchlist/__next.dashboard.watchlist.__PAGE__.txt +4 -4
  97. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/watchlist/index.html +1 -1
  98. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/dashboard/watchlist/index.txt +4 -4
  99. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/index.html +1 -1
  100. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/index.txt +2 -2
  101. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/conftest.py +7 -1
  102. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/test_api.py +1 -1
  103. dividendcase-0.3.0/tests/test_withholding.py +113 -0
  104. {dividendcase-0.2.0 → dividendcase-0.3.0}/uv.lock +1 -1
  105. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/0lfebwmsk92ym.js +0 -1
  106. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/0ozczpntpufql.js +0 -1
  107. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/1-ift1mtsuqvh.js +0 -1
  108. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/1g926afh71co9.css +0 -4
  109. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/1xrz4-jij46i_.js +0 -1
  110. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/2_gbzm-n4fs0v.js +0 -1
  111. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/2aqpz6z087bo4.js +0 -1
  112. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/2ft48jvqut7tm.js +0 -1
  113. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/2hoqsdgpu5ma3.js +0 -1
  114. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/2o72ftwupypgx.js +0 -1
  115. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/3cju952ndgmmn.js +0 -1
  116. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/3il2yixgws-43.js +0 -1
  117. dividendcase-0.2.0/src/dividendcase/web/_next/static/chunks/431n5e16l34_0.js +0 -1
  118. {dividendcase-0.2.0 → dividendcase-0.3.0}/.dockerignore +0 -0
  119. {dividendcase-0.2.0 → dividendcase-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  120. {dividendcase-0.2.0 → dividendcase-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  121. {dividendcase-0.2.0 → dividendcase-0.3.0}/.github/ISSUE_TEMPLATE/idea.yml +0 -0
  122. {dividendcase-0.2.0 → dividendcase-0.3.0}/.github/workflows/build.yml +0 -0
  123. {dividendcase-0.2.0 → dividendcase-0.3.0}/.github/workflows/release.yml +0 -0
  124. {dividendcase-0.2.0 → dividendcase-0.3.0}/.github/workflows/tests.yml +0 -0
  125. {dividendcase-0.2.0 → dividendcase-0.3.0}/.gitignore +0 -0
  126. {dividendcase-0.2.0 → dividendcase-0.3.0}/.python-version +0 -0
  127. {dividendcase-0.2.0 → dividendcase-0.3.0}/CONTRIBUTING.md +0 -0
  128. {dividendcase-0.2.0 → dividendcase-0.3.0}/Dockerfile +0 -0
  129. {dividendcase-0.2.0 → dividendcase-0.3.0}/LICENSE +0 -0
  130. {dividendcase-0.2.0 → dividendcase-0.3.0}/SECURITY.md +0 -0
  131. {dividendcase-0.2.0 → dividendcase-0.3.0}/scripts/build_web.py +0 -0
  132. {dividendcase-0.2.0 → dividendcase-0.3.0}/scripts/check_dist.py +0 -0
  133. {dividendcase-0.2.0 → dividendcase-0.3.0}/scripts/smoke_test.py +0 -0
  134. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/__init__.py +0 -0
  135. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/__main__.py +0 -0
  136. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/__init__.py +0 -0
  137. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/__init__.py +0 -0
  138. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/data.py +0 -0
  139. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/deps.py +0 -0
  140. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/dividends.py +0 -0
  141. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/excel_io.py +0 -0
  142. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/fx.py +0 -0
  143. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/health.py +0 -0
  144. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/investment.py +0 -0
  145. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/portfolios.py +0 -0
  146. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/search.py +0 -0
  147. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/stocks.py +0 -0
  148. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/api/v1/watchlist.py +0 -0
  149. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/cli.py +0 -0
  150. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/config.py +0 -0
  151. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/crud/__init__.py +0 -0
  152. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/crud/dividend.py +0 -0
  153. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/crud/stock.py +0 -0
  154. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/database.py +0 -0
  155. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/main.py +0 -0
  156. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/migrate.py +0 -0
  157. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/migrations/env.py +0 -0
  158. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/migrations/script.py.mako +0 -0
  159. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/migrations/versions/0001_baseline.py +0 -0
  160. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/migrations/versions/0002_check_for_updates.py +0 -0
  161. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/migrations/versions/0003_fx_rates_and_setup.py +0 -0
  162. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/__init__.py +0 -0
  163. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/dividend.py +0 -0
  164. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/fx_rate.py +0 -0
  165. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/scheduler_run.py +0 -0
  166. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/stock.py +0 -0
  167. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/user_investment.py +0 -0
  168. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/user_portfolio.py +0 -0
  169. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/user_watchlist.py +0 -0
  170. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/models/user_watchlist_group.py +0 -0
  171. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/scheduler/__init__.py +0 -0
  172. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/scheduler/tasks.py +0 -0
  173. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/__init__.py +0 -0
  174. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/dividend.py +0 -0
  175. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/investment.py +0 -0
  176. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/stock.py +0 -0
  177. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/schemas/watchlist.py +0 -0
  178. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/__init__.py +0 -0
  179. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/benchmark.py +0 -0
  180. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/derived.py +0 -0
  181. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/fx.py +0 -0
  182. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/refresh.py +0 -0
  183. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/universe.py +0 -0
  184. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/updates.py +0 -0
  185. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/services/yahoo_fetcher.py +0 -0
  186. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/.gitkeep +0 -0
  187. {dividendcase-0.2.0/src/dividendcase/web/_next/static/jykyXrPtkR3XGdQ9oSYUT → dividendcase-0.3.0/src/dividendcase/web/_next/static/ZWBqBpak7xVqht9vRBBgL}/_buildManifest.js +0 -0
  188. {dividendcase-0.2.0/src/dividendcase/web/_next/static/jykyXrPtkR3XGdQ9oSYUT → dividendcase-0.3.0/src/dividendcase/web/_next/static/ZWBqBpak7xVqht9vRBBgL}/_clientMiddlewareManifest.js +0 -0
  189. {dividendcase-0.2.0/src/dividendcase/web/_next/static/jykyXrPtkR3XGdQ9oSYUT → dividendcase-0.3.0/src/dividendcase/web/_next/static/ZWBqBpak7xVqht9vRBBgL}/_ssgManifest.js +0 -0
  190. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/0cz1d0mv5g_q7.js +0 -0
  191. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/0g-bslilw6tiu.js +0 -0
  192. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/0nmuijbkm3ipd.js +0 -0
  193. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/0vm7tw6itjxih.js +0 -0
  194. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/10oy-ed_zrrd9.js +0 -0
  195. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/13-u82nfffhrp.js +0 -0
  196. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/138wmfea-yk08.js +0 -0
  197. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/14jt62gawmtd9.js +0 -0
  198. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/1l-w55cdq629z.js +0 -0
  199. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/1q2bxv0xj7vse.js +0 -0
  200. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/1s5tue3q2i-8b.js +0 -0
  201. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/24f36pdyspt8c.js +0 -0
  202. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/2i51e627rllld.js +0 -0
  203. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/33-cg7-y-5zm5.js +0 -0
  204. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/3mc6dra1m0098.js +0 -0
  205. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/453cd1tlxz5wi.js +0 -0
  206. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/chunks/turbopack-1che7mqzsn0nh.js +0 -0
  207. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
  208. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
  209. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
  210. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
  211. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
  212. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
  213. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
  214. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/7ebf22b5a21034f8-s.p.3j3877k49yy0l.woff2 +0 -0
  215. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
  216. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
  217. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
  218. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/fc0a7394b875fa43-s.2ytmazkdrg7t9.woff2 +0 -0
  219. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
  220. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/_next/static/media/icon.0kxjuvpgwz_c6.svg +0 -0
  221. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/icon.svg +0 -0
  222. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/logo-full.svg +0 -0
  223. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/logo-icon.svg +0 -0
  224. {dividendcase-0.2.0 → dividendcase-0.3.0}/src/dividendcase/web/tickers.json +0 -0
  225. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/test_benchmark.py +0 -0
  226. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/test_cli.py +0 -0
  227. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/test_derived_and_updates.py +0 -0
  228. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/test_fx_and_setup.py +0 -0
  229. {dividendcase-0.2.0 → dividendcase-0.3.0}/tests/test_migrations.py +0 -0
@@ -3,6 +3,11 @@
3
3
  All notable changes to DividendCase. Versions follow [semantic versioning](https://semver.org/);
4
4
  while the version starts with 0, a minor release (0.2, 0.3…) may change things.
5
5
 
6
+ ## 0.3.0
7
+
8
+ - **Income after tax:** the Income and Calendar pages show dividends after the tax the paying country withholds (switch to "Before tax" any time). Rates for residents of Ireland, the UK, India, Canada, Australia and the US, by treaty where one applies, with the paperwork each assumes (a W-8BEN for US dividends, for example). Countries it doesn't cover yet are shown before tax and named. Settings lists every rate and lets you set the one your broker actually uses; stock pages show what's withheld for you.
9
+ - Stock suggestions (Compare, Watchlists, DRIP, Add holding) no longer get cut off by the card or dialog they're in.
10
+
6
11
  ## 0.2.0
7
12
 
8
13
  - **Screener:** a "Beat their index" filter and a "Vs index" column: price change plus dividends over the last ten years (or since the first stored payment, if at least three years ago) against the stock's local index over the same period, recomputed weekly and after each screener refresh.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dividendcase
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A free, open-source dividend tracker that runs on your own computer. Your data stays with you.
5
5
  Project-URL: Homepage, https://dividendcase.com
6
6
  Project-URL: Source, https://github.com/dividendcase/dividendcase
@@ -99,6 +99,7 @@ Then open <http://127.0.0.1:8765/dashboard/>. Keep `127.0.0.1:` in the port mapp
99
99
  ## What it does
100
100
 
101
101
  - **Income home:** what your holdings should pay over the next 12 months, month by month, all in your home currency or one currency at a time, with upcoming payments and where the income comes from.
102
+ - **After tax:** what's left once the paying country withholds its tax, for residents of Ireland, the UK, India, Canada, Australia and the US (treaty rates, with the paperwork each assumes); set your broker's actual rate for any country in Settings.
102
103
  - **Stock pages:** 10 years of dividend history, TTM yield, a safety score, dividend growth (CAGR) and growth streaks.
103
104
  - **Screener:** index members from six markets, filtered by market, yield, how often they pay and whether they beat their local index over ten years.
104
105
  - **Portfolios:** individual purchase lots in any currency, a 12-month income calendar, diversification charts, a benchmark comparison and a DRIP calculator.
@@ -51,6 +51,7 @@ Then open <http://127.0.0.1:8765/dashboard/>. Keep `127.0.0.1:` in the port mapp
51
51
  ## What it does
52
52
 
53
53
  - **Income home:** what your holdings should pay over the next 12 months, month by month, all in your home currency or one currency at a time, with upcoming payments and where the income comes from.
54
+ - **After tax:** what's left once the paying country withholds its tax, for residents of Ireland, the UK, India, Canada, Australia and the US (treaty rates, with the paperwork each assumes); set your broker's actual rate for any country in Settings.
54
55
  - **Stock pages:** 10 years of dividend history, TTM yield, a safety score, dividend growth (CAGR) and growth streaks.
55
56
  - **Screener:** index members from six markets, filtered by market, yield, how often they pay and whether they beat their local index over ten years.
56
57
  - **Portfolios:** individual purchase lots in any currency, a 12-month income calendar, diversification charts, a benchmark comparison and a DRIP calculator.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dividendcase"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "A free, open-source dividend tracker that runs on your own computer. Your data stays with you."
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-or-later"
@@ -30,7 +30,8 @@ from dividendcase.schemas.user_investment import (
30
30
  )
31
31
  from dividendcase.api.v1.deps import _get_user_id
32
32
  from dividendcase.api.v1.investment import EXCHANGE_BENCHMARKS, DEFAULT_BENCHMARK, _get_benchmark_data
33
- from dividendcase.services import fx
33
+ from dividendcase.services import fx, withholding
34
+ from dividendcase.models.user_preferences import UserPreferences
34
35
  from dividendcase.models.stock import Stock
35
36
 
36
37
  router = APIRouter()
@@ -622,6 +623,14 @@ async def income_calendar(
622
623
  today = date.today()
623
624
  entries: list[CalendarEntry] = []
624
625
 
626
+ # Withholding at source depends on where the user is resident for tax
627
+ prefs = (await db.execute(
628
+ select(UserPreferences).where(UserPreferences.user_id == user_id)
629
+ )).scalar_one_or_none()
630
+ residence = prefs.tax_residence if prefs else None
631
+ overrides = (prefs.withholding_overrides or {}) if prefs else {}
632
+ rules: dict[str, tuple] = {} # ticker → (source, rule)
633
+
625
634
  for ticker, total_shares in shares_per_ticker.items():
626
635
  stock = await get_stock(db, ticker)
627
636
  if not stock:
@@ -658,6 +667,8 @@ async def income_calendar(
658
667
 
659
668
  month_step = FREQ_MONTHS.get(freq, 3)
660
669
  currency = stock.currency or "USD"
670
+ source = withholding.source_country(stock.country, stock.exchange)
671
+ rules[ticker] = (source, withholding.rule_for(source, residence, overrides))
661
672
 
662
673
  # Project next 12 months of payments
663
674
  next_date = last_div_date + relativedelta(months=month_step)
@@ -682,15 +693,39 @@ async def income_calendar(
682
693
  # Sort by date
683
694
  entries.sort(key=lambda e: e.expected_date)
684
695
 
696
+ # India's TDS for residents applies only above ₹10,000 a year from one company
697
+ yearly_inr: dict[str, float] = defaultdict(float)
698
+ for e in entries:
699
+ if e.currency == "INR":
700
+ yearly_inr[e.ticker_symbol] += e.estimated_amount
701
+ unestimated: set[str] = set()
702
+ for e in entries:
703
+ source, rule = rules.get(e.ticker_symbol, (None, None))
704
+ e.source_country = source
705
+ if rule is None:
706
+ e.net_amount = e.estimated_amount
707
+ if source:
708
+ unestimated.add(source)
709
+ continue
710
+ rate = withholding.withheld_rate(rule, source, residence, yearly_inr.get(e.ticker_symbol))
711
+ e.withholding_rate = rate
712
+ e.withholding_basis = rule.basis
713
+ e.withholding_note = rule.note
714
+ e.net_amount = round(e.estimated_amount * (1 - rate / 100), 2)
715
+
685
716
  # Compute monthly, currency, and monthly-by-currency totals
686
717
  monthly_totals: dict[str, float] = defaultdict(float)
687
718
  currency_totals: dict[str, float] = defaultdict(float)
688
719
  monthly_by_currency: dict[str, dict[str, float]] = defaultdict(lambda: defaultdict(float))
720
+ net_currency_totals: dict[str, float] = defaultdict(float)
721
+ net_monthly_by_currency: dict[str, dict[str, float]] = defaultdict(lambda: defaultdict(float))
689
722
  for e in entries:
690
723
  key = e.expected_date.strftime("%Y-%m")
691
724
  monthly_totals[key] += e.estimated_amount
692
725
  currency_totals[e.currency] += e.estimated_amount
693
726
  monthly_by_currency[e.currency][key] += e.estimated_amount
727
+ net_currency_totals[e.currency] += e.net_amount
728
+ net_monthly_by_currency[e.currency][key] += e.net_amount
694
729
 
695
730
  annual_total = sum(e.estimated_amount for e in entries)
696
731
 
@@ -703,4 +738,11 @@ async def income_calendar(
703
738
  curr: {m: round(v, 2) for m, v in months.items()}
704
739
  for curr, months in monthly_by_currency.items()
705
740
  },
741
+ residence=residence,
742
+ net_currency_totals={k: round(v, 2) for k, v in net_currency_totals.items()},
743
+ net_monthly_totals_by_currency={
744
+ curr: {m: round(v, 2) for m, v in months.items()}
745
+ for curr, months in net_monthly_by_currency.items()
746
+ },
747
+ unestimated_sources=sorted(unestimated),
706
748
  )
@@ -1,5 +1,5 @@
1
1
  from fastapi import APIRouter
2
- from dividendcase.api.v1 import stocks, dividends, search, watchlist, health, investment, portfolio, portfolios, excel_io, user, data, fx
2
+ from dividendcase.api.v1 import stocks, dividends, search, watchlist, health, investment, portfolio, portfolios, excel_io, user, data, fx, withholding
3
3
 
4
4
  api_router = APIRouter()
5
5
 
@@ -15,3 +15,4 @@ api_router.include_router(excel_io.router, prefix="/excel", tags=["excel"])
15
15
  api_router.include_router(user.router, prefix="/user", tags=["user"])
16
16
  api_router.include_router(data.router, prefix="/data", tags=["data"])
17
17
  api_router.include_router(fx.router, prefix="/fx", tags=["exchange rates"])
18
+ api_router.include_router(withholding.router, prefix="/withholding", tags=["withholding tax"])
@@ -70,6 +70,14 @@ async def update_preferences(
70
70
  prefs.screener_markets = updates.screener_markets
71
71
  if updates.complete_setup:
72
72
  prefs.setup_completed_at = datetime.now(timezone.utc)
73
+ if updates.withholding_overrides is not None:
74
+ merged = dict(prefs.withholding_overrides or {})
75
+ for country, rate in updates.withholding_overrides.items():
76
+ if rate is None:
77
+ merged.pop(country, None)
78
+ else:
79
+ merged[country] = rate
80
+ prefs.withholding_overrides = merged
73
81
 
74
82
  await db.commit()
75
83
  await db.refresh(prefs)
@@ -0,0 +1,73 @@
1
+ """Withholding tax estimates for the user's tax residence (Settings, stock pages)."""
2
+ from typing import Optional
3
+ from uuid import UUID
4
+
5
+ from fastapi import APIRouter, Depends, Query
6
+ from sqlalchemy import select
7
+ from sqlalchemy.ext.asyncio import AsyncSession
8
+
9
+ from dividendcase.api.v1.deps import _get_user_id
10
+ from dividendcase.database import get_db
11
+ from dividendcase.models import Stock, UserInvestment, UserPreferences
12
+ from dividendcase.services import withholding
13
+
14
+ router = APIRouter()
15
+
16
+
17
+ @router.get("")
18
+ async def withholding_table(
19
+ ticker: Optional[str] = Query(None, description="Also say what applies to this stock"),
20
+ db: AsyncSession = Depends(get_db),
21
+ user_id: UUID = Depends(_get_user_id),
22
+ ):
23
+ """The rate for each supported source country, and where the user's holdings pay from."""
24
+ prefs = (await db.execute(
25
+ select(UserPreferences).where(UserPreferences.user_id == user_id)
26
+ )).scalar_one_or_none()
27
+ residence = prefs.tax_residence if prefs else None
28
+ overrides = (prefs.withholding_overrides or {}) if prefs else {}
29
+
30
+ held = (await db.execute(
31
+ select(Stock.ticker_symbol, Stock.country, Stock.exchange)
32
+ .join(UserInvestment, UserInvestment.ticker_symbol == Stock.ticker_symbol)
33
+ .where(UserInvestment.user_id == user_id)
34
+ .distinct()
35
+ )).all()
36
+ sources: dict[str, list[str]] = {}
37
+ for held_ticker, country, exchange in held:
38
+ source = withholding.source_country(country, exchange)
39
+ if source:
40
+ sources.setdefault(source, []).append(held_ticker)
41
+
42
+ rows = withholding.table_for(residence, overrides)
43
+ known = {row["source"] for row in rows}
44
+ for source in sorted(set(sources) - known):
45
+ rule = withholding.rule_for(source, residence, overrides)
46
+ rows.append({
47
+ "source": source, "name": source,
48
+ "rate": rule.rate if rule else None, "basis": rule.basis if rule else None,
49
+ "note": rule.note if rule else "Not estimated yet: dividends from here are shown before tax. Set the rate your broker withholds to include it.",
50
+ "default_rate": None, "default_note": None,
51
+ })
52
+ for row in rows:
53
+ row["your_stocks"] = sorted(sources.get(row["source"], []))
54
+ for_stock = None
55
+ if ticker:
56
+ stock = (await db.execute(select(Stock).where(Stock.ticker_symbol == ticker.upper()))).scalar_one_or_none()
57
+ if stock is not None:
58
+ source = withholding.source_country(stock.country, stock.exchange)
59
+ rule = withholding.rule_for(source, residence, overrides)
60
+ for_stock = {
61
+ "ticker": stock.ticker_symbol,
62
+ "source": source,
63
+ "source_name": withholding.NAMES.get(source or "", source),
64
+ "rate": rule.rate if rule else None,
65
+ "basis": rule.basis if rule else None,
66
+ "note": rule.note if rule else None,
67
+ }
68
+ return {
69
+ "residence": residence,
70
+ "residence_name": withholding.NAMES.get(residence or "", residence),
71
+ "rows": rows,
72
+ "for_stock": for_stock,
73
+ }
@@ -0,0 +1,27 @@
1
+ """withholding overrides
2
+
3
+ Revision ID: 0004
4
+ Revises: 0003
5
+ Created: 2026-09-29 16:20:58.714377
6
+ """
7
+ from typing import Sequence, Union
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+
13
+ revision: str = '0004'
14
+ down_revision: Union[str, None] = '0003'
15
+ branch_labels: Union[str, Sequence[str], None] = None
16
+ depends_on: Union[str, Sequence[str], None] = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ with op.batch_alter_table('user_preferences', schema=None) as batch_op:
21
+ batch_op.add_column(sa.Column('withholding_overrides', sa.JSON(), nullable=True))
22
+
23
+
24
+ def downgrade() -> None:
25
+ with op.batch_alter_table('user_preferences', schema=None) as batch_op:
26
+ batch_op.drop_column('withholding_overrides')
27
+
@@ -19,4 +19,6 @@ class UserPreferences(Base):
19
19
  tax_residence = Column(String(2))
20
20
  screener_markets = Column(JSON)
21
21
  setup_completed_at = Column(DateTime(timezone=True))
22
+ # Withholding rates the user set by hand, percent by source country: {"US": 30}
23
+ withholding_overrides = Column(JSON)
22
24
  created_at = Column(DateTime(timezone=True), server_default=func.now())
@@ -95,6 +95,12 @@ class CalendarEntry(BaseModel):
95
95
  total_shares: float
96
96
  currency: str
97
97
  payment_frequency: str
98
+ # Withholding at source for the user's tax residence (services/withholding.py)
99
+ source_country: Optional[str] = None # "US", or a country name v1 doesn't estimate
100
+ withholding_rate: Optional[float] = None # percent; None = not estimated (shown gross)
101
+ withholding_basis: Optional[str] = None # treaty, statutory, domestic, none, override
102
+ withholding_note: Optional[str] = None
103
+ net_amount: float = 0.0 # estimated_amount after withholding
98
104
 
99
105
 
100
106
  class IncomeCalendarResponse(BaseModel):
@@ -103,6 +109,11 @@ class IncomeCalendarResponse(BaseModel):
103
109
  annual_total: float
104
110
  currency_totals: dict[str, float] # {"USD": 500.0, "INR": 2000.0}
105
111
  monthly_totals_by_currency: dict[str, dict[str, float]] = {} # {"USD": {"2026-01": 100.0, ...}}
112
+ # After withholding, and what wasn't estimated
113
+ residence: Optional[str] = None
114
+ net_currency_totals: dict[str, float] = {}
115
+ net_monthly_totals_by_currency: dict[str, dict[str, float]] = {}
116
+ unestimated_sources: list[str] = []
106
117
 
107
118
 
108
119
  # ── Excel Import/Export schemas ─────────────────────────────────────────
@@ -1,7 +1,7 @@
1
1
  from datetime import datetime
2
2
  from typing import Literal, Optional
3
3
 
4
- from pydantic import BaseModel, Field
4
+ from pydantic import BaseModel, Field, field_validator
5
5
 
6
6
 
7
7
  VALID_BENCHMARKS = Literal["SP500", "FTSE100", "NIFTY50", "ASX200", "TSX60"]
@@ -10,6 +10,11 @@ VALID_MARKETS = Literal["SP500", "NIFTY50", "TSX60", "ASX200", "FTSE100", "ISEQ2
10
10
 
11
11
 
12
12
  class UserPreferences(BaseModel):
13
+ @field_validator("withholding_overrides", mode="before")
14
+ @classmethod
15
+ def _none_is_empty(cls, v):
16
+ return v or {}
17
+
13
18
  default_benchmark: str = "SP500"
14
19
  date_format: str = "DD/MM/YYYY"
15
20
  watchlist_collapsed: bool = False
@@ -18,6 +23,7 @@ class UserPreferences(BaseModel):
18
23
  tax_residence: Optional[str] = None
19
24
  screener_markets: Optional[list[str]] = None # None = every market
20
25
  setup_completed_at: Optional[datetime] = None
26
+ withholding_overrides: dict[str, float] = {}
21
27
 
22
28
  model_config = {"from_attributes": True}
23
29
 
@@ -32,3 +38,19 @@ class UserPreferencesUpdate(BaseModel):
32
38
  screener_markets: Optional[list[VALID_MARKETS]] = None
33
39
  # True when the first-run setup screen is finished
34
40
  complete_setup: Optional[bool] = None
41
+ # Rates to use instead of the estimates, percent by source country; null removes one
42
+ withholding_overrides: Optional[dict[str, Optional[float]]] = None
43
+
44
+ @field_validator("withholding_overrides")
45
+ @classmethod
46
+ def _check_overrides(cls, v):
47
+ return None if v is None else valid_overrides(v)
48
+
49
+
50
+ def valid_overrides(value: dict[str, Optional[float]]) -> dict[str, Optional[float]]:
51
+ for country, rate in value.items():
52
+ if not (1 <= len(country) <= 40):
53
+ raise ValueError(f"Not a country: {country!r}")
54
+ if rate is not None and not (0 <= rate <= 100):
55
+ raise ValueError(f"A withholding rate is a percentage from 0 to 100, not {rate}")
56
+ return value
@@ -0,0 +1,147 @@
1
+ """Dividend withholding tax: how much the paying country keeps before a dividend reaches you.
2
+
3
+ v1 covers six countries, as sources and as tax residences: Ireland, the UK, India, Canada,
4
+ Australia and the US. Rates are for an individual holding shares directly (portfolio
5
+ dividends, well under 10% of the company). These are estimates of tax taken **at source**,
6
+ not the final tax you owe where you live, and not tax advice. People can set their own
7
+ rate for any country in Settings, which always wins.
8
+
9
+ Where a treaty rate depends on paperwork (a W-8BEN for US dividends, a tax residency
10
+ certificate for India) the table assumes it's done and says so in the note; without it the
11
+ statutory rate applies.
12
+
13
+ Sources (checked September 2026, to be reviewed by a tax professional before 1.0):
14
+ US IRS Publication 515 and treaty tables; Canada Revenue Agency Part XIII rates; HMRC
15
+ (no UK withholding on ordinary dividends); Irish Revenue DWT (25% from 2020); India Income
16
+ Tax Act s.195 / s.194 and the DTAAs with each country; Australian Taxation Office
17
+ (franked dividends aren't withheld).
18
+ """
19
+ from dataclasses import dataclass
20
+ from typing import Optional
21
+
22
+ SUPPORTED = ("IE", "GB", "IN", "CA", "AU", "US")
23
+
24
+ # Rate for residents of countries without a treaty rule below (percent)
25
+ STATUTORY = {"US": 30.0, "CA": 25.0, "GB": 0.0, "IE": 25.0, "IN": 20.8, "AU": 0.0}
26
+
27
+ NAMES = {
28
+ "IE": "Ireland", "GB": "United Kingdom", "IN": "India", "CA": "Canada", "AU": "Australia",
29
+ "US": "United States", "ZZ": "somewhere else",
30
+ }
31
+
32
+ # Yahoo's company country (Stock.country) → ISO code
33
+ COUNTRY_CODES = {
34
+ "united states": "US", "usa": "US", "united kingdom": "GB", "uk": "GB", "ireland": "IE",
35
+ "india": "IN", "canada": "CA", "australia": "AU",
36
+ }
37
+
38
+ # Where a listing is when the company's country isn't stored (screener stocks)
39
+ EXCHANGE_COUNTRIES = {
40
+ "NYSE": "US", "NASDAQ": "US", "NMS": "US", "NYQ": "US", "NGM": "US", "NCM": "US", "PCX": "US", "BTS": "US",
41
+ "TSX": "CA", "TOR": "CA", "LSE": "GB", "ISE": "IE", "NSE": "IN", "BSE": "IN", "BOM": "IN", "ASX": "AU",
42
+ }
43
+
44
+ W8BEN = "with a W-8BEN on file with your broker; 30% without it"
45
+ TRC = "with a tax residency certificate and Form 10F given to the company or broker; 20.8% without them"
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class Rule:
50
+ rate: float # percent withheld
51
+ basis: str # "treaty", "statutory", "domestic", "none" or "override"
52
+ note: str
53
+
54
+
55
+ def _source_rules(source: str, residence: str) -> Rule:
56
+ if source == "GB":
57
+ return Rule(0.0, "none", "The UK doesn't withhold tax on ordinary dividends (REIT property income is taxed at 20%).")
58
+ if source == "AU":
59
+ if residence == "AU":
60
+ return Rule(0.0, "domestic", "No withholding for Australian residents; franking credits are claimed in your return.")
61
+ return Rule(0.0, "none", "Franked dividends aren't withheld. Any unfranked part is withheld at 15% under a treaty (30% otherwise).")
62
+
63
+ if source == residence:
64
+ return {
65
+ "US": Rule(0.0, "domestic", "No withholding for US residents; dividends are taxed in your return."),
66
+ "CA": Rule(0.0, "domestic", "No withholding for Canadian residents; dividends are taxed in your return."),
67
+ "IE": Rule(25.0, "domestic", "Irish dividend withholding tax, credited against your income tax."),
68
+ "IN": Rule(10.0, "domestic", "10% TDS when a company pays you more than ₹10,000 in a financial year; credited against your income tax."),
69
+ }[source]
70
+
71
+ if source == "US":
72
+ if residence == "IN":
73
+ return Rule(25.0, "treaty", f"India–US treaty rate {W8BEN}.")
74
+ if residence in ("IE", "GB", "CA", "AU"):
75
+ return Rule(15.0, "treaty", f"Treaty rate {W8BEN}.")
76
+ if source == "CA":
77
+ if residence == "IN":
78
+ return Rule(25.0, "treaty", "Canada–India treaty rate for portfolio holdings (the same as Canada's statutory rate).")
79
+ if residence in ("US", "GB", "IE", "AU"):
80
+ return Rule(15.0, "treaty", "Treaty rate, applied by your broker once it knows your residence (25% otherwise).")
81
+ if source == "IE":
82
+ return Rule(25.0, "statutory", "Irish dividend withholding tax. Residents of treaty countries can be exempt with a non-resident declaration, or reclaim the excess.")
83
+ if source == "IN":
84
+ treaty = {"IE": 10.0, "GB": 15.0, "AU": 15.0}
85
+ if residence in treaty:
86
+ return Rule(treaty[residence], "treaty", f"Treaty rate {TRC}.")
87
+ if residence in ("US", "CA"):
88
+ return Rule(20.8, "statutory", "20% plus 4% cess for non-residents; the treaty rate (25%) is higher, so it doesn't help.")
89
+
90
+ return Rule(STATUTORY[source], "statutory", "The country's standard rate for non-residents; a treaty may lower it.")
91
+
92
+
93
+ INDIA_TDS_THRESHOLD_INR = 10_000
94
+
95
+
96
+ def rule_for(source: Optional[str], residence: Optional[str], overrides: Optional[dict] = None) -> Optional[Rule]:
97
+ """The withholding that applies to dividends from `source` for a resident of `residence`.
98
+
99
+ None when the source country isn't one v1 estimates (the dividend is shown gross).
100
+ """
101
+ if not source:
102
+ return None
103
+ overrides = overrides or {}
104
+ if source in overrides and overrides[source] is not None:
105
+ return Rule(float(overrides[source]), "override", "The rate you set in Settings.")
106
+ if source not in SUPPORTED:
107
+ return None
108
+ return _source_rules(source, residence if residence in SUPPORTED else "ZZ")
109
+
110
+
111
+ def source_country(country: Optional[str], exchange: Optional[str]) -> Optional[str]:
112
+ """ISO code of the country a dividend comes from: the company's, else its exchange's."""
113
+ name = (country or "").strip()
114
+ if name and name.lower() != "unknown":
115
+ # A country v1 doesn't estimate (an ADR of a Spanish company, say) stays by name,
116
+ # so it's shown gross and labelled rather than mistaken for its exchange's country
117
+ return COUNTRY_CODES.get(name.lower(), name)
118
+ return EXCHANGE_COUNTRIES.get((exchange or "").upper())
119
+
120
+
121
+ def withheld_rate(rule: Optional[Rule], source: Optional[str], residence: Optional[str],
122
+ yearly_amount_in_inr: Optional[float] = None) -> float:
123
+ """The percentage actually withheld, after thresholds (India's ₹10,000 TDS for residents)."""
124
+ if rule is None:
125
+ return 0.0
126
+ if rule.basis == "domestic" and source == "IN" and residence == "IN":
127
+ if yearly_amount_in_inr is not None and yearly_amount_in_inr <= INDIA_TDS_THRESHOLD_INR:
128
+ return 0.0
129
+ return rule.rate
130
+
131
+
132
+ def table_for(residence: Optional[str], overrides: Optional[dict] = None) -> list[dict]:
133
+ """Every supported source country and the rate a resident of `residence` would see."""
134
+ rows = []
135
+ for source in SUPPORTED:
136
+ rule = rule_for(source, residence, overrides)
137
+ default = rule_for(source, residence, None)
138
+ rows.append({
139
+ "source": source,
140
+ "name": NAMES[source],
141
+ "rate": rule.rate,
142
+ "basis": rule.basis,
143
+ "note": rule.note,
144
+ "default_rate": default.rate,
145
+ "default_note": default.note,
146
+ })
147
+ return rows
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en" class="dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/1g926afh71co9.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/3mc6dra1m0098.js"/><script src="/_next/static/chunks/2i51e627rllld.js" async=""></script><script src="/_next/static/chunks/14jt62gawmtd9.js" async=""></script><script src="/_next/static/chunks/138wmfea-yk08.js" async=""></script><script src="/_next/static/chunks/turbopack-1che7mqzsn0nh.js" async=""></script><script src="/_next/static/chunks/453cd1tlxz5wi.js" async=""></script><meta name="robots" content="noindex"/><meta name="theme-color" content="#0e0e13"/><meta name="color-scheme" content="dark"/><title>DividendCase</title><meta name="description" content="A free, open-source dividend tracker that runs on your own computer"/><link rel="icon" href="/logo-icon.svg"/><link rel="apple-touch-icon" href="/logo-icon.svg"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><script src="/_next/static/chunks/0cz1d0mv5g_q7.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/3mc6dra1m0098.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"ViewportBoundary\"]\na:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"MetadataBoundary\"]\nc:I[68027,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/1g926afh71co9.css\",\"style\"]\n7:X\n0:{\"P\":null,\"c\":[\"\",\"_not-found\",\"\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4624],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/1g926afh71co9.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/453cd1tlxz5wi.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$7\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/1g926afh71co9.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"r\":\"$undefined\",\"s\":\"$undefined\",\"a\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"jykyXrPtkR3XGdQ9oSYUT\"}\n7:C\n9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#0e0e13\"}],[\"$\",\"meta\",\"3\",{\"name\":\"color-scheme\",\"content\":\"dark\"}]]\nd:I[27201,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"IconMark\"]\n6:null\nb:[[\"$\",\"title\",\"0\",{\"children\":\"DividendCase\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A free, open-source dividend tracker that runs on your own computer\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"link\",\"3\",{\"rel\":\"apple-touch-icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"$Ld\",\"4\",{}]]\n"])</script></body></html>
1
+ <!DOCTYPE html><html lang="en" class="dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/20i38r94ivt58.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/3mc6dra1m0098.js"/><script src="/_next/static/chunks/2i51e627rllld.js" async=""></script><script src="/_next/static/chunks/14jt62gawmtd9.js" async=""></script><script src="/_next/static/chunks/138wmfea-yk08.js" async=""></script><script src="/_next/static/chunks/turbopack-1che7mqzsn0nh.js" async=""></script><script src="/_next/static/chunks/453cd1tlxz5wi.js" async=""></script><meta name="robots" content="noindex"/><meta name="theme-color" content="#0e0e13"/><meta name="color-scheme" content="dark"/><title>DividendCase</title><meta name="description" content="A free, open-source dividend tracker that runs on your own computer"/><link rel="icon" href="/logo-icon.svg"/><link rel="apple-touch-icon" href="/logo-icon.svg"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><script src="/_next/static/chunks/0cz1d0mv5g_q7.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/3mc6dra1m0098.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"ViewportBoundary\"]\na:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"MetadataBoundary\"]\nc:I[68027,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/20i38r94ivt58.css\",\"style\"]\n7:X\n0:{\"P\":null,\"c\":[\"\",\"_not-found\",\"\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4624],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/20i38r94ivt58.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/453cd1tlxz5wi.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$7\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/20i38r94ivt58.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"r\":\"$undefined\",\"s\":\"$undefined\",\"a\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"ZWBqBpak7xVqht9vRBBgL\"}\n7:C\n9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#0e0e13\"}],[\"$\",\"meta\",\"3\",{\"name\":\"color-scheme\",\"content\":\"dark\"}]]\nd:I[27201,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"IconMark\"]\n6:null\nb:[[\"$\",\"title\",\"0\",{\"children\":\"DividendCase\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A free, open-source dividend tracker that runs on your own computer\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"link\",\"3\",{\"rel\":\"apple-touch-icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"$Ld\",\"4\",{}]]\n"])</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en" class="dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/1g926afh71co9.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/3mc6dra1m0098.js"/><script src="/_next/static/chunks/2i51e627rllld.js" async=""></script><script src="/_next/static/chunks/14jt62gawmtd9.js" async=""></script><script src="/_next/static/chunks/138wmfea-yk08.js" async=""></script><script src="/_next/static/chunks/turbopack-1che7mqzsn0nh.js" async=""></script><script src="/_next/static/chunks/453cd1tlxz5wi.js" async=""></script><meta name="robots" content="noindex"/><meta name="theme-color" content="#0e0e13"/><meta name="color-scheme" content="dark"/><title>DividendCase</title><meta name="description" content="A free, open-source dividend tracker that runs on your own computer"/><link rel="icon" href="/logo-icon.svg"/><link rel="apple-touch-icon" href="/logo-icon.svg"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><script src="/_next/static/chunks/0cz1d0mv5g_q7.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/3mc6dra1m0098.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"ViewportBoundary\"]\na:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"MetadataBoundary\"]\nc:I[68027,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/1g926afh71co9.css\",\"style\"]\n7:X\n0:{\"P\":null,\"c\":[\"\",\"_not-found\",\"\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4624],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/1g926afh71co9.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/453cd1tlxz5wi.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$7\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/1g926afh71co9.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"r\":\"$undefined\",\"s\":\"$undefined\",\"a\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"jykyXrPtkR3XGdQ9oSYUT\"}\n7:C\n9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#0e0e13\"}],[\"$\",\"meta\",\"3\",{\"name\":\"color-scheme\",\"content\":\"dark\"}]]\nd:I[27201,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"IconMark\"]\n6:null\nb:[[\"$\",\"title\",\"0\",{\"children\":\"DividendCase\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A free, open-source dividend tracker that runs on your own computer\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"link\",\"3\",{\"rel\":\"apple-touch-icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"$Ld\",\"4\",{}]]\n"])</script></body></html>
1
+ <!DOCTYPE html><html lang="en" class="dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/20i38r94ivt58.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/3mc6dra1m0098.js"/><script src="/_next/static/chunks/2i51e627rllld.js" async=""></script><script src="/_next/static/chunks/14jt62gawmtd9.js" async=""></script><script src="/_next/static/chunks/138wmfea-yk08.js" async=""></script><script src="/_next/static/chunks/turbopack-1che7mqzsn0nh.js" async=""></script><script src="/_next/static/chunks/453cd1tlxz5wi.js" async=""></script><meta name="robots" content="noindex"/><meta name="theme-color" content="#0e0e13"/><meta name="color-scheme" content="dark"/><title>DividendCase</title><meta name="description" content="A free, open-source dividend tracker that runs on your own computer"/><link rel="icon" href="/logo-icon.svg"/><link rel="apple-touch-icon" href="/logo-icon.svg"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><script src="/_next/static/chunks/0cz1d0mv5g_q7.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/3mc6dra1m0098.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"ViewportBoundary\"]\na:I[97367,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"MetadataBoundary\"]\nc:I[68027,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/20i38r94ivt58.css\",\"style\"]\n7:X\n0:{\"P\":null,\"c\":[\"\",\"_not-found\",\"\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4608]},\"$undefined\",\"$undefined\",4624],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/20i38r94ivt58.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/453cd1tlxz5wi.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark geist_9c6cb61b-module__8NX9hq__variable geist_mono_d6617093-module__z61v7q__variable instrument_serif_2ef3d2eb-module__gc1GGW__variable\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$7\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/20i38r94ivt58.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"r\":\"$undefined\",\"s\":\"$undefined\",\"a\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"ZWBqBpak7xVqht9vRBBgL\"}\n7:C\n9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#0e0e13\"}],[\"$\",\"meta\",\"3\",{\"name\":\"color-scheme\",\"content\":\"dark\"}]]\nd:I[27201,[\"/_next/static/chunks/453cd1tlxz5wi.js\"],\"IconMark\"]\n6:null\nb:[[\"$\",\"title\",\"0\",{\"children\":\"DividendCase\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A free, open-source dividend tracker that runs on your own computer\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"link\",\"3\",{\"rel\":\"apple-touch-icon\",\"href\":\"/logo-icon.svg\"}],[\"$\",\"$Ld\",\"4\",{}]]\n"])</script></body></html>