emailengine-app 1.14.8 → 2.60.1

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 (2139) hide show
  1. package/.env.development +49 -0
  2. package/.env.example +82 -0
  3. package/.env.production +87 -0
  4. package/.eslintignore +1 -0
  5. package/.github/workflows/deploy.yml +104 -0
  6. package/.github/workflows/release.yaml +107 -0
  7. package/.github/workflows/test.yml +82 -0
  8. package/.ncurc.js +19 -5
  9. package/.prettierignore +44 -0
  10. package/CHANGELOG.md +1110 -0
  11. package/DOCKER_DEPLOYMENT.md +495 -0
  12. package/Dockerfile +53 -6
  13. package/Dockerfile-legacy +18 -0
  14. package/Fluid-Attacks-Results.csv +1 -0
  15. package/Gruntfile.js +46 -5
  16. package/LICENSE_EMAILENGINE.txt +110 -0
  17. package/README.md +72 -344
  18. package/app.json +40 -0
  19. package/bin/emailengine.js +283 -38
  20. package/config/default.toml +9 -11
  21. package/config/test.toml +45 -0
  22. package/copy-static-files.sh +34 -0
  23. package/data/google-crawlers.json +797 -0
  24. package/docker-compose.yml +103 -31
  25. package/encrypt.js +85 -10
  26. package/eslint.config.js +110 -0
  27. package/examples/auth-server.js +121 -69
  28. package/examples/grafana-dashboard.json +2375 -0
  29. package/help.txt +84 -0
  30. package/install.sh +426 -0
  31. package/lib/account.js +2348 -124
  32. package/lib/add-trackers.js +119 -0
  33. package/lib/api-routes/bull-board-routes.js +60 -0
  34. package/lib/api-routes/chat-routes.js +519 -0
  35. package/lib/api-routes/template-routes.js +490 -0
  36. package/lib/append-list.js +9 -2
  37. package/lib/arf-detect.js +200 -0
  38. package/lib/autodetect-imap-settings.js +781 -0
  39. package/lib/bounce-detect.js +280 -37
  40. package/lib/capa.js +97 -0
  41. package/lib/consts.js +210 -1
  42. package/lib/db.js +227 -8
  43. package/lib/document-store.js +54 -0
  44. package/lib/email-client/base-client.js +3677 -0
  45. package/lib/email-client/gmail-client.js +2796 -0
  46. package/lib/email-client/imap/mailbox.js +3721 -0
  47. package/lib/email-client/imap/subconnection.js +269 -0
  48. package/lib/email-client/imap-client.js +2628 -0
  49. package/lib/email-client/outlook-client.js +3805 -0
  50. package/lib/encrypt.js +85 -14
  51. package/lib/es.js +784 -0
  52. package/lib/feature-flags.js +42 -0
  53. package/lib/gateway.js +271 -0
  54. package/lib/generate-text-preview.js +56 -0
  55. package/lib/get-raw-email.js +302 -42
  56. package/lib/get-secret.js +23 -67
  57. package/lib/headers-rewriter.js +33 -0
  58. package/lib/imapproxy/imap-core/index.js +4 -0
  59. package/lib/imapproxy/imap-core/lib/commands/append.js +187 -0
  60. package/lib/imapproxy/imap-core/lib/commands/authenticate-plain.js +145 -0
  61. package/lib/imapproxy/imap-core/lib/commands/capability.js +13 -0
  62. package/lib/imapproxy/imap-core/lib/commands/check.js +10 -0
  63. package/lib/imapproxy/imap-core/lib/commands/close.js +44 -0
  64. package/lib/imapproxy/imap-core/lib/commands/compress.js +102 -0
  65. package/lib/imapproxy/imap-core/lib/commands/copy.js +109 -0
  66. package/lib/imapproxy/imap-core/lib/commands/create.js +93 -0
  67. package/lib/imapproxy/imap-core/lib/commands/delete.js +84 -0
  68. package/lib/imapproxy/imap-core/lib/commands/enable.js +36 -0
  69. package/lib/imapproxy/imap-core/lib/commands/expunge.js +68 -0
  70. package/lib/imapproxy/imap-core/lib/commands/fetch.js +385 -0
  71. package/lib/imapproxy/imap-core/lib/commands/getquota.js +85 -0
  72. package/lib/imapproxy/imap-core/lib/commands/getquotaroot.js +111 -0
  73. package/lib/imapproxy/imap-core/lib/commands/id.js +111 -0
  74. package/lib/imapproxy/imap-core/lib/commands/idle.js +45 -0
  75. package/lib/imapproxy/imap-core/lib/commands/list.js +218 -0
  76. package/lib/imapproxy/imap-core/lib/commands/login.js +135 -0
  77. package/lib/imapproxy/imap-core/lib/commands/logout.js +26 -0
  78. package/lib/imapproxy/imap-core/lib/commands/lsub.js +102 -0
  79. package/lib/imapproxy/imap-core/lib/commands/move.js +106 -0
  80. package/lib/imapproxy/imap-core/lib/commands/namespace.js +14 -0
  81. package/lib/imapproxy/imap-core/lib/commands/noop.js +10 -0
  82. package/lib/imapproxy/imap-core/lib/commands/rename.js +102 -0
  83. package/lib/imapproxy/imap-core/lib/commands/search.js +306 -0
  84. package/lib/imapproxy/imap-core/lib/commands/select.js +248 -0
  85. package/lib/imapproxy/imap-core/lib/commands/setquota.js +24 -0
  86. package/lib/imapproxy/imap-core/lib/commands/starttls.js +100 -0
  87. package/lib/imapproxy/imap-core/lib/commands/status.js +149 -0
  88. package/lib/imapproxy/imap-core/lib/commands/store.js +208 -0
  89. package/lib/imapproxy/imap-core/lib/commands/subscribe.js +69 -0
  90. package/lib/imapproxy/imap-core/lib/commands/uid-expunge.js +71 -0
  91. package/lib/imapproxy/imap-core/lib/commands/uid-store.js +170 -0
  92. package/lib/imapproxy/imap-core/lib/commands/unselect.js +14 -0
  93. package/lib/imapproxy/imap-core/lib/commands/unsubscribe.js +69 -0
  94. package/lib/imapproxy/imap-core/lib/handler/README.md +146 -0
  95. package/lib/imapproxy/imap-core/lib/handler/imap-compile-stream.js +252 -0
  96. package/lib/imapproxy/imap-core/lib/handler/imap-compiler.js +134 -0
  97. package/lib/imapproxy/imap-core/lib/handler/imap-formal-syntax.js +147 -0
  98. package/lib/imapproxy/imap-core/lib/handler/imap-handler.js +11 -0
  99. package/lib/imapproxy/imap-core/lib/handler/imap-parser.js +678 -0
  100. package/lib/imapproxy/imap-core/lib/imap-command.js +381 -0
  101. package/lib/imapproxy/imap-core/lib/imap-composer.js +71 -0
  102. package/lib/imapproxy/imap-core/lib/imap-connection.js +929 -0
  103. package/lib/imapproxy/imap-core/lib/imap-server.js +426 -0
  104. package/lib/imapproxy/imap-core/lib/imap-stream.js +172 -0
  105. package/lib/imapproxy/imap-core/lib/imap-tools.js +789 -0
  106. package/lib/imapproxy/imap-core/lib/indexer/body-structure.js +295 -0
  107. package/lib/imapproxy/imap-core/lib/indexer/create-envelope.js +103 -0
  108. package/lib/imapproxy/imap-core/lib/indexer/indexer.js +904 -0
  109. package/lib/imapproxy/imap-core/lib/indexer/parse-mime-tree.js +340 -0
  110. package/lib/imapproxy/imap-core/lib/length-limiter.js +76 -0
  111. package/lib/imapproxy/imap-core/lib/parse-date.js +225 -0
  112. package/lib/imapproxy/imap-core/lib/search.js +330 -0
  113. package/lib/imapproxy/imap-core/lib/tls-options.js +69 -0
  114. package/lib/imapproxy/imap-core/memory-notifier.js +129 -0
  115. package/lib/imapproxy/imap-core/test/client.js +46 -0
  116. package/lib/imapproxy/imap-core/test/fixtures/append.eml +1196 -0
  117. package/lib/imapproxy/imap-core/test/fixtures/chunks.js +44 -0
  118. package/lib/imapproxy/imap-core/test/fixtures/fix1.eml +6 -0
  119. package/lib/imapproxy/imap-core/test/fixtures/fix2.eml +599 -0
  120. package/lib/imapproxy/imap-core/test/fixtures/fix3.eml +32 -0
  121. package/lib/imapproxy/imap-core/test/fixtures/fix4.eml +6 -0
  122. package/lib/imapproxy/imap-core/test/fixtures/mimetorture.eml +599 -0
  123. package/lib/imapproxy/imap-core/test/fixtures/mimetorture.js +2740 -0
  124. package/lib/imapproxy/imap-core/test/fixtures/mimetorture.json +1411 -0
  125. package/lib/imapproxy/imap-core/test/fixtures/mimetree.js +85 -0
  126. package/lib/imapproxy/imap-core/test/fixtures/nodemailer.eml +582 -0
  127. package/lib/imapproxy/imap-core/test/fixtures/ryan_finnie_mime_torture.eml +599 -0
  128. package/lib/imapproxy/imap-core/test/fixtures/simple.eml +42 -0
  129. package/lib/imapproxy/imap-core/test/fixtures/simple.json +164 -0
  130. package/lib/imapproxy/imap-core/test/imap-compile-stream-test.js +671 -0
  131. package/lib/imapproxy/imap-core/test/imap-compiler-test.js +272 -0
  132. package/lib/imapproxy/imap-core/test/imap-indexer-test.js +236 -0
  133. package/lib/imapproxy/imap-core/test/imap-parser-test.js +922 -0
  134. package/lib/imapproxy/imap-core/test/memory-notifier.js +129 -0
  135. package/lib/imapproxy/imap-core/test/prepare.sh +74 -0
  136. package/lib/imapproxy/imap-core/test/protocol-test.js +1756 -0
  137. package/lib/imapproxy/imap-core/test/search-test.js +1356 -0
  138. package/lib/imapproxy/imap-core/test/test-client.js +152 -0
  139. package/lib/imapproxy/imap-core/test/test-server.js +623 -0
  140. package/lib/imapproxy/imap-core/test/tools-test.js +22 -0
  141. package/lib/imapproxy/imap-server.js +577 -0
  142. package/lib/lists.js +92 -0
  143. package/lib/llm-pre-process.js +141 -0
  144. package/lib/logger.js +43 -4
  145. package/lib/lua/ee-get-idempotency.lua +74 -0
  146. package/lib/lua/ee-list-add.lua +34 -0
  147. package/lib/lua/ee-list-remove.lua +37 -0
  148. package/lib/lua/h-incrby-exists.lua +28 -0
  149. package/lib/lua/h-push.lua +32 -0
  150. package/lib/lua/h-set-bigger.lua +40 -0
  151. package/lib/lua/h-set-exists.lua +29 -0
  152. package/lib/lua/h-set-new.lua +29 -0
  153. package/lib/lua/h-update-bigger.lua +45 -0
  154. package/lib/lua/s-list-accounts.lua +64 -14
  155. package/lib/lua/z-expunge.lua +86 -10
  156. package/lib/lua/z-get-by-uid.lua +28 -5
  157. package/lib/lua/z-get-mailbox-id.lua +24 -2
  158. package/lib/lua/z-get-mailbox-path.lua +16 -0
  159. package/lib/lua/z-get.lua +27 -4
  160. package/lib/lua/z-set.lua +24 -2
  161. package/lib/metrics-collector.js +209 -0
  162. package/lib/oauth/gmail.js +663 -0
  163. package/lib/oauth/mail-ru.js +310 -0
  164. package/lib/oauth/outlook.js +541 -0
  165. package/lib/oauth/pubsub/google.js +247 -0
  166. package/lib/oauth2-apps.js +1420 -0
  167. package/lib/outbox.js +140 -0
  168. package/lib/payload-examples-documents.json +404 -0
  169. package/lib/payload-examples-webhooks.json +266 -0
  170. package/lib/pre-process.js +193 -0
  171. package/lib/rate-limit.js +32 -0
  172. package/lib/reconnection-manager.js +106 -0
  173. package/lib/redis-scan-delete.js +82 -0
  174. package/lib/redis-url.js +78 -0
  175. package/lib/rewrite-text-nodes.js +267 -0
  176. package/lib/routes-ui.js +10247 -0
  177. package/lib/schemas.js +1576 -187
  178. package/lib/settings.js +263 -12
  179. package/lib/sub-script.js +109 -0
  180. package/lib/templates.js +240 -0
  181. package/lib/threads.js +155 -0
  182. package/lib/tokens.js +353 -0
  183. package/lib/tools.js +1773 -41
  184. package/lib/translations.js +33 -0
  185. package/lib/webhooks.js +605 -0
  186. package/list-generate.js +96 -0
  187. package/package.json +130 -54
  188. package/render.yaml +44 -0
  189. package/sbom.json +1 -0
  190. package/scan.js +14 -2
  191. package/scripts/README.md +50 -0
  192. package/scripts/refresh-test-tokens.js +180 -0
  193. package/server.js +2902 -376
  194. package/setup-production.sh +201 -0
  195. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/css/bootstrap-grid.css +3 -3
  196. package/static/bootstrap-4.6.2-dist/css/bootstrap-grid.css.map +1 -0
  197. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/css/bootstrap-grid.min.css +3 -3
  198. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/css/bootstrap-grid.min.css.map +1 -1
  199. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/css/bootstrap-reboot.css +3 -3
  200. package/static/bootstrap-4.6.2-dist/css/bootstrap-reboot.css.map +1 -0
  201. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/css/bootstrap-reboot.min.css +3 -3
  202. package/static/bootstrap-4.6.2-dist/css/bootstrap-reboot.min.css.map +1 -0
  203. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/css/bootstrap.css +60 -26
  204. package/static/bootstrap-4.6.2-dist/css/bootstrap.css.map +1 -0
  205. package/static/bootstrap-4.6.2-dist/css/bootstrap.min.css +7 -0
  206. package/static/bootstrap-4.6.2-dist/css/bootstrap.min.css.map +1 -0
  207. package/static/bootstrap-4.6.2-dist/js/bootstrap.bundle.js +7155 -0
  208. package/static/bootstrap-4.6.2-dist/js/bootstrap.bundle.js.map +784 -0
  209. package/static/bootstrap-4.6.2-dist/js/bootstrap.bundle.min.js +7 -0
  210. package/static/bootstrap-4.6.2-dist/js/bootstrap.bundle.min.js.map +959 -0
  211. package/static/{bootstrap-4.6.0-dist → bootstrap-4.6.2-dist}/js/bootstrap.js +792 -868
  212. package/static/bootstrap-4.6.2-dist/js/bootstrap.js.map +1 -0
  213. package/static/bootstrap-4.6.2-dist/js/bootstrap.min.js +7 -0
  214. package/static/bootstrap-4.6.2-dist/js/bootstrap.min.js.map +1 -0
  215. package/static/css/app.css +146 -0
  216. package/static/css/arena.css +777 -0
  217. package/static/css/default.min.css +9 -0
  218. package/static/css/highlight.min.css +9 -0
  219. package/static/css/sb-admin-2.min.css +10 -0
  220. package/static/emailengine.ico +0 -0
  221. package/static/favicon/android-chrome-192x192.png +0 -0
  222. package/static/favicon/android-chrome-512x512.png +0 -0
  223. package/static/favicon/apple-touch-icon.png +0 -0
  224. package/static/favicon/favicon-16x16.png +0 -0
  225. package/static/favicon/favicon-32x32.png +0 -0
  226. package/static/favicon/favicon.ico +0 -0
  227. package/static/favicon.ico +0 -0
  228. package/static/fonts/nunito/OFL.txt +93 -0
  229. package/static/fonts/nunito/XRXV3I6Li01BKofINeaBTMnFcQ.woff2 +0 -0
  230. package/static/fonts/nunito-font.css +66 -0
  231. package/static/front/EmailEngine_logo_horiz.png +0 -0
  232. package/static/front/EmailEngine_logo_vert.png +0 -0
  233. package/static/front/index.html +57 -0
  234. package/static/front/logo.png +0 -0
  235. package/static/imap-capabilities-1.csv +71 -0
  236. package/static/index.html +30 -713
  237. package/static/js/ace/README.txt +1 -0
  238. package/static/js/ace/ace.js +23 -0
  239. package/static/js/ace/ext-language_tools.js +8 -0
  240. package/static/js/ace/ext-searchbox.js +8 -0
  241. package/static/js/ace/mode-handlebars.js +8 -0
  242. package/static/js/ace/mode-html.js +8 -0
  243. package/static/js/ace/mode-javascript.js +8 -0
  244. package/static/js/ace/mode-json.js +8 -0
  245. package/static/js/ace/mode-markdown.js +8 -0
  246. package/static/js/ace/snippets/javascript.js +8 -0
  247. package/static/js/ace/snippets/markdown.js +8 -0
  248. package/static/js/ace/theme-kuroir.js +8 -0
  249. package/static/js/ace/theme-xcode.js +8 -0
  250. package/static/js/ace/worker-html.js +1 -0
  251. package/static/js/ace/worker-javascript.js +1 -0
  252. package/static/js/ace/worker-json.js +1 -0
  253. package/static/js/app.js +526 -0
  254. package/static/js/bootstrap-autocomplete.min.js +1 -0
  255. package/static/js/clipboard.min.js +517 -0
  256. package/static/js/ee-client.js +1977 -0
  257. package/static/js/evaluation-worker.js +47 -0
  258. package/static/js/highlight.min.js +1173 -0
  259. package/static/js/jquery-3.6.0.min.js +2 -0
  260. package/static/js/sb-admin-2.min.js +7 -0
  261. package/static/licenses.html +6606 -50
  262. package/static/logo/EmailEngine_logo_horiz.png +0 -0
  263. package/static/logo/EmailEngine_logo_vert.png +0 -0
  264. package/static/logo.png +0 -0
  265. package/static/logo_transparent.png +0 -0
  266. package/static/logo_transparent_small.png +0 -0
  267. package/static/logo_wide.png +0 -0
  268. package/static/preview/header-template.png +0 -0
  269. package/static/preview/render.png +0 -0
  270. package/static/preview/translation.png +0 -0
  271. package/static/providers/google_dark.png +0 -0
  272. package/static/providers/google_dark_edited.png +0 -0
  273. package/static/providers/google_light.png +0 -0
  274. package/static/providers/ms_dark.svg +1 -0
  275. package/static/providers/ms_light.svg +1 -0
  276. package/static/robots.txt +4 -0
  277. package/static/undraw_profile.svg +38 -0
  278. package/static/vendor/fontawesome-free/LICENSE.txt +34 -0
  279. package/static/vendor/fontawesome-free/attribution.js +3 -0
  280. package/static/vendor/fontawesome-free/css/all.css +4619 -0
  281. package/static/vendor/fontawesome-free/css/all.min.css +5 -0
  282. package/static/vendor/fontawesome-free/css/brands.css +15 -0
  283. package/static/vendor/fontawesome-free/css/brands.min.css +5 -0
  284. package/static/vendor/fontawesome-free/css/fontawesome.css +4585 -0
  285. package/static/vendor/fontawesome-free/css/fontawesome.min.css +5 -0
  286. package/static/vendor/fontawesome-free/css/regular.css +15 -0
  287. package/static/vendor/fontawesome-free/css/regular.min.css +5 -0
  288. package/static/vendor/fontawesome-free/css/solid.css +16 -0
  289. package/static/vendor/fontawesome-free/css/solid.min.css +5 -0
  290. package/static/vendor/fontawesome-free/css/svg-with-js.css +371 -0
  291. package/static/vendor/fontawesome-free/css/svg-with-js.min.css +5 -0
  292. package/static/vendor/fontawesome-free/css/v4-shims.css +2172 -0
  293. package/static/vendor/fontawesome-free/css/v4-shims.min.css +5 -0
  294. package/static/vendor/fontawesome-free/js/all.js +4467 -0
  295. package/static/vendor/fontawesome-free/js/all.min.js +5 -0
  296. package/static/vendor/fontawesome-free/js/brands.js +586 -0
  297. package/static/vendor/fontawesome-free/js/brands.min.js +5 -0
  298. package/static/vendor/fontawesome-free/js/conflict-detection.js +998 -0
  299. package/static/vendor/fontawesome-free/js/conflict-detection.min.js +5 -0
  300. package/static/vendor/fontawesome-free/js/fontawesome.js +2483 -0
  301. package/static/vendor/fontawesome-free/js/fontawesome.min.js +5 -0
  302. package/static/vendor/fontawesome-free/js/regular.js +280 -0
  303. package/static/vendor/fontawesome-free/js/regular.min.js +5 -0
  304. package/static/vendor/fontawesome-free/js/solid.js +1130 -0
  305. package/static/vendor/fontawesome-free/js/solid.min.js +5 -0
  306. package/static/vendor/fontawesome-free/js/v4-shims.js +68 -0
  307. package/static/vendor/fontawesome-free/js/v4-shims.min.js +5 -0
  308. package/static/vendor/fontawesome-free/less/_animated.less +19 -0
  309. package/static/vendor/fontawesome-free/less/_bordered-pulled.less +16 -0
  310. package/static/vendor/fontawesome-free/less/_core.less +12 -0
  311. package/static/vendor/fontawesome-free/less/_fixed-width.less +6 -0
  312. package/static/vendor/fontawesome-free/less/_icons.less +1462 -0
  313. package/static/vendor/fontawesome-free/less/_larger.less +27 -0
  314. package/static/vendor/fontawesome-free/less/_list.less +18 -0
  315. package/static/vendor/fontawesome-free/less/_mixins.less +56 -0
  316. package/static/vendor/fontawesome-free/less/_rotated-flipped.less +24 -0
  317. package/static/vendor/fontawesome-free/less/_screen-reader.less +5 -0
  318. package/static/vendor/fontawesome-free/less/_shims.less +2066 -0
  319. package/static/vendor/fontawesome-free/less/_stacked.less +22 -0
  320. package/static/vendor/fontawesome-free/less/_variables.less +1474 -0
  321. package/static/vendor/fontawesome-free/less/brands.less +23 -0
  322. package/static/vendor/fontawesome-free/less/fontawesome.less +16 -0
  323. package/static/vendor/fontawesome-free/less/regular.less +23 -0
  324. package/static/vendor/fontawesome-free/less/solid.less +24 -0
  325. package/static/vendor/fontawesome-free/less/v4-shims.less +6 -0
  326. package/static/vendor/fontawesome-free/metadata/categories.yml +2572 -0
  327. package/static/vendor/fontawesome-free/metadata/icons.yml +21783 -0
  328. package/static/vendor/fontawesome-free/metadata/shims.yml +298 -0
  329. package/static/vendor/fontawesome-free/metadata/sponsors.yml +744 -0
  330. package/static/vendor/fontawesome-free/package.json +58 -0
  331. package/static/vendor/fontawesome-free/scss/_animated.scss +20 -0
  332. package/static/vendor/fontawesome-free/scss/_bordered-pulled.scss +20 -0
  333. package/static/vendor/fontawesome-free/scss/_core.scss +21 -0
  334. package/static/vendor/fontawesome-free/scss/_fixed-width.scss +6 -0
  335. package/static/vendor/fontawesome-free/scss/_icons.scss +1462 -0
  336. package/static/vendor/fontawesome-free/scss/_larger.scss +23 -0
  337. package/static/vendor/fontawesome-free/scss/_list.scss +18 -0
  338. package/static/vendor/fontawesome-free/scss/_mixins.scss +56 -0
  339. package/static/vendor/fontawesome-free/scss/_rotated-flipped.scss +24 -0
  340. package/static/vendor/fontawesome-free/scss/_screen-reader.scss +5 -0
  341. package/static/vendor/fontawesome-free/scss/_shims.scss +2066 -0
  342. package/static/vendor/fontawesome-free/scss/_stacked.scss +31 -0
  343. package/static/vendor/fontawesome-free/scss/_variables.scss +1479 -0
  344. package/static/vendor/fontawesome-free/scss/brands.scss +23 -0
  345. package/static/vendor/fontawesome-free/scss/fontawesome.scss +16 -0
  346. package/static/vendor/fontawesome-free/scss/regular.scss +23 -0
  347. package/static/vendor/fontawesome-free/scss/solid.scss +24 -0
  348. package/static/vendor/fontawesome-free/scss/v4-shims.scss +6 -0
  349. package/static/vendor/fontawesome-free/sprites/brands.svg +1381 -0
  350. package/static/vendor/fontawesome-free/sprites/regular.svg +463 -0
  351. package/static/vendor/fontawesome-free/sprites/solid.svg +3013 -0
  352. package/static/vendor/fontawesome-free/svgs/brands/500px.svg +1 -0
  353. package/static/vendor/fontawesome-free/svgs/brands/accessible-icon.svg +1 -0
  354. package/static/vendor/fontawesome-free/svgs/brands/accusoft.svg +1 -0
  355. package/static/vendor/fontawesome-free/svgs/brands/acquisitions-incorporated.svg +1 -0
  356. package/static/vendor/fontawesome-free/svgs/brands/adn.svg +1 -0
  357. package/static/vendor/fontawesome-free/svgs/brands/adversal.svg +1 -0
  358. package/static/vendor/fontawesome-free/svgs/brands/affiliatetheme.svg +1 -0
  359. package/static/vendor/fontawesome-free/svgs/brands/airbnb.svg +1 -0
  360. package/static/vendor/fontawesome-free/svgs/brands/algolia.svg +1 -0
  361. package/static/vendor/fontawesome-free/svgs/brands/alipay.svg +1 -0
  362. package/static/vendor/fontawesome-free/svgs/brands/amazon-pay.svg +1 -0
  363. package/static/vendor/fontawesome-free/svgs/brands/amazon.svg +1 -0
  364. package/static/vendor/fontawesome-free/svgs/brands/amilia.svg +1 -0
  365. package/static/vendor/fontawesome-free/svgs/brands/android.svg +1 -0
  366. package/static/vendor/fontawesome-free/svgs/brands/angellist.svg +1 -0
  367. package/static/vendor/fontawesome-free/svgs/brands/angrycreative.svg +1 -0
  368. package/static/vendor/fontawesome-free/svgs/brands/angular.svg +1 -0
  369. package/static/vendor/fontawesome-free/svgs/brands/app-store-ios.svg +1 -0
  370. package/static/vendor/fontawesome-free/svgs/brands/app-store.svg +1 -0
  371. package/static/vendor/fontawesome-free/svgs/brands/apper.svg +1 -0
  372. package/static/vendor/fontawesome-free/svgs/brands/apple-pay.svg +1 -0
  373. package/static/vendor/fontawesome-free/svgs/brands/apple.svg +1 -0
  374. package/static/vendor/fontawesome-free/svgs/brands/artstation.svg +1 -0
  375. package/static/vendor/fontawesome-free/svgs/brands/asymmetrik.svg +1 -0
  376. package/static/vendor/fontawesome-free/svgs/brands/atlassian.svg +1 -0
  377. package/static/vendor/fontawesome-free/svgs/brands/audible.svg +1 -0
  378. package/static/vendor/fontawesome-free/svgs/brands/autoprefixer.svg +1 -0
  379. package/static/vendor/fontawesome-free/svgs/brands/avianex.svg +1 -0
  380. package/static/vendor/fontawesome-free/svgs/brands/aviato.svg +1 -0
  381. package/static/vendor/fontawesome-free/svgs/brands/aws.svg +1 -0
  382. package/static/vendor/fontawesome-free/svgs/brands/bandcamp.svg +1 -0
  383. package/static/vendor/fontawesome-free/svgs/brands/battle-net.svg +1 -0
  384. package/static/vendor/fontawesome-free/svgs/brands/behance-square.svg +1 -0
  385. package/static/vendor/fontawesome-free/svgs/brands/behance.svg +1 -0
  386. package/static/vendor/fontawesome-free/svgs/brands/bimobject.svg +1 -0
  387. package/static/vendor/fontawesome-free/svgs/brands/bitbucket.svg +1 -0
  388. package/static/vendor/fontawesome-free/svgs/brands/bitcoin.svg +1 -0
  389. package/static/vendor/fontawesome-free/svgs/brands/bity.svg +1 -0
  390. package/static/vendor/fontawesome-free/svgs/brands/black-tie.svg +1 -0
  391. package/static/vendor/fontawesome-free/svgs/brands/blackberry.svg +1 -0
  392. package/static/vendor/fontawesome-free/svgs/brands/blogger-b.svg +1 -0
  393. package/static/vendor/fontawesome-free/svgs/brands/blogger.svg +1 -0
  394. package/static/vendor/fontawesome-free/svgs/brands/bluetooth-b.svg +1 -0
  395. package/static/vendor/fontawesome-free/svgs/brands/bluetooth.svg +1 -0
  396. package/static/vendor/fontawesome-free/svgs/brands/bootstrap.svg +1 -0
  397. package/static/vendor/fontawesome-free/svgs/brands/btc.svg +1 -0
  398. package/static/vendor/fontawesome-free/svgs/brands/buffer.svg +1 -0
  399. package/static/vendor/fontawesome-free/svgs/brands/buromobelexperte.svg +1 -0
  400. package/static/vendor/fontawesome-free/svgs/brands/buy-n-large.svg +1 -0
  401. package/static/vendor/fontawesome-free/svgs/brands/buysellads.svg +1 -0
  402. package/static/vendor/fontawesome-free/svgs/brands/canadian-maple-leaf.svg +1 -0
  403. package/static/vendor/fontawesome-free/svgs/brands/cc-amazon-pay.svg +1 -0
  404. package/static/vendor/fontawesome-free/svgs/brands/cc-amex.svg +1 -0
  405. package/static/vendor/fontawesome-free/svgs/brands/cc-apple-pay.svg +1 -0
  406. package/static/vendor/fontawesome-free/svgs/brands/cc-diners-club.svg +1 -0
  407. package/static/vendor/fontawesome-free/svgs/brands/cc-discover.svg +1 -0
  408. package/static/vendor/fontawesome-free/svgs/brands/cc-jcb.svg +1 -0
  409. package/static/vendor/fontawesome-free/svgs/brands/cc-mastercard.svg +1 -0
  410. package/static/vendor/fontawesome-free/svgs/brands/cc-paypal.svg +1 -0
  411. package/static/vendor/fontawesome-free/svgs/brands/cc-stripe.svg +1 -0
  412. package/static/vendor/fontawesome-free/svgs/brands/cc-visa.svg +1 -0
  413. package/static/vendor/fontawesome-free/svgs/brands/centercode.svg +1 -0
  414. package/static/vendor/fontawesome-free/svgs/brands/centos.svg +1 -0
  415. package/static/vendor/fontawesome-free/svgs/brands/chrome.svg +1 -0
  416. package/static/vendor/fontawesome-free/svgs/brands/chromecast.svg +1 -0
  417. package/static/vendor/fontawesome-free/svgs/brands/cloudflare.svg +1 -0
  418. package/static/vendor/fontawesome-free/svgs/brands/cloudscale.svg +1 -0
  419. package/static/vendor/fontawesome-free/svgs/brands/cloudsmith.svg +1 -0
  420. package/static/vendor/fontawesome-free/svgs/brands/cloudversify.svg +1 -0
  421. package/static/vendor/fontawesome-free/svgs/brands/codepen.svg +1 -0
  422. package/static/vendor/fontawesome-free/svgs/brands/codiepie.svg +1 -0
  423. package/static/vendor/fontawesome-free/svgs/brands/confluence.svg +1 -0
  424. package/static/vendor/fontawesome-free/svgs/brands/connectdevelop.svg +1 -0
  425. package/static/vendor/fontawesome-free/svgs/brands/contao.svg +1 -0
  426. package/static/vendor/fontawesome-free/svgs/brands/cotton-bureau.svg +1 -0
  427. package/static/vendor/fontawesome-free/svgs/brands/cpanel.svg +1 -0
  428. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-by.svg +1 -0
  429. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-nc-eu.svg +1 -0
  430. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-nc-jp.svg +1 -0
  431. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-nc.svg +1 -0
  432. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-nd.svg +1 -0
  433. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-pd-alt.svg +1 -0
  434. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-pd.svg +1 -0
  435. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-remix.svg +1 -0
  436. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-sa.svg +1 -0
  437. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-sampling-plus.svg +1 -0
  438. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-sampling.svg +1 -0
  439. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-share.svg +1 -0
  440. package/static/vendor/fontawesome-free/svgs/brands/creative-commons-zero.svg +1 -0
  441. package/static/vendor/fontawesome-free/svgs/brands/creative-commons.svg +1 -0
  442. package/static/vendor/fontawesome-free/svgs/brands/critical-role.svg +1 -0
  443. package/static/vendor/fontawesome-free/svgs/brands/css3-alt.svg +1 -0
  444. package/static/vendor/fontawesome-free/svgs/brands/css3.svg +1 -0
  445. package/static/vendor/fontawesome-free/svgs/brands/cuttlefish.svg +1 -0
  446. package/static/vendor/fontawesome-free/svgs/brands/d-and-d-beyond.svg +1 -0
  447. package/static/vendor/fontawesome-free/svgs/brands/d-and-d.svg +1 -0
  448. package/static/vendor/fontawesome-free/svgs/brands/dailymotion.svg +1 -0
  449. package/static/vendor/fontawesome-free/svgs/brands/dashcube.svg +1 -0
  450. package/static/vendor/fontawesome-free/svgs/brands/deezer.svg +1 -0
  451. package/static/vendor/fontawesome-free/svgs/brands/delicious.svg +1 -0
  452. package/static/vendor/fontawesome-free/svgs/brands/deploydog.svg +1 -0
  453. package/static/vendor/fontawesome-free/svgs/brands/deskpro.svg +1 -0
  454. package/static/vendor/fontawesome-free/svgs/brands/dev.svg +1 -0
  455. package/static/vendor/fontawesome-free/svgs/brands/deviantart.svg +1 -0
  456. package/static/vendor/fontawesome-free/svgs/brands/dhl.svg +1 -0
  457. package/static/vendor/fontawesome-free/svgs/brands/diaspora.svg +1 -0
  458. package/static/vendor/fontawesome-free/svgs/brands/digg.svg +1 -0
  459. package/static/vendor/fontawesome-free/svgs/brands/digital-ocean.svg +1 -0
  460. package/static/vendor/fontawesome-free/svgs/brands/discord.svg +1 -0
  461. package/static/vendor/fontawesome-free/svgs/brands/discourse.svg +1 -0
  462. package/static/vendor/fontawesome-free/svgs/brands/dochub.svg +1 -0
  463. package/static/vendor/fontawesome-free/svgs/brands/docker.svg +1 -0
  464. package/static/vendor/fontawesome-free/svgs/brands/draft2digital.svg +1 -0
  465. package/static/vendor/fontawesome-free/svgs/brands/dribbble-square.svg +1 -0
  466. package/static/vendor/fontawesome-free/svgs/brands/dribbble.svg +1 -0
  467. package/static/vendor/fontawesome-free/svgs/brands/dropbox.svg +1 -0
  468. package/static/vendor/fontawesome-free/svgs/brands/drupal.svg +1 -0
  469. package/static/vendor/fontawesome-free/svgs/brands/dyalog.svg +1 -0
  470. package/static/vendor/fontawesome-free/svgs/brands/earlybirds.svg +1 -0
  471. package/static/vendor/fontawesome-free/svgs/brands/ebay.svg +1 -0
  472. package/static/vendor/fontawesome-free/svgs/brands/edge-legacy.svg +1 -0
  473. package/static/vendor/fontawesome-free/svgs/brands/edge.svg +1 -0
  474. package/static/vendor/fontawesome-free/svgs/brands/elementor.svg +1 -0
  475. package/static/vendor/fontawesome-free/svgs/brands/ello.svg +1 -0
  476. package/static/vendor/fontawesome-free/svgs/brands/ember.svg +1 -0
  477. package/static/vendor/fontawesome-free/svgs/brands/empire.svg +1 -0
  478. package/static/vendor/fontawesome-free/svgs/brands/envira.svg +1 -0
  479. package/static/vendor/fontawesome-free/svgs/brands/erlang.svg +1 -0
  480. package/static/vendor/fontawesome-free/svgs/brands/ethereum.svg +1 -0
  481. package/static/vendor/fontawesome-free/svgs/brands/etsy.svg +1 -0
  482. package/static/vendor/fontawesome-free/svgs/brands/evernote.svg +1 -0
  483. package/static/vendor/fontawesome-free/svgs/brands/expeditedssl.svg +1 -0
  484. package/static/vendor/fontawesome-free/svgs/brands/facebook-f.svg +1 -0
  485. package/static/vendor/fontawesome-free/svgs/brands/facebook-messenger.svg +1 -0
  486. package/static/vendor/fontawesome-free/svgs/brands/facebook-square.svg +1 -0
  487. package/static/vendor/fontawesome-free/svgs/brands/facebook.svg +1 -0
  488. package/static/vendor/fontawesome-free/svgs/brands/fantasy-flight-games.svg +1 -0
  489. package/static/vendor/fontawesome-free/svgs/brands/fedex.svg +1 -0
  490. package/static/vendor/fontawesome-free/svgs/brands/fedora.svg +1 -0
  491. package/static/vendor/fontawesome-free/svgs/brands/figma.svg +1 -0
  492. package/static/vendor/fontawesome-free/svgs/brands/firefox-browser.svg +1 -0
  493. package/static/vendor/fontawesome-free/svgs/brands/firefox.svg +1 -0
  494. package/static/vendor/fontawesome-free/svgs/brands/first-order-alt.svg +1 -0
  495. package/static/vendor/fontawesome-free/svgs/brands/first-order.svg +1 -0
  496. package/static/vendor/fontawesome-free/svgs/brands/firstdraft.svg +1 -0
  497. package/static/vendor/fontawesome-free/svgs/brands/flickr.svg +1 -0
  498. package/static/vendor/fontawesome-free/svgs/brands/flipboard.svg +1 -0
  499. package/static/vendor/fontawesome-free/svgs/brands/fly.svg +1 -0
  500. package/static/vendor/fontawesome-free/svgs/brands/font-awesome-alt.svg +1 -0
  501. package/static/vendor/fontawesome-free/svgs/brands/font-awesome-flag.svg +1 -0
  502. package/static/vendor/fontawesome-free/svgs/brands/font-awesome-logo-full.svg +1 -0
  503. package/static/vendor/fontawesome-free/svgs/brands/font-awesome.svg +1 -0
  504. package/static/vendor/fontawesome-free/svgs/brands/fonticons-fi.svg +1 -0
  505. package/static/vendor/fontawesome-free/svgs/brands/fonticons.svg +1 -0
  506. package/static/vendor/fontawesome-free/svgs/brands/fort-awesome-alt.svg +1 -0
  507. package/static/vendor/fontawesome-free/svgs/brands/fort-awesome.svg +1 -0
  508. package/static/vendor/fontawesome-free/svgs/brands/forumbee.svg +1 -0
  509. package/static/vendor/fontawesome-free/svgs/brands/foursquare.svg +1 -0
  510. package/static/vendor/fontawesome-free/svgs/brands/free-code-camp.svg +1 -0
  511. package/static/vendor/fontawesome-free/svgs/brands/freebsd.svg +1 -0
  512. package/static/vendor/fontawesome-free/svgs/brands/fulcrum.svg +1 -0
  513. package/static/vendor/fontawesome-free/svgs/brands/galactic-republic.svg +1 -0
  514. package/static/vendor/fontawesome-free/svgs/brands/galactic-senate.svg +1 -0
  515. package/static/vendor/fontawesome-free/svgs/brands/get-pocket.svg +1 -0
  516. package/static/vendor/fontawesome-free/svgs/brands/gg-circle.svg +1 -0
  517. package/static/vendor/fontawesome-free/svgs/brands/gg.svg +1 -0
  518. package/static/vendor/fontawesome-free/svgs/brands/git-alt.svg +1 -0
  519. package/static/vendor/fontawesome-free/svgs/brands/git-square.svg +1 -0
  520. package/static/vendor/fontawesome-free/svgs/brands/git.svg +1 -0
  521. package/static/vendor/fontawesome-free/svgs/brands/github-alt.svg +1 -0
  522. package/static/vendor/fontawesome-free/svgs/brands/github-square.svg +1 -0
  523. package/static/vendor/fontawesome-free/svgs/brands/github.svg +1 -0
  524. package/static/vendor/fontawesome-free/svgs/brands/gitkraken.svg +1 -0
  525. package/static/vendor/fontawesome-free/svgs/brands/gitlab.svg +1 -0
  526. package/static/vendor/fontawesome-free/svgs/brands/gitter.svg +1 -0
  527. package/static/vendor/fontawesome-free/svgs/brands/glide-g.svg +1 -0
  528. package/static/vendor/fontawesome-free/svgs/brands/glide.svg +1 -0
  529. package/static/vendor/fontawesome-free/svgs/brands/gofore.svg +1 -0
  530. package/static/vendor/fontawesome-free/svgs/brands/goodreads-g.svg +1 -0
  531. package/static/vendor/fontawesome-free/svgs/brands/goodreads.svg +1 -0
  532. package/static/vendor/fontawesome-free/svgs/brands/google-drive.svg +1 -0
  533. package/static/vendor/fontawesome-free/svgs/brands/google-pay.svg +1 -0
  534. package/static/vendor/fontawesome-free/svgs/brands/google-play.svg +1 -0
  535. package/static/vendor/fontawesome-free/svgs/brands/google-plus-g.svg +1 -0
  536. package/static/vendor/fontawesome-free/svgs/brands/google-plus-square.svg +1 -0
  537. package/static/vendor/fontawesome-free/svgs/brands/google-plus.svg +1 -0
  538. package/static/vendor/fontawesome-free/svgs/brands/google-wallet.svg +1 -0
  539. package/static/vendor/fontawesome-free/svgs/brands/google.svg +1 -0
  540. package/static/vendor/fontawesome-free/svgs/brands/gratipay.svg +1 -0
  541. package/static/vendor/fontawesome-free/svgs/brands/grav.svg +1 -0
  542. package/static/vendor/fontawesome-free/svgs/brands/gripfire.svg +1 -0
  543. package/static/vendor/fontawesome-free/svgs/brands/grunt.svg +1 -0
  544. package/static/vendor/fontawesome-free/svgs/brands/guilded.svg +1 -0
  545. package/static/vendor/fontawesome-free/svgs/brands/gulp.svg +1 -0
  546. package/static/vendor/fontawesome-free/svgs/brands/hacker-news-square.svg +1 -0
  547. package/static/vendor/fontawesome-free/svgs/brands/hacker-news.svg +1 -0
  548. package/static/vendor/fontawesome-free/svgs/brands/hackerrank.svg +1 -0
  549. package/static/vendor/fontawesome-free/svgs/brands/hips.svg +1 -0
  550. package/static/vendor/fontawesome-free/svgs/brands/hire-a-helper.svg +1 -0
  551. package/static/vendor/fontawesome-free/svgs/brands/hive.svg +1 -0
  552. package/static/vendor/fontawesome-free/svgs/brands/hooli.svg +1 -0
  553. package/static/vendor/fontawesome-free/svgs/brands/hornbill.svg +1 -0
  554. package/static/vendor/fontawesome-free/svgs/brands/hotjar.svg +1 -0
  555. package/static/vendor/fontawesome-free/svgs/brands/houzz.svg +1 -0
  556. package/static/vendor/fontawesome-free/svgs/brands/html5.svg +1 -0
  557. package/static/vendor/fontawesome-free/svgs/brands/hubspot.svg +1 -0
  558. package/static/vendor/fontawesome-free/svgs/brands/ideal.svg +1 -0
  559. package/static/vendor/fontawesome-free/svgs/brands/imdb.svg +1 -0
  560. package/static/vendor/fontawesome-free/svgs/brands/innosoft.svg +1 -0
  561. package/static/vendor/fontawesome-free/svgs/brands/instagram-square.svg +1 -0
  562. package/static/vendor/fontawesome-free/svgs/brands/instagram.svg +1 -0
  563. package/static/vendor/fontawesome-free/svgs/brands/instalod.svg +1 -0
  564. package/static/vendor/fontawesome-free/svgs/brands/intercom.svg +1 -0
  565. package/static/vendor/fontawesome-free/svgs/brands/internet-explorer.svg +1 -0
  566. package/static/vendor/fontawesome-free/svgs/brands/invision.svg +1 -0
  567. package/static/vendor/fontawesome-free/svgs/brands/ioxhost.svg +1 -0
  568. package/static/vendor/fontawesome-free/svgs/brands/itch-io.svg +1 -0
  569. package/static/vendor/fontawesome-free/svgs/brands/itunes-note.svg +1 -0
  570. package/static/vendor/fontawesome-free/svgs/brands/itunes.svg +1 -0
  571. package/static/vendor/fontawesome-free/svgs/brands/java.svg +1 -0
  572. package/static/vendor/fontawesome-free/svgs/brands/jedi-order.svg +1 -0
  573. package/static/vendor/fontawesome-free/svgs/brands/jenkins.svg +1 -0
  574. package/static/vendor/fontawesome-free/svgs/brands/jira.svg +1 -0
  575. package/static/vendor/fontawesome-free/svgs/brands/joget.svg +1 -0
  576. package/static/vendor/fontawesome-free/svgs/brands/joomla.svg +1 -0
  577. package/static/vendor/fontawesome-free/svgs/brands/js-square.svg +1 -0
  578. package/static/vendor/fontawesome-free/svgs/brands/js.svg +1 -0
  579. package/static/vendor/fontawesome-free/svgs/brands/jsfiddle.svg +1 -0
  580. package/static/vendor/fontawesome-free/svgs/brands/kaggle.svg +1 -0
  581. package/static/vendor/fontawesome-free/svgs/brands/keybase.svg +1 -0
  582. package/static/vendor/fontawesome-free/svgs/brands/keycdn.svg +1 -0
  583. package/static/vendor/fontawesome-free/svgs/brands/kickstarter-k.svg +1 -0
  584. package/static/vendor/fontawesome-free/svgs/brands/kickstarter.svg +1 -0
  585. package/static/vendor/fontawesome-free/svgs/brands/korvue.svg +1 -0
  586. package/static/vendor/fontawesome-free/svgs/brands/laravel.svg +1 -0
  587. package/static/vendor/fontawesome-free/svgs/brands/lastfm-square.svg +1 -0
  588. package/static/vendor/fontawesome-free/svgs/brands/lastfm.svg +1 -0
  589. package/static/vendor/fontawesome-free/svgs/brands/leanpub.svg +1 -0
  590. package/static/vendor/fontawesome-free/svgs/brands/less.svg +1 -0
  591. package/static/vendor/fontawesome-free/svgs/brands/line.svg +1 -0
  592. package/static/vendor/fontawesome-free/svgs/brands/linkedin-in.svg +1 -0
  593. package/static/vendor/fontawesome-free/svgs/brands/linkedin.svg +1 -0
  594. package/static/vendor/fontawesome-free/svgs/brands/linode.svg +1 -0
  595. package/static/vendor/fontawesome-free/svgs/brands/linux.svg +1 -0
  596. package/static/vendor/fontawesome-free/svgs/brands/lyft.svg +1 -0
  597. package/static/vendor/fontawesome-free/svgs/brands/magento.svg +1 -0
  598. package/static/vendor/fontawesome-free/svgs/brands/mailchimp.svg +1 -0
  599. package/static/vendor/fontawesome-free/svgs/brands/mandalorian.svg +1 -0
  600. package/static/vendor/fontawesome-free/svgs/brands/markdown.svg +1 -0
  601. package/static/vendor/fontawesome-free/svgs/brands/mastodon.svg +1 -0
  602. package/static/vendor/fontawesome-free/svgs/brands/maxcdn.svg +1 -0
  603. package/static/vendor/fontawesome-free/svgs/brands/mdb.svg +1 -0
  604. package/static/vendor/fontawesome-free/svgs/brands/medapps.svg +1 -0
  605. package/static/vendor/fontawesome-free/svgs/brands/medium-m.svg +1 -0
  606. package/static/vendor/fontawesome-free/svgs/brands/medium.svg +1 -0
  607. package/static/vendor/fontawesome-free/svgs/brands/medrt.svg +1 -0
  608. package/static/vendor/fontawesome-free/svgs/brands/meetup.svg +1 -0
  609. package/static/vendor/fontawesome-free/svgs/brands/megaport.svg +1 -0
  610. package/static/vendor/fontawesome-free/svgs/brands/mendeley.svg +1 -0
  611. package/static/vendor/fontawesome-free/svgs/brands/microblog.svg +1 -0
  612. package/static/vendor/fontawesome-free/svgs/brands/microsoft.svg +1 -0
  613. package/static/vendor/fontawesome-free/svgs/brands/mix.svg +1 -0
  614. package/static/vendor/fontawesome-free/svgs/brands/mixcloud.svg +1 -0
  615. package/static/vendor/fontawesome-free/svgs/brands/mixer.svg +1 -0
  616. package/static/vendor/fontawesome-free/svgs/brands/mizuni.svg +1 -0
  617. package/static/vendor/fontawesome-free/svgs/brands/modx.svg +1 -0
  618. package/static/vendor/fontawesome-free/svgs/brands/monero.svg +1 -0
  619. package/static/vendor/fontawesome-free/svgs/brands/napster.svg +1 -0
  620. package/static/vendor/fontawesome-free/svgs/brands/neos.svg +1 -0
  621. package/static/vendor/fontawesome-free/svgs/brands/nimblr.svg +1 -0
  622. package/static/vendor/fontawesome-free/svgs/brands/node-js.svg +1 -0
  623. package/static/vendor/fontawesome-free/svgs/brands/node.svg +1 -0
  624. package/static/vendor/fontawesome-free/svgs/brands/npm.svg +1 -0
  625. package/static/vendor/fontawesome-free/svgs/brands/ns8.svg +1 -0
  626. package/static/vendor/fontawesome-free/svgs/brands/nutritionix.svg +1 -0
  627. package/static/vendor/fontawesome-free/svgs/brands/octopus-deploy.svg +1 -0
  628. package/static/vendor/fontawesome-free/svgs/brands/odnoklassniki-square.svg +1 -0
  629. package/static/vendor/fontawesome-free/svgs/brands/odnoklassniki.svg +1 -0
  630. package/static/vendor/fontawesome-free/svgs/brands/old-republic.svg +1 -0
  631. package/static/vendor/fontawesome-free/svgs/brands/opencart.svg +1 -0
  632. package/static/vendor/fontawesome-free/svgs/brands/openid.svg +1 -0
  633. package/static/vendor/fontawesome-free/svgs/brands/opera.svg +1 -0
  634. package/static/vendor/fontawesome-free/svgs/brands/optin-monster.svg +1 -0
  635. package/static/vendor/fontawesome-free/svgs/brands/orcid.svg +1 -0
  636. package/static/vendor/fontawesome-free/svgs/brands/osi.svg +1 -0
  637. package/static/vendor/fontawesome-free/svgs/brands/page4.svg +1 -0
  638. package/static/vendor/fontawesome-free/svgs/brands/pagelines.svg +1 -0
  639. package/static/vendor/fontawesome-free/svgs/brands/palfed.svg +1 -0
  640. package/static/vendor/fontawesome-free/svgs/brands/patreon.svg +1 -0
  641. package/static/vendor/fontawesome-free/svgs/brands/paypal.svg +1 -0
  642. package/static/vendor/fontawesome-free/svgs/brands/penny-arcade.svg +1 -0
  643. package/static/vendor/fontawesome-free/svgs/brands/perbyte.svg +1 -0
  644. package/static/vendor/fontawesome-free/svgs/brands/periscope.svg +1 -0
  645. package/static/vendor/fontawesome-free/svgs/brands/phabricator.svg +1 -0
  646. package/static/vendor/fontawesome-free/svgs/brands/phoenix-framework.svg +1 -0
  647. package/static/vendor/fontawesome-free/svgs/brands/phoenix-squadron.svg +1 -0
  648. package/static/vendor/fontawesome-free/svgs/brands/php.svg +1 -0
  649. package/static/vendor/fontawesome-free/svgs/brands/pied-piper-alt.svg +1 -0
  650. package/static/vendor/fontawesome-free/svgs/brands/pied-piper-hat.svg +1 -0
  651. package/static/vendor/fontawesome-free/svgs/brands/pied-piper-pp.svg +1 -0
  652. package/static/vendor/fontawesome-free/svgs/brands/pied-piper-square.svg +1 -0
  653. package/static/vendor/fontawesome-free/svgs/brands/pied-piper.svg +1 -0
  654. package/static/vendor/fontawesome-free/svgs/brands/pinterest-p.svg +1 -0
  655. package/static/vendor/fontawesome-free/svgs/brands/pinterest-square.svg +1 -0
  656. package/static/vendor/fontawesome-free/svgs/brands/pinterest.svg +1 -0
  657. package/static/vendor/fontawesome-free/svgs/brands/playstation.svg +1 -0
  658. package/static/vendor/fontawesome-free/svgs/brands/product-hunt.svg +1 -0
  659. package/static/vendor/fontawesome-free/svgs/brands/pushed.svg +1 -0
  660. package/static/vendor/fontawesome-free/svgs/brands/python.svg +1 -0
  661. package/static/vendor/fontawesome-free/svgs/brands/qq.svg +1 -0
  662. package/static/vendor/fontawesome-free/svgs/brands/quinscape.svg +1 -0
  663. package/static/vendor/fontawesome-free/svgs/brands/quora.svg +1 -0
  664. package/static/vendor/fontawesome-free/svgs/brands/r-project.svg +1 -0
  665. package/static/vendor/fontawesome-free/svgs/brands/raspberry-pi.svg +1 -0
  666. package/static/vendor/fontawesome-free/svgs/brands/ravelry.svg +1 -0
  667. package/static/vendor/fontawesome-free/svgs/brands/react.svg +1 -0
  668. package/static/vendor/fontawesome-free/svgs/brands/reacteurope.svg +1 -0
  669. package/static/vendor/fontawesome-free/svgs/brands/readme.svg +1 -0
  670. package/static/vendor/fontawesome-free/svgs/brands/rebel.svg +1 -0
  671. package/static/vendor/fontawesome-free/svgs/brands/red-river.svg +1 -0
  672. package/static/vendor/fontawesome-free/svgs/brands/reddit-alien.svg +1 -0
  673. package/static/vendor/fontawesome-free/svgs/brands/reddit-square.svg +1 -0
  674. package/static/vendor/fontawesome-free/svgs/brands/reddit.svg +1 -0
  675. package/static/vendor/fontawesome-free/svgs/brands/redhat.svg +1 -0
  676. package/static/vendor/fontawesome-free/svgs/brands/renren.svg +1 -0
  677. package/static/vendor/fontawesome-free/svgs/brands/replyd.svg +1 -0
  678. package/static/vendor/fontawesome-free/svgs/brands/researchgate.svg +1 -0
  679. package/static/vendor/fontawesome-free/svgs/brands/resolving.svg +1 -0
  680. package/static/vendor/fontawesome-free/svgs/brands/rev.svg +1 -0
  681. package/static/vendor/fontawesome-free/svgs/brands/rocketchat.svg +1 -0
  682. package/static/vendor/fontawesome-free/svgs/brands/rockrms.svg +1 -0
  683. package/static/vendor/fontawesome-free/svgs/brands/rust.svg +1 -0
  684. package/static/vendor/fontawesome-free/svgs/brands/safari.svg +1 -0
  685. package/static/vendor/fontawesome-free/svgs/brands/salesforce.svg +1 -0
  686. package/static/vendor/fontawesome-free/svgs/brands/sass.svg +1 -0
  687. package/static/vendor/fontawesome-free/svgs/brands/schlix.svg +1 -0
  688. package/static/vendor/fontawesome-free/svgs/brands/scribd.svg +1 -0
  689. package/static/vendor/fontawesome-free/svgs/brands/searchengin.svg +1 -0
  690. package/static/vendor/fontawesome-free/svgs/brands/sellcast.svg +1 -0
  691. package/static/vendor/fontawesome-free/svgs/brands/sellsy.svg +1 -0
  692. package/static/vendor/fontawesome-free/svgs/brands/servicestack.svg +1 -0
  693. package/static/vendor/fontawesome-free/svgs/brands/shirtsinbulk.svg +1 -0
  694. package/static/vendor/fontawesome-free/svgs/brands/shopify.svg +1 -0
  695. package/static/vendor/fontawesome-free/svgs/brands/shopware.svg +1 -0
  696. package/static/vendor/fontawesome-free/svgs/brands/simplybuilt.svg +1 -0
  697. package/static/vendor/fontawesome-free/svgs/brands/sistrix.svg +1 -0
  698. package/static/vendor/fontawesome-free/svgs/brands/sith.svg +1 -0
  699. package/static/vendor/fontawesome-free/svgs/brands/sketch.svg +1 -0
  700. package/static/vendor/fontawesome-free/svgs/brands/skyatlas.svg +1 -0
  701. package/static/vendor/fontawesome-free/svgs/brands/skype.svg +1 -0
  702. package/static/vendor/fontawesome-free/svgs/brands/slack-hash.svg +1 -0
  703. package/static/vendor/fontawesome-free/svgs/brands/slack.svg +1 -0
  704. package/static/vendor/fontawesome-free/svgs/brands/slideshare.svg +1 -0
  705. package/static/vendor/fontawesome-free/svgs/brands/snapchat-ghost.svg +1 -0
  706. package/static/vendor/fontawesome-free/svgs/brands/snapchat-square.svg +1 -0
  707. package/static/vendor/fontawesome-free/svgs/brands/snapchat.svg +1 -0
  708. package/static/vendor/fontawesome-free/svgs/brands/soundcloud.svg +1 -0
  709. package/static/vendor/fontawesome-free/svgs/brands/sourcetree.svg +1 -0
  710. package/static/vendor/fontawesome-free/svgs/brands/speakap.svg +1 -0
  711. package/static/vendor/fontawesome-free/svgs/brands/speaker-deck.svg +1 -0
  712. package/static/vendor/fontawesome-free/svgs/brands/spotify.svg +1 -0
  713. package/static/vendor/fontawesome-free/svgs/brands/squarespace.svg +1 -0
  714. package/static/vendor/fontawesome-free/svgs/brands/stack-exchange.svg +1 -0
  715. package/static/vendor/fontawesome-free/svgs/brands/stack-overflow.svg +1 -0
  716. package/static/vendor/fontawesome-free/svgs/brands/stackpath.svg +1 -0
  717. package/static/vendor/fontawesome-free/svgs/brands/staylinked.svg +1 -0
  718. package/static/vendor/fontawesome-free/svgs/brands/steam-square.svg +1 -0
  719. package/static/vendor/fontawesome-free/svgs/brands/steam-symbol.svg +1 -0
  720. package/static/vendor/fontawesome-free/svgs/brands/steam.svg +1 -0
  721. package/static/vendor/fontawesome-free/svgs/brands/sticker-mule.svg +1 -0
  722. package/static/vendor/fontawesome-free/svgs/brands/strava.svg +1 -0
  723. package/static/vendor/fontawesome-free/svgs/brands/stripe-s.svg +1 -0
  724. package/static/vendor/fontawesome-free/svgs/brands/stripe.svg +1 -0
  725. package/static/vendor/fontawesome-free/svgs/brands/studiovinari.svg +1 -0
  726. package/static/vendor/fontawesome-free/svgs/brands/stumbleupon-circle.svg +1 -0
  727. package/static/vendor/fontawesome-free/svgs/brands/stumbleupon.svg +1 -0
  728. package/static/vendor/fontawesome-free/svgs/brands/superpowers.svg +1 -0
  729. package/static/vendor/fontawesome-free/svgs/brands/supple.svg +1 -0
  730. package/static/vendor/fontawesome-free/svgs/brands/suse.svg +1 -0
  731. package/static/vendor/fontawesome-free/svgs/brands/swift.svg +1 -0
  732. package/static/vendor/fontawesome-free/svgs/brands/symfony.svg +1 -0
  733. package/static/vendor/fontawesome-free/svgs/brands/teamspeak.svg +1 -0
  734. package/static/vendor/fontawesome-free/svgs/brands/telegram-plane.svg +1 -0
  735. package/static/vendor/fontawesome-free/svgs/brands/telegram.svg +1 -0
  736. package/static/vendor/fontawesome-free/svgs/brands/tencent-weibo.svg +1 -0
  737. package/static/vendor/fontawesome-free/svgs/brands/the-red-yeti.svg +1 -0
  738. package/static/vendor/fontawesome-free/svgs/brands/themeco.svg +1 -0
  739. package/static/vendor/fontawesome-free/svgs/brands/themeisle.svg +1 -0
  740. package/static/vendor/fontawesome-free/svgs/brands/think-peaks.svg +1 -0
  741. package/static/vendor/fontawesome-free/svgs/brands/tiktok.svg +1 -0
  742. package/static/vendor/fontawesome-free/svgs/brands/trade-federation.svg +1 -0
  743. package/static/vendor/fontawesome-free/svgs/brands/trello.svg +1 -0
  744. package/static/vendor/fontawesome-free/svgs/brands/tripadvisor.svg +1 -0
  745. package/static/vendor/fontawesome-free/svgs/brands/tumblr-square.svg +1 -0
  746. package/static/vendor/fontawesome-free/svgs/brands/tumblr.svg +1 -0
  747. package/static/vendor/fontawesome-free/svgs/brands/twitch.svg +1 -0
  748. package/static/vendor/fontawesome-free/svgs/brands/twitter-square.svg +1 -0
  749. package/static/vendor/fontawesome-free/svgs/brands/twitter.svg +1 -0
  750. package/static/vendor/fontawesome-free/svgs/brands/typo3.svg +1 -0
  751. package/static/vendor/fontawesome-free/svgs/brands/uber.svg +1 -0
  752. package/static/vendor/fontawesome-free/svgs/brands/ubuntu.svg +1 -0
  753. package/static/vendor/fontawesome-free/svgs/brands/uikit.svg +1 -0
  754. package/static/vendor/fontawesome-free/svgs/brands/umbraco.svg +1 -0
  755. package/static/vendor/fontawesome-free/svgs/brands/uncharted.svg +1 -0
  756. package/static/vendor/fontawesome-free/svgs/brands/uniregistry.svg +1 -0
  757. package/static/vendor/fontawesome-free/svgs/brands/unity.svg +1 -0
  758. package/static/vendor/fontawesome-free/svgs/brands/unsplash.svg +1 -0
  759. package/static/vendor/fontawesome-free/svgs/brands/untappd.svg +1 -0
  760. package/static/vendor/fontawesome-free/svgs/brands/ups.svg +1 -0
  761. package/static/vendor/fontawesome-free/svgs/brands/usb.svg +1 -0
  762. package/static/vendor/fontawesome-free/svgs/brands/usps.svg +1 -0
  763. package/static/vendor/fontawesome-free/svgs/brands/ussunnah.svg +1 -0
  764. package/static/vendor/fontawesome-free/svgs/brands/vaadin.svg +1 -0
  765. package/static/vendor/fontawesome-free/svgs/brands/viacoin.svg +1 -0
  766. package/static/vendor/fontawesome-free/svgs/brands/viadeo-square.svg +1 -0
  767. package/static/vendor/fontawesome-free/svgs/brands/viadeo.svg +1 -0
  768. package/static/vendor/fontawesome-free/svgs/brands/viber.svg +1 -0
  769. package/static/vendor/fontawesome-free/svgs/brands/vimeo-square.svg +1 -0
  770. package/static/vendor/fontawesome-free/svgs/brands/vimeo-v.svg +1 -0
  771. package/static/vendor/fontawesome-free/svgs/brands/vimeo.svg +1 -0
  772. package/static/vendor/fontawesome-free/svgs/brands/vine.svg +1 -0
  773. package/static/vendor/fontawesome-free/svgs/brands/vk.svg +1 -0
  774. package/static/vendor/fontawesome-free/svgs/brands/vnv.svg +1 -0
  775. package/static/vendor/fontawesome-free/svgs/brands/vuejs.svg +1 -0
  776. package/static/vendor/fontawesome-free/svgs/brands/watchman-monitoring.svg +1 -0
  777. package/static/vendor/fontawesome-free/svgs/brands/waze.svg +1 -0
  778. package/static/vendor/fontawesome-free/svgs/brands/weebly.svg +1 -0
  779. package/static/vendor/fontawesome-free/svgs/brands/weibo.svg +1 -0
  780. package/static/vendor/fontawesome-free/svgs/brands/weixin.svg +1 -0
  781. package/static/vendor/fontawesome-free/svgs/brands/whatsapp-square.svg +1 -0
  782. package/static/vendor/fontawesome-free/svgs/brands/whatsapp.svg +1 -0
  783. package/static/vendor/fontawesome-free/svgs/brands/whmcs.svg +1 -0
  784. package/static/vendor/fontawesome-free/svgs/brands/wikipedia-w.svg +1 -0
  785. package/static/vendor/fontawesome-free/svgs/brands/windows.svg +1 -0
  786. package/static/vendor/fontawesome-free/svgs/brands/wix.svg +1 -0
  787. package/static/vendor/fontawesome-free/svgs/brands/wizards-of-the-coast.svg +1 -0
  788. package/static/vendor/fontawesome-free/svgs/brands/wodu.svg +1 -0
  789. package/static/vendor/fontawesome-free/svgs/brands/wolf-pack-battalion.svg +1 -0
  790. package/static/vendor/fontawesome-free/svgs/brands/wordpress-simple.svg +1 -0
  791. package/static/vendor/fontawesome-free/svgs/brands/wordpress.svg +1 -0
  792. package/static/vendor/fontawesome-free/svgs/brands/wpbeginner.svg +1 -0
  793. package/static/vendor/fontawesome-free/svgs/brands/wpexplorer.svg +1 -0
  794. package/static/vendor/fontawesome-free/svgs/brands/wpforms.svg +1 -0
  795. package/static/vendor/fontawesome-free/svgs/brands/wpressr.svg +1 -0
  796. package/static/vendor/fontawesome-free/svgs/brands/xbox.svg +1 -0
  797. package/static/vendor/fontawesome-free/svgs/brands/xing-square.svg +1 -0
  798. package/static/vendor/fontawesome-free/svgs/brands/xing.svg +1 -0
  799. package/static/vendor/fontawesome-free/svgs/brands/y-combinator.svg +1 -0
  800. package/static/vendor/fontawesome-free/svgs/brands/yahoo.svg +1 -0
  801. package/static/vendor/fontawesome-free/svgs/brands/yammer.svg +1 -0
  802. package/static/vendor/fontawesome-free/svgs/brands/yandex-international.svg +1 -0
  803. package/static/vendor/fontawesome-free/svgs/brands/yandex.svg +1 -0
  804. package/static/vendor/fontawesome-free/svgs/brands/yarn.svg +1 -0
  805. package/static/vendor/fontawesome-free/svgs/brands/yelp.svg +1 -0
  806. package/static/vendor/fontawesome-free/svgs/brands/yoast.svg +1 -0
  807. package/static/vendor/fontawesome-free/svgs/brands/youtube-square.svg +1 -0
  808. package/static/vendor/fontawesome-free/svgs/brands/youtube.svg +1 -0
  809. package/static/vendor/fontawesome-free/svgs/brands/zhihu.svg +1 -0
  810. package/static/vendor/fontawesome-free/svgs/regular/address-book.svg +1 -0
  811. package/static/vendor/fontawesome-free/svgs/regular/address-card.svg +1 -0
  812. package/static/vendor/fontawesome-free/svgs/regular/angry.svg +1 -0
  813. package/static/vendor/fontawesome-free/svgs/regular/arrow-alt-circle-down.svg +1 -0
  814. package/static/vendor/fontawesome-free/svgs/regular/arrow-alt-circle-left.svg +1 -0
  815. package/static/vendor/fontawesome-free/svgs/regular/arrow-alt-circle-right.svg +1 -0
  816. package/static/vendor/fontawesome-free/svgs/regular/arrow-alt-circle-up.svg +1 -0
  817. package/static/vendor/fontawesome-free/svgs/regular/bell-slash.svg +1 -0
  818. package/static/vendor/fontawesome-free/svgs/regular/bell.svg +1 -0
  819. package/static/vendor/fontawesome-free/svgs/regular/bookmark.svg +1 -0
  820. package/static/vendor/fontawesome-free/svgs/regular/building.svg +1 -0
  821. package/static/vendor/fontawesome-free/svgs/regular/calendar-alt.svg +1 -0
  822. package/static/vendor/fontawesome-free/svgs/regular/calendar-check.svg +1 -0
  823. package/static/vendor/fontawesome-free/svgs/regular/calendar-minus.svg +1 -0
  824. package/static/vendor/fontawesome-free/svgs/regular/calendar-plus.svg +1 -0
  825. package/static/vendor/fontawesome-free/svgs/regular/calendar-times.svg +1 -0
  826. package/static/vendor/fontawesome-free/svgs/regular/calendar.svg +1 -0
  827. package/static/vendor/fontawesome-free/svgs/regular/caret-square-down.svg +1 -0
  828. package/static/vendor/fontawesome-free/svgs/regular/caret-square-left.svg +1 -0
  829. package/static/vendor/fontawesome-free/svgs/regular/caret-square-right.svg +1 -0
  830. package/static/vendor/fontawesome-free/svgs/regular/caret-square-up.svg +1 -0
  831. package/static/vendor/fontawesome-free/svgs/regular/chart-bar.svg +1 -0
  832. package/static/vendor/fontawesome-free/svgs/regular/check-circle.svg +1 -0
  833. package/static/vendor/fontawesome-free/svgs/regular/check-square.svg +1 -0
  834. package/static/vendor/fontawesome-free/svgs/regular/circle.svg +1 -0
  835. package/static/vendor/fontawesome-free/svgs/regular/clipboard.svg +1 -0
  836. package/static/vendor/fontawesome-free/svgs/regular/clock.svg +1 -0
  837. package/static/vendor/fontawesome-free/svgs/regular/clone.svg +1 -0
  838. package/static/vendor/fontawesome-free/svgs/regular/closed-captioning.svg +1 -0
  839. package/static/vendor/fontawesome-free/svgs/regular/comment-alt.svg +1 -0
  840. package/static/vendor/fontawesome-free/svgs/regular/comment-dots.svg +1 -0
  841. package/static/vendor/fontawesome-free/svgs/regular/comment.svg +1 -0
  842. package/static/vendor/fontawesome-free/svgs/regular/comments.svg +1 -0
  843. package/static/vendor/fontawesome-free/svgs/regular/compass.svg +1 -0
  844. package/static/vendor/fontawesome-free/svgs/regular/copy.svg +1 -0
  845. package/static/vendor/fontawesome-free/svgs/regular/copyright.svg +1 -0
  846. package/static/vendor/fontawesome-free/svgs/regular/credit-card.svg +1 -0
  847. package/static/vendor/fontawesome-free/svgs/regular/dizzy.svg +1 -0
  848. package/static/vendor/fontawesome-free/svgs/regular/dot-circle.svg +1 -0
  849. package/static/vendor/fontawesome-free/svgs/regular/edit.svg +1 -0
  850. package/static/vendor/fontawesome-free/svgs/regular/envelope-open.svg +1 -0
  851. package/static/vendor/fontawesome-free/svgs/regular/envelope.svg +1 -0
  852. package/static/vendor/fontawesome-free/svgs/regular/eye-slash.svg +1 -0
  853. package/static/vendor/fontawesome-free/svgs/regular/eye.svg +1 -0
  854. package/static/vendor/fontawesome-free/svgs/regular/file-alt.svg +1 -0
  855. package/static/vendor/fontawesome-free/svgs/regular/file-archive.svg +1 -0
  856. package/static/vendor/fontawesome-free/svgs/regular/file-audio.svg +1 -0
  857. package/static/vendor/fontawesome-free/svgs/regular/file-code.svg +1 -0
  858. package/static/vendor/fontawesome-free/svgs/regular/file-excel.svg +1 -0
  859. package/static/vendor/fontawesome-free/svgs/regular/file-image.svg +1 -0
  860. package/static/vendor/fontawesome-free/svgs/regular/file-pdf.svg +1 -0
  861. package/static/vendor/fontawesome-free/svgs/regular/file-powerpoint.svg +1 -0
  862. package/static/vendor/fontawesome-free/svgs/regular/file-video.svg +1 -0
  863. package/static/vendor/fontawesome-free/svgs/regular/file-word.svg +1 -0
  864. package/static/vendor/fontawesome-free/svgs/regular/file.svg +1 -0
  865. package/static/vendor/fontawesome-free/svgs/regular/flag.svg +1 -0
  866. package/static/vendor/fontawesome-free/svgs/regular/flushed.svg +1 -0
  867. package/static/vendor/fontawesome-free/svgs/regular/folder-open.svg +1 -0
  868. package/static/vendor/fontawesome-free/svgs/regular/folder.svg +1 -0
  869. package/static/vendor/fontawesome-free/svgs/regular/font-awesome-logo-full.svg +1 -0
  870. package/static/vendor/fontawesome-free/svgs/regular/frown-open.svg +1 -0
  871. package/static/vendor/fontawesome-free/svgs/regular/frown.svg +1 -0
  872. package/static/vendor/fontawesome-free/svgs/regular/futbol.svg +1 -0
  873. package/static/vendor/fontawesome-free/svgs/regular/gem.svg +1 -0
  874. package/static/vendor/fontawesome-free/svgs/regular/grimace.svg +1 -0
  875. package/static/vendor/fontawesome-free/svgs/regular/grin-alt.svg +1 -0
  876. package/static/vendor/fontawesome-free/svgs/regular/grin-beam-sweat.svg +1 -0
  877. package/static/vendor/fontawesome-free/svgs/regular/grin-beam.svg +1 -0
  878. package/static/vendor/fontawesome-free/svgs/regular/grin-hearts.svg +1 -0
  879. package/static/vendor/fontawesome-free/svgs/regular/grin-squint-tears.svg +1 -0
  880. package/static/vendor/fontawesome-free/svgs/regular/grin-squint.svg +1 -0
  881. package/static/vendor/fontawesome-free/svgs/regular/grin-stars.svg +1 -0
  882. package/static/vendor/fontawesome-free/svgs/regular/grin-tears.svg +1 -0
  883. package/static/vendor/fontawesome-free/svgs/regular/grin-tongue-squint.svg +1 -0
  884. package/static/vendor/fontawesome-free/svgs/regular/grin-tongue-wink.svg +1 -0
  885. package/static/vendor/fontawesome-free/svgs/regular/grin-tongue.svg +1 -0
  886. package/static/vendor/fontawesome-free/svgs/regular/grin-wink.svg +1 -0
  887. package/static/vendor/fontawesome-free/svgs/regular/grin.svg +1 -0
  888. package/static/vendor/fontawesome-free/svgs/regular/hand-lizard.svg +1 -0
  889. package/static/vendor/fontawesome-free/svgs/regular/hand-paper.svg +1 -0
  890. package/static/vendor/fontawesome-free/svgs/regular/hand-peace.svg +1 -0
  891. package/static/vendor/fontawesome-free/svgs/regular/hand-point-down.svg +1 -0
  892. package/static/vendor/fontawesome-free/svgs/regular/hand-point-left.svg +1 -0
  893. package/static/vendor/fontawesome-free/svgs/regular/hand-point-right.svg +1 -0
  894. package/static/vendor/fontawesome-free/svgs/regular/hand-point-up.svg +1 -0
  895. package/static/vendor/fontawesome-free/svgs/regular/hand-pointer.svg +1 -0
  896. package/static/vendor/fontawesome-free/svgs/regular/hand-rock.svg +1 -0
  897. package/static/vendor/fontawesome-free/svgs/regular/hand-scissors.svg +1 -0
  898. package/static/vendor/fontawesome-free/svgs/regular/hand-spock.svg +1 -0
  899. package/static/vendor/fontawesome-free/svgs/regular/handshake.svg +1 -0
  900. package/static/vendor/fontawesome-free/svgs/regular/hdd.svg +1 -0
  901. package/static/vendor/fontawesome-free/svgs/regular/heart.svg +1 -0
  902. package/static/vendor/fontawesome-free/svgs/regular/hospital.svg +1 -0
  903. package/static/vendor/fontawesome-free/svgs/regular/hourglass.svg +1 -0
  904. package/static/vendor/fontawesome-free/svgs/regular/id-badge.svg +1 -0
  905. package/static/vendor/fontawesome-free/svgs/regular/id-card.svg +1 -0
  906. package/static/vendor/fontawesome-free/svgs/regular/image.svg +1 -0
  907. package/static/vendor/fontawesome-free/svgs/regular/images.svg +1 -0
  908. package/static/vendor/fontawesome-free/svgs/regular/keyboard.svg +1 -0
  909. package/static/vendor/fontawesome-free/svgs/regular/kiss-beam.svg +1 -0
  910. package/static/vendor/fontawesome-free/svgs/regular/kiss-wink-heart.svg +1 -0
  911. package/static/vendor/fontawesome-free/svgs/regular/kiss.svg +1 -0
  912. package/static/vendor/fontawesome-free/svgs/regular/laugh-beam.svg +1 -0
  913. package/static/vendor/fontawesome-free/svgs/regular/laugh-squint.svg +1 -0
  914. package/static/vendor/fontawesome-free/svgs/regular/laugh-wink.svg +1 -0
  915. package/static/vendor/fontawesome-free/svgs/regular/laugh.svg +1 -0
  916. package/static/vendor/fontawesome-free/svgs/regular/lemon.svg +1 -0
  917. package/static/vendor/fontawesome-free/svgs/regular/life-ring.svg +1 -0
  918. package/static/vendor/fontawesome-free/svgs/regular/lightbulb.svg +1 -0
  919. package/static/vendor/fontawesome-free/svgs/regular/list-alt.svg +1 -0
  920. package/static/vendor/fontawesome-free/svgs/regular/map.svg +1 -0
  921. package/static/vendor/fontawesome-free/svgs/regular/meh-blank.svg +1 -0
  922. package/static/vendor/fontawesome-free/svgs/regular/meh-rolling-eyes.svg +1 -0
  923. package/static/vendor/fontawesome-free/svgs/regular/meh.svg +1 -0
  924. package/static/vendor/fontawesome-free/svgs/regular/minus-square.svg +1 -0
  925. package/static/vendor/fontawesome-free/svgs/regular/money-bill-alt.svg +1 -0
  926. package/static/vendor/fontawesome-free/svgs/regular/moon.svg +1 -0
  927. package/static/vendor/fontawesome-free/svgs/regular/newspaper.svg +1 -0
  928. package/static/vendor/fontawesome-free/svgs/regular/object-group.svg +1 -0
  929. package/static/vendor/fontawesome-free/svgs/regular/object-ungroup.svg +1 -0
  930. package/static/vendor/fontawesome-free/svgs/regular/paper-plane.svg +1 -0
  931. package/static/vendor/fontawesome-free/svgs/regular/pause-circle.svg +1 -0
  932. package/static/vendor/fontawesome-free/svgs/regular/play-circle.svg +1 -0
  933. package/static/vendor/fontawesome-free/svgs/regular/plus-square.svg +1 -0
  934. package/static/vendor/fontawesome-free/svgs/regular/question-circle.svg +1 -0
  935. package/static/vendor/fontawesome-free/svgs/regular/registered.svg +1 -0
  936. package/static/vendor/fontawesome-free/svgs/regular/sad-cry.svg +1 -0
  937. package/static/vendor/fontawesome-free/svgs/regular/sad-tear.svg +1 -0
  938. package/static/vendor/fontawesome-free/svgs/regular/save.svg +1 -0
  939. package/static/vendor/fontawesome-free/svgs/regular/share-square.svg +1 -0
  940. package/static/vendor/fontawesome-free/svgs/regular/smile-beam.svg +1 -0
  941. package/static/vendor/fontawesome-free/svgs/regular/smile-wink.svg +1 -0
  942. package/static/vendor/fontawesome-free/svgs/regular/smile.svg +1 -0
  943. package/static/vendor/fontawesome-free/svgs/regular/snowflake.svg +1 -0
  944. package/static/vendor/fontawesome-free/svgs/regular/square.svg +1 -0
  945. package/static/vendor/fontawesome-free/svgs/regular/star-half.svg +1 -0
  946. package/static/vendor/fontawesome-free/svgs/regular/star.svg +1 -0
  947. package/static/vendor/fontawesome-free/svgs/regular/sticky-note.svg +1 -0
  948. package/static/vendor/fontawesome-free/svgs/regular/stop-circle.svg +1 -0
  949. package/static/vendor/fontawesome-free/svgs/regular/sun.svg +1 -0
  950. package/static/vendor/fontawesome-free/svgs/regular/surprise.svg +1 -0
  951. package/static/vendor/fontawesome-free/svgs/regular/thumbs-down.svg +1 -0
  952. package/static/vendor/fontawesome-free/svgs/regular/thumbs-up.svg +1 -0
  953. package/static/vendor/fontawesome-free/svgs/regular/times-circle.svg +1 -0
  954. package/static/vendor/fontawesome-free/svgs/regular/tired.svg +1 -0
  955. package/static/vendor/fontawesome-free/svgs/regular/trash-alt.svg +1 -0
  956. package/static/vendor/fontawesome-free/svgs/regular/user-circle.svg +1 -0
  957. package/static/vendor/fontawesome-free/svgs/regular/user.svg +1 -0
  958. package/static/vendor/fontawesome-free/svgs/regular/window-close.svg +1 -0
  959. package/static/vendor/fontawesome-free/svgs/regular/window-maximize.svg +1 -0
  960. package/static/vendor/fontawesome-free/svgs/regular/window-minimize.svg +1 -0
  961. package/static/vendor/fontawesome-free/svgs/regular/window-restore.svg +1 -0
  962. package/static/vendor/fontawesome-free/svgs/solid/ad.svg +1 -0
  963. package/static/vendor/fontawesome-free/svgs/solid/address-book.svg +1 -0
  964. package/static/vendor/fontawesome-free/svgs/solid/address-card.svg +1 -0
  965. package/static/vendor/fontawesome-free/svgs/solid/adjust.svg +1 -0
  966. package/static/vendor/fontawesome-free/svgs/solid/air-freshener.svg +1 -0
  967. package/static/vendor/fontawesome-free/svgs/solid/align-center.svg +1 -0
  968. package/static/vendor/fontawesome-free/svgs/solid/align-justify.svg +1 -0
  969. package/static/vendor/fontawesome-free/svgs/solid/align-left.svg +1 -0
  970. package/static/vendor/fontawesome-free/svgs/solid/align-right.svg +1 -0
  971. package/static/vendor/fontawesome-free/svgs/solid/allergies.svg +1 -0
  972. package/static/vendor/fontawesome-free/svgs/solid/ambulance.svg +1 -0
  973. package/static/vendor/fontawesome-free/svgs/solid/american-sign-language-interpreting.svg +1 -0
  974. package/static/vendor/fontawesome-free/svgs/solid/anchor.svg +1 -0
  975. package/static/vendor/fontawesome-free/svgs/solid/angle-double-down.svg +1 -0
  976. package/static/vendor/fontawesome-free/svgs/solid/angle-double-left.svg +1 -0
  977. package/static/vendor/fontawesome-free/svgs/solid/angle-double-right.svg +1 -0
  978. package/static/vendor/fontawesome-free/svgs/solid/angle-double-up.svg +1 -0
  979. package/static/vendor/fontawesome-free/svgs/solid/angle-down.svg +1 -0
  980. package/static/vendor/fontawesome-free/svgs/solid/angle-left.svg +1 -0
  981. package/static/vendor/fontawesome-free/svgs/solid/angle-right.svg +1 -0
  982. package/static/vendor/fontawesome-free/svgs/solid/angle-up.svg +1 -0
  983. package/static/vendor/fontawesome-free/svgs/solid/angry.svg +1 -0
  984. package/static/vendor/fontawesome-free/svgs/solid/ankh.svg +1 -0
  985. package/static/vendor/fontawesome-free/svgs/solid/apple-alt.svg +1 -0
  986. package/static/vendor/fontawesome-free/svgs/solid/archive.svg +1 -0
  987. package/static/vendor/fontawesome-free/svgs/solid/archway.svg +1 -0
  988. package/static/vendor/fontawesome-free/svgs/solid/arrow-alt-circle-down.svg +1 -0
  989. package/static/vendor/fontawesome-free/svgs/solid/arrow-alt-circle-left.svg +1 -0
  990. package/static/vendor/fontawesome-free/svgs/solid/arrow-alt-circle-right.svg +1 -0
  991. package/static/vendor/fontawesome-free/svgs/solid/arrow-alt-circle-up.svg +1 -0
  992. package/static/vendor/fontawesome-free/svgs/solid/arrow-circle-down.svg +1 -0
  993. package/static/vendor/fontawesome-free/svgs/solid/arrow-circle-left.svg +1 -0
  994. package/static/vendor/fontawesome-free/svgs/solid/arrow-circle-right.svg +1 -0
  995. package/static/vendor/fontawesome-free/svgs/solid/arrow-circle-up.svg +1 -0
  996. package/static/vendor/fontawesome-free/svgs/solid/arrow-down.svg +1 -0
  997. package/static/vendor/fontawesome-free/svgs/solid/arrow-left.svg +1 -0
  998. package/static/vendor/fontawesome-free/svgs/solid/arrow-right.svg +1 -0
  999. package/static/vendor/fontawesome-free/svgs/solid/arrow-up.svg +1 -0
  1000. package/static/vendor/fontawesome-free/svgs/solid/arrows-alt-h.svg +1 -0
  1001. package/static/vendor/fontawesome-free/svgs/solid/arrows-alt-v.svg +1 -0
  1002. package/static/vendor/fontawesome-free/svgs/solid/arrows-alt.svg +1 -0
  1003. package/static/vendor/fontawesome-free/svgs/solid/assistive-listening-systems.svg +1 -0
  1004. package/static/vendor/fontawesome-free/svgs/solid/asterisk.svg +1 -0
  1005. package/static/vendor/fontawesome-free/svgs/solid/at.svg +1 -0
  1006. package/static/vendor/fontawesome-free/svgs/solid/atlas.svg +1 -0
  1007. package/static/vendor/fontawesome-free/svgs/solid/atom.svg +1 -0
  1008. package/static/vendor/fontawesome-free/svgs/solid/audio-description.svg +1 -0
  1009. package/static/vendor/fontawesome-free/svgs/solid/award.svg +1 -0
  1010. package/static/vendor/fontawesome-free/svgs/solid/baby-carriage.svg +1 -0
  1011. package/static/vendor/fontawesome-free/svgs/solid/baby.svg +1 -0
  1012. package/static/vendor/fontawesome-free/svgs/solid/backspace.svg +1 -0
  1013. package/static/vendor/fontawesome-free/svgs/solid/backward.svg +1 -0
  1014. package/static/vendor/fontawesome-free/svgs/solid/bacon.svg +1 -0
  1015. package/static/vendor/fontawesome-free/svgs/solid/bacteria.svg +1 -0
  1016. package/static/vendor/fontawesome-free/svgs/solid/bacterium.svg +1 -0
  1017. package/static/vendor/fontawesome-free/svgs/solid/bahai.svg +1 -0
  1018. package/static/vendor/fontawesome-free/svgs/solid/balance-scale-left.svg +1 -0
  1019. package/static/vendor/fontawesome-free/svgs/solid/balance-scale-right.svg +1 -0
  1020. package/static/vendor/fontawesome-free/svgs/solid/balance-scale.svg +1 -0
  1021. package/static/vendor/fontawesome-free/svgs/solid/ban.svg +1 -0
  1022. package/static/vendor/fontawesome-free/svgs/solid/band-aid.svg +1 -0
  1023. package/static/vendor/fontawesome-free/svgs/solid/barcode.svg +1 -0
  1024. package/static/vendor/fontawesome-free/svgs/solid/bars.svg +1 -0
  1025. package/static/vendor/fontawesome-free/svgs/solid/baseball-ball.svg +1 -0
  1026. package/static/vendor/fontawesome-free/svgs/solid/basketball-ball.svg +1 -0
  1027. package/static/vendor/fontawesome-free/svgs/solid/bath.svg +1 -0
  1028. package/static/vendor/fontawesome-free/svgs/solid/battery-empty.svg +1 -0
  1029. package/static/vendor/fontawesome-free/svgs/solid/battery-full.svg +1 -0
  1030. package/static/vendor/fontawesome-free/svgs/solid/battery-half.svg +1 -0
  1031. package/static/vendor/fontawesome-free/svgs/solid/battery-quarter.svg +1 -0
  1032. package/static/vendor/fontawesome-free/svgs/solid/battery-three-quarters.svg +1 -0
  1033. package/static/vendor/fontawesome-free/svgs/solid/bed.svg +1 -0
  1034. package/static/vendor/fontawesome-free/svgs/solid/beer.svg +1 -0
  1035. package/static/vendor/fontawesome-free/svgs/solid/bell-slash.svg +1 -0
  1036. package/static/vendor/fontawesome-free/svgs/solid/bell.svg +1 -0
  1037. package/static/vendor/fontawesome-free/svgs/solid/bezier-curve.svg +1 -0
  1038. package/static/vendor/fontawesome-free/svgs/solid/bible.svg +1 -0
  1039. package/static/vendor/fontawesome-free/svgs/solid/bicycle.svg +1 -0
  1040. package/static/vendor/fontawesome-free/svgs/solid/biking.svg +1 -0
  1041. package/static/vendor/fontawesome-free/svgs/solid/binoculars.svg +1 -0
  1042. package/static/vendor/fontawesome-free/svgs/solid/biohazard.svg +1 -0
  1043. package/static/vendor/fontawesome-free/svgs/solid/birthday-cake.svg +1 -0
  1044. package/static/vendor/fontawesome-free/svgs/solid/blender-phone.svg +1 -0
  1045. package/static/vendor/fontawesome-free/svgs/solid/blender.svg +1 -0
  1046. package/static/vendor/fontawesome-free/svgs/solid/blind.svg +1 -0
  1047. package/static/vendor/fontawesome-free/svgs/solid/blog.svg +1 -0
  1048. package/static/vendor/fontawesome-free/svgs/solid/bold.svg +1 -0
  1049. package/static/vendor/fontawesome-free/svgs/solid/bolt.svg +1 -0
  1050. package/static/vendor/fontawesome-free/svgs/solid/bomb.svg +1 -0
  1051. package/static/vendor/fontawesome-free/svgs/solid/bone.svg +1 -0
  1052. package/static/vendor/fontawesome-free/svgs/solid/bong.svg +1 -0
  1053. package/static/vendor/fontawesome-free/svgs/solid/book-dead.svg +1 -0
  1054. package/static/vendor/fontawesome-free/svgs/solid/book-medical.svg +1 -0
  1055. package/static/vendor/fontawesome-free/svgs/solid/book-open.svg +1 -0
  1056. package/static/vendor/fontawesome-free/svgs/solid/book-reader.svg +1 -0
  1057. package/static/vendor/fontawesome-free/svgs/solid/book.svg +1 -0
  1058. package/static/vendor/fontawesome-free/svgs/solid/bookmark.svg +1 -0
  1059. package/static/vendor/fontawesome-free/svgs/solid/border-all.svg +1 -0
  1060. package/static/vendor/fontawesome-free/svgs/solid/border-none.svg +1 -0
  1061. package/static/vendor/fontawesome-free/svgs/solid/border-style.svg +1 -0
  1062. package/static/vendor/fontawesome-free/svgs/solid/bowling-ball.svg +1 -0
  1063. package/static/vendor/fontawesome-free/svgs/solid/box-open.svg +1 -0
  1064. package/static/vendor/fontawesome-free/svgs/solid/box-tissue.svg +1 -0
  1065. package/static/vendor/fontawesome-free/svgs/solid/box.svg +1 -0
  1066. package/static/vendor/fontawesome-free/svgs/solid/boxes.svg +1 -0
  1067. package/static/vendor/fontawesome-free/svgs/solid/braille.svg +1 -0
  1068. package/static/vendor/fontawesome-free/svgs/solid/brain.svg +1 -0
  1069. package/static/vendor/fontawesome-free/svgs/solid/bread-slice.svg +1 -0
  1070. package/static/vendor/fontawesome-free/svgs/solid/briefcase-medical.svg +1 -0
  1071. package/static/vendor/fontawesome-free/svgs/solid/briefcase.svg +1 -0
  1072. package/static/vendor/fontawesome-free/svgs/solid/broadcast-tower.svg +1 -0
  1073. package/static/vendor/fontawesome-free/svgs/solid/broom.svg +1 -0
  1074. package/static/vendor/fontawesome-free/svgs/solid/brush.svg +1 -0
  1075. package/static/vendor/fontawesome-free/svgs/solid/bug.svg +1 -0
  1076. package/static/vendor/fontawesome-free/svgs/solid/building.svg +1 -0
  1077. package/static/vendor/fontawesome-free/svgs/solid/bullhorn.svg +1 -0
  1078. package/static/vendor/fontawesome-free/svgs/solid/bullseye.svg +1 -0
  1079. package/static/vendor/fontawesome-free/svgs/solid/burn.svg +1 -0
  1080. package/static/vendor/fontawesome-free/svgs/solid/bus-alt.svg +1 -0
  1081. package/static/vendor/fontawesome-free/svgs/solid/bus.svg +1 -0
  1082. package/static/vendor/fontawesome-free/svgs/solid/business-time.svg +1 -0
  1083. package/static/vendor/fontawesome-free/svgs/solid/calculator.svg +1 -0
  1084. package/static/vendor/fontawesome-free/svgs/solid/calendar-alt.svg +1 -0
  1085. package/static/vendor/fontawesome-free/svgs/solid/calendar-check.svg +1 -0
  1086. package/static/vendor/fontawesome-free/svgs/solid/calendar-day.svg +1 -0
  1087. package/static/vendor/fontawesome-free/svgs/solid/calendar-minus.svg +1 -0
  1088. package/static/vendor/fontawesome-free/svgs/solid/calendar-plus.svg +1 -0
  1089. package/static/vendor/fontawesome-free/svgs/solid/calendar-times.svg +1 -0
  1090. package/static/vendor/fontawesome-free/svgs/solid/calendar-week.svg +1 -0
  1091. package/static/vendor/fontawesome-free/svgs/solid/calendar.svg +1 -0
  1092. package/static/vendor/fontawesome-free/svgs/solid/camera-retro.svg +1 -0
  1093. package/static/vendor/fontawesome-free/svgs/solid/camera.svg +1 -0
  1094. package/static/vendor/fontawesome-free/svgs/solid/campground.svg +1 -0
  1095. package/static/vendor/fontawesome-free/svgs/solid/candy-cane.svg +1 -0
  1096. package/static/vendor/fontawesome-free/svgs/solid/cannabis.svg +1 -0
  1097. package/static/vendor/fontawesome-free/svgs/solid/capsules.svg +1 -0
  1098. package/static/vendor/fontawesome-free/svgs/solid/car-alt.svg +1 -0
  1099. package/static/vendor/fontawesome-free/svgs/solid/car-battery.svg +1 -0
  1100. package/static/vendor/fontawesome-free/svgs/solid/car-crash.svg +1 -0
  1101. package/static/vendor/fontawesome-free/svgs/solid/car-side.svg +1 -0
  1102. package/static/vendor/fontawesome-free/svgs/solid/car.svg +1 -0
  1103. package/static/vendor/fontawesome-free/svgs/solid/caravan.svg +1 -0
  1104. package/static/vendor/fontawesome-free/svgs/solid/caret-down.svg +1 -0
  1105. package/static/vendor/fontawesome-free/svgs/solid/caret-left.svg +1 -0
  1106. package/static/vendor/fontawesome-free/svgs/solid/caret-right.svg +1 -0
  1107. package/static/vendor/fontawesome-free/svgs/solid/caret-square-down.svg +1 -0
  1108. package/static/vendor/fontawesome-free/svgs/solid/caret-square-left.svg +1 -0
  1109. package/static/vendor/fontawesome-free/svgs/solid/caret-square-right.svg +1 -0
  1110. package/static/vendor/fontawesome-free/svgs/solid/caret-square-up.svg +1 -0
  1111. package/static/vendor/fontawesome-free/svgs/solid/caret-up.svg +1 -0
  1112. package/static/vendor/fontawesome-free/svgs/solid/carrot.svg +1 -0
  1113. package/static/vendor/fontawesome-free/svgs/solid/cart-arrow-down.svg +1 -0
  1114. package/static/vendor/fontawesome-free/svgs/solid/cart-plus.svg +1 -0
  1115. package/static/vendor/fontawesome-free/svgs/solid/cash-register.svg +1 -0
  1116. package/static/vendor/fontawesome-free/svgs/solid/cat.svg +1 -0
  1117. package/static/vendor/fontawesome-free/svgs/solid/certificate.svg +1 -0
  1118. package/static/vendor/fontawesome-free/svgs/solid/chair.svg +1 -0
  1119. package/static/vendor/fontawesome-free/svgs/solid/chalkboard-teacher.svg +1 -0
  1120. package/static/vendor/fontawesome-free/svgs/solid/chalkboard.svg +1 -0
  1121. package/static/vendor/fontawesome-free/svgs/solid/charging-station.svg +1 -0
  1122. package/static/vendor/fontawesome-free/svgs/solid/chart-area.svg +1 -0
  1123. package/static/vendor/fontawesome-free/svgs/solid/chart-bar.svg +1 -0
  1124. package/static/vendor/fontawesome-free/svgs/solid/chart-line.svg +1 -0
  1125. package/static/vendor/fontawesome-free/svgs/solid/chart-pie.svg +1 -0
  1126. package/static/vendor/fontawesome-free/svgs/solid/check-circle.svg +1 -0
  1127. package/static/vendor/fontawesome-free/svgs/solid/check-double.svg +1 -0
  1128. package/static/vendor/fontawesome-free/svgs/solid/check-square.svg +1 -0
  1129. package/static/vendor/fontawesome-free/svgs/solid/check.svg +1 -0
  1130. package/static/vendor/fontawesome-free/svgs/solid/cheese.svg +1 -0
  1131. package/static/vendor/fontawesome-free/svgs/solid/chess-bishop.svg +1 -0
  1132. package/static/vendor/fontawesome-free/svgs/solid/chess-board.svg +1 -0
  1133. package/static/vendor/fontawesome-free/svgs/solid/chess-king.svg +1 -0
  1134. package/static/vendor/fontawesome-free/svgs/solid/chess-knight.svg +1 -0
  1135. package/static/vendor/fontawesome-free/svgs/solid/chess-pawn.svg +1 -0
  1136. package/static/vendor/fontawesome-free/svgs/solid/chess-queen.svg +1 -0
  1137. package/static/vendor/fontawesome-free/svgs/solid/chess-rook.svg +1 -0
  1138. package/static/vendor/fontawesome-free/svgs/solid/chess.svg +1 -0
  1139. package/static/vendor/fontawesome-free/svgs/solid/chevron-circle-down.svg +1 -0
  1140. package/static/vendor/fontawesome-free/svgs/solid/chevron-circle-left.svg +1 -0
  1141. package/static/vendor/fontawesome-free/svgs/solid/chevron-circle-right.svg +1 -0
  1142. package/static/vendor/fontawesome-free/svgs/solid/chevron-circle-up.svg +1 -0
  1143. package/static/vendor/fontawesome-free/svgs/solid/chevron-down.svg +1 -0
  1144. package/static/vendor/fontawesome-free/svgs/solid/chevron-left.svg +1 -0
  1145. package/static/vendor/fontawesome-free/svgs/solid/chevron-right.svg +1 -0
  1146. package/static/vendor/fontawesome-free/svgs/solid/chevron-up.svg +1 -0
  1147. package/static/vendor/fontawesome-free/svgs/solid/child.svg +1 -0
  1148. package/static/vendor/fontawesome-free/svgs/solid/church.svg +1 -0
  1149. package/static/vendor/fontawesome-free/svgs/solid/circle-notch.svg +1 -0
  1150. package/static/vendor/fontawesome-free/svgs/solid/circle.svg +1 -0
  1151. package/static/vendor/fontawesome-free/svgs/solid/city.svg +1 -0
  1152. package/static/vendor/fontawesome-free/svgs/solid/clinic-medical.svg +1 -0
  1153. package/static/vendor/fontawesome-free/svgs/solid/clipboard-check.svg +1 -0
  1154. package/static/vendor/fontawesome-free/svgs/solid/clipboard-list.svg +1 -0
  1155. package/static/vendor/fontawesome-free/svgs/solid/clipboard.svg +1 -0
  1156. package/static/vendor/fontawesome-free/svgs/solid/clock.svg +1 -0
  1157. package/static/vendor/fontawesome-free/svgs/solid/clone.svg +1 -0
  1158. package/static/vendor/fontawesome-free/svgs/solid/closed-captioning.svg +1 -0
  1159. package/static/vendor/fontawesome-free/svgs/solid/cloud-download-alt.svg +1 -0
  1160. package/static/vendor/fontawesome-free/svgs/solid/cloud-meatball.svg +1 -0
  1161. package/static/vendor/fontawesome-free/svgs/solid/cloud-moon-rain.svg +1 -0
  1162. package/static/vendor/fontawesome-free/svgs/solid/cloud-moon.svg +1 -0
  1163. package/static/vendor/fontawesome-free/svgs/solid/cloud-rain.svg +1 -0
  1164. package/static/vendor/fontawesome-free/svgs/solid/cloud-showers-heavy.svg +1 -0
  1165. package/static/vendor/fontawesome-free/svgs/solid/cloud-sun-rain.svg +1 -0
  1166. package/static/vendor/fontawesome-free/svgs/solid/cloud-sun.svg +1 -0
  1167. package/static/vendor/fontawesome-free/svgs/solid/cloud-upload-alt.svg +1 -0
  1168. package/static/vendor/fontawesome-free/svgs/solid/cloud.svg +1 -0
  1169. package/static/vendor/fontawesome-free/svgs/solid/cocktail.svg +1 -0
  1170. package/static/vendor/fontawesome-free/svgs/solid/code-branch.svg +1 -0
  1171. package/static/vendor/fontawesome-free/svgs/solid/code.svg +1 -0
  1172. package/static/vendor/fontawesome-free/svgs/solid/coffee.svg +1 -0
  1173. package/static/vendor/fontawesome-free/svgs/solid/cog.svg +1 -0
  1174. package/static/vendor/fontawesome-free/svgs/solid/cogs.svg +1 -0
  1175. package/static/vendor/fontawesome-free/svgs/solid/coins.svg +1 -0
  1176. package/static/vendor/fontawesome-free/svgs/solid/columns.svg +1 -0
  1177. package/static/vendor/fontawesome-free/svgs/solid/comment-alt.svg +1 -0
  1178. package/static/vendor/fontawesome-free/svgs/solid/comment-dollar.svg +1 -0
  1179. package/static/vendor/fontawesome-free/svgs/solid/comment-dots.svg +1 -0
  1180. package/static/vendor/fontawesome-free/svgs/solid/comment-medical.svg +1 -0
  1181. package/static/vendor/fontawesome-free/svgs/solid/comment-slash.svg +1 -0
  1182. package/static/vendor/fontawesome-free/svgs/solid/comment.svg +1 -0
  1183. package/static/vendor/fontawesome-free/svgs/solid/comments-dollar.svg +1 -0
  1184. package/static/vendor/fontawesome-free/svgs/solid/comments.svg +1 -0
  1185. package/static/vendor/fontawesome-free/svgs/solid/compact-disc.svg +1 -0
  1186. package/static/vendor/fontawesome-free/svgs/solid/compass.svg +1 -0
  1187. package/static/vendor/fontawesome-free/svgs/solid/compress-alt.svg +1 -0
  1188. package/static/vendor/fontawesome-free/svgs/solid/compress-arrows-alt.svg +1 -0
  1189. package/static/vendor/fontawesome-free/svgs/solid/compress.svg +1 -0
  1190. package/static/vendor/fontawesome-free/svgs/solid/concierge-bell.svg +1 -0
  1191. package/static/vendor/fontawesome-free/svgs/solid/cookie-bite.svg +1 -0
  1192. package/static/vendor/fontawesome-free/svgs/solid/cookie.svg +1 -0
  1193. package/static/vendor/fontawesome-free/svgs/solid/copy.svg +1 -0
  1194. package/static/vendor/fontawesome-free/svgs/solid/copyright.svg +1 -0
  1195. package/static/vendor/fontawesome-free/svgs/solid/couch.svg +1 -0
  1196. package/static/vendor/fontawesome-free/svgs/solid/credit-card.svg +1 -0
  1197. package/static/vendor/fontawesome-free/svgs/solid/crop-alt.svg +1 -0
  1198. package/static/vendor/fontawesome-free/svgs/solid/crop.svg +1 -0
  1199. package/static/vendor/fontawesome-free/svgs/solid/cross.svg +1 -0
  1200. package/static/vendor/fontawesome-free/svgs/solid/crosshairs.svg +1 -0
  1201. package/static/vendor/fontawesome-free/svgs/solid/crow.svg +1 -0
  1202. package/static/vendor/fontawesome-free/svgs/solid/crown.svg +1 -0
  1203. package/static/vendor/fontawesome-free/svgs/solid/crutch.svg +1 -0
  1204. package/static/vendor/fontawesome-free/svgs/solid/cube.svg +1 -0
  1205. package/static/vendor/fontawesome-free/svgs/solid/cubes.svg +1 -0
  1206. package/static/vendor/fontawesome-free/svgs/solid/cut.svg +1 -0
  1207. package/static/vendor/fontawesome-free/svgs/solid/database.svg +1 -0
  1208. package/static/vendor/fontawesome-free/svgs/solid/deaf.svg +1 -0
  1209. package/static/vendor/fontawesome-free/svgs/solid/democrat.svg +1 -0
  1210. package/static/vendor/fontawesome-free/svgs/solid/desktop.svg +1 -0
  1211. package/static/vendor/fontawesome-free/svgs/solid/dharmachakra.svg +1 -0
  1212. package/static/vendor/fontawesome-free/svgs/solid/diagnoses.svg +1 -0
  1213. package/static/vendor/fontawesome-free/svgs/solid/dice-d20.svg +1 -0
  1214. package/static/vendor/fontawesome-free/svgs/solid/dice-d6.svg +1 -0
  1215. package/static/vendor/fontawesome-free/svgs/solid/dice-five.svg +1 -0
  1216. package/static/vendor/fontawesome-free/svgs/solid/dice-four.svg +1 -0
  1217. package/static/vendor/fontawesome-free/svgs/solid/dice-one.svg +1 -0
  1218. package/static/vendor/fontawesome-free/svgs/solid/dice-six.svg +1 -0
  1219. package/static/vendor/fontawesome-free/svgs/solid/dice-three.svg +1 -0
  1220. package/static/vendor/fontawesome-free/svgs/solid/dice-two.svg +1 -0
  1221. package/static/vendor/fontawesome-free/svgs/solid/dice.svg +1 -0
  1222. package/static/vendor/fontawesome-free/svgs/solid/digital-tachograph.svg +1 -0
  1223. package/static/vendor/fontawesome-free/svgs/solid/directions.svg +1 -0
  1224. package/static/vendor/fontawesome-free/svgs/solid/disease.svg +1 -0
  1225. package/static/vendor/fontawesome-free/svgs/solid/divide.svg +1 -0
  1226. package/static/vendor/fontawesome-free/svgs/solid/dizzy.svg +1 -0
  1227. package/static/vendor/fontawesome-free/svgs/solid/dna.svg +1 -0
  1228. package/static/vendor/fontawesome-free/svgs/solid/dog.svg +1 -0
  1229. package/static/vendor/fontawesome-free/svgs/solid/dollar-sign.svg +1 -0
  1230. package/static/vendor/fontawesome-free/svgs/solid/dolly-flatbed.svg +1 -0
  1231. package/static/vendor/fontawesome-free/svgs/solid/dolly.svg +1 -0
  1232. package/static/vendor/fontawesome-free/svgs/solid/donate.svg +1 -0
  1233. package/static/vendor/fontawesome-free/svgs/solid/door-closed.svg +1 -0
  1234. package/static/vendor/fontawesome-free/svgs/solid/door-open.svg +1 -0
  1235. package/static/vendor/fontawesome-free/svgs/solid/dot-circle.svg +1 -0
  1236. package/static/vendor/fontawesome-free/svgs/solid/dove.svg +1 -0
  1237. package/static/vendor/fontawesome-free/svgs/solid/download.svg +1 -0
  1238. package/static/vendor/fontawesome-free/svgs/solid/drafting-compass.svg +1 -0
  1239. package/static/vendor/fontawesome-free/svgs/solid/dragon.svg +1 -0
  1240. package/static/vendor/fontawesome-free/svgs/solid/draw-polygon.svg +1 -0
  1241. package/static/vendor/fontawesome-free/svgs/solid/drum-steelpan.svg +1 -0
  1242. package/static/vendor/fontawesome-free/svgs/solid/drum.svg +1 -0
  1243. package/static/vendor/fontawesome-free/svgs/solid/drumstick-bite.svg +1 -0
  1244. package/static/vendor/fontawesome-free/svgs/solid/dumbbell.svg +1 -0
  1245. package/static/vendor/fontawesome-free/svgs/solid/dumpster-fire.svg +1 -0
  1246. package/static/vendor/fontawesome-free/svgs/solid/dumpster.svg +1 -0
  1247. package/static/vendor/fontawesome-free/svgs/solid/dungeon.svg +1 -0
  1248. package/static/vendor/fontawesome-free/svgs/solid/edit.svg +1 -0
  1249. package/static/vendor/fontawesome-free/svgs/solid/egg.svg +1 -0
  1250. package/static/vendor/fontawesome-free/svgs/solid/eject.svg +1 -0
  1251. package/static/vendor/fontawesome-free/svgs/solid/ellipsis-h.svg +1 -0
  1252. package/static/vendor/fontawesome-free/svgs/solid/ellipsis-v.svg +1 -0
  1253. package/static/vendor/fontawesome-free/svgs/solid/envelope-open-text.svg +1 -0
  1254. package/static/vendor/fontawesome-free/svgs/solid/envelope-open.svg +1 -0
  1255. package/static/vendor/fontawesome-free/svgs/solid/envelope-square.svg +1 -0
  1256. package/static/vendor/fontawesome-free/svgs/solid/envelope.svg +1 -0
  1257. package/static/vendor/fontawesome-free/svgs/solid/equals.svg +1 -0
  1258. package/static/vendor/fontawesome-free/svgs/solid/eraser.svg +1 -0
  1259. package/static/vendor/fontawesome-free/svgs/solid/ethernet.svg +1 -0
  1260. package/static/vendor/fontawesome-free/svgs/solid/euro-sign.svg +1 -0
  1261. package/static/vendor/fontawesome-free/svgs/solid/exchange-alt.svg +1 -0
  1262. package/static/vendor/fontawesome-free/svgs/solid/exclamation-circle.svg +1 -0
  1263. package/static/vendor/fontawesome-free/svgs/solid/exclamation-triangle.svg +1 -0
  1264. package/static/vendor/fontawesome-free/svgs/solid/exclamation.svg +1 -0
  1265. package/static/vendor/fontawesome-free/svgs/solid/expand-alt.svg +1 -0
  1266. package/static/vendor/fontawesome-free/svgs/solid/expand-arrows-alt.svg +1 -0
  1267. package/static/vendor/fontawesome-free/svgs/solid/expand.svg +1 -0
  1268. package/static/vendor/fontawesome-free/svgs/solid/external-link-alt.svg +1 -0
  1269. package/static/vendor/fontawesome-free/svgs/solid/external-link-square-alt.svg +1 -0
  1270. package/static/vendor/fontawesome-free/svgs/solid/eye-dropper.svg +1 -0
  1271. package/static/vendor/fontawesome-free/svgs/solid/eye-slash.svg +1 -0
  1272. package/static/vendor/fontawesome-free/svgs/solid/eye.svg +1 -0
  1273. package/static/vendor/fontawesome-free/svgs/solid/fan.svg +1 -0
  1274. package/static/vendor/fontawesome-free/svgs/solid/fast-backward.svg +1 -0
  1275. package/static/vendor/fontawesome-free/svgs/solid/fast-forward.svg +1 -0
  1276. package/static/vendor/fontawesome-free/svgs/solid/faucet.svg +1 -0
  1277. package/static/vendor/fontawesome-free/svgs/solid/fax.svg +1 -0
  1278. package/static/vendor/fontawesome-free/svgs/solid/feather-alt.svg +1 -0
  1279. package/static/vendor/fontawesome-free/svgs/solid/feather.svg +1 -0
  1280. package/static/vendor/fontawesome-free/svgs/solid/female.svg +1 -0
  1281. package/static/vendor/fontawesome-free/svgs/solid/fighter-jet.svg +1 -0
  1282. package/static/vendor/fontawesome-free/svgs/solid/file-alt.svg +1 -0
  1283. package/static/vendor/fontawesome-free/svgs/solid/file-archive.svg +1 -0
  1284. package/static/vendor/fontawesome-free/svgs/solid/file-audio.svg +1 -0
  1285. package/static/vendor/fontawesome-free/svgs/solid/file-code.svg +1 -0
  1286. package/static/vendor/fontawesome-free/svgs/solid/file-contract.svg +1 -0
  1287. package/static/vendor/fontawesome-free/svgs/solid/file-csv.svg +1 -0
  1288. package/static/vendor/fontawesome-free/svgs/solid/file-download.svg +1 -0
  1289. package/static/vendor/fontawesome-free/svgs/solid/file-excel.svg +1 -0
  1290. package/static/vendor/fontawesome-free/svgs/solid/file-export.svg +1 -0
  1291. package/static/vendor/fontawesome-free/svgs/solid/file-image.svg +1 -0
  1292. package/static/vendor/fontawesome-free/svgs/solid/file-import.svg +1 -0
  1293. package/static/vendor/fontawesome-free/svgs/solid/file-invoice-dollar.svg +1 -0
  1294. package/static/vendor/fontawesome-free/svgs/solid/file-invoice.svg +1 -0
  1295. package/static/vendor/fontawesome-free/svgs/solid/file-medical-alt.svg +1 -0
  1296. package/static/vendor/fontawesome-free/svgs/solid/file-medical.svg +1 -0
  1297. package/static/vendor/fontawesome-free/svgs/solid/file-pdf.svg +1 -0
  1298. package/static/vendor/fontawesome-free/svgs/solid/file-powerpoint.svg +1 -0
  1299. package/static/vendor/fontawesome-free/svgs/solid/file-prescription.svg +1 -0
  1300. package/static/vendor/fontawesome-free/svgs/solid/file-signature.svg +1 -0
  1301. package/static/vendor/fontawesome-free/svgs/solid/file-upload.svg +1 -0
  1302. package/static/vendor/fontawesome-free/svgs/solid/file-video.svg +1 -0
  1303. package/static/vendor/fontawesome-free/svgs/solid/file-word.svg +1 -0
  1304. package/static/vendor/fontawesome-free/svgs/solid/file.svg +1 -0
  1305. package/static/vendor/fontawesome-free/svgs/solid/fill-drip.svg +1 -0
  1306. package/static/vendor/fontawesome-free/svgs/solid/fill.svg +1 -0
  1307. package/static/vendor/fontawesome-free/svgs/solid/film.svg +1 -0
  1308. package/static/vendor/fontawesome-free/svgs/solid/filter.svg +1 -0
  1309. package/static/vendor/fontawesome-free/svgs/solid/fingerprint.svg +1 -0
  1310. package/static/vendor/fontawesome-free/svgs/solid/fire-alt.svg +1 -0
  1311. package/static/vendor/fontawesome-free/svgs/solid/fire-extinguisher.svg +1 -0
  1312. package/static/vendor/fontawesome-free/svgs/solid/fire.svg +1 -0
  1313. package/static/vendor/fontawesome-free/svgs/solid/first-aid.svg +1 -0
  1314. package/static/vendor/fontawesome-free/svgs/solid/fish.svg +1 -0
  1315. package/static/vendor/fontawesome-free/svgs/solid/fist-raised.svg +1 -0
  1316. package/static/vendor/fontawesome-free/svgs/solid/flag-checkered.svg +1 -0
  1317. package/static/vendor/fontawesome-free/svgs/solid/flag-usa.svg +1 -0
  1318. package/static/vendor/fontawesome-free/svgs/solid/flag.svg +1 -0
  1319. package/static/vendor/fontawesome-free/svgs/solid/flask.svg +1 -0
  1320. package/static/vendor/fontawesome-free/svgs/solid/flushed.svg +1 -0
  1321. package/static/vendor/fontawesome-free/svgs/solid/folder-minus.svg +1 -0
  1322. package/static/vendor/fontawesome-free/svgs/solid/folder-open.svg +1 -0
  1323. package/static/vendor/fontawesome-free/svgs/solid/folder-plus.svg +1 -0
  1324. package/static/vendor/fontawesome-free/svgs/solid/folder.svg +1 -0
  1325. package/static/vendor/fontawesome-free/svgs/solid/font-awesome-logo-full.svg +1 -0
  1326. package/static/vendor/fontawesome-free/svgs/solid/font.svg +1 -0
  1327. package/static/vendor/fontawesome-free/svgs/solid/football-ball.svg +1 -0
  1328. package/static/vendor/fontawesome-free/svgs/solid/forward.svg +1 -0
  1329. package/static/vendor/fontawesome-free/svgs/solid/frog.svg +1 -0
  1330. package/static/vendor/fontawesome-free/svgs/solid/frown-open.svg +1 -0
  1331. package/static/vendor/fontawesome-free/svgs/solid/frown.svg +1 -0
  1332. package/static/vendor/fontawesome-free/svgs/solid/funnel-dollar.svg +1 -0
  1333. package/static/vendor/fontawesome-free/svgs/solid/futbol.svg +1 -0
  1334. package/static/vendor/fontawesome-free/svgs/solid/gamepad.svg +1 -0
  1335. package/static/vendor/fontawesome-free/svgs/solid/gas-pump.svg +1 -0
  1336. package/static/vendor/fontawesome-free/svgs/solid/gavel.svg +1 -0
  1337. package/static/vendor/fontawesome-free/svgs/solid/gem.svg +1 -0
  1338. package/static/vendor/fontawesome-free/svgs/solid/genderless.svg +1 -0
  1339. package/static/vendor/fontawesome-free/svgs/solid/ghost.svg +1 -0
  1340. package/static/vendor/fontawesome-free/svgs/solid/gift.svg +1 -0
  1341. package/static/vendor/fontawesome-free/svgs/solid/gifts.svg +1 -0
  1342. package/static/vendor/fontawesome-free/svgs/solid/glass-cheers.svg +1 -0
  1343. package/static/vendor/fontawesome-free/svgs/solid/glass-martini-alt.svg +1 -0
  1344. package/static/vendor/fontawesome-free/svgs/solid/glass-martini.svg +1 -0
  1345. package/static/vendor/fontawesome-free/svgs/solid/glass-whiskey.svg +1 -0
  1346. package/static/vendor/fontawesome-free/svgs/solid/glasses.svg +1 -0
  1347. package/static/vendor/fontawesome-free/svgs/solid/globe-africa.svg +1 -0
  1348. package/static/vendor/fontawesome-free/svgs/solid/globe-americas.svg +1 -0
  1349. package/static/vendor/fontawesome-free/svgs/solid/globe-asia.svg +1 -0
  1350. package/static/vendor/fontawesome-free/svgs/solid/globe-europe.svg +1 -0
  1351. package/static/vendor/fontawesome-free/svgs/solid/globe.svg +1 -0
  1352. package/static/vendor/fontawesome-free/svgs/solid/golf-ball.svg +1 -0
  1353. package/static/vendor/fontawesome-free/svgs/solid/gopuram.svg +1 -0
  1354. package/static/vendor/fontawesome-free/svgs/solid/graduation-cap.svg +1 -0
  1355. package/static/vendor/fontawesome-free/svgs/solid/greater-than-equal.svg +1 -0
  1356. package/static/vendor/fontawesome-free/svgs/solid/greater-than.svg +1 -0
  1357. package/static/vendor/fontawesome-free/svgs/solid/grimace.svg +1 -0
  1358. package/static/vendor/fontawesome-free/svgs/solid/grin-alt.svg +1 -0
  1359. package/static/vendor/fontawesome-free/svgs/solid/grin-beam-sweat.svg +1 -0
  1360. package/static/vendor/fontawesome-free/svgs/solid/grin-beam.svg +1 -0
  1361. package/static/vendor/fontawesome-free/svgs/solid/grin-hearts.svg +1 -0
  1362. package/static/vendor/fontawesome-free/svgs/solid/grin-squint-tears.svg +1 -0
  1363. package/static/vendor/fontawesome-free/svgs/solid/grin-squint.svg +1 -0
  1364. package/static/vendor/fontawesome-free/svgs/solid/grin-stars.svg +1 -0
  1365. package/static/vendor/fontawesome-free/svgs/solid/grin-tears.svg +1 -0
  1366. package/static/vendor/fontawesome-free/svgs/solid/grin-tongue-squint.svg +1 -0
  1367. package/static/vendor/fontawesome-free/svgs/solid/grin-tongue-wink.svg +1 -0
  1368. package/static/vendor/fontawesome-free/svgs/solid/grin-tongue.svg +1 -0
  1369. package/static/vendor/fontawesome-free/svgs/solid/grin-wink.svg +1 -0
  1370. package/static/vendor/fontawesome-free/svgs/solid/grin.svg +1 -0
  1371. package/static/vendor/fontawesome-free/svgs/solid/grip-horizontal.svg +1 -0
  1372. package/static/vendor/fontawesome-free/svgs/solid/grip-lines-vertical.svg +1 -0
  1373. package/static/vendor/fontawesome-free/svgs/solid/grip-lines.svg +1 -0
  1374. package/static/vendor/fontawesome-free/svgs/solid/grip-vertical.svg +1 -0
  1375. package/static/vendor/fontawesome-free/svgs/solid/guitar.svg +1 -0
  1376. package/static/vendor/fontawesome-free/svgs/solid/h-square.svg +1 -0
  1377. package/static/vendor/fontawesome-free/svgs/solid/hamburger.svg +1 -0
  1378. package/static/vendor/fontawesome-free/svgs/solid/hammer.svg +1 -0
  1379. package/static/vendor/fontawesome-free/svgs/solid/hamsa.svg +1 -0
  1380. package/static/vendor/fontawesome-free/svgs/solid/hand-holding-heart.svg +1 -0
  1381. package/static/vendor/fontawesome-free/svgs/solid/hand-holding-medical.svg +1 -0
  1382. package/static/vendor/fontawesome-free/svgs/solid/hand-holding-usd.svg +1 -0
  1383. package/static/vendor/fontawesome-free/svgs/solid/hand-holding-water.svg +1 -0
  1384. package/static/vendor/fontawesome-free/svgs/solid/hand-holding.svg +1 -0
  1385. package/static/vendor/fontawesome-free/svgs/solid/hand-lizard.svg +1 -0
  1386. package/static/vendor/fontawesome-free/svgs/solid/hand-middle-finger.svg +1 -0
  1387. package/static/vendor/fontawesome-free/svgs/solid/hand-paper.svg +1 -0
  1388. package/static/vendor/fontawesome-free/svgs/solid/hand-peace.svg +1 -0
  1389. package/static/vendor/fontawesome-free/svgs/solid/hand-point-down.svg +1 -0
  1390. package/static/vendor/fontawesome-free/svgs/solid/hand-point-left.svg +1 -0
  1391. package/static/vendor/fontawesome-free/svgs/solid/hand-point-right.svg +1 -0
  1392. package/static/vendor/fontawesome-free/svgs/solid/hand-point-up.svg +1 -0
  1393. package/static/vendor/fontawesome-free/svgs/solid/hand-pointer.svg +1 -0
  1394. package/static/vendor/fontawesome-free/svgs/solid/hand-rock.svg +1 -0
  1395. package/static/vendor/fontawesome-free/svgs/solid/hand-scissors.svg +1 -0
  1396. package/static/vendor/fontawesome-free/svgs/solid/hand-sparkles.svg +1 -0
  1397. package/static/vendor/fontawesome-free/svgs/solid/hand-spock.svg +1 -0
  1398. package/static/vendor/fontawesome-free/svgs/solid/hands-helping.svg +1 -0
  1399. package/static/vendor/fontawesome-free/svgs/solid/hands-wash.svg +1 -0
  1400. package/static/vendor/fontawesome-free/svgs/solid/hands.svg +1 -0
  1401. package/static/vendor/fontawesome-free/svgs/solid/handshake-alt-slash.svg +1 -0
  1402. package/static/vendor/fontawesome-free/svgs/solid/handshake-slash.svg +1 -0
  1403. package/static/vendor/fontawesome-free/svgs/solid/handshake.svg +1 -0
  1404. package/static/vendor/fontawesome-free/svgs/solid/hanukiah.svg +1 -0
  1405. package/static/vendor/fontawesome-free/svgs/solid/hard-hat.svg +1 -0
  1406. package/static/vendor/fontawesome-free/svgs/solid/hashtag.svg +1 -0
  1407. package/static/vendor/fontawesome-free/svgs/solid/hat-cowboy-side.svg +1 -0
  1408. package/static/vendor/fontawesome-free/svgs/solid/hat-cowboy.svg +1 -0
  1409. package/static/vendor/fontawesome-free/svgs/solid/hat-wizard.svg +1 -0
  1410. package/static/vendor/fontawesome-free/svgs/solid/hdd.svg +1 -0
  1411. package/static/vendor/fontawesome-free/svgs/solid/head-side-cough-slash.svg +1 -0
  1412. package/static/vendor/fontawesome-free/svgs/solid/head-side-cough.svg +1 -0
  1413. package/static/vendor/fontawesome-free/svgs/solid/head-side-mask.svg +1 -0
  1414. package/static/vendor/fontawesome-free/svgs/solid/head-side-virus.svg +1 -0
  1415. package/static/vendor/fontawesome-free/svgs/solid/heading.svg +1 -0
  1416. package/static/vendor/fontawesome-free/svgs/solid/headphones-alt.svg +1 -0
  1417. package/static/vendor/fontawesome-free/svgs/solid/headphones.svg +1 -0
  1418. package/static/vendor/fontawesome-free/svgs/solid/headset.svg +1 -0
  1419. package/static/vendor/fontawesome-free/svgs/solid/heart-broken.svg +1 -0
  1420. package/static/vendor/fontawesome-free/svgs/solid/heart.svg +1 -0
  1421. package/static/vendor/fontawesome-free/svgs/solid/heartbeat.svg +1 -0
  1422. package/static/vendor/fontawesome-free/svgs/solid/helicopter.svg +1 -0
  1423. package/static/vendor/fontawesome-free/svgs/solid/highlighter.svg +1 -0
  1424. package/static/vendor/fontawesome-free/svgs/solid/hiking.svg +1 -0
  1425. package/static/vendor/fontawesome-free/svgs/solid/hippo.svg +1 -0
  1426. package/static/vendor/fontawesome-free/svgs/solid/history.svg +1 -0
  1427. package/static/vendor/fontawesome-free/svgs/solid/hockey-puck.svg +1 -0
  1428. package/static/vendor/fontawesome-free/svgs/solid/holly-berry.svg +1 -0
  1429. package/static/vendor/fontawesome-free/svgs/solid/home.svg +1 -0
  1430. package/static/vendor/fontawesome-free/svgs/solid/horse-head.svg +1 -0
  1431. package/static/vendor/fontawesome-free/svgs/solid/horse.svg +1 -0
  1432. package/static/vendor/fontawesome-free/svgs/solid/hospital-alt.svg +1 -0
  1433. package/static/vendor/fontawesome-free/svgs/solid/hospital-symbol.svg +1 -0
  1434. package/static/vendor/fontawesome-free/svgs/solid/hospital-user.svg +1 -0
  1435. package/static/vendor/fontawesome-free/svgs/solid/hospital.svg +1 -0
  1436. package/static/vendor/fontawesome-free/svgs/solid/hot-tub.svg +1 -0
  1437. package/static/vendor/fontawesome-free/svgs/solid/hotdog.svg +1 -0
  1438. package/static/vendor/fontawesome-free/svgs/solid/hotel.svg +1 -0
  1439. package/static/vendor/fontawesome-free/svgs/solid/hourglass-end.svg +1 -0
  1440. package/static/vendor/fontawesome-free/svgs/solid/hourglass-half.svg +1 -0
  1441. package/static/vendor/fontawesome-free/svgs/solid/hourglass-start.svg +1 -0
  1442. package/static/vendor/fontawesome-free/svgs/solid/hourglass.svg +1 -0
  1443. package/static/vendor/fontawesome-free/svgs/solid/house-damage.svg +1 -0
  1444. package/static/vendor/fontawesome-free/svgs/solid/house-user.svg +1 -0
  1445. package/static/vendor/fontawesome-free/svgs/solid/hryvnia.svg +1 -0
  1446. package/static/vendor/fontawesome-free/svgs/solid/i-cursor.svg +1 -0
  1447. package/static/vendor/fontawesome-free/svgs/solid/ice-cream.svg +1 -0
  1448. package/static/vendor/fontawesome-free/svgs/solid/icicles.svg +1 -0
  1449. package/static/vendor/fontawesome-free/svgs/solid/icons.svg +1 -0
  1450. package/static/vendor/fontawesome-free/svgs/solid/id-badge.svg +1 -0
  1451. package/static/vendor/fontawesome-free/svgs/solid/id-card-alt.svg +1 -0
  1452. package/static/vendor/fontawesome-free/svgs/solid/id-card.svg +1 -0
  1453. package/static/vendor/fontawesome-free/svgs/solid/igloo.svg +1 -0
  1454. package/static/vendor/fontawesome-free/svgs/solid/image.svg +1 -0
  1455. package/static/vendor/fontawesome-free/svgs/solid/images.svg +1 -0
  1456. package/static/vendor/fontawesome-free/svgs/solid/inbox.svg +1 -0
  1457. package/static/vendor/fontawesome-free/svgs/solid/indent.svg +1 -0
  1458. package/static/vendor/fontawesome-free/svgs/solid/industry.svg +1 -0
  1459. package/static/vendor/fontawesome-free/svgs/solid/infinity.svg +1 -0
  1460. package/static/vendor/fontawesome-free/svgs/solid/info-circle.svg +1 -0
  1461. package/static/vendor/fontawesome-free/svgs/solid/info.svg +1 -0
  1462. package/static/vendor/fontawesome-free/svgs/solid/italic.svg +1 -0
  1463. package/static/vendor/fontawesome-free/svgs/solid/jedi.svg +1 -0
  1464. package/static/vendor/fontawesome-free/svgs/solid/joint.svg +1 -0
  1465. package/static/vendor/fontawesome-free/svgs/solid/journal-whills.svg +1 -0
  1466. package/static/vendor/fontawesome-free/svgs/solid/kaaba.svg +1 -0
  1467. package/static/vendor/fontawesome-free/svgs/solid/key.svg +1 -0
  1468. package/static/vendor/fontawesome-free/svgs/solid/keyboard.svg +1 -0
  1469. package/static/vendor/fontawesome-free/svgs/solid/khanda.svg +1 -0
  1470. package/static/vendor/fontawesome-free/svgs/solid/kiss-beam.svg +1 -0
  1471. package/static/vendor/fontawesome-free/svgs/solid/kiss-wink-heart.svg +1 -0
  1472. package/static/vendor/fontawesome-free/svgs/solid/kiss.svg +1 -0
  1473. package/static/vendor/fontawesome-free/svgs/solid/kiwi-bird.svg +1 -0
  1474. package/static/vendor/fontawesome-free/svgs/solid/landmark.svg +1 -0
  1475. package/static/vendor/fontawesome-free/svgs/solid/language.svg +1 -0
  1476. package/static/vendor/fontawesome-free/svgs/solid/laptop-code.svg +1 -0
  1477. package/static/vendor/fontawesome-free/svgs/solid/laptop-house.svg +1 -0
  1478. package/static/vendor/fontawesome-free/svgs/solid/laptop-medical.svg +1 -0
  1479. package/static/vendor/fontawesome-free/svgs/solid/laptop.svg +1 -0
  1480. package/static/vendor/fontawesome-free/svgs/solid/laugh-beam.svg +1 -0
  1481. package/static/vendor/fontawesome-free/svgs/solid/laugh-squint.svg +1 -0
  1482. package/static/vendor/fontawesome-free/svgs/solid/laugh-wink.svg +1 -0
  1483. package/static/vendor/fontawesome-free/svgs/solid/laugh.svg +1 -0
  1484. package/static/vendor/fontawesome-free/svgs/solid/layer-group.svg +1 -0
  1485. package/static/vendor/fontawesome-free/svgs/solid/leaf.svg +1 -0
  1486. package/static/vendor/fontawesome-free/svgs/solid/lemon.svg +1 -0
  1487. package/static/vendor/fontawesome-free/svgs/solid/less-than-equal.svg +1 -0
  1488. package/static/vendor/fontawesome-free/svgs/solid/less-than.svg +1 -0
  1489. package/static/vendor/fontawesome-free/svgs/solid/level-down-alt.svg +1 -0
  1490. package/static/vendor/fontawesome-free/svgs/solid/level-up-alt.svg +1 -0
  1491. package/static/vendor/fontawesome-free/svgs/solid/life-ring.svg +1 -0
  1492. package/static/vendor/fontawesome-free/svgs/solid/lightbulb.svg +1 -0
  1493. package/static/vendor/fontawesome-free/svgs/solid/link.svg +1 -0
  1494. package/static/vendor/fontawesome-free/svgs/solid/lira-sign.svg +1 -0
  1495. package/static/vendor/fontawesome-free/svgs/solid/list-alt.svg +1 -0
  1496. package/static/vendor/fontawesome-free/svgs/solid/list-ol.svg +1 -0
  1497. package/static/vendor/fontawesome-free/svgs/solid/list-ul.svg +1 -0
  1498. package/static/vendor/fontawesome-free/svgs/solid/list.svg +1 -0
  1499. package/static/vendor/fontawesome-free/svgs/solid/location-arrow.svg +1 -0
  1500. package/static/vendor/fontawesome-free/svgs/solid/lock-open.svg +1 -0
  1501. package/static/vendor/fontawesome-free/svgs/solid/lock.svg +1 -0
  1502. package/static/vendor/fontawesome-free/svgs/solid/long-arrow-alt-down.svg +1 -0
  1503. package/static/vendor/fontawesome-free/svgs/solid/long-arrow-alt-left.svg +1 -0
  1504. package/static/vendor/fontawesome-free/svgs/solid/long-arrow-alt-right.svg +1 -0
  1505. package/static/vendor/fontawesome-free/svgs/solid/long-arrow-alt-up.svg +1 -0
  1506. package/static/vendor/fontawesome-free/svgs/solid/low-vision.svg +1 -0
  1507. package/static/vendor/fontawesome-free/svgs/solid/luggage-cart.svg +1 -0
  1508. package/static/vendor/fontawesome-free/svgs/solid/lungs-virus.svg +1 -0
  1509. package/static/vendor/fontawesome-free/svgs/solid/lungs.svg +1 -0
  1510. package/static/vendor/fontawesome-free/svgs/solid/magic.svg +1 -0
  1511. package/static/vendor/fontawesome-free/svgs/solid/magnet.svg +1 -0
  1512. package/static/vendor/fontawesome-free/svgs/solid/mail-bulk.svg +1 -0
  1513. package/static/vendor/fontawesome-free/svgs/solid/male.svg +1 -0
  1514. package/static/vendor/fontawesome-free/svgs/solid/map-marked-alt.svg +1 -0
  1515. package/static/vendor/fontawesome-free/svgs/solid/map-marked.svg +1 -0
  1516. package/static/vendor/fontawesome-free/svgs/solid/map-marker-alt.svg +1 -0
  1517. package/static/vendor/fontawesome-free/svgs/solid/map-marker.svg +1 -0
  1518. package/static/vendor/fontawesome-free/svgs/solid/map-pin.svg +1 -0
  1519. package/static/vendor/fontawesome-free/svgs/solid/map-signs.svg +1 -0
  1520. package/static/vendor/fontawesome-free/svgs/solid/map.svg +1 -0
  1521. package/static/vendor/fontawesome-free/svgs/solid/marker.svg +1 -0
  1522. package/static/vendor/fontawesome-free/svgs/solid/mars-double.svg +1 -0
  1523. package/static/vendor/fontawesome-free/svgs/solid/mars-stroke-h.svg +1 -0
  1524. package/static/vendor/fontawesome-free/svgs/solid/mars-stroke-v.svg +1 -0
  1525. package/static/vendor/fontawesome-free/svgs/solid/mars-stroke.svg +1 -0
  1526. package/static/vendor/fontawesome-free/svgs/solid/mars.svg +1 -0
  1527. package/static/vendor/fontawesome-free/svgs/solid/mask.svg +1 -0
  1528. package/static/vendor/fontawesome-free/svgs/solid/medal.svg +1 -0
  1529. package/static/vendor/fontawesome-free/svgs/solid/medkit.svg +1 -0
  1530. package/static/vendor/fontawesome-free/svgs/solid/meh-blank.svg +1 -0
  1531. package/static/vendor/fontawesome-free/svgs/solid/meh-rolling-eyes.svg +1 -0
  1532. package/static/vendor/fontawesome-free/svgs/solid/meh.svg +1 -0
  1533. package/static/vendor/fontawesome-free/svgs/solid/memory.svg +1 -0
  1534. package/static/vendor/fontawesome-free/svgs/solid/menorah.svg +1 -0
  1535. package/static/vendor/fontawesome-free/svgs/solid/mercury.svg +1 -0
  1536. package/static/vendor/fontawesome-free/svgs/solid/meteor.svg +1 -0
  1537. package/static/vendor/fontawesome-free/svgs/solid/microchip.svg +1 -0
  1538. package/static/vendor/fontawesome-free/svgs/solid/microphone-alt-slash.svg +1 -0
  1539. package/static/vendor/fontawesome-free/svgs/solid/microphone-alt.svg +1 -0
  1540. package/static/vendor/fontawesome-free/svgs/solid/microphone-slash.svg +1 -0
  1541. package/static/vendor/fontawesome-free/svgs/solid/microphone.svg +1 -0
  1542. package/static/vendor/fontawesome-free/svgs/solid/microscope.svg +1 -0
  1543. package/static/vendor/fontawesome-free/svgs/solid/minus-circle.svg +1 -0
  1544. package/static/vendor/fontawesome-free/svgs/solid/minus-square.svg +1 -0
  1545. package/static/vendor/fontawesome-free/svgs/solid/minus.svg +1 -0
  1546. package/static/vendor/fontawesome-free/svgs/solid/mitten.svg +1 -0
  1547. package/static/vendor/fontawesome-free/svgs/solid/mobile-alt.svg +1 -0
  1548. package/static/vendor/fontawesome-free/svgs/solid/mobile.svg +1 -0
  1549. package/static/vendor/fontawesome-free/svgs/solid/money-bill-alt.svg +1 -0
  1550. package/static/vendor/fontawesome-free/svgs/solid/money-bill-wave-alt.svg +1 -0
  1551. package/static/vendor/fontawesome-free/svgs/solid/money-bill-wave.svg +1 -0
  1552. package/static/vendor/fontawesome-free/svgs/solid/money-bill.svg +1 -0
  1553. package/static/vendor/fontawesome-free/svgs/solid/money-check-alt.svg +1 -0
  1554. package/static/vendor/fontawesome-free/svgs/solid/money-check.svg +1 -0
  1555. package/static/vendor/fontawesome-free/svgs/solid/monument.svg +1 -0
  1556. package/static/vendor/fontawesome-free/svgs/solid/moon.svg +1 -0
  1557. package/static/vendor/fontawesome-free/svgs/solid/mortar-pestle.svg +1 -0
  1558. package/static/vendor/fontawesome-free/svgs/solid/mosque.svg +1 -0
  1559. package/static/vendor/fontawesome-free/svgs/solid/motorcycle.svg +1 -0
  1560. package/static/vendor/fontawesome-free/svgs/solid/mountain.svg +1 -0
  1561. package/static/vendor/fontawesome-free/svgs/solid/mouse-pointer.svg +1 -0
  1562. package/static/vendor/fontawesome-free/svgs/solid/mouse.svg +1 -0
  1563. package/static/vendor/fontawesome-free/svgs/solid/mug-hot.svg +1 -0
  1564. package/static/vendor/fontawesome-free/svgs/solid/music.svg +1 -0
  1565. package/static/vendor/fontawesome-free/svgs/solid/network-wired.svg +1 -0
  1566. package/static/vendor/fontawesome-free/svgs/solid/neuter.svg +1 -0
  1567. package/static/vendor/fontawesome-free/svgs/solid/newspaper.svg +1 -0
  1568. package/static/vendor/fontawesome-free/svgs/solid/not-equal.svg +1 -0
  1569. package/static/vendor/fontawesome-free/svgs/solid/notes-medical.svg +1 -0
  1570. package/static/vendor/fontawesome-free/svgs/solid/object-group.svg +1 -0
  1571. package/static/vendor/fontawesome-free/svgs/solid/object-ungroup.svg +1 -0
  1572. package/static/vendor/fontawesome-free/svgs/solid/oil-can.svg +1 -0
  1573. package/static/vendor/fontawesome-free/svgs/solid/om.svg +1 -0
  1574. package/static/vendor/fontawesome-free/svgs/solid/otter.svg +1 -0
  1575. package/static/vendor/fontawesome-free/svgs/solid/outdent.svg +1 -0
  1576. package/static/vendor/fontawesome-free/svgs/solid/pager.svg +1 -0
  1577. package/static/vendor/fontawesome-free/svgs/solid/paint-brush.svg +1 -0
  1578. package/static/vendor/fontawesome-free/svgs/solid/paint-roller.svg +1 -0
  1579. package/static/vendor/fontawesome-free/svgs/solid/palette.svg +1 -0
  1580. package/static/vendor/fontawesome-free/svgs/solid/pallet.svg +1 -0
  1581. package/static/vendor/fontawesome-free/svgs/solid/paper-plane.svg +1 -0
  1582. package/static/vendor/fontawesome-free/svgs/solid/paperclip.svg +1 -0
  1583. package/static/vendor/fontawesome-free/svgs/solid/parachute-box.svg +1 -0
  1584. package/static/vendor/fontawesome-free/svgs/solid/paragraph.svg +1 -0
  1585. package/static/vendor/fontawesome-free/svgs/solid/parking.svg +1 -0
  1586. package/static/vendor/fontawesome-free/svgs/solid/passport.svg +1 -0
  1587. package/static/vendor/fontawesome-free/svgs/solid/pastafarianism.svg +1 -0
  1588. package/static/vendor/fontawesome-free/svgs/solid/paste.svg +1 -0
  1589. package/static/vendor/fontawesome-free/svgs/solid/pause-circle.svg +1 -0
  1590. package/static/vendor/fontawesome-free/svgs/solid/pause.svg +1 -0
  1591. package/static/vendor/fontawesome-free/svgs/solid/paw.svg +1 -0
  1592. package/static/vendor/fontawesome-free/svgs/solid/peace.svg +1 -0
  1593. package/static/vendor/fontawesome-free/svgs/solid/pen-alt.svg +1 -0
  1594. package/static/vendor/fontawesome-free/svgs/solid/pen-fancy.svg +1 -0
  1595. package/static/vendor/fontawesome-free/svgs/solid/pen-nib.svg +1 -0
  1596. package/static/vendor/fontawesome-free/svgs/solid/pen-square.svg +1 -0
  1597. package/static/vendor/fontawesome-free/svgs/solid/pen.svg +1 -0
  1598. package/static/vendor/fontawesome-free/svgs/solid/pencil-alt.svg +1 -0
  1599. package/static/vendor/fontawesome-free/svgs/solid/pencil-ruler.svg +1 -0
  1600. package/static/vendor/fontawesome-free/svgs/solid/people-arrows.svg +1 -0
  1601. package/static/vendor/fontawesome-free/svgs/solid/people-carry.svg +1 -0
  1602. package/static/vendor/fontawesome-free/svgs/solid/pepper-hot.svg +1 -0
  1603. package/static/vendor/fontawesome-free/svgs/solid/percent.svg +1 -0
  1604. package/static/vendor/fontawesome-free/svgs/solid/percentage.svg +1 -0
  1605. package/static/vendor/fontawesome-free/svgs/solid/person-booth.svg +1 -0
  1606. package/static/vendor/fontawesome-free/svgs/solid/phone-alt.svg +1 -0
  1607. package/static/vendor/fontawesome-free/svgs/solid/phone-slash.svg +1 -0
  1608. package/static/vendor/fontawesome-free/svgs/solid/phone-square-alt.svg +1 -0
  1609. package/static/vendor/fontawesome-free/svgs/solid/phone-square.svg +1 -0
  1610. package/static/vendor/fontawesome-free/svgs/solid/phone-volume.svg +1 -0
  1611. package/static/vendor/fontawesome-free/svgs/solid/phone.svg +1 -0
  1612. package/static/vendor/fontawesome-free/svgs/solid/photo-video.svg +1 -0
  1613. package/static/vendor/fontawesome-free/svgs/solid/piggy-bank.svg +1 -0
  1614. package/static/vendor/fontawesome-free/svgs/solid/pills.svg +1 -0
  1615. package/static/vendor/fontawesome-free/svgs/solid/pizza-slice.svg +1 -0
  1616. package/static/vendor/fontawesome-free/svgs/solid/place-of-worship.svg +1 -0
  1617. package/static/vendor/fontawesome-free/svgs/solid/plane-arrival.svg +1 -0
  1618. package/static/vendor/fontawesome-free/svgs/solid/plane-departure.svg +1 -0
  1619. package/static/vendor/fontawesome-free/svgs/solid/plane-slash.svg +1 -0
  1620. package/static/vendor/fontawesome-free/svgs/solid/plane.svg +1 -0
  1621. package/static/vendor/fontawesome-free/svgs/solid/play-circle.svg +1 -0
  1622. package/static/vendor/fontawesome-free/svgs/solid/play.svg +1 -0
  1623. package/static/vendor/fontawesome-free/svgs/solid/plug.svg +1 -0
  1624. package/static/vendor/fontawesome-free/svgs/solid/plus-circle.svg +1 -0
  1625. package/static/vendor/fontawesome-free/svgs/solid/plus-square.svg +1 -0
  1626. package/static/vendor/fontawesome-free/svgs/solid/plus.svg +1 -0
  1627. package/static/vendor/fontawesome-free/svgs/solid/podcast.svg +1 -0
  1628. package/static/vendor/fontawesome-free/svgs/solid/poll-h.svg +1 -0
  1629. package/static/vendor/fontawesome-free/svgs/solid/poll.svg +1 -0
  1630. package/static/vendor/fontawesome-free/svgs/solid/poo-storm.svg +1 -0
  1631. package/static/vendor/fontawesome-free/svgs/solid/poo.svg +1 -0
  1632. package/static/vendor/fontawesome-free/svgs/solid/poop.svg +1 -0
  1633. package/static/vendor/fontawesome-free/svgs/solid/portrait.svg +1 -0
  1634. package/static/vendor/fontawesome-free/svgs/solid/pound-sign.svg +1 -0
  1635. package/static/vendor/fontawesome-free/svgs/solid/power-off.svg +1 -0
  1636. package/static/vendor/fontawesome-free/svgs/solid/pray.svg +1 -0
  1637. package/static/vendor/fontawesome-free/svgs/solid/praying-hands.svg +1 -0
  1638. package/static/vendor/fontawesome-free/svgs/solid/prescription-bottle-alt.svg +1 -0
  1639. package/static/vendor/fontawesome-free/svgs/solid/prescription-bottle.svg +1 -0
  1640. package/static/vendor/fontawesome-free/svgs/solid/prescription.svg +1 -0
  1641. package/static/vendor/fontawesome-free/svgs/solid/print.svg +1 -0
  1642. package/static/vendor/fontawesome-free/svgs/solid/procedures.svg +1 -0
  1643. package/static/vendor/fontawesome-free/svgs/solid/project-diagram.svg +1 -0
  1644. package/static/vendor/fontawesome-free/svgs/solid/pump-medical.svg +1 -0
  1645. package/static/vendor/fontawesome-free/svgs/solid/pump-soap.svg +1 -0
  1646. package/static/vendor/fontawesome-free/svgs/solid/puzzle-piece.svg +1 -0
  1647. package/static/vendor/fontawesome-free/svgs/solid/qrcode.svg +1 -0
  1648. package/static/vendor/fontawesome-free/svgs/solid/question-circle.svg +1 -0
  1649. package/static/vendor/fontawesome-free/svgs/solid/question.svg +1 -0
  1650. package/static/vendor/fontawesome-free/svgs/solid/quidditch.svg +1 -0
  1651. package/static/vendor/fontawesome-free/svgs/solid/quote-left.svg +1 -0
  1652. package/static/vendor/fontawesome-free/svgs/solid/quote-right.svg +1 -0
  1653. package/static/vendor/fontawesome-free/svgs/solid/quran.svg +1 -0
  1654. package/static/vendor/fontawesome-free/svgs/solid/radiation-alt.svg +1 -0
  1655. package/static/vendor/fontawesome-free/svgs/solid/radiation.svg +1 -0
  1656. package/static/vendor/fontawesome-free/svgs/solid/rainbow.svg +1 -0
  1657. package/static/vendor/fontawesome-free/svgs/solid/random.svg +1 -0
  1658. package/static/vendor/fontawesome-free/svgs/solid/receipt.svg +1 -0
  1659. package/static/vendor/fontawesome-free/svgs/solid/record-vinyl.svg +1 -0
  1660. package/static/vendor/fontawesome-free/svgs/solid/recycle.svg +1 -0
  1661. package/static/vendor/fontawesome-free/svgs/solid/redo-alt.svg +1 -0
  1662. package/static/vendor/fontawesome-free/svgs/solid/redo.svg +1 -0
  1663. package/static/vendor/fontawesome-free/svgs/solid/registered.svg +1 -0
  1664. package/static/vendor/fontawesome-free/svgs/solid/remove-format.svg +1 -0
  1665. package/static/vendor/fontawesome-free/svgs/solid/reply-all.svg +1 -0
  1666. package/static/vendor/fontawesome-free/svgs/solid/reply.svg +1 -0
  1667. package/static/vendor/fontawesome-free/svgs/solid/republican.svg +1 -0
  1668. package/static/vendor/fontawesome-free/svgs/solid/restroom.svg +1 -0
  1669. package/static/vendor/fontawesome-free/svgs/solid/retweet.svg +1 -0
  1670. package/static/vendor/fontawesome-free/svgs/solid/ribbon.svg +1 -0
  1671. package/static/vendor/fontawesome-free/svgs/solid/ring.svg +1 -0
  1672. package/static/vendor/fontawesome-free/svgs/solid/road.svg +1 -0
  1673. package/static/vendor/fontawesome-free/svgs/solid/robot.svg +1 -0
  1674. package/static/vendor/fontawesome-free/svgs/solid/rocket.svg +1 -0
  1675. package/static/vendor/fontawesome-free/svgs/solid/route.svg +1 -0
  1676. package/static/vendor/fontawesome-free/svgs/solid/rss-square.svg +1 -0
  1677. package/static/vendor/fontawesome-free/svgs/solid/rss.svg +1 -0
  1678. package/static/vendor/fontawesome-free/svgs/solid/ruble-sign.svg +1 -0
  1679. package/static/vendor/fontawesome-free/svgs/solid/ruler-combined.svg +1 -0
  1680. package/static/vendor/fontawesome-free/svgs/solid/ruler-horizontal.svg +1 -0
  1681. package/static/vendor/fontawesome-free/svgs/solid/ruler-vertical.svg +1 -0
  1682. package/static/vendor/fontawesome-free/svgs/solid/ruler.svg +1 -0
  1683. package/static/vendor/fontawesome-free/svgs/solid/running.svg +1 -0
  1684. package/static/vendor/fontawesome-free/svgs/solid/rupee-sign.svg +1 -0
  1685. package/static/vendor/fontawesome-free/svgs/solid/sad-cry.svg +1 -0
  1686. package/static/vendor/fontawesome-free/svgs/solid/sad-tear.svg +1 -0
  1687. package/static/vendor/fontawesome-free/svgs/solid/satellite-dish.svg +1 -0
  1688. package/static/vendor/fontawesome-free/svgs/solid/satellite.svg +1 -0
  1689. package/static/vendor/fontawesome-free/svgs/solid/save.svg +1 -0
  1690. package/static/vendor/fontawesome-free/svgs/solid/school.svg +1 -0
  1691. package/static/vendor/fontawesome-free/svgs/solid/screwdriver.svg +1 -0
  1692. package/static/vendor/fontawesome-free/svgs/solid/scroll.svg +1 -0
  1693. package/static/vendor/fontawesome-free/svgs/solid/sd-card.svg +1 -0
  1694. package/static/vendor/fontawesome-free/svgs/solid/search-dollar.svg +1 -0
  1695. package/static/vendor/fontawesome-free/svgs/solid/search-location.svg +1 -0
  1696. package/static/vendor/fontawesome-free/svgs/solid/search-minus.svg +1 -0
  1697. package/static/vendor/fontawesome-free/svgs/solid/search-plus.svg +1 -0
  1698. package/static/vendor/fontawesome-free/svgs/solid/search.svg +1 -0
  1699. package/static/vendor/fontawesome-free/svgs/solid/seedling.svg +1 -0
  1700. package/static/vendor/fontawesome-free/svgs/solid/server.svg +1 -0
  1701. package/static/vendor/fontawesome-free/svgs/solid/shapes.svg +1 -0
  1702. package/static/vendor/fontawesome-free/svgs/solid/share-alt-square.svg +1 -0
  1703. package/static/vendor/fontawesome-free/svgs/solid/share-alt.svg +1 -0
  1704. package/static/vendor/fontawesome-free/svgs/solid/share-square.svg +1 -0
  1705. package/static/vendor/fontawesome-free/svgs/solid/share.svg +1 -0
  1706. package/static/vendor/fontawesome-free/svgs/solid/shekel-sign.svg +1 -0
  1707. package/static/vendor/fontawesome-free/svgs/solid/shield-alt.svg +1 -0
  1708. package/static/vendor/fontawesome-free/svgs/solid/shield-virus.svg +1 -0
  1709. package/static/vendor/fontawesome-free/svgs/solid/ship.svg +1 -0
  1710. package/static/vendor/fontawesome-free/svgs/solid/shipping-fast.svg +1 -0
  1711. package/static/vendor/fontawesome-free/svgs/solid/shoe-prints.svg +1 -0
  1712. package/static/vendor/fontawesome-free/svgs/solid/shopping-bag.svg +1 -0
  1713. package/static/vendor/fontawesome-free/svgs/solid/shopping-basket.svg +1 -0
  1714. package/static/vendor/fontawesome-free/svgs/solid/shopping-cart.svg +1 -0
  1715. package/static/vendor/fontawesome-free/svgs/solid/shower.svg +1 -0
  1716. package/static/vendor/fontawesome-free/svgs/solid/shuttle-van.svg +1 -0
  1717. package/static/vendor/fontawesome-free/svgs/solid/sign-in-alt.svg +1 -0
  1718. package/static/vendor/fontawesome-free/svgs/solid/sign-language.svg +1 -0
  1719. package/static/vendor/fontawesome-free/svgs/solid/sign-out-alt.svg +1 -0
  1720. package/static/vendor/fontawesome-free/svgs/solid/sign.svg +1 -0
  1721. package/static/vendor/fontawesome-free/svgs/solid/signal.svg +1 -0
  1722. package/static/vendor/fontawesome-free/svgs/solid/signature.svg +1 -0
  1723. package/static/vendor/fontawesome-free/svgs/solid/sim-card.svg +1 -0
  1724. package/static/vendor/fontawesome-free/svgs/solid/sink.svg +1 -0
  1725. package/static/vendor/fontawesome-free/svgs/solid/sitemap.svg +1 -0
  1726. package/static/vendor/fontawesome-free/svgs/solid/skating.svg +1 -0
  1727. package/static/vendor/fontawesome-free/svgs/solid/skiing-nordic.svg +1 -0
  1728. package/static/vendor/fontawesome-free/svgs/solid/skiing.svg +1 -0
  1729. package/static/vendor/fontawesome-free/svgs/solid/skull-crossbones.svg +1 -0
  1730. package/static/vendor/fontawesome-free/svgs/solid/skull.svg +1 -0
  1731. package/static/vendor/fontawesome-free/svgs/solid/slash.svg +1 -0
  1732. package/static/vendor/fontawesome-free/svgs/solid/sleigh.svg +1 -0
  1733. package/static/vendor/fontawesome-free/svgs/solid/sliders-h.svg +1 -0
  1734. package/static/vendor/fontawesome-free/svgs/solid/smile-beam.svg +1 -0
  1735. package/static/vendor/fontawesome-free/svgs/solid/smile-wink.svg +1 -0
  1736. package/static/vendor/fontawesome-free/svgs/solid/smile.svg +1 -0
  1737. package/static/vendor/fontawesome-free/svgs/solid/smog.svg +1 -0
  1738. package/static/vendor/fontawesome-free/svgs/solid/smoking-ban.svg +1 -0
  1739. package/static/vendor/fontawesome-free/svgs/solid/smoking.svg +1 -0
  1740. package/static/vendor/fontawesome-free/svgs/solid/sms.svg +1 -0
  1741. package/static/vendor/fontawesome-free/svgs/solid/snowboarding.svg +1 -0
  1742. package/static/vendor/fontawesome-free/svgs/solid/snowflake.svg +1 -0
  1743. package/static/vendor/fontawesome-free/svgs/solid/snowman.svg +1 -0
  1744. package/static/vendor/fontawesome-free/svgs/solid/snowplow.svg +1 -0
  1745. package/static/vendor/fontawesome-free/svgs/solid/soap.svg +1 -0
  1746. package/static/vendor/fontawesome-free/svgs/solid/socks.svg +1 -0
  1747. package/static/vendor/fontawesome-free/svgs/solid/solar-panel.svg +1 -0
  1748. package/static/vendor/fontawesome-free/svgs/solid/sort-alpha-down-alt.svg +1 -0
  1749. package/static/vendor/fontawesome-free/svgs/solid/sort-alpha-down.svg +1 -0
  1750. package/static/vendor/fontawesome-free/svgs/solid/sort-alpha-up-alt.svg +1 -0
  1751. package/static/vendor/fontawesome-free/svgs/solid/sort-alpha-up.svg +1 -0
  1752. package/static/vendor/fontawesome-free/svgs/solid/sort-amount-down-alt.svg +1 -0
  1753. package/static/vendor/fontawesome-free/svgs/solid/sort-amount-down.svg +1 -0
  1754. package/static/vendor/fontawesome-free/svgs/solid/sort-amount-up-alt.svg +1 -0
  1755. package/static/vendor/fontawesome-free/svgs/solid/sort-amount-up.svg +1 -0
  1756. package/static/vendor/fontawesome-free/svgs/solid/sort-down.svg +1 -0
  1757. package/static/vendor/fontawesome-free/svgs/solid/sort-numeric-down-alt.svg +1 -0
  1758. package/static/vendor/fontawesome-free/svgs/solid/sort-numeric-down.svg +1 -0
  1759. package/static/vendor/fontawesome-free/svgs/solid/sort-numeric-up-alt.svg +1 -0
  1760. package/static/vendor/fontawesome-free/svgs/solid/sort-numeric-up.svg +1 -0
  1761. package/static/vendor/fontawesome-free/svgs/solid/sort-up.svg +1 -0
  1762. package/static/vendor/fontawesome-free/svgs/solid/sort.svg +1 -0
  1763. package/static/vendor/fontawesome-free/svgs/solid/spa.svg +1 -0
  1764. package/static/vendor/fontawesome-free/svgs/solid/space-shuttle.svg +1 -0
  1765. package/static/vendor/fontawesome-free/svgs/solid/spell-check.svg +1 -0
  1766. package/static/vendor/fontawesome-free/svgs/solid/spider.svg +1 -0
  1767. package/static/vendor/fontawesome-free/svgs/solid/spinner.svg +1 -0
  1768. package/static/vendor/fontawesome-free/svgs/solid/splotch.svg +1 -0
  1769. package/static/vendor/fontawesome-free/svgs/solid/spray-can.svg +1 -0
  1770. package/static/vendor/fontawesome-free/svgs/solid/square-full.svg +1 -0
  1771. package/static/vendor/fontawesome-free/svgs/solid/square-root-alt.svg +1 -0
  1772. package/static/vendor/fontawesome-free/svgs/solid/square.svg +1 -0
  1773. package/static/vendor/fontawesome-free/svgs/solid/stamp.svg +1 -0
  1774. package/static/vendor/fontawesome-free/svgs/solid/star-and-crescent.svg +1 -0
  1775. package/static/vendor/fontawesome-free/svgs/solid/star-half-alt.svg +1 -0
  1776. package/static/vendor/fontawesome-free/svgs/solid/star-half.svg +1 -0
  1777. package/static/vendor/fontawesome-free/svgs/solid/star-of-david.svg +1 -0
  1778. package/static/vendor/fontawesome-free/svgs/solid/star-of-life.svg +1 -0
  1779. package/static/vendor/fontawesome-free/svgs/solid/star.svg +1 -0
  1780. package/static/vendor/fontawesome-free/svgs/solid/step-backward.svg +1 -0
  1781. package/static/vendor/fontawesome-free/svgs/solid/step-forward.svg +1 -0
  1782. package/static/vendor/fontawesome-free/svgs/solid/stethoscope.svg +1 -0
  1783. package/static/vendor/fontawesome-free/svgs/solid/sticky-note.svg +1 -0
  1784. package/static/vendor/fontawesome-free/svgs/solid/stop-circle.svg +1 -0
  1785. package/static/vendor/fontawesome-free/svgs/solid/stop.svg +1 -0
  1786. package/static/vendor/fontawesome-free/svgs/solid/stopwatch-20.svg +1 -0
  1787. package/static/vendor/fontawesome-free/svgs/solid/stopwatch.svg +1 -0
  1788. package/static/vendor/fontawesome-free/svgs/solid/store-alt-slash.svg +1 -0
  1789. package/static/vendor/fontawesome-free/svgs/solid/store-alt.svg +1 -0
  1790. package/static/vendor/fontawesome-free/svgs/solid/store-slash.svg +1 -0
  1791. package/static/vendor/fontawesome-free/svgs/solid/store.svg +1 -0
  1792. package/static/vendor/fontawesome-free/svgs/solid/stream.svg +1 -0
  1793. package/static/vendor/fontawesome-free/svgs/solid/street-view.svg +1 -0
  1794. package/static/vendor/fontawesome-free/svgs/solid/strikethrough.svg +1 -0
  1795. package/static/vendor/fontawesome-free/svgs/solid/stroopwafel.svg +1 -0
  1796. package/static/vendor/fontawesome-free/svgs/solid/subscript.svg +1 -0
  1797. package/static/vendor/fontawesome-free/svgs/solid/subway.svg +1 -0
  1798. package/static/vendor/fontawesome-free/svgs/solid/suitcase-rolling.svg +1 -0
  1799. package/static/vendor/fontawesome-free/svgs/solid/suitcase.svg +1 -0
  1800. package/static/vendor/fontawesome-free/svgs/solid/sun.svg +1 -0
  1801. package/static/vendor/fontawesome-free/svgs/solid/superscript.svg +1 -0
  1802. package/static/vendor/fontawesome-free/svgs/solid/surprise.svg +1 -0
  1803. package/static/vendor/fontawesome-free/svgs/solid/swatchbook.svg +1 -0
  1804. package/static/vendor/fontawesome-free/svgs/solid/swimmer.svg +1 -0
  1805. package/static/vendor/fontawesome-free/svgs/solid/swimming-pool.svg +1 -0
  1806. package/static/vendor/fontawesome-free/svgs/solid/synagogue.svg +1 -0
  1807. package/static/vendor/fontawesome-free/svgs/solid/sync-alt.svg +1 -0
  1808. package/static/vendor/fontawesome-free/svgs/solid/sync.svg +1 -0
  1809. package/static/vendor/fontawesome-free/svgs/solid/syringe.svg +1 -0
  1810. package/static/vendor/fontawesome-free/svgs/solid/table-tennis.svg +1 -0
  1811. package/static/vendor/fontawesome-free/svgs/solid/table.svg +1 -0
  1812. package/static/vendor/fontawesome-free/svgs/solid/tablet-alt.svg +1 -0
  1813. package/static/vendor/fontawesome-free/svgs/solid/tablet.svg +1 -0
  1814. package/static/vendor/fontawesome-free/svgs/solid/tablets.svg +1 -0
  1815. package/static/vendor/fontawesome-free/svgs/solid/tachometer-alt.svg +1 -0
  1816. package/static/vendor/fontawesome-free/svgs/solid/tag.svg +1 -0
  1817. package/static/vendor/fontawesome-free/svgs/solid/tags.svg +1 -0
  1818. package/static/vendor/fontawesome-free/svgs/solid/tape.svg +1 -0
  1819. package/static/vendor/fontawesome-free/svgs/solid/tasks.svg +1 -0
  1820. package/static/vendor/fontawesome-free/svgs/solid/taxi.svg +1 -0
  1821. package/static/vendor/fontawesome-free/svgs/solid/teeth-open.svg +1 -0
  1822. package/static/vendor/fontawesome-free/svgs/solid/teeth.svg +1 -0
  1823. package/static/vendor/fontawesome-free/svgs/solid/temperature-high.svg +1 -0
  1824. package/static/vendor/fontawesome-free/svgs/solid/temperature-low.svg +1 -0
  1825. package/static/vendor/fontawesome-free/svgs/solid/tenge.svg +1 -0
  1826. package/static/vendor/fontawesome-free/svgs/solid/terminal.svg +1 -0
  1827. package/static/vendor/fontawesome-free/svgs/solid/text-height.svg +1 -0
  1828. package/static/vendor/fontawesome-free/svgs/solid/text-width.svg +1 -0
  1829. package/static/vendor/fontawesome-free/svgs/solid/th-large.svg +1 -0
  1830. package/static/vendor/fontawesome-free/svgs/solid/th-list.svg +1 -0
  1831. package/static/vendor/fontawesome-free/svgs/solid/th.svg +1 -0
  1832. package/static/vendor/fontawesome-free/svgs/solid/theater-masks.svg +1 -0
  1833. package/static/vendor/fontawesome-free/svgs/solid/thermometer-empty.svg +1 -0
  1834. package/static/vendor/fontawesome-free/svgs/solid/thermometer-full.svg +1 -0
  1835. package/static/vendor/fontawesome-free/svgs/solid/thermometer-half.svg +1 -0
  1836. package/static/vendor/fontawesome-free/svgs/solid/thermometer-quarter.svg +1 -0
  1837. package/static/vendor/fontawesome-free/svgs/solid/thermometer-three-quarters.svg +1 -0
  1838. package/static/vendor/fontawesome-free/svgs/solid/thermometer.svg +1 -0
  1839. package/static/vendor/fontawesome-free/svgs/solid/thumbs-down.svg +1 -0
  1840. package/static/vendor/fontawesome-free/svgs/solid/thumbs-up.svg +1 -0
  1841. package/static/vendor/fontawesome-free/svgs/solid/thumbtack.svg +1 -0
  1842. package/static/vendor/fontawesome-free/svgs/solid/ticket-alt.svg +1 -0
  1843. package/static/vendor/fontawesome-free/svgs/solid/times-circle.svg +1 -0
  1844. package/static/vendor/fontawesome-free/svgs/solid/times.svg +1 -0
  1845. package/static/vendor/fontawesome-free/svgs/solid/tint-slash.svg +1 -0
  1846. package/static/vendor/fontawesome-free/svgs/solid/tint.svg +1 -0
  1847. package/static/vendor/fontawesome-free/svgs/solid/tired.svg +1 -0
  1848. package/static/vendor/fontawesome-free/svgs/solid/toggle-off.svg +1 -0
  1849. package/static/vendor/fontawesome-free/svgs/solid/toggle-on.svg +1 -0
  1850. package/static/vendor/fontawesome-free/svgs/solid/toilet-paper-slash.svg +1 -0
  1851. package/static/vendor/fontawesome-free/svgs/solid/toilet-paper.svg +1 -0
  1852. package/static/vendor/fontawesome-free/svgs/solid/toilet.svg +1 -0
  1853. package/static/vendor/fontawesome-free/svgs/solid/toolbox.svg +1 -0
  1854. package/static/vendor/fontawesome-free/svgs/solid/tools.svg +1 -0
  1855. package/static/vendor/fontawesome-free/svgs/solid/tooth.svg +1 -0
  1856. package/static/vendor/fontawesome-free/svgs/solid/torah.svg +1 -0
  1857. package/static/vendor/fontawesome-free/svgs/solid/torii-gate.svg +1 -0
  1858. package/static/vendor/fontawesome-free/svgs/solid/tractor.svg +1 -0
  1859. package/static/vendor/fontawesome-free/svgs/solid/trademark.svg +1 -0
  1860. package/static/vendor/fontawesome-free/svgs/solid/traffic-light.svg +1 -0
  1861. package/static/vendor/fontawesome-free/svgs/solid/trailer.svg +1 -0
  1862. package/static/vendor/fontawesome-free/svgs/solid/train.svg +1 -0
  1863. package/static/vendor/fontawesome-free/svgs/solid/tram.svg +1 -0
  1864. package/static/vendor/fontawesome-free/svgs/solid/transgender-alt.svg +1 -0
  1865. package/static/vendor/fontawesome-free/svgs/solid/transgender.svg +1 -0
  1866. package/static/vendor/fontawesome-free/svgs/solid/trash-alt.svg +1 -0
  1867. package/static/vendor/fontawesome-free/svgs/solid/trash-restore-alt.svg +1 -0
  1868. package/static/vendor/fontawesome-free/svgs/solid/trash-restore.svg +1 -0
  1869. package/static/vendor/fontawesome-free/svgs/solid/trash.svg +1 -0
  1870. package/static/vendor/fontawesome-free/svgs/solid/tree.svg +1 -0
  1871. package/static/vendor/fontawesome-free/svgs/solid/trophy.svg +1 -0
  1872. package/static/vendor/fontawesome-free/svgs/solid/truck-loading.svg +1 -0
  1873. package/static/vendor/fontawesome-free/svgs/solid/truck-monster.svg +1 -0
  1874. package/static/vendor/fontawesome-free/svgs/solid/truck-moving.svg +1 -0
  1875. package/static/vendor/fontawesome-free/svgs/solid/truck-pickup.svg +1 -0
  1876. package/static/vendor/fontawesome-free/svgs/solid/truck.svg +1 -0
  1877. package/static/vendor/fontawesome-free/svgs/solid/tshirt.svg +1 -0
  1878. package/static/vendor/fontawesome-free/svgs/solid/tty.svg +1 -0
  1879. package/static/vendor/fontawesome-free/svgs/solid/tv.svg +1 -0
  1880. package/static/vendor/fontawesome-free/svgs/solid/umbrella-beach.svg +1 -0
  1881. package/static/vendor/fontawesome-free/svgs/solid/umbrella.svg +1 -0
  1882. package/static/vendor/fontawesome-free/svgs/solid/underline.svg +1 -0
  1883. package/static/vendor/fontawesome-free/svgs/solid/undo-alt.svg +1 -0
  1884. package/static/vendor/fontawesome-free/svgs/solid/undo.svg +1 -0
  1885. package/static/vendor/fontawesome-free/svgs/solid/universal-access.svg +1 -0
  1886. package/static/vendor/fontawesome-free/svgs/solid/university.svg +1 -0
  1887. package/static/vendor/fontawesome-free/svgs/solid/unlink.svg +1 -0
  1888. package/static/vendor/fontawesome-free/svgs/solid/unlock-alt.svg +1 -0
  1889. package/static/vendor/fontawesome-free/svgs/solid/unlock.svg +1 -0
  1890. package/static/vendor/fontawesome-free/svgs/solid/upload.svg +1 -0
  1891. package/static/vendor/fontawesome-free/svgs/solid/user-alt-slash.svg +1 -0
  1892. package/static/vendor/fontawesome-free/svgs/solid/user-alt.svg +1 -0
  1893. package/static/vendor/fontawesome-free/svgs/solid/user-astronaut.svg +1 -0
  1894. package/static/vendor/fontawesome-free/svgs/solid/user-check.svg +1 -0
  1895. package/static/vendor/fontawesome-free/svgs/solid/user-circle.svg +1 -0
  1896. package/static/vendor/fontawesome-free/svgs/solid/user-clock.svg +1 -0
  1897. package/static/vendor/fontawesome-free/svgs/solid/user-cog.svg +1 -0
  1898. package/static/vendor/fontawesome-free/svgs/solid/user-edit.svg +1 -0
  1899. package/static/vendor/fontawesome-free/svgs/solid/user-friends.svg +1 -0
  1900. package/static/vendor/fontawesome-free/svgs/solid/user-graduate.svg +1 -0
  1901. package/static/vendor/fontawesome-free/svgs/solid/user-injured.svg +1 -0
  1902. package/static/vendor/fontawesome-free/svgs/solid/user-lock.svg +1 -0
  1903. package/static/vendor/fontawesome-free/svgs/solid/user-md.svg +1 -0
  1904. package/static/vendor/fontawesome-free/svgs/solid/user-minus.svg +1 -0
  1905. package/static/vendor/fontawesome-free/svgs/solid/user-ninja.svg +1 -0
  1906. package/static/vendor/fontawesome-free/svgs/solid/user-nurse.svg +1 -0
  1907. package/static/vendor/fontawesome-free/svgs/solid/user-plus.svg +1 -0
  1908. package/static/vendor/fontawesome-free/svgs/solid/user-secret.svg +1 -0
  1909. package/static/vendor/fontawesome-free/svgs/solid/user-shield.svg +1 -0
  1910. package/static/vendor/fontawesome-free/svgs/solid/user-slash.svg +1 -0
  1911. package/static/vendor/fontawesome-free/svgs/solid/user-tag.svg +1 -0
  1912. package/static/vendor/fontawesome-free/svgs/solid/user-tie.svg +1 -0
  1913. package/static/vendor/fontawesome-free/svgs/solid/user-times.svg +1 -0
  1914. package/static/vendor/fontawesome-free/svgs/solid/user.svg +1 -0
  1915. package/static/vendor/fontawesome-free/svgs/solid/users-cog.svg +1 -0
  1916. package/static/vendor/fontawesome-free/svgs/solid/users-slash.svg +1 -0
  1917. package/static/vendor/fontawesome-free/svgs/solid/users.svg +1 -0
  1918. package/static/vendor/fontawesome-free/svgs/solid/utensil-spoon.svg +1 -0
  1919. package/static/vendor/fontawesome-free/svgs/solid/utensils.svg +1 -0
  1920. package/static/vendor/fontawesome-free/svgs/solid/vector-square.svg +1 -0
  1921. package/static/vendor/fontawesome-free/svgs/solid/venus-double.svg +1 -0
  1922. package/static/vendor/fontawesome-free/svgs/solid/venus-mars.svg +1 -0
  1923. package/static/vendor/fontawesome-free/svgs/solid/venus.svg +1 -0
  1924. package/static/vendor/fontawesome-free/svgs/solid/vest-patches.svg +1 -0
  1925. package/static/vendor/fontawesome-free/svgs/solid/vest.svg +1 -0
  1926. package/static/vendor/fontawesome-free/svgs/solid/vial.svg +1 -0
  1927. package/static/vendor/fontawesome-free/svgs/solid/vials.svg +1 -0
  1928. package/static/vendor/fontawesome-free/svgs/solid/video-slash.svg +1 -0
  1929. package/static/vendor/fontawesome-free/svgs/solid/video.svg +1 -0
  1930. package/static/vendor/fontawesome-free/svgs/solid/vihara.svg +1 -0
  1931. package/static/vendor/fontawesome-free/svgs/solid/virus-slash.svg +1 -0
  1932. package/static/vendor/fontawesome-free/svgs/solid/virus.svg +1 -0
  1933. package/static/vendor/fontawesome-free/svgs/solid/viruses.svg +1 -0
  1934. package/static/vendor/fontawesome-free/svgs/solid/voicemail.svg +1 -0
  1935. package/static/vendor/fontawesome-free/svgs/solid/volleyball-ball.svg +1 -0
  1936. package/static/vendor/fontawesome-free/svgs/solid/volume-down.svg +1 -0
  1937. package/static/vendor/fontawesome-free/svgs/solid/volume-mute.svg +1 -0
  1938. package/static/vendor/fontawesome-free/svgs/solid/volume-off.svg +1 -0
  1939. package/static/vendor/fontawesome-free/svgs/solid/volume-up.svg +1 -0
  1940. package/static/vendor/fontawesome-free/svgs/solid/vote-yea.svg +1 -0
  1941. package/static/vendor/fontawesome-free/svgs/solid/vr-cardboard.svg +1 -0
  1942. package/static/vendor/fontawesome-free/svgs/solid/walking.svg +1 -0
  1943. package/static/vendor/fontawesome-free/svgs/solid/wallet.svg +1 -0
  1944. package/static/vendor/fontawesome-free/svgs/solid/warehouse.svg +1 -0
  1945. package/static/vendor/fontawesome-free/svgs/solid/water.svg +1 -0
  1946. package/static/vendor/fontawesome-free/svgs/solid/wave-square.svg +1 -0
  1947. package/static/vendor/fontawesome-free/svgs/solid/weight-hanging.svg +1 -0
  1948. package/static/vendor/fontawesome-free/svgs/solid/weight.svg +1 -0
  1949. package/static/vendor/fontawesome-free/svgs/solid/wheelchair.svg +1 -0
  1950. package/static/vendor/fontawesome-free/svgs/solid/wifi.svg +1 -0
  1951. package/static/vendor/fontawesome-free/svgs/solid/wind.svg +1 -0
  1952. package/static/vendor/fontawesome-free/svgs/solid/window-close.svg +1 -0
  1953. package/static/vendor/fontawesome-free/svgs/solid/window-maximize.svg +1 -0
  1954. package/static/vendor/fontawesome-free/svgs/solid/window-minimize.svg +1 -0
  1955. package/static/vendor/fontawesome-free/svgs/solid/window-restore.svg +1 -0
  1956. package/static/vendor/fontawesome-free/svgs/solid/wine-bottle.svg +1 -0
  1957. package/static/vendor/fontawesome-free/svgs/solid/wine-glass-alt.svg +1 -0
  1958. package/static/vendor/fontawesome-free/svgs/solid/wine-glass.svg +1 -0
  1959. package/static/vendor/fontawesome-free/svgs/solid/won-sign.svg +1 -0
  1960. package/static/vendor/fontawesome-free/svgs/solid/wrench.svg +1 -0
  1961. package/static/vendor/fontawesome-free/svgs/solid/x-ray.svg +1 -0
  1962. package/static/vendor/fontawesome-free/svgs/solid/yen-sign.svg +1 -0
  1963. package/static/vendor/fontawesome-free/svgs/solid/yin-yang.svg +1 -0
  1964. package/static/vendor/fontawesome-free/webfonts/fa-brands-400.eot +0 -0
  1965. package/static/vendor/fontawesome-free/webfonts/fa-brands-400.svg +3717 -0
  1966. package/static/vendor/fontawesome-free/webfonts/fa-brands-400.ttf +0 -0
  1967. package/static/vendor/fontawesome-free/webfonts/fa-brands-400.woff +0 -0
  1968. package/static/vendor/fontawesome-free/webfonts/fa-brands-400.woff2 +0 -0
  1969. package/static/vendor/fontawesome-free/webfonts/fa-regular-400.eot +0 -0
  1970. package/static/vendor/fontawesome-free/webfonts/fa-regular-400.svg +801 -0
  1971. package/static/vendor/fontawesome-free/webfonts/fa-regular-400.ttf +0 -0
  1972. package/static/vendor/fontawesome-free/webfonts/fa-regular-400.woff +0 -0
  1973. package/static/vendor/fontawesome-free/webfonts/fa-regular-400.woff2 +0 -0
  1974. package/static/vendor/fontawesome-free/webfonts/fa-solid-900.eot +0 -0
  1975. package/static/vendor/fontawesome-free/webfonts/fa-solid-900.svg +5034 -0
  1976. package/static/vendor/fontawesome-free/webfonts/fa-solid-900.ttf +0 -0
  1977. package/static/vendor/fontawesome-free/webfonts/fa-solid-900.woff +0 -0
  1978. package/static/vendor/fontawesome-free/webfonts/fa-solid-900.woff2 +0 -0
  1979. package/static/vendor/handlebars/handlebars.min-v4.7.7.js +29 -0
  1980. package/static/vendor/jquery/jquery.js +10881 -0
  1981. package/static/vendor/jquery/jquery.min.js +2 -0
  1982. package/static/vendor/jquery/jquery.min.map +1 -0
  1983. package/static/vendor/jquery/jquery.slim.js +8782 -0
  1984. package/static/vendor/jquery/jquery.slim.min.js +2 -0
  1985. package/static/vendor/jquery/jquery.slim.min.map +1 -0
  1986. package/static/vendor/jquery-easing/jquery.easing.min.js +1 -0
  1987. package/systemd/emailengine.service +11 -3
  1988. package/systemd/nginx-proxy.conf +1 -1
  1989. package/test/api-test.js +899 -0
  1990. package/test/bounce-test.js +151 -0
  1991. package/test/fixtures/bounces/163.eml +2521 -0
  1992. package/test/fixtures/bounces/fastmail.eml +242 -0
  1993. package/test/fixtures/bounces/gmail.eml +252 -0
  1994. package/test/fixtures/bounces/hotmail.eml +655 -0
  1995. package/test/fixtures/bounces/mailru.eml +121 -0
  1996. package/test/fixtures/bounces/outlook.eml +1107 -0
  1997. package/test/fixtures/bounces/postfix.eml +101 -0
  1998. package/test/fixtures/bounces/rambler.eml +116 -0
  1999. package/test/fixtures/bounces/workmail.eml +142 -0
  2000. package/test/fixtures/bounces/yahoo.eml +139 -0
  2001. package/test/fixtures/bounces/zoho.eml +83 -0
  2002. package/test/fixtures/bounces/zonemta.eml +100 -0
  2003. package/test/oauth2-apps-test.js +301 -0
  2004. package/test/sendonly-test.js +160 -0
  2005. package/test/test-config.js +34 -0
  2006. package/test/webhooks-server.js +39 -0
  2007. package/translations/README.md +16 -0
  2008. package/translations/de.mo +0 -0
  2009. package/translations/de.po +335 -0
  2010. package/translations/en.mo +0 -0
  2011. package/translations/en.po +310 -0
  2012. package/translations/et.mo +0 -0
  2013. package/translations/et.po +331 -0
  2014. package/translations/fr.mo +0 -0
  2015. package/translations/fr.po +333 -0
  2016. package/translations/ja.mo +0 -0
  2017. package/translations/ja.po +322 -0
  2018. package/translations/locales.json +43 -0
  2019. package/translations/messages.pot +323 -0
  2020. package/translations/nl.mo +0 -0
  2021. package/translations/nl.po +325 -0
  2022. package/translations/pl.mo +0 -0
  2023. package/translations/pl.po +328 -0
  2024. package/update-info.sh +10 -0
  2025. package/views/account/login.hbs +54 -0
  2026. package/views/account/password.hbs +88 -0
  2027. package/views/account/security.hbs +269 -0
  2028. package/views/account/totp.hbs +30 -0
  2029. package/views/accounts/account.hbs +1254 -0
  2030. package/views/accounts/browse.hbs +102 -0
  2031. package/views/accounts/edit.hbs +332 -0
  2032. package/views/accounts/index.hbs +143 -0
  2033. package/views/accounts/register/imap-server.hbs +507 -0
  2034. package/views/accounts/register/imap.hbs +56 -0
  2035. package/views/accounts/register/index.hbs +52 -0
  2036. package/views/arena/index.hbs +4 -0
  2037. package/views/config/ai.hbs +820 -0
  2038. package/views/config/document-store/chat.hbs +362 -0
  2039. package/views/config/document-store/index.hbs +231 -0
  2040. package/views/config/document-store/mappings/index.hbs +116 -0
  2041. package/views/config/document-store/mappings/new.hbs +95 -0
  2042. package/views/config/document-store/pre-processing/index.hbs +459 -0
  2043. package/views/config/imap-proxy.hbs +479 -0
  2044. package/views/config/license.hbs +256 -0
  2045. package/views/config/logging.hbs +61 -0
  2046. package/views/config/network.hbs +334 -0
  2047. package/views/config/oauth/app.hbs +309 -0
  2048. package/views/config/oauth/edit.hbs +92 -0
  2049. package/views/config/oauth/index.hbs +150 -0
  2050. package/views/config/oauth/new.hbs +90 -0
  2051. package/views/config/oauth.hbs +354 -0
  2052. package/views/config/service-preview.hbs +14 -0
  2053. package/views/config/service.hbs +718 -0
  2054. package/views/config/smtp.hbs +525 -0
  2055. package/views/config/webhooks.hbs +404 -0
  2056. package/views/dashboard.hbs +315 -0
  2057. package/views/error.hbs +6 -1
  2058. package/views/gateways/edit.hbs +52 -0
  2059. package/views/gateways/gateway.hbs +120 -0
  2060. package/views/gateways/index.hbs +152 -0
  2061. package/views/gateways/new.hbs +61 -0
  2062. package/views/index.hbs +21 -0
  2063. package/views/internals/index.hbs +170 -0
  2064. package/views/internals/thread.hbs +143 -0
  2065. package/views/layout/app.hbs +516 -0
  2066. package/views/layout/login.hbs +78 -0
  2067. package/views/layout/main.hbs +67 -0
  2068. package/views/layout/public.hbs +90 -0
  2069. package/views/legal.hbs +83 -0
  2070. package/views/license.hbs +5 -0
  2071. package/views/partials/accounts_header.hbs +6 -0
  2072. package/views/partials/add_account_modal.hbs +60 -0
  2073. package/views/partials/address_list.hbs +37 -0
  2074. package/views/partials/alerts.hbs +33 -0
  2075. package/views/partials/document_store_header.hbs +52 -0
  2076. package/views/partials/editor_scope_info.hbs +10 -0
  2077. package/views/partials/gateway_form.hbs +65 -0
  2078. package/views/partials/gateway_js.hbs +90 -0
  2079. package/views/partials/gateways_header.hbs +6 -0
  2080. package/views/partials/oauth_config_header.hbs +10 -0
  2081. package/views/partials/oauth_form.hbs +1204 -0
  2082. package/views/partials/scope_info.hbs +134 -0
  2083. package/views/partials/security_header.hbs +11 -0
  2084. package/views/partials/side_menu.hbs +114 -0
  2085. package/views/partials/template_form.hbs +121 -0
  2086. package/views/partials/templates_header.hbs +6 -0
  2087. package/views/partials/test_send.hbs +327 -0
  2088. package/views/partials/tokens_header.hbs +6 -0
  2089. package/views/partials/webhook_form.hbs +151 -0
  2090. package/views/partials/webhooks_editor_functions.hbs +372 -0
  2091. package/views/partials/webhooks_header.hbs +6 -0
  2092. package/views/redirect.hbs +1 -0
  2093. package/views/swagger/index.hbs +76 -0
  2094. package/views/templates/edit.hbs +87 -0
  2095. package/views/templates/index.hbs +208 -0
  2096. package/views/templates/new.hbs +85 -0
  2097. package/views/templates/template.hbs +423 -0
  2098. package/views/tokens/index.hbs +207 -0
  2099. package/views/tokens/new.hbs +230 -0
  2100. package/views/unsubscribe.hbs +93 -0
  2101. package/views/upgrade.hbs +56 -0
  2102. package/views/webhooks/edit.hbs +31 -0
  2103. package/views/webhooks/index.hbs +144 -0
  2104. package/views/webhooks/new.hbs +27 -0
  2105. package/views/webhooks/webhook.hbs +265 -0
  2106. package/winconf.js +93 -0
  2107. package/workers/api.js +8246 -1256
  2108. package/workers/documents.js +1120 -0
  2109. package/workers/imap-proxy.js +91 -0
  2110. package/workers/imap.js +552 -161
  2111. package/workers/smtp.js +355 -82
  2112. package/workers/submit.js +319 -54
  2113. package/workers/webhooks.js +542 -80
  2114. package/.eslintrc +0 -14
  2115. package/.github/FUNDING.yml +0 -4
  2116. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  2117. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  2118. package/LICENSE.txt +0 -661
  2119. package/examples/api.md +0 -137
  2120. package/lib/connection.js +0 -1769
  2121. package/lib/lua/z-push.lua +0 -14
  2122. package/lib/mailbox.js +0 -1546
  2123. package/license-report-config.json +0 -3
  2124. package/licenses.txt +0 -37
  2125. package/static/bootstrap-4.6.0-dist/css/bootstrap-grid.css.map +0 -1
  2126. package/static/bootstrap-4.6.0-dist/css/bootstrap-reboot.css.map +0 -1
  2127. package/static/bootstrap-4.6.0-dist/css/bootstrap-reboot.min.css.map +0 -1
  2128. package/static/bootstrap-4.6.0-dist/css/bootstrap.css.map +0 -1
  2129. package/static/bootstrap-4.6.0-dist/css/bootstrap.min.css +0 -7
  2130. package/static/bootstrap-4.6.0-dist/css/bootstrap.min.css.map +0 -1
  2131. package/static/bootstrap-4.6.0-dist/js/bootstrap.bundle.js +0 -7045
  2132. package/static/bootstrap-4.6.0-dist/js/bootstrap.bundle.js.map +0 -1
  2133. package/static/bootstrap-4.6.0-dist/js/bootstrap.bundle.min.js +0 -7
  2134. package/static/bootstrap-4.6.0-dist/js/bootstrap.bundle.min.js.map +0 -1
  2135. package/static/bootstrap-4.6.0-dist/js/bootstrap.js.map +0 -1
  2136. package/static/bootstrap-4.6.0-dist/js/bootstrap.min.js +0 -7
  2137. package/static/bootstrap-4.6.0-dist/js/bootstrap.min.js.map +0 -1
  2138. package/static/js/emailengine.js +0 -581
  2139. package/workers/arena.js +0 -89
@@ -0,0 +1,2796 @@
1
+ 'use strict';
2
+
3
+ const { Account } = require('../account');
4
+ const { oauth2Apps } = require('../oauth2-apps');
5
+ const getSecret = require('../get-secret');
6
+ const msgpack = require('msgpack5')();
7
+ const addressparser = require('nodemailer/lib/addressparser');
8
+ const libmime = require('libmime');
9
+ const he = require('he');
10
+ const { BaseClient, metricsMeta } = require('./base-client');
11
+ const { mimeHtml } = require('@postalsys/email-text-tools');
12
+ const { emitChangeEvent } = require('../tools');
13
+ const { Gateway } = require('../gateway');
14
+
15
+ const {
16
+ MESSAGE_UPDATED_NOTIFY,
17
+ MESSAGE_DELETED_NOTIFY,
18
+ MESSAGE_MISSING_NOTIFY,
19
+ EMAIL_SENT_NOTIFY,
20
+ REDIS_PREFIX,
21
+ AUTH_ERROR_NOTIFY,
22
+ AUTH_SUCCESS_NOTIFY
23
+ } = require('../consts');
24
+
25
+ // Gmail API configuration
26
+ const GMAIL_API_BASE = 'https://gmail.googleapis.com';
27
+ const LIST_BATCH_SIZE = 10; // how many listing requests to run at the same time
28
+
29
+ // Labels to exclude from folder listings
30
+ const SKIP_LABELS = ['UNREAD', 'STARRED', 'IMPORTANT', 'CHAT', 'CATEGORY_PERSONAL'];
31
+
32
+ // Maps Gmail system labels to IMAP special-use flags
33
+ const SYSTEM_LABELS = {
34
+ SENT: '\\Sent',
35
+ INBOX: '\\Inbox',
36
+ TRASH: '\\Trash',
37
+ DRAFT: '\\Drafts',
38
+ SPAM: '\\Junk',
39
+ IMPORTANT: '\\Important'
40
+ };
41
+
42
+ // User-friendly names for system labels
43
+ const SYSTEM_NAMES = {
44
+ SENT: 'Sent ',
45
+ INBOX: 'Inbox',
46
+ TRASH: 'Trash',
47
+ DRAFT: 'Drafts',
48
+ SPAM: 'Spam',
49
+ CATEGORY_FORUMS: 'Forums',
50
+ CATEGORY_UPDATES: 'Updates',
51
+ CATEGORY_SOCIAL: 'Social',
52
+ CATEGORY_PROMOTIONS: 'Promotions'
53
+ };
54
+
55
+ // Reverse mapping for IMAP special-use to Gmail labels
56
+ const SYSTEM_LABELS_REV = {};
57
+ for (let label of Object.keys(SYSTEM_LABELS)) {
58
+ SYSTEM_LABELS_REV[SYSTEM_LABELS[label]] = label;
59
+ }
60
+
61
+ // Timing constants for Gmail Pub/Sub watch
62
+ const RENEW_WATCH_TTL = 60 * 60 * 1000; // 1h - how often to check if watch needs renewal
63
+ const MIN_WATCH_TTL = 24 * 3600 * 1000; // 1day - minimum time before renewing watch
64
+
65
+ /*
66
+ Gmail API implementation status:
67
+
68
+ ✅ listMessages - with cursor-based pagination
69
+ ✅ getText
70
+ ✅ getMessage
71
+ ✅ updateMessage
72
+ ✅ updateMessages
73
+ ✅ listMailboxes
74
+ ✅ moveMessage
75
+ ✅ moveMessages
76
+ ✅ deleteMessage - no force option (moves to trash)
77
+ ✅ deleteMessages - no force option (moves to trash)
78
+ ✅ getRawMessage
79
+ 🟡 getQuota - not supported by Gmail API
80
+ ✅ createMailbox
81
+ ✅ renameMailbox
82
+ ✅ deleteMailbox
83
+ ✅ getAttachment
84
+ ✅ submitMessage
85
+ ✅ uploadMessage
86
+ 🟡 subconnections - not supported (no IDLE equivalent)
87
+ */
88
+
89
+ /**
90
+ * Handles cursor-based pagination for Gmail API
91
+ * Gmail uses pageTokens, but we wrap them in a more complex cursor
92
+ * to support backward pagination and multiple pages
93
+ */
94
+ class PageCursor {
95
+ static create(cursorStr) {
96
+ return new PageCursor(cursorStr);
97
+ }
98
+
99
+ constructor(cursorStr) {
100
+ this.type = 'gmail';
101
+ this.cursorList = []; // Array of page tokens for navigation history
102
+ this.cursorStr = '';
103
+
104
+ if (cursorStr) {
105
+ // Extract cursor type prefix
106
+ let splitPos = cursorStr.indexOf('_');
107
+ if (splitPos >= 0) {
108
+ let cursorType = cursorStr.substring(0, splitPos);
109
+ cursorStr = cursorStr.substring(splitPos + 1);
110
+ if (cursorType && this.type !== cursorType) {
111
+ let error = new Error('Invalid cursor');
112
+ error.code = 'InvalidCursorType';
113
+ error.statusCode = 400;
114
+ throw error;
115
+ }
116
+ }
117
+
118
+ // Decode cursor data
119
+ try {
120
+ this.cursorList = msgpack.decode(Buffer.from(cursorStr, 'base64url'));
121
+ this.cursorStr = cursorStr;
122
+ } catch (err) {
123
+ this.cursorList = [];
124
+ this.cursorStr = '';
125
+ }
126
+ }
127
+ }
128
+
129
+ toString() {
130
+ return this.cursorStr;
131
+ }
132
+
133
+ /**
134
+ * Gets current page information from cursor
135
+ * @returns {Object} Current page details
136
+ */
137
+ currentPage() {
138
+ if (this.cursorList.length < 1) {
139
+ return { page: 0, cursor: '', pageCursor: '' };
140
+ }
141
+
142
+ return { page: this.cursorList.length, cursor: this.decodeCursorValue(this.cursorList.at(-1)), pageCursor: this.cursorStr };
143
+ }
144
+
145
+ /**
146
+ * Creates cursor for next page
147
+ * @param {string} nextPageCursor - Gmail's nextPageToken
148
+ * @returns {string|null} Encoded cursor string
149
+ */
150
+ nextPageCursor(nextPageCursor) {
151
+ if (!nextPageCursor) {
152
+ return null;
153
+ }
154
+ let encodedCursor = this.encodeCursorValue(nextPageCursor);
155
+ // if nextPageCursor is an array, then it will be flattened, have to push instead
156
+ let cursorListCopy = this.cursorList.concat([]);
157
+ cursorListCopy.push(encodedCursor);
158
+ return this.type + '_' + msgpack.encode(cursorListCopy).toString('base64url');
159
+ }
160
+
161
+ /**
162
+ * Creates cursor for previous page by removing last page token
163
+ * @returns {string|null} Encoded cursor string
164
+ */
165
+ prevPageCursor() {
166
+ if (this.cursorList.length < 1) {
167
+ return null;
168
+ }
169
+
170
+ return this.type + '_' + msgpack.encode(this.cursorList.slice(0, this.cursorList.length - 1)).toString('base64url');
171
+ }
172
+
173
+ /**
174
+ * Encodes a cursor value (page token) for storage
175
+ * Handles very large numeric IDs by chunking them
176
+ * @param {string} cursor - Page token to encode
177
+ * @returns {Buffer|Array<Buffer>} Encoded cursor
178
+ */
179
+ encodeCursorValue(cursor) {
180
+ let hexNr = BigInt(cursor).toString(16);
181
+
182
+ // split to chunks of 16. This monstrosity ensures that we start from the right
183
+ let chunks = hexNr
184
+ .split('')
185
+ .reverse()
186
+ .join('')
187
+ .split(/(.{16})/)
188
+ .filter(v => v)
189
+ .reverse()
190
+ .map(v => v.split('').reverse().join(''))
191
+ .map(v => {
192
+ let n = BigInt(`0x${v}`);
193
+ let buf = Buffer.alloc(8);
194
+ buf.writeBigUInt64LE(n, 0);
195
+ return buf;
196
+ });
197
+
198
+ return chunks.length > 1 ? chunks : chunks[0];
199
+ }
200
+
201
+ /**
202
+ * Decodes a stored cursor value back to page token
203
+ * @param {Buffer|Array<Buffer>} value - Encoded cursor
204
+ * @returns {string|null} Decoded page token
205
+ */
206
+ decodeCursorValue(value) {
207
+ if (!value || !value.length) {
208
+ return null;
209
+ }
210
+
211
+ if (typeof value[0] === 'number') {
212
+ value = [value];
213
+ }
214
+
215
+ let hexNr = value
216
+ .map(buf => {
217
+ let n = buf.readBigUInt64LE(0);
218
+ let hexN = n.toString(16);
219
+ if (hexN.length < 16) {
220
+ // add missing zero padding
221
+ hexN = '0'.repeat(16 - hexN.length) + hexN;
222
+ }
223
+ return hexN;
224
+ })
225
+ .join('');
226
+
227
+ return BigInt('0x' + hexNr).toString(10);
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Gmail-specific email client implementation
233
+ * Uses Gmail API instead of IMAP for better performance and features
234
+ */
235
+ class GmailClient extends BaseClient {
236
+ constructor(account, options) {
237
+ super(account, options);
238
+
239
+ this.cachedAccessToken = null;
240
+ this.cachedAccessTokenRaw = null;
241
+
242
+ // pseudo path for webhooks - Gmail doesn't have folders like IMAP
243
+ this.path = '\\All';
244
+ this.listingEntry = { specialUse: '\\All' };
245
+
246
+ this.processingHistory = null;
247
+ this.renewWatchTimer = null;
248
+
249
+ this.cachedLabels = null;
250
+ }
251
+
252
+ /**
253
+ * Makes authenticated request to Gmail API
254
+ * Handles token refresh automatically
255
+ * @param {...any} args - Request parameters
256
+ * @returns {Object} API response
257
+ */
258
+ async request(...args) {
259
+ let result, accessToken;
260
+ try {
261
+ accessToken = await this.getToken();
262
+ } catch (err) {
263
+ this.logger.error({ msg: 'Failed to load access token', account: this.account, err });
264
+ throw err;
265
+ }
266
+
267
+ try {
268
+ if (!this.oAuth2Client) {
269
+ await this.getClient();
270
+ }
271
+ result = await this.oAuth2Client.request(accessToken, ...args);
272
+
273
+ // Track successful API request
274
+ metricsMeta({ account: this.account }, this.logger, 'oauth2ApiRequest', 'inc', { status: 'success', provider: 'gmail', statusCode: '200' });
275
+ } catch (err) {
276
+ // Log client errors (4xx) at debug level - these are expected operational errors
277
+ // Log server errors (5xx) and other failures at error level
278
+ const status = err.oauthRequest?.status;
279
+ const isClientError = status >= 400 && status < 500;
280
+
281
+ if (isClientError) {
282
+ this.logger.debug({ msg: 'API request failed with client error', account: this.account, err });
283
+ } else {
284
+ this.logger.error({ msg: 'Failed to run API request', account: this.account, err });
285
+ }
286
+
287
+ // Track failed API request
288
+ const statusCode = String(err.oauthRequest?.status || 0);
289
+ metricsMeta({ account: this.account }, this.logger, 'oauth2ApiRequest', 'inc', { status: 'failure', provider: 'gmail', statusCode });
290
+
291
+ throw err;
292
+ }
293
+
294
+ return result;
295
+ }
296
+
297
+ // PUBLIC METHODS
298
+
299
+ /**
300
+ * Initializes Gmail connection and sets up real-time notifications
301
+ * @param {Object} opts - Initialization options
302
+ */
303
+ async init(opts) {
304
+ opts = opts || {};
305
+
306
+ this.state = 'connecting';
307
+ await this.setStateVal();
308
+
309
+ await this.getAccount();
310
+ await this.getClient(true);
311
+
312
+ // Ensure access token exists to get scopes
313
+ let accountData;
314
+ try {
315
+ await this.getToken();
316
+ // Reload account data after getting access token to ensure we have the latest OAuth2 scopes
317
+ accountData = await this.accountObject.loadAccountData(this.account);
318
+ } catch (err) {
319
+ this.logger.error({
320
+ msg: 'Failed to get token or reload account data during init',
321
+ account: this.account,
322
+ err
323
+ });
324
+ throw err;
325
+ }
326
+
327
+ // Check if send-only mode
328
+ const scopes = accountData.oauth2?.accessToken?.scope || accountData.oauth2?.scope || [];
329
+ const { hasSendScope, hasReadScope } = this.accountObject.checkAccountScopes('gmail', scopes);
330
+ const isSendOnly = hasSendScope && !hasReadScope;
331
+
332
+ this.logger.info({
333
+ msg: 'Account scopes loaded',
334
+ account: this.account,
335
+ scopes,
336
+ hasSendScope,
337
+ hasReadScope,
338
+ isSendOnly
339
+ });
340
+
341
+ if (!isSendOnly) {
342
+ // Set up Gmail Pub/Sub watch for real-time notifications (not needed for send-only)
343
+ await this.renewWatch(accountData, opts);
344
+ }
345
+
346
+ // Fetch user profile to verify authentication
347
+ let profileRes;
348
+ let userInfoRes;
349
+ try {
350
+ if (isSendOnly) {
351
+ // For send-only accounts, use Google UserInfo endpoint which works with openid/email/profile scopes
352
+ userInfoRes = await this.request(`https://www.googleapis.com/oauth2/v2/userinfo`, 'get');
353
+ } else {
354
+ // For full access accounts, use Gmail profile endpoint to also get historyId
355
+ profileRes = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/profile`);
356
+ }
357
+ } catch (err) {
358
+ this.state = 'authenticationError';
359
+ await this.setStateVal();
360
+
361
+ err.authenticationFailed = true;
362
+
363
+ if (!err.errorNotified) {
364
+ err.errorNotified = true;
365
+ await this.notify(false, AUTH_ERROR_NOTIFY, {
366
+ response: err.oauthRequest?.response?.error?.message || err.response,
367
+ serverResponseCode: 'ApiRequestError'
368
+ });
369
+ }
370
+
371
+ throw err;
372
+ }
373
+
374
+ let updates = {};
375
+
376
+ // Update account email if changed
377
+ if (isSendOnly) {
378
+ // Extract email from UserInfo response for send-only accounts
379
+ if (userInfoRes?.email && accountData.oauth2.auth?.user !== userInfoRes.email) {
380
+ updates._oldOAuth2User = accountData.oauth2.auth?.user;
381
+ updates.oauth2 = {
382
+ partial: true,
383
+ auth: Object.assign(accountData.oauth2.auth || {}, {
384
+ user: userInfoRes.email
385
+ })
386
+ };
387
+ }
388
+ } else {
389
+ // Extract email from profile for full access accounts
390
+ if (profileRes.emailAddress && accountData.oauth2.auth?.user !== profileRes.emailAddress) {
391
+ updates._oldOAuth2User = accountData.oauth2.auth?.user; // needed for cleanups
392
+ updates.oauth2 = {
393
+ partial: true,
394
+ auth: Object.assign(accountData.oauth2.auth || {}, {
395
+ // update username
396
+ user: profileRes.emailAddress
397
+ })
398
+ };
399
+ }
400
+ }
401
+
402
+ // Detect and store user locale (only for full access accounts)
403
+ if (!accountData.locale && !isSendOnly) {
404
+ try {
405
+ let locale = await this.getLocale();
406
+ if (locale) {
407
+ updates.locale = locale;
408
+ }
409
+ } catch (err) {
410
+ // not very important if succeeds or not
411
+ this.logger.error({
412
+ msg: 'Failed to resolve locale for account',
413
+ err
414
+ });
415
+ }
416
+ }
417
+
418
+ if (Object.keys(updates).length) {
419
+ await this.accountObject.update(updates);
420
+ accountData = await this.accountObject.loadAccountData(this.account, false);
421
+ }
422
+
423
+ this.logger.info({
424
+ msg: isSendOnly ? 'Initializing Gmail send-only account' : 'Initializing Gmail account',
425
+ provider: accountData.oauth2.provider,
426
+ user: accountData.oauth2.auth?.user,
427
+ sendOnly: isSendOnly
428
+ });
429
+
430
+ // Ensure Pub/Sub subscription mapping is correct
431
+ if (
432
+ accountData.oauth2.auth?.user &&
433
+ (await this.redis.hget(`${REDIS_PREFIX}oapp:h:${accountData.oauth2.provider}`, accountData.oauth2.auth?.user?.toLowerCase())) !== this.account
434
+ ) {
435
+ await this.redis.hset(`${REDIS_PREFIX}oapp:h:${accountData.oauth2.provider}`, accountData.oauth2.auth?.user?.toLowerCase(), this.account);
436
+ this.logger.info({ msg: 'Re-set missing Google Pub/Sub subscription', account: this.account, emailAddress: accountData.oauth2.auth?.user });
437
+ }
438
+
439
+ if (!isSendOnly) {
440
+ // Check and process history changes since last sync (only for full access accounts)
441
+ let historyId = Number(profileRes?.historyId) || null;
442
+ if (!accountData.googleHistoryId) {
443
+ // set as initial
444
+ await this.redis.hset(this.getAccountKey(), 'googleHistoryId', historyId.toString());
445
+ accountData.googleHistoryId = historyId;
446
+ this.logger.info({ msg: 'Re-set missing Google History ID', account: this.account, historyId });
447
+ }
448
+
449
+ if (historyId && accountData.googleHistoryId && historyId > accountData.googleHistoryId) {
450
+ // changes detected
451
+ this.triggerSync(accountData.googleHistoryId, historyId);
452
+ }
453
+
454
+ // Schedule periodic watch renewal (only for full access accounts)
455
+ this.setupRenewWatchTimer();
456
+ }
457
+
458
+ // Determine if this is a reconnection after error
459
+ let prevConnectedCount = await this.redis.hget(this.getAccountKey(), `state:count:connected`);
460
+ let isFirstSuccessfulConnection = prevConnectedCount === '0'; // string zero means the account has been initialized but not yet connected
461
+
462
+ this.state = 'connected';
463
+ await this.setStateVal();
464
+
465
+ let isiInitial = !!isFirstSuccessfulConnection;
466
+
467
+ if (!isFirstSuccessfulConnection) {
468
+ // check if the connection was previously in an errored state
469
+ let prevLastErrorState = await this.redis.hget(this.getAccountKey(), 'lastErrorState');
470
+ if (prevLastErrorState) {
471
+ try {
472
+ prevLastErrorState = JSON.parse(prevLastErrorState);
473
+ } catch (err) {
474
+ // ignore
475
+ }
476
+ }
477
+
478
+ if (prevLastErrorState && typeof prevLastErrorState === 'object' && Object.keys(prevLastErrorState).length) {
479
+ // was previously errored
480
+ isFirstSuccessfulConnection = true;
481
+ }
482
+ }
483
+
484
+ // Send appropriate authentication success notification
485
+ if (isFirstSuccessfulConnection) {
486
+ this.logger.info({ msg: 'Successful login without a previous active session', account: this.account, isiInitial, prevActive: false });
487
+ await this.notify(false, AUTH_SUCCESS_NOTIFY, {
488
+ user: accountData.oauth2?.auth?.user
489
+ });
490
+ } else {
491
+ this.logger.info({ msg: 'Successful login with a previous active session', account: this.account, isiInitial, prevActive: true });
492
+ }
493
+
494
+ // Clear any previous error state
495
+ await this.redis.hdel(this.getAccountKey(), 'lastErrorState', 'lastError:errorCount', 'lastError:first');
496
+ await emitChangeEvent(this.logger, this.account, 'state', this.state);
497
+ }
498
+
499
+ /**
500
+ * Closes Gmail connection and stops watch renewal
501
+ */
502
+ async close() {
503
+ clearTimeout(this.renewWatchTimer);
504
+ this.closed = true;
505
+
506
+ if (['init', 'connecting', 'syncing', 'connected'].includes(this.state)) {
507
+ this.state = 'disconnected';
508
+ await this.setStateVal();
509
+ await emitChangeEvent(this.logger, this.account, 'state', this.state);
510
+ }
511
+
512
+ return null;
513
+ }
514
+
515
+ async currentState() {
516
+ return (await this.redis.hget(this.getAccountKey(), 'state')) || 'disconnected';
517
+ }
518
+
519
+ async delete() {
520
+ clearTimeout(this.renewWatchTimer);
521
+ this.closed = true;
522
+
523
+ if (['init', 'connecting', 'syncing', 'connected'].includes(this.state)) {
524
+ this.state = 'disconnected';
525
+ await this.setStateVal();
526
+ await emitChangeEvent(this.logger, this.account, 'state', this.state);
527
+ }
528
+
529
+ return null;
530
+ }
531
+
532
+ async reconnect() {
533
+ return await this.init({ forceWatchRenewal: true });
534
+ }
535
+
536
+ /**
537
+ * Lists Gmail labels as IMAP-style mailboxes
538
+ * @param {Object} options - Listing options including status query
539
+ * @returns {Array} Array of mailbox objects
540
+ */
541
+ async listMailboxes(options) {
542
+ await this.prepare();
543
+
544
+ let labelsResult = await this.getLabels();
545
+
546
+ // Filter out system labels we don't want to show
547
+ let labels = labelsResult.filter(label => !SKIP_LABELS.includes(label.id));
548
+
549
+ let resultLabels;
550
+ if (options && options.statusQuery?.unseen) {
551
+ // Fetch detailed label info including message counts
552
+ let promises = [];
553
+ resultLabels = [];
554
+
555
+ let resolvePromises = async () => {
556
+ if (!promises.length) {
557
+ return;
558
+ }
559
+ let resultList = await Promise.allSettled(promises);
560
+ for (let entry of resultList) {
561
+ if (entry.status === 'rejected') {
562
+ throw entry.reason;
563
+ }
564
+ if (entry.value) {
565
+ resultLabels.push(entry.value);
566
+ }
567
+ }
568
+ promises = [];
569
+ };
570
+
571
+ // Batch API requests for efficiency
572
+ for (let label of labels) {
573
+ promises.push(this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/labels/${label.id}`));
574
+ if (promises.length > LIST_BATCH_SIZE) {
575
+ await resolvePromises();
576
+ }
577
+ }
578
+ await resolvePromises();
579
+ } else {
580
+ resultLabels = labels;
581
+ }
582
+
583
+ // Convert Gmail labels to IMAP-style mailbox structure
584
+ let mailboxes = resultLabels
585
+ .map(label => {
586
+ let pathParts = label.name.split('/');
587
+ let name = pathParts.pop();
588
+ let parentPath = pathParts.join('/');
589
+
590
+ let folderData = {
591
+ id: label.id,
592
+ path: label.name,
593
+ delimiter: '/',
594
+ parentPath,
595
+ name: label.type === 'system' && SYSTEM_NAMES[name] ? SYSTEM_NAMES[name] : name,
596
+ listed: true,
597
+ subscribed: true
598
+ };
599
+
600
+ // Map system labels to IMAP special-use flags
601
+ if (label.type === 'system' && SYSTEM_LABELS.hasOwnProperty(label.id)) {
602
+ folderData.specialUse = SYSTEM_LABELS[label.id];
603
+ folderData.specialUseSource = 'extension';
604
+ }
605
+
606
+ // Hide category labels (they appear as tabs in Gmail UI)
607
+ if (label.type === 'system' && /^CATEGORY/.test(label.id)) {
608
+ return false;
609
+ }
610
+
611
+ // Include message counts if requested
612
+ if (!isNaN(label.messagesTotal) && options?.statusQuery?.messages) {
613
+ folderData.status = {
614
+ messages: Number(label.messagesTotal) || 0,
615
+ unseen: Number(label.messagesUnread) || 0
616
+ };
617
+ }
618
+
619
+ return folderData;
620
+ })
621
+ .filter(value => value)
622
+ .sort((a, b) => {
623
+ // Sort: INBOX first, then special folders, then alphabetical
624
+ if (a.path === 'INBOX') {
625
+ return -1;
626
+ } else if (b.path === 'INBOX') {
627
+ return 1;
628
+ }
629
+
630
+ if (a.specialUse && !b.specialUse) {
631
+ return -1;
632
+ } else if (!a.specialUse && b.specialUse) {
633
+ return 1;
634
+ }
635
+
636
+ return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
637
+ });
638
+
639
+ return mailboxes;
640
+ }
641
+
642
+ /**
643
+ * Lists messages with Gmail API, supporting search and pagination
644
+ * @param {Object} query - Search and pagination parameters
645
+ * @param {Object} options - Additional options
646
+ * @returns {Object} Paginated message list
647
+ */
648
+ async listMessages(query, options) {
649
+ options = options || {};
650
+
651
+ await this.prepare();
652
+
653
+ // Gmail doesn't support numeric page numbers, only cursors
654
+ let page = Number(query.page) || 0;
655
+ if (page > 0) {
656
+ let error = new Error('Invalid page number. Only paging cursors are allowed for Gmail accounts.');
657
+ error.code = 'InvalidInput';
658
+ error.statusCode = 400;
659
+ throw error;
660
+ }
661
+
662
+ let pageSize = Math.abs(Number(query.pageSize) || 20);
663
+ let requestQuery = {
664
+ maxResults: pageSize
665
+ };
666
+
667
+ let pageCursor = PageCursor.create(query.cursor);
668
+
669
+ let path;
670
+ if (query.path && query.path !== '\\All') {
671
+ // Convert path to Gmail label ID
672
+ let label = await this.getLabel(query.path);
673
+ if (!label) {
674
+ return false;
675
+ }
676
+ requestQuery.labelIds = [label.id];
677
+ }
678
+
679
+ let messageList = [];
680
+
681
+ if (query.search) {
682
+ if (query.search.emailId) {
683
+ // Return only a single matching email
684
+
685
+ let messageEntry = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${query.search.emailId}`, 'get', {
686
+ format: 'full'
687
+ });
688
+
689
+ if (messageEntry) {
690
+ messageList.push(this.formatMessage(messageEntry, { path }));
691
+ }
692
+
693
+ let messageCount = messageList.length;
694
+ let pages = Math.ceil(messageCount / pageSize);
695
+
696
+ return {
697
+ total: messageCount,
698
+ page: 0,
699
+ pages,
700
+ nextPageCursor: null,
701
+ prevPageCursor: null,
702
+ messages: messageList
703
+ };
704
+ }
705
+
706
+ if (query.search.threadId) {
707
+ // Threading is a special case - fetch entire thread
708
+ let threadListingResult = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/threads/${query.search.threadId}`, 'get', {
709
+ format: 'full'
710
+ });
711
+
712
+ let messageCount = threadListingResult?.messages?.length || 0;
713
+ let currentPage = pageCursor.currentPage();
714
+
715
+ let nextPageToken = null;
716
+ if (messageCount > pageSize) {
717
+ // Handle pagination within thread
718
+ let pageStart = 0;
719
+
720
+ if (currentPage?.cursor) {
721
+ pageStart = Number(currentPage.cursor) || 0;
722
+ }
723
+
724
+ if (pageStart + pageSize < messageCount) {
725
+ nextPageToken = (pageStart + pageSize).toString(10);
726
+ }
727
+
728
+ // extract messages for the current page only
729
+ threadListingResult.messages = threadListingResult.messages.slice(pageStart, pageStart + pageSize, messageCount);
730
+ }
731
+
732
+ if (threadListingResult?.messages) {
733
+ for (let entry of threadListingResult.messages) {
734
+ messageList.push(this.formatMessage(entry, { path }));
735
+ }
736
+ }
737
+
738
+ let pages = Math.ceil(messageCount / pageSize);
739
+ let nextPageCursor = pageCursor.nextPageCursor(nextPageToken);
740
+ let prevPageCursor = pageCursor.prevPageCursor();
741
+
742
+ return {
743
+ total: messageCount,
744
+ page: currentPage.page,
745
+ pages,
746
+ nextPageCursor,
747
+ prevPageCursor,
748
+ messages: messageList
749
+ };
750
+ }
751
+
752
+ // Convert IMAP-style search to Gmail query
753
+ // NB! Might throw if using unsupported search terms
754
+ const preparedQuery = this.prepareQuery(query.search);
755
+ if (preparedQuery) {
756
+ requestQuery.q = this.prepareQuery(query.search);
757
+ }
758
+ }
759
+
760
+ // Apply pagination cursor
761
+ let currentPage = pageCursor.currentPage();
762
+ if (currentPage?.cursor) {
763
+ requestQuery.pageToken = currentPage.cursor;
764
+ }
765
+
766
+ // Fetch message list
767
+ let listingResult = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages`, 'get', requestQuery);
768
+ let messageCount = listingResult.resultSizeEstimate;
769
+
770
+ let pages = Math.ceil(messageCount / pageSize);
771
+
772
+ let nextPageCursor = pageCursor.nextPageCursor(listingResult.nextPageToken);
773
+ let prevPageCursor = pageCursor.prevPageCursor();
774
+
775
+ if (options.metadataOnly) {
776
+ // Return just IDs without fetching full content
777
+ return {
778
+ total: messageCount,
779
+ page: currentPage.page,
780
+ pages,
781
+ nextPageCursor,
782
+ prevPageCursor,
783
+ messages: listingResult.messages
784
+ };
785
+ }
786
+
787
+ // Fetch message content for matching messages in batches
788
+
789
+ let promises = [];
790
+
791
+ let resolvePromises = async () => {
792
+ if (!promises.length) {
793
+ return;
794
+ }
795
+ let resultList = await Promise.allSettled(promises);
796
+ for (let entry of resultList) {
797
+ if (entry.status === 'rejected') {
798
+ throw entry.reason;
799
+ }
800
+ if (entry.value) {
801
+ messageList.push(this.formatMessage(entry.value, { path }));
802
+ }
803
+ }
804
+ promises = [];
805
+ };
806
+
807
+ for (let { id: message } of listingResult.messages || []) {
808
+ promises.push(this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${message}`));
809
+ if (promises.length > LIST_BATCH_SIZE) {
810
+ await resolvePromises();
811
+ }
812
+ }
813
+ await resolvePromises();
814
+
815
+ return {
816
+ total: messageCount,
817
+ page: currentPage.page,
818
+ pages,
819
+ nextPageCursor,
820
+ prevPageCursor,
821
+ messages: messageList
822
+ };
823
+ }
824
+
825
+ /**
826
+ * Fetches raw RFC822 message content
827
+ * @param {string} emailId - Gmail message ID
828
+ * @returns {Buffer} Raw message buffer
829
+ */
830
+ async getRawMessage(emailId) {
831
+ await this.prepare();
832
+
833
+ const requestQuery = {
834
+ format: 'raw'
835
+ };
836
+ const result = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${emailId}`, 'get', requestQuery);
837
+
838
+ return result?.raw ? Buffer.from(result?.raw, 'base64url') : null;
839
+ }
840
+
841
+ /**
842
+ * Deletes a message (moves to trash in Gmail)
843
+ * @param {string} emailId - Message ID
844
+ * @returns {Object} Deletion result
845
+ */
846
+ async deleteMessage(emailId /*, force*/) {
847
+ await this.prepare();
848
+
849
+ // Gmail doesn't permanently delete, just moves to trash
850
+ const url = `${GMAIL_API_BASE}/gmail/v1/users/me/messages/${emailId}/trash`;
851
+ const result = await this.request(url, 'post', Buffer.alloc(0));
852
+
853
+ return {
854
+ deleted: result && result.labelIds?.includes('TRASH'),
855
+ moved: {
856
+ message: result.id
857
+ }
858
+ };
859
+ }
860
+
861
+ /**
862
+ * Deletes multiple messages matching criteria
863
+ * @param {string} path - Source folder path
864
+ * @param {Object} search - Search criteria
865
+ * @returns {Object} Deletion result
866
+ */
867
+ async deleteMessages(path, search) {
868
+ await this.prepare();
869
+
870
+ path = [].concat(path || []).join('/');
871
+
872
+ let sourceLabel = path && path !== '\\All' ? await this.getLabel(path) : null;
873
+ if (path && path !== '\\All' && !sourceLabel) {
874
+ let error = new Error('Unknown path');
875
+ error.info = {
876
+ response: `Mailbox doesn't exist: ${path}`
877
+ };
878
+ error.code = 'NotFound';
879
+ error.statusCode = 404;
880
+ throw error;
881
+ }
882
+
883
+ // Add TRASH label and remove source label
884
+ let labelsUpdate = { add: 'TRASH' };
885
+ if (sourceLabel) {
886
+ labelsUpdate.delete = sourceLabel.id;
887
+ }
888
+
889
+ let updateResult = await this.updateMessages(path, search, { labels: labelsUpdate });
890
+
891
+ return {
892
+ deleted: true,
893
+ moved: {
894
+ destination: SYSTEM_NAMES.TRASH,
895
+ emailIds: updateResult.emailIds
896
+ }
897
+ };
898
+ }
899
+
900
+ /**
901
+ * Updates flags and labels for a single message
902
+ * @param {string} emailId - Message ID
903
+ * @param {Object} updates - Flags and labels to update
904
+ * @returns {Object} Update result with final state
905
+ */
906
+ async updateMessage(emailId, updates) {
907
+ await this.prepare();
908
+ updates = updates || {};
909
+
910
+ let addLabelIds = new Set();
911
+ let removeLabelIds = new Set();
912
+
913
+ // Convert IMAP flags to Gmail labels
914
+ if (updates.flags) {
915
+ let labelUpdates = [];
916
+
917
+ for (let flag of [].concat(updates.flags.add || [])) {
918
+ labelUpdates.push(this.flagToLabel(flag));
919
+ }
920
+
921
+ for (let flag of [].concat(updates.flags.delete || [])) {
922
+ labelUpdates.push(this.flagToLabel(flag, true));
923
+ }
924
+
925
+ labelUpdates
926
+ .filter(label => label)
927
+ .forEach(label => {
928
+ if (label.add) {
929
+ addLabelIds.add(label.add);
930
+ }
931
+ if (label.remove) {
932
+ removeLabelIds.add(label.remove);
933
+ }
934
+ });
935
+ }
936
+
937
+ // Process direct label updates
938
+ if (updates.labels) {
939
+ for (let label of [].concat(updates.labels.add || [])) {
940
+ // Convert IMAP special-use to Gmail label
941
+ if (SYSTEM_LABELS_REV.hasOwnProperty(label)) {
942
+ label = SYSTEM_LABELS_REV[label];
943
+ }
944
+ addLabelIds.add(label);
945
+ }
946
+
947
+ for (let label of [].concat(updates.labels.delete || [])) {
948
+ if (SYSTEM_LABELS_REV.hasOwnProperty(label)) {
949
+ label = SYSTEM_LABELS_REV[label];
950
+ }
951
+ removeLabelIds.add(label);
952
+ }
953
+ }
954
+
955
+ if (!addLabelIds.size && !removeLabelIds.size) {
956
+ return updates;
957
+ }
958
+
959
+ let labelUpdates = {};
960
+
961
+ if (addLabelIds.size) {
962
+ labelUpdates.addLabelIds = Array.from(addLabelIds);
963
+ }
964
+
965
+ if (removeLabelIds.size) {
966
+ labelUpdates.removeLabelIds = Array.from(removeLabelIds);
967
+ }
968
+
969
+ let modifyResult;
970
+
971
+ try {
972
+ modifyResult = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${emailId}/modify`, 'post', labelUpdates);
973
+ } catch (err) {
974
+ switch (err?.oauthRequest?.response?.error?.code) {
975
+ case 400: {
976
+ // invalid name
977
+ let error = new Error(err?.oauthRequest?.response?.error?.message || 'Invalid label');
978
+ error.info = {
979
+ response: err?.oauthRequest?.response?.error?.message
980
+ };
981
+ error.code = err?.oauthRequest?.response?.error?.status;
982
+ error.statusCode = 400;
983
+ throw error;
984
+ }
985
+
986
+ case 403: {
987
+ // permission denied
988
+ let error = new Error(err?.oauthRequest?.response?.error?.message || 'Permission Denied');
989
+ error.info = {
990
+ response: err?.oauthRequest?.response?.error?.message
991
+ };
992
+ error.code = err?.oauthRequest?.response?.error?.status;
993
+ error.statusCode = 403;
994
+ throw error;
995
+ }
996
+ }
997
+
998
+ throw err;
999
+ }
1000
+
1001
+ // Return final state after update
1002
+ let { flags: messageFlags, labels: messageLabels } = this.formatFlagsAndLabels(modifyResult);
1003
+
1004
+ let response = {
1005
+ flags: Object.assign({}, updates.flags || {}, { result: messageFlags || [] }),
1006
+ labels: Object.assign({}, updates.labels || {}, { result: messageLabels || [] })
1007
+ };
1008
+
1009
+ return response;
1010
+ }
1011
+
1012
+ /**
1013
+ * Updates multiple messages matching search criteria
1014
+ * @param {string} path - Source folder path
1015
+ * @param {Object} search - Search criteria
1016
+ * @param {Object} updates - Updates to apply
1017
+ * @returns {Object} Update result
1018
+ */
1019
+ async updateMessages(path, search, updates) {
1020
+ await this.prepare();
1021
+ updates = updates || {};
1022
+
1023
+ // Step 1. Resolve matching messages
1024
+ let messages = [];
1025
+ let cursor;
1026
+
1027
+ let maxMessages = 1000;
1028
+ let notDone = true;
1029
+
1030
+ // Fetch all matching messages (up to limit)
1031
+ while (notDone && !search.emailIds) {
1032
+ let messageListResult = await this.listMessages(
1033
+ {
1034
+ path,
1035
+ pageSize: 250,
1036
+ search,
1037
+ cursor
1038
+ },
1039
+ { metadataOnly: true }
1040
+ );
1041
+
1042
+ if (messageListResult?.messages) {
1043
+ messages = messages.concat(messageListResult?.messages);
1044
+ if (messages.length >= maxMessages) {
1045
+ messages = messages.slice(0, maxMessages);
1046
+ notDone = false;
1047
+ break;
1048
+ }
1049
+ }
1050
+
1051
+ if (!messageListResult.nextPageCursor) {
1052
+ notDone = false;
1053
+ break;
1054
+ }
1055
+ cursor = messageListResult.nextPageCursor;
1056
+ }
1057
+
1058
+ let emailIds = search.emailIds || messages.map(message => message.id);
1059
+
1060
+ if (!emailIds?.length) {
1061
+ // nothing to do here
1062
+ return updates;
1063
+ }
1064
+
1065
+ let addLabelIds = new Set();
1066
+ let removeLabelIds = new Set();
1067
+
1068
+ // Convert flags to label operations
1069
+ if (updates.flags) {
1070
+ let labelUpdates = [];
1071
+
1072
+ for (let flag of [].concat(updates.flags.add || [])) {
1073
+ labelUpdates.push(this.flagToLabel(flag));
1074
+ }
1075
+
1076
+ for (let flag of [].concat(updates.flags.delete || [])) {
1077
+ labelUpdates.push(this.flagToLabel(flag), true);
1078
+ }
1079
+
1080
+ labelUpdates
1081
+ .filter(label => label)
1082
+ .forEach(label => {
1083
+ if (label.add) {
1084
+ addLabelIds.add(label.add);
1085
+ }
1086
+ if (label.remove) {
1087
+ removeLabelIds.add(label.remove);
1088
+ }
1089
+ });
1090
+ }
1091
+
1092
+ if (updates.labels) {
1093
+ for (let label of [].concat(updates.labels.add || [])) {
1094
+ addLabelIds.add(label);
1095
+ }
1096
+
1097
+ for (let label of [].concat(updates.labels.delete || [])) {
1098
+ removeLabelIds.add(label);
1099
+ }
1100
+ }
1101
+
1102
+ if (!addLabelIds.size && !removeLabelIds.size) {
1103
+ return { flags: {}, labels: {} };
1104
+ }
1105
+
1106
+ let labelUpdates = {
1107
+ ids: emailIds
1108
+ };
1109
+
1110
+ if (addLabelIds.size) {
1111
+ labelUpdates.addLabelIds = Array.from(addLabelIds);
1112
+ }
1113
+
1114
+ if (removeLabelIds.size) {
1115
+ labelUpdates.removeLabelIds = Array.from(removeLabelIds);
1116
+ }
1117
+
1118
+ // Batch modify all messages
1119
+ await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/batchModify`, 'post', labelUpdates, { returnText: true });
1120
+
1121
+ return Object.assign({}, updates, {
1122
+ emailIds
1123
+ });
1124
+ }
1125
+
1126
+ /**
1127
+ * Moves a message between folders (labels)
1128
+ * @param {string} emailId - Message ID
1129
+ * @param {Object} target - Target folder
1130
+ * @param {Object} options - Move options
1131
+ * @returns {Object} Move result
1132
+ */
1133
+ async moveMessage(emailId, target, options) {
1134
+ await this.prepare();
1135
+
1136
+ options = options || {};
1137
+
1138
+ let path = [].concat(target?.path || []).join('/');
1139
+
1140
+ let label = await this.getLabel(path);
1141
+ if (!label) {
1142
+ let error = new Error('Unknown path');
1143
+ error.info = {
1144
+ response: `Mailbox doesn't exist: ${path}`
1145
+ };
1146
+ error.code = 'NotFound';
1147
+ error.statusCode = 404;
1148
+ throw error;
1149
+ }
1150
+ let labelsUpdate = { add: [label.id] };
1151
+
1152
+ let sourcePath = options.source?.path;
1153
+
1154
+ let sourceLabel = sourcePath ? await this.getLabel(sourcePath) : null;
1155
+ if (sourcePath && !sourceLabel) {
1156
+ let error = new Error('Unknown path');
1157
+ error.info = {
1158
+ response: `Mailbox doesn't exist: ${sourcePath}`
1159
+ };
1160
+ error.code = 'NotFound';
1161
+ error.statusCode = 404;
1162
+ throw error;
1163
+ }
1164
+
1165
+ if (sourceLabel) {
1166
+ labelsUpdate.delete = sourceLabel.id;
1167
+ }
1168
+
1169
+ await this.updateMessage(emailId, { labels: labelsUpdate });
1170
+
1171
+ return {
1172
+ path,
1173
+ id: emailId
1174
+ };
1175
+ }
1176
+
1177
+ /**
1178
+ * Moves multiple messages between folders
1179
+ * @param {string} source - Source folder path
1180
+ * @param {Object} search - Search criteria
1181
+ * @param {Object} target - Target folder
1182
+ * @returns {Object} Move result
1183
+ */
1184
+ async moveMessages(source, search, target) {
1185
+ await this.prepare();
1186
+
1187
+ let path = [].concat(target?.path || []).join('/');
1188
+
1189
+ let targetLabel = await this.getLabel(path);
1190
+ if (!targetLabel) {
1191
+ let error = new Error('Unknown path');
1192
+ error.info = {
1193
+ response: `Mailbox doesn't exist: ${path}`
1194
+ };
1195
+ error.code = 'NotFound';
1196
+ error.statusCode = 404;
1197
+ throw error;
1198
+ }
1199
+
1200
+ let sourceLabel = source ? await this.getLabel(source) : null;
1201
+ if (source && !sourceLabel) {
1202
+ let error = new Error('Unknown path');
1203
+ error.info = {
1204
+ response: `Mailbox doesn't exist: ${source}`
1205
+ };
1206
+ error.code = 'NotFound';
1207
+ error.statusCode = 404;
1208
+ throw error;
1209
+ }
1210
+
1211
+ let labelsUpdate = { add: targetLabel.id };
1212
+ if (sourceLabel) {
1213
+ labelsUpdate.delete = sourceLabel.id;
1214
+ }
1215
+
1216
+ let updateResult = await this.updateMessages(source, search, { labels: labelsUpdate });
1217
+
1218
+ return {
1219
+ path,
1220
+ emailIds: updateResult?.emailIds || null
1221
+ };
1222
+ }
1223
+
1224
+ /**
1225
+ * Downloads attachment content
1226
+ * @param {string} attachmentId - Encoded attachment identifier
1227
+ * @returns {Object} Attachment data with headers
1228
+ */
1229
+ async getAttachment(attachmentId) {
1230
+ let attachmentData = await this.getAttachmentContent(attachmentId);
1231
+
1232
+ if (!attachmentData || !attachmentData.content) {
1233
+ return false;
1234
+ }
1235
+
1236
+ // Generate proper Content-Disposition header with filename
1237
+ let filenameParam = '';
1238
+ if (attachmentData.filename) {
1239
+ let isCleartextFilename = attachmentData.filename && /^[a-z0-9 _\-()^[\]~=,+*$]+$/i.test(attachmentData.filename);
1240
+ if (isCleartextFilename) {
1241
+ filenameParam = `; filename=${JSON.stringify(attachmentData.filename)}`;
1242
+ } else {
1243
+ // Use RFC 5987 encoding for non-ASCII filenames
1244
+ filenameParam = `; filename=${JSON.stringify(he.encode(attachmentData.filename))}; filename*=utf-8''${encodeURIComponent(
1245
+ attachmentData.filename
1246
+ )}`;
1247
+ }
1248
+ }
1249
+
1250
+ const contentResponse = {
1251
+ headers: {
1252
+ 'content-type': attachmentData.mimeType || 'application/octet-stream',
1253
+ 'content-disposition': 'attachment' + filenameParam
1254
+ },
1255
+ contentType: attachmentData.contentType,
1256
+ filename: attachmentData.filename,
1257
+ disposition: attachmentData.disposition,
1258
+ data: attachmentData.content
1259
+ };
1260
+
1261
+ return contentResponse;
1262
+ }
1263
+
1264
+ /**
1265
+ * Fetches full message data with optional enhancements
1266
+ * @param {string} emailId - Message ID
1267
+ * @param {Object} options - Fetch options
1268
+ * @returns {Object} Complete message data
1269
+ */
1270
+ async getMessage(emailId, options) {
1271
+ options = options || {};
1272
+ await this.prepare();
1273
+
1274
+ // Enable all enhancements for web-safe HTML
1275
+ if (options.webSafeHtml) {
1276
+ options.textType = '*';
1277
+ options.embedAttachedImages = true;
1278
+ options.preProcessHtml = true;
1279
+ }
1280
+
1281
+ const requestQuery = {
1282
+ format: 'full'
1283
+ };
1284
+ const messageData = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${emailId}`, 'get', requestQuery);
1285
+
1286
+ let formattedMessage = this.formatMessage(messageData, { extended: true, textType: options.textType });
1287
+
1288
+ // Mark as seen if requested
1289
+ if (options.markAsSeen && (!formattedMessage.flags || !formattedMessage.flags.includes('\\Seen'))) {
1290
+ //
1291
+ try {
1292
+ let response = await this.updateMessage(emailId, { flags: { add: ['\\Seen'] } });
1293
+ if (response?.flags?.result) {
1294
+ formattedMessage.flags = response?.flags?.result;
1295
+ }
1296
+ } catch (err) {
1297
+ this.logger.debug({ msg: 'Failed to mark message as Seen', message: emailId, err });
1298
+ }
1299
+ }
1300
+
1301
+ // Generate web-safe HTML if requested
1302
+ if (options.preProcessHtml && formattedMessage.text && (formattedMessage.text.html || formattedMessage.text.plain)) {
1303
+ formattedMessage.text.html = mimeHtml({
1304
+ html: formattedMessage.text.html,
1305
+ text: formattedMessage.text.plain
1306
+ });
1307
+ formattedMessage.text.webSafe = true;
1308
+ }
1309
+
1310
+ // Embed inline images as data URIs
1311
+ if (options.embedAttachedImages && formattedMessage.text?.html && formattedMessage.attachments) {
1312
+ let attachmentMap = new Map();
1313
+
1314
+ // Find CID references in HTML
1315
+ for (let attachment of formattedMessage.attachments) {
1316
+ let contentId = attachment.contentId && attachment.contentId.replace(/^<|>$/g, '');
1317
+ if (contentId && formattedMessage.text.html.indexOf(contentId) >= 0) {
1318
+ attachmentMap.set(contentId, { attachment, content: null });
1319
+ }
1320
+ }
1321
+
1322
+ // Download referenced attachments
1323
+ for (let entry of attachmentMap.values()) {
1324
+ if (!entry.content) {
1325
+ entry.content = await this.getAttachmentContent(entry.attachment.id);
1326
+ }
1327
+ }
1328
+
1329
+ // Replace CID references with data URIs
1330
+ formattedMessage.text.html = formattedMessage.text.html.replace(/\bcid:([^"'\s>]+)/g, (fullMatch, cidMatch) => {
1331
+ if (attachmentMap.has(cidMatch)) {
1332
+ let { content } = attachmentMap.get(cidMatch);
1333
+ if (content.content) {
1334
+ return `data:${content.contentType || 'application/octet-stream'};base64,${content.content.toString('base64')}`;
1335
+ }
1336
+ }
1337
+ return fullMatch;
1338
+ });
1339
+ }
1340
+
1341
+ return formattedMessage;
1342
+ }
1343
+
1344
+ /**
1345
+ * Fetches text content for a message
1346
+ * @param {string} textId - Encoded text identifier
1347
+ * @param {Object} options - Text options
1348
+ * @returns {Object} Text content
1349
+ */
1350
+ async getText(textId, options) {
1351
+ options = options || {};
1352
+ await this.prepare();
1353
+
1354
+ // Decode text part references
1355
+ const [emailId, textParts] = msgpack.decode(Buffer.from(textId, 'base64url'));
1356
+
1357
+ const bodyParts = new Map();
1358
+
1359
+ // Map part IDs to content types
1360
+ textParts[0].forEach(p => {
1361
+ bodyParts.set(p, 'text');
1362
+ });
1363
+
1364
+ textParts[1].forEach(p => {
1365
+ bodyParts.set(p, 'html');
1366
+ });
1367
+
1368
+ const requestQuery = {
1369
+ format: 'full'
1370
+ };
1371
+ const messageData = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${emailId}`, 'get', requestQuery);
1372
+
1373
+ const response = {};
1374
+
1375
+ if (options.textType && options.textType !== '*') {
1376
+ response[options.textType] = '';
1377
+ }
1378
+
1379
+ // Walk message structure to find text parts
1380
+ const textContent = {};
1381
+ const walkBodyParts = node => {
1382
+ let textType = bodyParts.has(node.partId) ? bodyParts.get(node.partId) : false;
1383
+
1384
+ if (textType && (options.textType === '*' || options.textType === textType) && node.body?.data) {
1385
+ if (!textContent[textType]) {
1386
+ textContent[textType] = [];
1387
+ }
1388
+ textContent[textType].push(Buffer.from(node.body.data, 'base64'));
1389
+ }
1390
+
1391
+ if (Array.isArray(node.parts)) {
1392
+ for (let part of node.parts) {
1393
+ walkBodyParts(part);
1394
+ }
1395
+ }
1396
+ };
1397
+ walkBodyParts(messageData.payload);
1398
+
1399
+ // Concatenate text parts
1400
+ for (let key of Object.keys(textContent)) {
1401
+ response[key] = textContent[key].map(buf => buf.toString()).join('\n');
1402
+ }
1403
+
1404
+ response.hasMore = false;
1405
+
1406
+ return response;
1407
+ }
1408
+
1409
+ /**
1410
+ * Uploads a new message to Gmail
1411
+ * @param {Object} data - Message data
1412
+ * @returns {Object} Upload result
1413
+ */
1414
+ async uploadMessage(data) {
1415
+ await this.prepare();
1416
+
1417
+ let path = [].concat(data.path || []).join('/');
1418
+
1419
+ let targetLabel = await this.getLabel(path);
1420
+ if (!targetLabel) {
1421
+ let error = new Error('Unknown path');
1422
+ error.info = {
1423
+ response: `Mailbox doesn't exist: ${path}`
1424
+ };
1425
+ error.code = 'NotFound';
1426
+ error.statusCode = 404;
1427
+ throw error;
1428
+ }
1429
+
1430
+ // Generate raw message
1431
+ let { raw, messageId, referencedMessage, documentStoreUsed } = await this.prepareRawMessage(data);
1432
+ if (raw?.buffer) {
1433
+ // convert from a Uint8Array to a Buffer
1434
+ raw = Buffer.from(raw);
1435
+ }
1436
+
1437
+ let payload = {
1438
+ labelIds: [targetLabel.id],
1439
+ raw: raw.toString('base64url')
1440
+ };
1441
+
1442
+ // Maintain thread if replying
1443
+ if (referencedMessage?.threadId) {
1444
+ payload.threadId = referencedMessage.threadId;
1445
+ }
1446
+
1447
+ let uploadInfo;
1448
+ try {
1449
+ uploadInfo = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages?internalDateSource=dateHeader`, 'post', payload);
1450
+ } catch (err) {
1451
+ switch (err?.oauthRequest?.response?.error?.code) {
1452
+ case 403: {
1453
+ // permission denied
1454
+ let error = new Error(err?.oauthRequest?.response?.error?.message || 'Permission Denied');
1455
+ error.info = {
1456
+ response: err?.oauthRequest?.response?.error?.message
1457
+ };
1458
+ error.code = err?.oauthRequest?.response?.error?.status;
1459
+ error.statusCode = 403;
1460
+ throw error;
1461
+ }
1462
+ }
1463
+
1464
+ throw err;
1465
+ }
1466
+
1467
+ let response = {
1468
+ id: uploadInfo?.id,
1469
+ path: [].concat(data.path || []).join('/'),
1470
+ messageId
1471
+ };
1472
+
1473
+ if (data.reference && data.reference.message) {
1474
+ response.reference = {
1475
+ message: data.reference.message,
1476
+ documentStore: documentStoreUsed,
1477
+ success: referencedMessage ? true : false
1478
+ };
1479
+
1480
+ if (!referencedMessage) {
1481
+ response.reference.error = 'Referenced message was not found';
1482
+ }
1483
+ }
1484
+
1485
+ return response;
1486
+ }
1487
+
1488
+ /**
1489
+ * Sends a message via Gmail API or SMTP gateway
1490
+ * @param {Object} data - Message data
1491
+ * @returns {Object} Send result
1492
+ */
1493
+ async submitMessage(data) {
1494
+ await this.prepare();
1495
+
1496
+ let accountData = await this.accountObject.loadAccountData();
1497
+ if (!accountData.smtp && !accountData.oauth2 && !data.gateway) {
1498
+ // can not make connection
1499
+ let err = new Error('SMTP configuration not found');
1500
+ err.code = 'SMTPUnavailable';
1501
+ err.statusCode = 404;
1502
+ throw err;
1503
+ }
1504
+
1505
+ let { raw, messageId, queueId, job: jobData, envelope } = data;
1506
+
1507
+ if (raw?.buffer) {
1508
+ // convert from a Uint8Array to a Buffer
1509
+ raw = Buffer.from(raw);
1510
+ }
1511
+
1512
+ // Check if using external SMTP gateway
1513
+ let gatewayData;
1514
+ let gatewayObject;
1515
+ if (data.gateway) {
1516
+ gatewayObject = new Gateway({ gateway: data.gateway, redis: this.redis, secret: this.secret });
1517
+ try {
1518
+ gatewayData = await gatewayObject.loadGatewayData();
1519
+ } catch (err) {
1520
+ this.logger.info({ msg: 'Failed to load gateway data', messageId: data.messageId, gateway: data.gateway, err });
1521
+ }
1522
+ }
1523
+
1524
+ if (gatewayData) {
1525
+ // Send via SMTP gateway instead
1526
+ return await super.submitMessage(data);
1527
+ }
1528
+
1529
+ // Verify job still exists
1530
+ const submitJobEntry = await this.submitQueue.getJob(jobData.id);
1531
+ if (!submitJobEntry) {
1532
+ // already failed?
1533
+ this.logger.error({
1534
+ msg: 'Submit job was not found',
1535
+ job: jobData.id
1536
+ });
1537
+ return false;
1538
+ }
1539
+
1540
+ // Prepare for Gmail API send
1541
+ let contentType = 'message/rfc822';
1542
+ let payload = raw;
1543
+ let targetEndpoint = `/upload/gmail/v1/users/me/messages/send`;
1544
+
1545
+ // Use different endpoint for thread replies
1546
+ if (data?.reference?.threadId) {
1547
+ targetEndpoint = `/gmail/v1/users/me/messages/send`;
1548
+ contentType = 'application/json';
1549
+ payload = {
1550
+ raw: raw.toString('base64'),
1551
+ threadId: data?.reference?.threadId
1552
+ };
1553
+ }
1554
+
1555
+ // Send via Gmail API
1556
+ const submitInfo = await this.request(`${GMAIL_API_BASE}${targetEndpoint}`, 'post', payload, { contentType });
1557
+ /*
1558
+ SEND RESPONSE {
1559
+ id: '18f85d2eb6adb232',
1560
+ threadId: '18f85d2eb6adb232',
1561
+ labelIds: [ 'SENT' ]
1562
+ }
1563
+ */
1564
+
1565
+ let gmailMessageId;
1566
+ if (submitInfo?.id) {
1567
+ // Detect send-only mode - use same scope resolution as in account.js
1568
+ const scopes = accountData.oauth2?.accessToken?.scope || accountData.oauth2?.scope || [];
1569
+ const { hasSendScope, hasReadScope } = this.accountObject.checkAccountScopes('gmail', scopes);
1570
+ const isSendOnly = hasSendScope && !hasReadScope;
1571
+
1572
+ if (!isSendOnly) {
1573
+ // fetch message data to get actual Message-ID value (requires read scope)
1574
+ let messageEntry = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${submitInfo?.id}`, 'get', {
1575
+ format: 'metadata',
1576
+ metadataHeaders: 'message-id'
1577
+ });
1578
+ let messageIdHeader = messageEntry?.payload?.headers?.find(h => /^Message-ID$/i.test(h.name));
1579
+ gmailMessageId = messageIdHeader?.value;
1580
+ } else {
1581
+ // For send-only accounts, use the original messageId since we can't read messages back
1582
+ gmailMessageId = messageId;
1583
+ }
1584
+ }
1585
+
1586
+ try {
1587
+ // try to update job progress
1588
+ await submitJobEntry.updateProgress({
1589
+ status: 'smtp-completed',
1590
+ messageId: gmailMessageId,
1591
+ originalMessageId: messageId
1592
+ });
1593
+ } catch (err) {
1594
+ // ignore
1595
+ }
1596
+
1597
+ // Send success notification
1598
+ await this.notify(false, EMAIL_SENT_NOTIFY, {
1599
+ messageId: gmailMessageId,
1600
+ originalMessageId: messageId,
1601
+ queueId,
1602
+ envelope
1603
+ });
1604
+
1605
+ // Update feedback key if provided
1606
+ if (data.feedbackKey) {
1607
+ await this.redis
1608
+ .multi()
1609
+ .hset(data.feedbackKey, 'success', 'true')
1610
+ .expire(1 * 60 * 60);
1611
+ }
1612
+
1613
+ return {
1614
+ messageId: gmailMessageId
1615
+ };
1616
+ }
1617
+
1618
+ /**
1619
+ * Creates a new Gmail label (folder)
1620
+ * @param {string} path - Label path
1621
+ * @returns {Object} Creation result
1622
+ */
1623
+ async createMailbox(path) {
1624
+ path = [].concat(path || []).join('/');
1625
+
1626
+ await this.prepare();
1627
+
1628
+ let labelData = {
1629
+ name: path
1630
+ };
1631
+
1632
+ let label;
1633
+ try {
1634
+ label = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/labels`, 'post', labelData);
1635
+
1636
+ // clear cache
1637
+ this.cachedLabels = null;
1638
+ } catch (err) {
1639
+ switch (err?.oauthRequest?.response?.error?.code) {
1640
+ case 409:
1641
+ // already exists
1642
+ return {
1643
+ path,
1644
+ created: false
1645
+ };
1646
+
1647
+ case 400: {
1648
+ // invalid name
1649
+ let error = new Error('Create failed');
1650
+ error.info = {
1651
+ response: err?.oauthRequest?.response?.error?.message
1652
+ };
1653
+ error.code = err?.oauthRequest?.response?.error?.status;
1654
+ error.statusCode = 400;
1655
+ throw error;
1656
+ }
1657
+ }
1658
+
1659
+ throw err;
1660
+ }
1661
+
1662
+ return {
1663
+ mailboxId: label.id,
1664
+ path: label.name,
1665
+ created: true
1666
+ };
1667
+ }
1668
+
1669
+ /**
1670
+ * Modifies a Gmail label (rename only, subscription is ignored for Gmail)
1671
+ * @param {string} path - Current path
1672
+ * @param {string} newPath - New path (optional)
1673
+ * @param {boolean} subscribed - Ignored for Gmail API
1674
+ * @returns {Object} Modify result
1675
+ */
1676
+ async modifyMailbox(path, newPath, subscribed) {
1677
+ // Gmail API does not support subscription management, so we ignore the subscribed parameter
1678
+ // If no newPath provided, just return the current path without changes
1679
+ if (!newPath) {
1680
+ return {
1681
+ path: [].concat(path || []).join('/'),
1682
+ renamed: false
1683
+ };
1684
+ }
1685
+
1686
+ return await this.renameMailbox(path, newPath);
1687
+ }
1688
+
1689
+ /**
1690
+ * Renames a Gmail label
1691
+ * @param {string} path - Current path
1692
+ * @param {string} newPath - New path
1693
+ * @returns {Object} Rename result
1694
+ */
1695
+ async renameMailbox(path, newPath) {
1696
+ path = [].concat(path || []).join('/');
1697
+ newPath = [].concat(newPath || []).join('/');
1698
+
1699
+ await this.prepare();
1700
+
1701
+ let existingLabel = await this.getLabel(path);
1702
+ if (!existingLabel || existingLabel.type !== 'user') {
1703
+ return {
1704
+ path,
1705
+ newPath,
1706
+ renamed: false
1707
+ };
1708
+ }
1709
+
1710
+ let labelData = {
1711
+ name: newPath
1712
+ };
1713
+
1714
+ let label;
1715
+ try {
1716
+ label = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/labels/${existingLabel.id}`, 'patch', labelData);
1717
+
1718
+ // clear cache
1719
+ this.cachedLabels = null;
1720
+ } catch (err) {
1721
+ switch (err?.oauthRequest?.response?.error?.code) {
1722
+ case 409:
1723
+ case 400: {
1724
+ // invalid name
1725
+ let error = new Error('Rename failed');
1726
+ error.info = {
1727
+ response: err?.oauthRequest?.response?.error?.message
1728
+ };
1729
+ error.code = err?.oauthRequest?.response?.error?.status;
1730
+ error.statusCode = 400;
1731
+ throw error;
1732
+ }
1733
+ }
1734
+
1735
+ throw err;
1736
+ }
1737
+
1738
+ return {
1739
+ mailboxId: existingLabel.id,
1740
+ path,
1741
+ newPath: label.name,
1742
+ renamed: true
1743
+ };
1744
+ }
1745
+
1746
+ /**
1747
+ * Deletes a Gmail label
1748
+ * @param {string} path - Label path
1749
+ * @returns {Object} Deletion result
1750
+ */
1751
+ async deleteMailbox(path) {
1752
+ path = [].concat(path || []).join('/');
1753
+
1754
+ await this.prepare();
1755
+
1756
+ let existingLabel = await this.getLabel(path);
1757
+ if (!existingLabel || existingLabel.type !== 'user') {
1758
+ return {
1759
+ path,
1760
+ deleted: false
1761
+ };
1762
+ }
1763
+
1764
+ try {
1765
+ await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/labels/${existingLabel.id}`, 'delete', Buffer.alloc(0), { returnText: true });
1766
+
1767
+ // clear cache
1768
+ this.cachedLabels = null;
1769
+ } catch (err) {
1770
+ switch (err?.oauthRequest?.response?.error?.code) {
1771
+ case 409:
1772
+ case 400: {
1773
+ // invalid name
1774
+ let error = new Error('Delete failed');
1775
+ error.info = {
1776
+ response: err?.oauthRequest?.response?.error?.message
1777
+ };
1778
+ error.code = err?.oauthRequest?.response?.error?.status;
1779
+ error.statusCode = 400;
1780
+ throw error;
1781
+ }
1782
+ }
1783
+
1784
+ throw err;
1785
+ }
1786
+
1787
+ return {
1788
+ mailboxId: existingLabel.id,
1789
+ path,
1790
+ deleted: true
1791
+ };
1792
+ }
1793
+
1794
+ /**
1795
+ * Handles external notifications from Gmail Pub/Sub
1796
+ * @param {Object} message - Pub/Sub message
1797
+ * @returns {boolean} Processing result
1798
+ */
1799
+ async externalNotify(message) {
1800
+ let { historyId } = message || {};
1801
+
1802
+ let existingHistoryId = Number(await this.redis.hget(this.getAccountKey(), 'googleHistoryId')) || null;
1803
+ if (historyId && (!existingHistoryId || historyId > existingHistoryId)) {
1804
+ // changes detected
1805
+ this.triggerSync(existingHistoryId, historyId);
1806
+ }
1807
+
1808
+ return true;
1809
+ }
1810
+
1811
+ // PRIVATE METHODS
1812
+
1813
+ getAccountKey() {
1814
+ return `${REDIS_PREFIX}iad:${this.account}`;
1815
+ }
1816
+
1817
+ async getAccount() {
1818
+ if (this.accountObject) {
1819
+ return this.accountObject;
1820
+ }
1821
+ this.accountObject = new Account({ redis: this.redis, account: this.account, secret: await getSecret() });
1822
+ return this.accountObject;
1823
+ }
1824
+
1825
+ async getToken() {
1826
+ let tokenData;
1827
+ try {
1828
+ tokenData = await this.accountObject.getActiveAccessTokenData();
1829
+ if (!['init', 'connecting', 'connected'].includes(this.state)) {
1830
+ // We're in an error state (authenticationError, disconnected, etc.)
1831
+ // But we just got a valid token, so we've recovered
1832
+ this.state = 'connected';
1833
+ await this.setStateVal();
1834
+ }
1835
+
1836
+ // Track successful token refresh (only if token was actually refreshed, not cached)
1837
+ if (!tokenData.cached) {
1838
+ metricsMeta({ account: this.account }, this.logger, 'oauth2TokenRefresh', 'inc', { status: 'success', provider: 'gmail', statusCode: '200' });
1839
+ }
1840
+ } catch (E) {
1841
+ if (E.code === 'ETokenRefresh') {
1842
+ // treat as authentication failure
1843
+ this.state = 'authenticationError';
1844
+ await this.setStateVal();
1845
+
1846
+ E.authenticationFailed = true;
1847
+
1848
+ // Track failed token refresh
1849
+ const statusCode = String(E.statusCode || 0);
1850
+ metricsMeta({ account: this.account }, this.logger, 'oauth2TokenRefresh', 'inc', { status: 'failure', provider: 'gmail', statusCode });
1851
+
1852
+ if (!E.errorNotified) {
1853
+ E.errorNotified = true;
1854
+ await this.notify(false, AUTH_ERROR_NOTIFY, {
1855
+ response: E.oauthRequest?.response?.error?.message || E.response,
1856
+ serverResponseCode: 'TokenGenerationError'
1857
+ });
1858
+ }
1859
+ }
1860
+
1861
+ throw E;
1862
+ }
1863
+ return tokenData.accessToken;
1864
+ }
1865
+
1866
+ async getClient(force) {
1867
+ if (this.oAuth2Client && !force) {
1868
+ return this.oAuth2Client;
1869
+ }
1870
+ let accountData = await this.accountObject.loadAccountData(this.account, false);
1871
+ this.oAuth2Client = await oauth2Apps.getClient(accountData.oauth2.provider, {
1872
+ logger: this.logger,
1873
+ logRaw: this.options.logRaw
1874
+ });
1875
+ return this.oAuth2Client;
1876
+ }
1877
+
1878
+ async prepare() {
1879
+ await this.getAccount();
1880
+ await this.getClient();
1881
+ }
1882
+
1883
+ /**
1884
+ * Sets up timer to periodically renew Gmail watch subscription
1885
+ */
1886
+ setupRenewWatchTimer() {
1887
+ if (this.closed) {
1888
+ return;
1889
+ }
1890
+ clearTimeout(this.renewWatchTimer);
1891
+ this.renewWatchTimer = setTimeout(() => {
1892
+ if (this.closed) {
1893
+ return;
1894
+ }
1895
+ this.renewWatch()
1896
+ .catch(err => {
1897
+ this.logger.error({ msg: 'Failed to renew Gmail subscription watch', account: this.account, err });
1898
+ })
1899
+ .finally(() => {
1900
+ // restart timer
1901
+ this.setupRenewWatchTimer();
1902
+ });
1903
+ }, RENEW_WATCH_TTL);
1904
+ this.renewWatchTimer.unref();
1905
+ }
1906
+
1907
+ /**
1908
+ * Renews Gmail Pub/Sub watch subscription
1909
+ * @param {Object} accountData - Account data
1910
+ * @param {Object} opts - Renewal options
1911
+ */
1912
+ async renewWatch(accountData, opts) {
1913
+ let { forceWatchRenewal } = opts || {};
1914
+
1915
+ if (!accountData) {
1916
+ await this.getAccount();
1917
+ accountData = await this.accountObject.loadAccountData(this.account, false);
1918
+ }
1919
+
1920
+ let now = Date.now();
1921
+
1922
+ // Check if renewal is needed
1923
+ if (accountData._app?.pubSubApp && (forceWatchRenewal || !accountData.lastWatch || accountData.lastWatch < new Date(now - MIN_WATCH_TTL))) {
1924
+ let appData = await oauth2Apps.get(accountData._app?.pubSubApp);
1925
+ if (appData?.pubSubTopic && appData.pubSubIamPolicy) {
1926
+ await this.prepare();
1927
+ try {
1928
+ // Request Gmail to send notifications to Pub/Sub topic
1929
+ let watchResponse = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/watch`, 'post', {
1930
+ topicName: appData?.pubSubTopic
1931
+ });
1932
+ // { historyId: '3663748', expiration: '1720183655953' }
1933
+ await this.accountObject.update({
1934
+ lastWatch: new Date(now),
1935
+ watchResponse,
1936
+ watchFailure: null
1937
+ });
1938
+ this.logger.info({
1939
+ msg: 'Renewed Gmail pubsub watch',
1940
+ account: this.account,
1941
+ watchResponse
1942
+ });
1943
+ } catch (err) {
1944
+ await this.accountObject.update({
1945
+ lastWatch: new Date(now),
1946
+ watchFailure: {
1947
+ err: err.message,
1948
+ req: err.oauthRequest
1949
+ }
1950
+ });
1951
+ this.logger.error({
1952
+ msg: 'Failed to set up Gmail pubsub watch',
1953
+ account: this.account,
1954
+ err
1955
+ });
1956
+ }
1957
+ }
1958
+ }
1959
+ }
1960
+
1961
+ /**
1962
+ * Fetches all Gmail labels with caching
1963
+ * @param {boolean} force - Force refresh
1964
+ * @returns {Array} Label list
1965
+ */
1966
+ async getLabels(force) {
1967
+ let now = Date.now();
1968
+ if (this.cachedLabels && !force && now <= this.cachedLabelsTime + 3600 * 1000) {
1969
+ return this.cachedLabels;
1970
+ }
1971
+
1972
+ try {
1973
+ let cachedLabels = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/labels`);
1974
+ this.cachedLabels = cachedLabels?.labels;
1975
+ this.cachedLabelsTime = now;
1976
+
1977
+ return this.cachedLabels;
1978
+ } catch (err) {
1979
+ if (this.cachedLabels) {
1980
+ return this.cachedLabels;
1981
+ }
1982
+ throw err;
1983
+ }
1984
+ }
1985
+
1986
+ /**
1987
+ * Resolves a label by path or ID
1988
+ * @param {string} path - Label path or ID
1989
+ * @returns {Object|false} Label object or false if not found
1990
+ */
1991
+ async getLabel(path) {
1992
+ path = []
1993
+ .concat(path || '')
1994
+ .join('/')
1995
+ .replace(/^INBOX(\/|$)/gi, 'INBOX');
1996
+
1997
+ // Try system label mappings first
1998
+ for (let label of Object.keys(SYSTEM_LABELS)) {
1999
+ if (SYSTEM_LABELS[label].toLowerCase() === path.toLowerCase()) {
2000
+ path = label;
2001
+ break;
2002
+ }
2003
+ }
2004
+
2005
+ for (let label of Object.keys(SYSTEM_NAMES)) {
2006
+ if (SYSTEM_NAMES[label].toLowerCase() === path.toLowerCase()) {
2007
+ path = label;
2008
+ break;
2009
+ }
2010
+ }
2011
+
2012
+ let labelsResult = await this.getLabels();
2013
+ let label = labelsResult.find(entry => entry.name === path || entry.id === path);
2014
+ if (!label) {
2015
+ // try again by fetching the list without cache
2016
+ labelsResult = await this.getLabels(true);
2017
+ label = labelsResult.find(entry => entry.name === path || entry.id === path);
2018
+ }
2019
+
2020
+ if (!label) {
2021
+ return false;
2022
+ }
2023
+
2024
+ return label;
2025
+ }
2026
+
2027
+ /**
2028
+ * Extracts envelope data from Gmail message
2029
+ * @param {Object} messageData - Gmail message object
2030
+ * @returns {Object} Envelope with parsed addresses
2031
+ */
2032
+ getEnvelope(messageData) {
2033
+ let envelope = {};
2034
+
2035
+ // Parse address headers
2036
+ for (let key of ['from', 'to', 'cc', 'bcc', 'sender', 'reply-to']) {
2037
+ for (let header of messageData.payload.headers.filter(header => header.name.toLowerCase() === key)) {
2038
+ let parsed = addressparser(header.value, { flatten: true });
2039
+
2040
+ let envelopekey = key.toLowerCase().replace(/-(.)/g, (o, c) => c.toUpperCase());
2041
+
2042
+ envelope[envelopekey] = [].concat(envelope[envelopekey] || []).concat(parsed || []);
2043
+ }
2044
+ }
2045
+
2046
+ envelope.messageId = messageData.payload.headers.find(header => header.name.toLowerCase() === 'message-id')?.value?.trim();
2047
+ envelope.inReplyTo = messageData.payload.headers.find(header => header.name.toLowerCase() === 'in-reply-to')?.value?.trim();
2048
+
2049
+ return envelope;
2050
+ }
2051
+
2052
+ /**
2053
+ * Extracts attachments and text parts from message structure
2054
+ * @param {Object} messageData - Gmail message
2055
+ * @param {Object} options - Processing options
2056
+ * @returns {Object} Attachments and text information
2057
+ */
2058
+ getAttachmentList(messageData, options) {
2059
+ options = options || {};
2060
+
2061
+ let encodedTextSize = {};
2062
+ const attachments = [];
2063
+ const textParts = [[], [], []]; // [plain, html, other]
2064
+ const textContents = [[], [], []];
2065
+
2066
+ /**
2067
+ * Recursively walks message MIME structure
2068
+ * @param {Object} node - MIME part node
2069
+ * @param {boolean} isRelated - Whether part is inside multipart/related
2070
+ */
2071
+ let walk = (node, isRelated) => {
2072
+ if (node.mimeType === 'multipart/related') {
2073
+ isRelated = true;
2074
+ }
2075
+
2076
+ // Parse content headers
2077
+ const dispositionHeader = node.headers?.find(header => /^content-disposition$/i.test(header.name))?.value || '';
2078
+ const contentTypeHeader = node.headers?.find(header => /^content-type$/i.test(header.name))?.value || '';
2079
+ const contentId = (node.headers?.find(header => /^content-id$/i.test(header.name))?.value || '').toString().trim();
2080
+
2081
+ let disposition;
2082
+ if (dispositionHeader) {
2083
+ disposition = libmime.parseHeaderValue(dispositionHeader);
2084
+ disposition.value = (disposition.value || '').toString().trim().toLowerCase();
2085
+ }
2086
+
2087
+ let contentType;
2088
+ if (contentTypeHeader) {
2089
+ contentType = libmime.parseHeaderValue(contentTypeHeader);
2090
+ contentType.value = (contentType.value || '').toString().trim().toLowerCase();
2091
+ }
2092
+
2093
+ if (!/^multipart\//.test(node.mimeType)) {
2094
+ if (node.body.attachmentId) {
2095
+ // This is an attachment
2096
+ const attachmentIdProps = [
2097
+ messageData.id,
2098
+ node.mimeType || null,
2099
+ disposition?.value || null,
2100
+ node.filename || null,
2101
+ node.body.attachmentId
2102
+ ];
2103
+
2104
+ const attachment = {
2105
+ // Create stable attachment ID
2106
+ id: msgpack.encode(attachmentIdProps).toString('base64url'),
2107
+ contentType: node.mimeType,
2108
+ encodedSize: node.body.size,
2109
+
2110
+ embedded: isRelated,
2111
+ inline: disposition?.value === 'inline' || (!disposition && isRelated)
2112
+ };
2113
+
2114
+ if (node.filename) {
2115
+ attachment.filename = node.filename;
2116
+ }
2117
+
2118
+ if (contentId) {
2119
+ attachment.contentId = contentId.replace(/^<*/, '<').replace(/>*$/, '>');
2120
+ }
2121
+
2122
+ // Calendar method for iCal
2123
+ if (typeof contentType?.params?.method === 'string') {
2124
+ attachment.method = contentType.params.method;
2125
+ }
2126
+
2127
+ attachments.push(attachment);
2128
+ } else if ((!disposition || disposition.value === 'inline') && /^text\/(plain|html)/.test(node.mimeType)) {
2129
+ // This is a text part
2130
+ let type = node.mimeType.substr(5);
2131
+ if (!encodedTextSize[type]) {
2132
+ encodedTextSize[type] = 0;
2133
+ }
2134
+ encodedTextSize[type] += node.body.size;
2135
+
2136
+ // Track part IDs and optionally extract content
2137
+ switch (type) {
2138
+ case 'plain':
2139
+ textParts[0].push(node.partId);
2140
+ if ([type, '*'].includes(options.textType)) {
2141
+ textContents[0].push(Buffer.from(node.body.data, 'base64'));
2142
+ }
2143
+ break;
2144
+ case 'html':
2145
+ textParts[1].push(node.partId);
2146
+ if ([type, '*'].includes(options.textType)) {
2147
+ textContents[1].push(Buffer.from(node.body.data, 'base64'));
2148
+ }
2149
+ break;
2150
+ default:
2151
+ textParts[2].push(node.partId);
2152
+ if (['*'].includes(options.textType)) {
2153
+ textContents[0].push(Buffer.from(node.body.data, 'base64'));
2154
+ }
2155
+ break;
2156
+ }
2157
+ }
2158
+ }
2159
+
2160
+ // Process child parts
2161
+ if (node.parts) {
2162
+ node.parts.forEach(childNode => walk(childNode, isRelated));
2163
+ }
2164
+ };
2165
+
2166
+ walk(messageData.payload, false);
2167
+
2168
+ // Concatenate text parts
2169
+ for (let i = 0; i < textContents.length; i++) {
2170
+ textContents[i] = textContents[i].length ? Buffer.concat(textContents[i]) : null;
2171
+ }
2172
+
2173
+ return {
2174
+ attachments,
2175
+ textId: msgpack.encode([messageData.id, textParts]).toString('base64url'),
2176
+ encodedTextSize,
2177
+ textContents
2178
+ };
2179
+ }
2180
+
2181
+ /**
2182
+ * Converts Gmail labels to IMAP-style flags and labels
2183
+ * @param {Object} messageData - Gmail message
2184
+ * @returns {Object} Flags, labels, and category
2185
+ */
2186
+ formatFlagsAndLabels(messageData) {
2187
+ messageData = messageData || {};
2188
+
2189
+ let flags = [];
2190
+ let labels = [];
2191
+ let category;
2192
+
2193
+ // Convert Gmail labels to IMAP flags
2194
+ if (!messageData.labelIds?.includes('UNREAD')) {
2195
+ flags.push('\\Seen');
2196
+ }
2197
+
2198
+ if (messageData.labelIds?.includes('STARRED')) {
2199
+ flags.push('\\Flagged');
2200
+ }
2201
+
2202
+ if (messageData.labelIds?.includes('DRAFTS')) {
2203
+ flags.push('\\Draft');
2204
+ }
2205
+
2206
+ // Process labels
2207
+ for (let label of messageData.labelIds || []) {
2208
+ if (SKIP_LABELS.includes(label)) {
2209
+ continue;
2210
+ }
2211
+ if (SYSTEM_LABELS.hasOwnProperty(label)) {
2212
+ labels.push(SYSTEM_LABELS[label]);
2213
+ } else if (SYSTEM_NAMES.hasOwnProperty(label) && /^CATEGORY/.test(label)) {
2214
+ // Extract category name
2215
+ category = label.split('_').pop().toLowerCase();
2216
+ } else {
2217
+ labels.push(label);
2218
+ }
2219
+ }
2220
+
2221
+ // Default to primary category if in inbox
2222
+ if (!category && labels.includes('\\Inbox')) {
2223
+ category = 'primary';
2224
+ }
2225
+
2226
+ return { flags, labels, category };
2227
+ }
2228
+
2229
+ /**
2230
+ * Formats Gmail message to standard EmailEngine format
2231
+ * @param {Object} messageData - Raw Gmail message
2232
+ * @param {Object} options - Formatting options
2233
+ * @returns {Object} Formatted message
2234
+ */
2235
+ formatMessage(messageData, options) {
2236
+ let { extended, path, textType } = options || {};
2237
+
2238
+ let date = messageData.internalDate && !isNaN(messageData.internalDate) ? new Date(Number(messageData.internalDate)) : undefined;
2239
+ if (date?.toString() === 'Invalid Date') {
2240
+ date = undefined;
2241
+ }
2242
+
2243
+ let { flags, labels, category } = this.formatFlagsAndLabels(messageData);
2244
+
2245
+ let envelope = this.getEnvelope(messageData);
2246
+
2247
+ // Extract all headers
2248
+ let headers = {};
2249
+ for (let header of messageData.payload.headers) {
2250
+ let key = header.name.toLowerCase();
2251
+ if (!headers[key]) {
2252
+ headers[key] = [header.value];
2253
+ } else {
2254
+ headers[key].push(header.value);
2255
+ }
2256
+ }
2257
+
2258
+ const { attachments, textId, encodedTextSize, textContents } = this.getAttachmentList(messageData, { textType });
2259
+
2260
+ // Decode snippet preview
2261
+ let preview;
2262
+ try {
2263
+ preview = he.decode(messageData.snippet);
2264
+ } catch (err) {
2265
+ preview = messageData.snippet;
2266
+ }
2267
+
2268
+ const result = {
2269
+ id: messageData.id,
2270
+ uid: messageData.uid,
2271
+
2272
+ path: (extended && path) || undefined,
2273
+
2274
+ emailId: messageData.id || undefined,
2275
+ threadId: messageData.threadId || undefined,
2276
+
2277
+ date: date ? date.toISOString() : undefined,
2278
+
2279
+ flags,
2280
+ labels,
2281
+ category,
2282
+
2283
+ unseen: !flags.includes('\\Seen') ? true : undefined,
2284
+ flagged: flags.includes('\\Flagged') ? true : undefined,
2285
+ draft: flags.includes('\\Draft') ? true : undefined,
2286
+
2287
+ size: messageData.sizeEstimate,
2288
+ subject: messageData.payload.headers.find(header => header.name.toLowerCase() === 'subject')?.value || undefined,
2289
+ from: envelope.from && envelope.from[0] ? envelope.from[0] : undefined,
2290
+
2291
+ replyTo: envelope.replyTo && envelope.replyTo.length ? envelope.replyTo : undefined,
2292
+ sender: extended && envelope.sender && envelope.sender[0] ? envelope.sender[0] : undefined,
2293
+
2294
+ to: envelope.to && envelope.to.length ? envelope.to : undefined,
2295
+ cc: envelope.cc && envelope.cc.length ? envelope.cc : undefined,
2296
+
2297
+ bcc: extended && envelope.bcc && envelope.bcc.length ? envelope.bcc : undefined,
2298
+
2299
+ attachments: attachments && attachments.length ? attachments : undefined,
2300
+ messageId: (envelope.messageId && envelope.messageId.toString().trim()) || undefined,
2301
+ inReplyTo: envelope.inReplyTo || undefined,
2302
+
2303
+ headers: extended ? headers : undefined,
2304
+
2305
+ text: textId
2306
+ ? {
2307
+ id: textId,
2308
+ encodedSize: encodedTextSize,
2309
+ plain: textContents?.[0]?.toString(),
2310
+ html: textContents?.[1]?.toString(),
2311
+ hasMore: textContents?.[0] || textContents?.[1] ? false : undefined
2312
+ }
2313
+ : undefined,
2314
+
2315
+ preview
2316
+ };
2317
+
2318
+ // Detect auto-replies
2319
+ if (this.isAutoreply(result)) {
2320
+ result.isAutoReply = true;
2321
+ }
2322
+
2323
+ // Set special-use based on labels
2324
+ for (let specialUseTag of ['\\Junk', '\\Sent', '\\Trash', '\\Inbox', '\\Drafts']) {
2325
+ if (result.labels && result.labels.includes(specialUseTag)) {
2326
+ result.messageSpecialUse = specialUseTag;
2327
+ break;
2328
+ }
2329
+ }
2330
+
2331
+ return result;
2332
+ }
2333
+
2334
+ /**
2335
+ * Downloads attachment content from Gmail
2336
+ * @param {string} attachmentId - Encoded attachment ID
2337
+ * @param {Object} options - Download options
2338
+ * @returns {Object|Buffer} Attachment data
2339
+ */
2340
+ async getAttachmentContent(attachmentId, options) {
2341
+ options = options || {};
2342
+ const [emailId, contentType, disposition, filename, id] = msgpack.decode(Buffer.from(attachmentId, 'base64url'));
2343
+
2344
+ await this.prepare();
2345
+
2346
+ const requestQuery = {};
2347
+ const result = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/messages/${emailId}/attachments/${id}`, 'get', requestQuery);
2348
+
2349
+ const content = result?.data ? Buffer.from(result?.data, 'base64url') : null;
2350
+
2351
+ return options.contentOnly
2352
+ ? content
2353
+ : {
2354
+ content,
2355
+ contentType,
2356
+ disposition,
2357
+ filename
2358
+ };
2359
+ }
2360
+
2361
+ /**
2362
+ * Formats search terms for Gmail API
2363
+ * @param {*} term - Search term
2364
+ * @param {string} quot - Quote character
2365
+ * @returns {string} Formatted term
2366
+ */
2367
+ formatSearchTerm(term, quot = '"') {
2368
+ if (typeof term === 'object' && term && Object.prototype.toString.apply(new Date()) === '[object Date]') {
2369
+ term = term.toISOString().substring(0, 10);
2370
+ }
2371
+
2372
+ term = (term || '')
2373
+ .toString()
2374
+ .replace(/[\s"]+/g, ' ')
2375
+ .trim();
2376
+
2377
+ if (term.indexOf(' ') >= 0) {
2378
+ return `${quot ? quot : ''}${term}${quot ? quot : ''}`;
2379
+ }
2380
+ return term;
2381
+ }
2382
+
2383
+ /**
2384
+ * Converts IMAP flags to Gmail label operations
2385
+ * @param {string} flag - IMAP flag
2386
+ * @param {boolean} remove - Whether to remove the flag
2387
+ * @returns {Object} Label operation
2388
+ */
2389
+ flagToLabel(flag, remove) {
2390
+ switch (flag) {
2391
+ case '\\Seen':
2392
+ // Gmail uses inverse logic for UNREAD label
2393
+ return { [remove ? 'add' : 'remove']: 'UNREAD' };
2394
+ case '\\Flagged':
2395
+ return { [remove ? 'remove' : 'add']: 'STARRED' };
2396
+ }
2397
+ }
2398
+
2399
+ /**
2400
+ * Converts IMAP SEARCH query to Gmail API query
2401
+ * @param {Object} search - IMAP search object
2402
+ * @returns {string} Gmail query string
2403
+ */
2404
+ prepareQuery(search) {
2405
+ search = search || {};
2406
+
2407
+ const queryParts = [];
2408
+
2409
+ // Check for unsupported search terms
2410
+ for (let disabledKey of ['seq', 'uid', 'paths', 'modseq', 'answered', 'deleted', 'draft']) {
2411
+ if (disabledKey in search) {
2412
+ let error = new Error(`Unsupported search term "${disabledKey}"`);
2413
+ error.code = 'UnsupportedSearchTerm';
2414
+ error.statusCode = 400;
2415
+ throw error;
2416
+ }
2417
+ }
2418
+
2419
+ // flagged
2420
+ if (typeof search.flagged === 'boolean') {
2421
+ queryParts.push(`${!search.flagged ? '-' : ''}is:starred`);
2422
+ }
2423
+
2424
+ // unseen
2425
+ if (typeof search.unseen === 'boolean') {
2426
+ queryParts.push(`is:${search.unseen ? 'unread' : 'read'}`);
2427
+ }
2428
+
2429
+ // seen
2430
+ if (typeof search.seen === 'boolean') {
2431
+ queryParts.push(`is:${search.seen ? 'read' : 'unread'}`);
2432
+ }
2433
+
2434
+ // Address fields
2435
+ for (let key of ['from', 'to', 'cc', 'bcc', 'subject']) {
2436
+ if (search[key]) {
2437
+ queryParts.push(`${key}:${this.formatSearchTerm(search[key])}`);
2438
+ }
2439
+ }
2440
+
2441
+ // Date ranges
2442
+ for (let key of ['since', 'sentSince']) {
2443
+ if (search[key]) {
2444
+ queryParts.push(`after:${this.formatSearchTerm(search[key], false)}`);
2445
+ }
2446
+ }
2447
+
2448
+ for (let key of ['before', 'sentBefore']) {
2449
+ if (search[key]) {
2450
+ queryParts.push(`before:${this.formatSearchTerm(search[key])}`);
2451
+ }
2452
+ }
2453
+
2454
+ // Header searches
2455
+ for (let headerKey of Object.keys(search.header || {})) {
2456
+ switch (headerKey.toLowerCase().trim()) {
2457
+ case 'message-id':
2458
+ queryParts.push(`rfc822msgid:${this.formatSearchTerm(search.header[headerKey])}`);
2459
+ break;
2460
+ default: {
2461
+ let error = new Error(`Unsupported search header "${headerKey}"`);
2462
+ error.code = 'UnsupportedSearchTerm';
2463
+ error.statusCode = 400;
2464
+ throw error;
2465
+ }
2466
+ }
2467
+ }
2468
+
2469
+ // Raw Gmail query passthrough
2470
+ if (search.gmailRaw && typeof search.gmailRaw === 'string') {
2471
+ queryParts.push(search.gmailRaw);
2472
+ }
2473
+
2474
+ // body search
2475
+ if (search.body && typeof search.body === 'string') {
2476
+ queryParts.push(`${this.formatSearchTerm(search.body)}`);
2477
+ }
2478
+
2479
+ return queryParts.join(' ').trim();
2480
+ }
2481
+
2482
+ /**
2483
+ * Triggers history sync processing
2484
+ * @param {number} currentHistoryId - Last known history ID
2485
+ * @param {number} updatedHistoryId - New history ID
2486
+ */
2487
+ triggerSync(currentHistoryId, updatedHistoryId) {
2488
+ if (this.processingHistory) {
2489
+ return;
2490
+ }
2491
+ this.processingHistory = true;
2492
+ this.processHistory(currentHistoryId, updatedHistoryId)
2493
+ .catch(err => {
2494
+ this.logger.error({ msg: 'Failed to process account history', currentHistoryId, updatedHistoryId, account: this.account, err });
2495
+ })
2496
+ .finally(() => {
2497
+ this.processingHistory = false;
2498
+ });
2499
+ }
2500
+
2501
+ /**
2502
+ * Processes a single history entry for changes
2503
+ * @param {Object} historyEntry - Gmail history entry
2504
+ */
2505
+ async processHistoryEntry(historyEntry) {
2506
+ let labels = await this.getLabels();
2507
+
2508
+ /**
2509
+ * Processes label changes and sends update notifications
2510
+ * @param {Array} labelsValue - Label change entries
2511
+ * @param {string} direction - 'add' or 'remove'
2512
+ */
2513
+ let processLabels = async (labelsValue, direction) => {
2514
+ let addedProp, deletedProp;
2515
+ switch (direction) {
2516
+ case 'remove':
2517
+ addedProp = 'deleted';
2518
+ deletedProp = 'added';
2519
+ break;
2520
+ case 'add':
2521
+ default:
2522
+ addedProp = 'added';
2523
+ deletedProp = 'deleted';
2524
+ break;
2525
+ }
2526
+
2527
+ for (let entry of labelsValue || []) {
2528
+ if (!entry?.message) {
2529
+ continue;
2530
+ }
2531
+
2532
+ let changes = { flags: { added: [], deleted: [] }, labels: { added: [], deleted: [] } };
2533
+
2534
+ // Convert label changes to flag/label changes
2535
+ for (let labelId of entry?.labelIds || []) {
2536
+ switch (labelId) {
2537
+ case 'UNREAD':
2538
+ changes.flags[deletedProp].push('\\Seen');
2539
+ break;
2540
+ case 'STARRED':
2541
+ changes.flags[addedProp].push('\\Flagged');
2542
+ break;
2543
+ case 'DRAFTS':
2544
+ changes.flags[addedProp].push('\\Draft');
2545
+ break;
2546
+ default:
2547
+ if (SKIP_LABELS.includes(labelId)) {
2548
+ continue;
2549
+ }
2550
+ if (SYSTEM_LABELS.hasOwnProperty(labelId)) {
2551
+ changes.labels[addedProp].push(SYSTEM_LABELS[labelId]);
2552
+ } else if (SYSTEM_NAMES.hasOwnProperty(labelId) && /^CATEGORY/.test(labelId)) {
2553
+ // ignore category labels
2554
+ } else {
2555
+ // resolve Path for the label
2556
+ let label = labels.find(label => label.id === labelId);
2557
+ if (label) {
2558
+ changes.labels[addedProp].push(label.name);
2559
+ }
2560
+ }
2561
+ break;
2562
+ }
2563
+ }
2564
+
2565
+ let { flags: messageFlags, labels: messageLabels } = this.formatFlagsAndLabels(entry?.message);
2566
+
2567
+ // clear empty values
2568
+ for (let key of ['added', 'deleted']) {
2569
+ if (!changes.flags[key]?.length) {
2570
+ delete changes.flags[key];
2571
+ }
2572
+ if (!changes.labels[key]?.length) {
2573
+ delete changes.labels[key];
2574
+ }
2575
+ }
2576
+
2577
+ if (!Object.keys(changes.flags).length) {
2578
+ delete changes.flags;
2579
+ } else {
2580
+ changes.flags.value = messageFlags;
2581
+ }
2582
+
2583
+ if (!Object.keys(changes.labels).length) {
2584
+ delete changes.labels;
2585
+ } else {
2586
+ changes.labels.value = messageLabels;
2587
+ }
2588
+
2589
+ let messageUpdate = {
2590
+ id: entry.message.id,
2591
+ threadId: entry.message.threadId,
2592
+ changes
2593
+ };
2594
+
2595
+ await this.notify(this, MESSAGE_UPDATED_NOTIFY, messageUpdate);
2596
+ }
2597
+ };
2598
+
2599
+ // Process label additions and removals
2600
+ await processLabels(historyEntry?.labelsAdded, 'add');
2601
+ await processLabels(historyEntry?.labelsRemoved, 'remove');
2602
+
2603
+ // Process deleted messages
2604
+ for (let entry of historyEntry?.messagesDeleted || []) {
2605
+ if (!entry?.message) {
2606
+ continue;
2607
+ }
2608
+ let { flags: messageFlags, labels: messageLabels, category: messageCategory } = this.formatFlagsAndLabels(entry?.message);
2609
+ let messageUpdate = {
2610
+ id: entry.message.id,
2611
+ threadId: entry.message.threadId,
2612
+ flags: messageFlags,
2613
+ labels: messageLabels,
2614
+ category: messageCategory
2615
+ };
2616
+ await this.notify(this, MESSAGE_DELETED_NOTIFY, messageUpdate);
2617
+ }
2618
+
2619
+ // Process new messages
2620
+ const newMessageOptions = await this.getMessageFetchOptions();
2621
+ for (let entry of historyEntry?.messagesAdded || []) {
2622
+ if (!entry?.message) {
2623
+ continue;
2624
+ }
2625
+
2626
+ const { flags: messageFlags, labels: messageLabels, category: messageCategory } = this.formatFlagsAndLabels(entry?.message);
2627
+ const eventEntry = {
2628
+ id: entry.message.id,
2629
+ threadId: entry.message.threadId,
2630
+ flags: messageFlags,
2631
+ labels: messageLabels,
2632
+ category: messageCategory
2633
+ };
2634
+
2635
+ const messageData = await this.prepareNewMessage(eventEntry, newMessageOptions);
2636
+ if (messageData) {
2637
+ await this.processNew(messageData, newMessageOptions);
2638
+ }
2639
+ }
2640
+ }
2641
+
2642
+ /**
2643
+ * Processes Gmail history changes since last sync
2644
+ * @param {number} currentHistoryId - Starting history ID
2645
+ * @param {number} updatedHistoryId - Target history ID
2646
+ */
2647
+ async processHistory(currentHistoryId, updatedHistoryId) {
2648
+ let newestHistoryId = currentHistoryId;
2649
+ let lastHistoryId = currentHistoryId;
2650
+
2651
+ /**
2652
+ * Fetches and processes a page of history
2653
+ * @param {string} pageToken - Pagination token
2654
+ */
2655
+ let getHistoryPage = async pageToken => {
2656
+ let queryArgs = {
2657
+ startHistoryId: currentHistoryId,
2658
+ maxResults: 500
2659
+ };
2660
+
2661
+ if (pageToken) {
2662
+ queryArgs.pageToken = pageToken;
2663
+ }
2664
+
2665
+ let historyRes;
2666
+ try {
2667
+ historyRes = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/history`, 'get', queryArgs);
2668
+ } catch (err) {
2669
+ switch (err?.oauthRequest?.response?.error?.code) {
2670
+ case 404: {
2671
+ // History ID too old
2672
+ this.logger.info({ msg: 'Provided history ID is too old', account: this.account, historyId: currentHistoryId, updatedHistoryId, err });
2673
+ // set to newest known value, ignore missed entries
2674
+ newestHistoryId = updatedHistoryId;
2675
+ return;
2676
+ }
2677
+ default:
2678
+ throw err;
2679
+ }
2680
+ }
2681
+
2682
+ // Process each history entry
2683
+ for (let entry of historyRes?.history || []) {
2684
+ try {
2685
+ await this.processHistoryEntry(entry);
2686
+ let historyEntryId = Number(entry?.id) || null;
2687
+ if (historyEntryId && historyEntryId > lastHistoryId) {
2688
+ await this.redis.hset(this.getAccountKey(), 'googleHistoryId', historyEntryId.toString());
2689
+ lastHistoryId = historyEntryId;
2690
+ }
2691
+ } catch (err) {
2692
+ this.logger.error({ msg: 'Failed to process history entry', account: this.account, entry, err });
2693
+ }
2694
+ }
2695
+
2696
+ if (Number(historyRes?.historyId) > newestHistoryId) {
2697
+ newestHistoryId = Number(historyRes.historyId);
2698
+ }
2699
+
2700
+ // Continue with next page
2701
+ if (historyRes?.nextPageToken) {
2702
+ await getHistoryPage(historyRes?.nextPageToken);
2703
+ }
2704
+ };
2705
+
2706
+ await getHistoryPage();
2707
+
2708
+ // Update to newest history ID
2709
+ if (newestHistoryId && newestHistoryId > currentHistoryId) {
2710
+ await this.redis.hset(this.getAccountKey(), 'googleHistoryId', newestHistoryId.toString());
2711
+ }
2712
+ }
2713
+
2714
+ /**
2715
+ * Prepares a new message for processing
2716
+ * @param {Object} eventEntry - Message event data
2717
+ * @param {Object} options - Processing options
2718
+ * @returns {Object} Prepared message data
2719
+ */
2720
+ async prepareNewMessage(eventEntry, options) {
2721
+ this.logger.debug({ msg: 'New message', id: eventEntry.id, flags: eventEntry.flags && Array.from(eventEntry.flags) });
2722
+
2723
+ // Configure header fetching
2724
+ if (options.fetchHeaders) {
2725
+ options.headers = options.fetchHeaders;
2726
+ } else {
2727
+ options.headers = 'headers' in options ? options.headers : false;
2728
+ }
2729
+
2730
+ let messageData = await this.getMessage(eventEntry.id, options);
2731
+
2732
+ if (!messageData) {
2733
+ await this.notify(this, MESSAGE_MISSING_NOTIFY, {
2734
+ id: eventEntry.id
2735
+ });
2736
+ return;
2737
+ }
2738
+
2739
+ // All new emails are "new" as message movement between folders is reported as label changes
2740
+ messageData.seemsLikeNew = true;
2741
+
2742
+ if (eventEntry.category) {
2743
+ messageData.category = eventEntry.category;
2744
+ }
2745
+
2746
+ // Determine special-use folder
2747
+ for (let specialUseTag of ['\\Junk', '\\Sent', '\\Trash', '\\Inbox', '\\Drafts']) {
2748
+ if (this.listingEntry.specialUse === specialUseTag || (messageData.labels && messageData.labels.includes(specialUseTag))) {
2749
+ messageData.messageSpecialUse = specialUseTag;
2750
+ break;
2751
+ }
2752
+ }
2753
+
2754
+ return messageData;
2755
+ }
2756
+
2757
+ /**
2758
+ * Fetches user's language preference
2759
+ * @returns {string} Language code
2760
+ */
2761
+ async getLocale() {
2762
+ let languageRes;
2763
+ try {
2764
+ languageRes = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/settings/language`, 'get');
2765
+ } catch (err) {
2766
+ switch (err?.oauthRequest?.response?.error?.code) {
2767
+ default:
2768
+ throw err;
2769
+ }
2770
+ }
2771
+
2772
+ return (languageRes?.displayLanguage || '').toString().split(/[-_]/).shift().trim().toLowerCase();
2773
+ }
2774
+
2775
+ /**
2776
+ * Lists email signatures from Gmail settings
2777
+ * @returns {Object} Signatures data
2778
+ */
2779
+ async listSignatures() {
2780
+ let signatureListRes;
2781
+ try {
2782
+ signatureListRes = await this.request(`${GMAIL_API_BASE}/gmail/v1/users/me/settings/sendAs`, 'get');
2783
+ } catch (err) {
2784
+ switch (err?.oauthRequest?.response?.error?.code) {
2785
+ default:
2786
+ throw err;
2787
+ }
2788
+ }
2789
+
2790
+ let signatures = signatureListRes?.sendAs?.map(entry => ({ address: entry.sendAsEmail, signature: entry.signature })).filter(entry => entry.signature);
2791
+
2792
+ return { signatures, signaturesSupported: true };
2793
+ }
2794
+ }
2795
+
2796
+ module.exports = { GmailClient };