From ba55f71855dca467a82324231281475ad3500664 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sat, 11 Mar 2023 22:04:36 -0800 Subject: [PATCH 01/28] Add okpush library --- package.json | 1 + yarn.lock | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+) diff --git a/package.json b/package.json index 9b87d4d4..71e5a4db 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "tsc": "cd assets && yarn tsc" }, "devDependencies": { + "okpush": "^0.0.6", "prettier": "^2.7.1" }, "prettier": { diff --git a/yarn.lock b/yarn.lock index 113c0c75..992c4697 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,442 @@ # yarn lockfile v1 +ansi-escapes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-6.0.0.tgz#68c580e87a489f6df3d761028bb93093fde6bd8a" + integrity sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw== + dependencies: + type-fest "^3.0.0" + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" + integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^5.0.0, chalk@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-spinners@^2.6.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" + integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== + +cli-width@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.0.0.tgz#a5622f6a3b0a9e3e711a25f099bf2399f608caf6" + integrity sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw== + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^9.4.1: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +figures@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-5.0.0.tgz#126cd055052dea699f8a54e8c9450e6ecfc44d5f" + integrity sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg== + dependencies: + escape-string-regexp "^5.0.0" + is-unicode-supported "^1.2.0" + +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d" + integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ== + +inquirer@^9.1.4: + version "9.1.4" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-9.1.4.tgz#482da8803670a64bd942bc5166a9547a19d41474" + integrity sha512-9hiJxE5gkK/cM2d1mTEnuurGTAoHebbkX0BYl3h7iEg7FYfuNIom+nDfBCSWtvSnoSrWCeBxqqBZu26xdlJlXA== + dependencies: + ansi-escapes "^6.0.0" + chalk "^5.1.2" + cli-cursor "^4.0.0" + cli-width "^4.0.0" + external-editor "^3.0.3" + figures "^5.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^6.1.2" + run-async "^2.4.0" + rxjs "^7.5.7" + string-width "^5.1.2" + strip-ansi "^7.0.1" + through "^2.3.6" + wrap-ansi "^8.0.1" + +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + +is-unicode-supported@^1.1.0, is-unicode-supported@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" + integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-5.1.0.tgz#a20e3b9a5f53fac6aeb8e2bb22c07cf2c8f16d93" + integrity sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA== + dependencies: + chalk "^5.0.0" + is-unicode-supported "^1.1.0" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +okpush@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/okpush/-/okpush-0.0.6.tgz#fc1285a0e80ec2823d561c86b71ccc8d55360f10" + integrity sha512-WzgjT0gS/WUraYviDqmC6HvESzNDzOJmEyyteMowXHDi1W/u2ikUmjKMU2p6B4amH1jZJZ8Eb/u0PxtwaBV0GA== + dependencies: + axios "^1.3.4" + chalk "^4.1.2" + commander "^9.4.1" + ini "^3.0.1" + inquirer "^9.1.4" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +ora@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/ora/-/ora-6.1.2.tgz#7b3c1356b42fd90fb1dad043d5dbe649388a0bf5" + integrity sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw== + dependencies: + bl "^5.0.0" + chalk "^5.0.0" + cli-cursor "^4.0.0" + cli-spinners "^2.6.1" + is-interactive "^2.0.0" + is-unicode-supported "^1.1.0" + log-symbols "^5.1.0" + strip-ansi "^7.0.1" + wcwidth "^1.0.1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + prettier@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^7.5.7: + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== + dependencies: + tslib "^2.1.0" + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tslib@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +type-fest@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.6.1.tgz#cf8025edeebfd6cf48de73573a5e1423350b9993" + integrity sha512-htXWckxlT6U4+ilVgweNliPqlsVSSucbxVexRYllyMVJDtf5rTjv6kF/s+qAd4QSL1BZcnJPEJavYBPQiWuZDA== + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +wrap-ansi@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" From 05d7854a19a163ba60e2e1a5b7ff2d4435b6d2fb Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 00:01:50 -0800 Subject: [PATCH 02/28] Start work on addie bot --- assets/src/addie.tsx | 8 + assets/src/images/therapist.png | Bin 0 -> 33186 bytes assets/src/models/index.ts | 1 + assets/src/models/message.ts | 8 + assets/src/screens/addie/Addie.tsx | 9 + assets/src/screens/addie/ChatMain.tsx | 132 ++++++++++++ assets/src/screens/addie/addieScript.ts | 198 ++++++++++++++++++ assets/src/stores/addieStore.ts | 45 ++++ assets/vite.config.ts | 1 + .../controllers/page_controller.ex | 4 + lib/sequence_web/router.ex | 2 + 11 files changed, 408 insertions(+) create mode 100644 assets/src/addie.tsx create mode 100644 assets/src/images/therapist.png create mode 100644 assets/src/models/message.ts create mode 100644 assets/src/screens/addie/Addie.tsx create mode 100644 assets/src/screens/addie/ChatMain.tsx create mode 100644 assets/src/screens/addie/addieScript.ts create mode 100644 assets/src/stores/addieStore.ts diff --git a/assets/src/addie.tsx b/assets/src/addie.tsx new file mode 100644 index 00000000..e02f9a81 --- /dev/null +++ b/assets/src/addie.tsx @@ -0,0 +1,8 @@ +import '@/styles/index.css' +import 'vite/modulepreload-polyfill' + +import { render } from 'preact' + +import Addie from '@/screens/addie/Addie' + +render(, document.getElementById('app')!) diff --git a/assets/src/images/therapist.png b/assets/src/images/therapist.png new file mode 100644 index 0000000000000000000000000000000000000000..4a1607f93321bb918f2468f726f50dcd8045dabf GIT binary patch literal 33186 zcmXt91yogC)4p_fgMfgvAR(P1h;(;{ba%IOh+MkCOLup-bW3-4H~-=N*3Vk3L);x_ zX7B0TW8a+`ht9Jv*7ZhqI=<--N{#Y_L*Y>s6wtx51m^tr2tallK@7*nMGaMh zgTuu|g%$g-Td|d<#2M_13)`WoPf;7ZvMxpzNh!2f|+C6V-Eh!S}`x{yqF@hd4>F?6-ql5SvN;`oD@12&vdxw*L ziUFb4$5HW6Y#C$_g@`nLJV+Z!TY4R>9V+Xi%n)(0zj?pUvkBq1vfg_{g`DqD??n;m zAd3E$exn_D>bFZPWypRSxcD$}Xx-}8_JSfo0>GXSu_4OvcBDVKo+JF}EZH5vKRfa} z2!aics(6Vgx?+JBG;^}5eTfowMb6w0*{pt&zkp(=`v~90fx1}$tb@h*2ZSjC15u`0 z(_Q0yKeOS~rNYdDMTqcZOc*@2;T2@}`E8Z)%3d!nCAUqX{tYL|l&B8A4!UGKOiC6- z5Tb&#WTB+6-kMDoxOX4y6ylHJ?~2wvZ{o}*!W{;zj~lC4M057p4xuV*%%-ISb`7nY z1z$5g5>xg)oFAsC{n5RTP!`JQL7$r9GjfXwVIPJnEoD%;1l0Q;b2^A7%rpH`yB;>l zHTUvqhf=V?lesgc$o$)jrHRt3kP?cly9lm(twKNlY5avr3rIiID4MkE^5Yo`rnNn9 zZw@Y)9!~}`Z8k(Jt|UmGazX#oHxrZei}as}1~USCg|gRYZ!2Sihyd;S82*?{ub52j z+w=B^f$O_}amNO823&mT&HwBR{L({~j|2`n{mDrL^-<4q3PkItZtHJ zcAi*qrQQ-$IGCa{x@=V$nlb~AU+JcgrT6X~%^mvPEa)15oK%6A0-H$|%69nrEvW7~ zRPB8yur5m6=;EcXDNzj%#=|Mlr9oF2obmt>ss&@s%O|97^0oF6qs>IwB{F1X-^dj#9Xi zkFe2Nl~jom5x1=N=RT?@!?hn{j9y?p2!kuT4n%_x;pjo4^GcG9e&YWA!YwN9Xb zHr9U~ln$%FvNdv4U%FY&8lDsIp+Op+mv=4`K7#4>A=jQ4C6e7}sPOPa!3GigNE88L z$RMoQ=-Sg~Tr;EIJLkXsj#`VTO&M`tYS}7P|HvB$8?3oJo@;6&f`&C+lO`NpE|-5l z=gq`G3KE{DlF1mr+ z^;@mie|GQt|C(Oju$Y`M&z_*)mk2YDFSA6RXOpS_ZxT|7GU^%4I3sv-mX4(VGM#OI zmNO7B@sbb0bIE6kQ?v5*Fy$+1TGdZ?l9(Wmy*WQqWB)8fE=5piMGm;=%X*>R$X5=N z_$&2{R+_lxPjuqOgiCj?gQr|}1b1iVHZ;b4HFyX_Ebi=5b=yHs>T9Zi2?jgJQv^r= zV&DWTazW=JPJn&y!DbJ7>4U8V3ADVhi?=0P*SMqb^V^$UEczQ8-oX0Q;28KSKg%D9 zeuxBsi|AL96qD!PUgg8xjHk!zol;X-_m5!2CLmqmdhumLeOp|!n(h?r7CTOFF3c_9V?!%bjGSAYFJ}mZPhX_oA$TiN2GfSAj}G{fx51Eny$a z@8VAVpsf)0r(r-JeVZ^C3hrK4s}v11aCt{`{wTZhWKM$M(9%hE;)T5(sP1`xe^ZV3j?-QTf?(T7?pr<~E zUAh6GWdKj;|HcF7WV=HR*1l4&75UuDLr*~bWD|p}Wr$x&n)EPSw{0Nv9LIXJalas07L@}pNJWa%k_j%`xRO8WydiM9V{ z)V=Hb2l=I^>@)d73CTjOudGR!O#?78>x7bpf*mBC;d=BO!K?xY4(89(`e;~n+RVVv zKh`ctUY{*#9cM$XCcI!-Wa+no5K%0T{!uh*3(L4OSVpeTVF^2_l(aX4*L^F zr3RVYIu%s06_31du^K_Fkqo*n@)+hX>wvBsKwowFV2|)FoP`=GnNZ`q60 zPnBMRfdO9S)Q8Z#Xj+}aGa({EXRnta9n|h5;~&@}X;CFmn00wzkKp&qPoFG*4ORJ< zZtal6VqyJ^fmIGogo}K3te@fX^`p}dP&}|G#=+WJ z`BaK~L82_Nc}udj`!mmce6-s}v!&|S5&z;lePxig?f(KzPvHQJoPm^N;jVw8Q@?eF zM!4K*u{fZWrmqo7c8$39=U7|2aIbFb;(ez7_IEHaVZ3s|O|vYK`>M25J%fN`Do7#I zfw1d4zSh-~!~3h!HZK%;VB`nRP9)#c9|spOd7EI_>6J5j{G?gvloE3Qm@9rot4^6mWhO3$(&0I-Qf)IZ5ZnIJ}=_ zr|=YECDu3nLj62g`Op4&a2}6wrGMR&MB;Zb?`40Hj*~H#Vc2|K&^h@*iIw$^DUDs_`e#y1JM%hF<^ zj9@`gD0TWMBs3fP4G%{;<`E;%*wnA$H!i3PTe9$SVt%9E=H6{ba53!xuf|6>0u!(@ z)=IHMi8>%AKKM2({B4NQ(Twej4}b9({2p$yKow=Cqq4|4fz^>HS%_@{N6o8+K+(xL&L(jH^+>3?`s5Z%axd;0Z}pEI7`@LJ>9-M zOn)r4u9nnTV}yWj&_#jMh6|$n16IW9aLa0mc2k)&O1@C1n!I+k!=b<@+NNZ9xFVOp z@M?>WdK?zIjR}|ca`HU(tG|O#i?UU!d8ebmjKQsp<4K3+09GBe@V7&Z7n-_H^lX_5 z4cPoFmh8N+lM`%g{@yJ2#%;Q^rqxTMP={1Ho4GFagmPrjex=u?us8N7o23FO1|!5~ z=5408a2ct1K)gmzTB$90t}*8ExzOq)P>#w>9()@N{M23TY{46yY_$`63{v)RC1aB_Le&OSUDM+MIv z_y$yx^vZuCw1hNEw;S7~It%zL5jJatnri9)UaFZMAghrOmNF(`no`2~A@V|$P1o>A zE13(@heP=+4-u)YPG0N}@4S}{m?|H1b(2vnX)VK?8RT>o!cKPMr|?eTA=9-@0Z8_| zK+MkK<-C4vi&mc*>bV%{Mhlzu6ppCKCZM%3JWA8iG^{O+6>X31UA<7#wp~$9FD5oW z6uysEWYAS(p^z05ln|>hPkxXKk1)Q-jS67<$$0bw7}oOHJT5_<{ya9avD)Q(bU?Hn zeczHw$O4h32dpvl*a6~)o_(P52>3QP?HeR@z72B?`KyO?_P6Nk6=C%^t(M#7nLmma zd&Hu>;?0DPYNR>W?_8f66pPBDg+6F}yu*4QjM~M83uJMaXt=Of_}Co)rTw!Y5$a)8W94bMGC zrKM#}+ZPb|ic0FG1vL)dc3Mm&NowLmr4$9;UKs_cLKn|&I+chBJzg%@15F)%2@dx8 zDn02tf$iSEPfS*3!$&$x91gX!slKb|@r|4F=gkTeqxXbL$ndUZc~sLz{VvOhSS-6O zj-uoAkQ69i7;mI?%iJ-%_yXN;e~~P@OavdSX_v*zXY1B5vK%AWP)`(}eP2t!4$~in zQ!OBSOD#43Sdu%Uh$peAlN?t#C<}me8{`X(_LaxxCz$YIFypo2>g5yP-u)o46Ek~L z$rlE_B|VHe38|Od92t%b)JFd~)tQOys`6-U(LriBKVf=jzBB5d`7uAIA!v#ck@mA8 z_1w+bLbmyH^R<8|c4wtc3{QhaGdKDQ!PR7N#(BMGYrS~G!RBRPi*hP*1vZ{tQmOzE z`WezY*tph57!H?F<~EIrx$tbUUo9NoB&|YP`5Y!w3}MplC0OUCcX{M^cm{{MAlf&( zm84D4HM|UZ+sg+yVWd2;1xyQu`a`Ar+`vr9O0wk-WRbYJJe%w>g2URr5+&vg^B69{ z!$A+pFMk4Op~2x%YyXOilF+8U(Bn<^yHI*@?=Dl;@XpFuK~t!2`*Mn3cxwwe@c<9i zd`f9I=L?gJ2aCYjq~!g|r|Ej6A93L~P7Dk~8ZmJvf?R=3+tRnJZrb9^Ia{&NSzE*~ zNiPrCe-F|dmjocBfy@y5h?Ki}#K-u(yxrZF6#Kb!b*hphYJQ$5>Ih!p#_ z6^_67zMf{_`1UQ=ROWL(8RvsyztW)TWd)g?8kj+e!gEs8g z&hvfR?GR<#i`FUSC~$mz_NKVkzGiDX*v~cQMNfeC3c+m4hVtN#iXbq* zj=za2tv&DI?bi8JIE-pO#i-%zLU)aaIh0i0fwed}&c5L!6`Hw{z@YLwS`K*VhT8xK z(IiIA-~Njn5GqMT(^jb<^wv_@HLKt;a6ic9X2O=QajUi$NJl4#xh5e=kZ4O^7{`ZLRbbY#z+**CPK9vL-G?(OzW zL9U20?{<^dY<~9c@z)e--C0Mo@bNX_=n&>^RW`?&&a5abf@8yTDW*beAFX#FpY|`h zWol9-^5)kEl&Z;xVfOh3ghtNWR9&gKAOmT7JPc*f5c%VwR1)`Wy$3|OjogRv+7isO zIcELOJxLbBr}H;QGYn}sU^KdI*~EqCv43d4#bywSnRuW|*t41ASunb8jqjy~Z( zP2-6zrbrB*%pK{qzQDvM?)IKKj+!nF{A+f*`umZcf`&NQzO~Ft)GZGBeIy-(7|Ioz z)Gr*D8Fg}}UhX7E=Wh<_Qnlf;Zi>qbs9bIpw?vAbSWR{_gs%8!S7@0)4%zx*lJosvqrFW#l@wEMo=2Hqh7c7us2VR@9F~0T;SLh!*sVXl ztY*<`x!oK_X~tYIh0oIwMCe)+Zod{92-`%j^oDodTyc@Ok7)}<9-?(86)=)xwfzCv z6&P{7)cd6(b{dXavp>qS=DICLVvy5kJ&BdaC6YhwR?KmH8d=n_{GCija#h*2+?Gq` z;nOlZ`87pTnW^{4XC!o{BK?!lSj5elSXLt2-;+TDcE9>?mR zg8JZ6qwQAvEo*wh?bJ;>h<|JV@LdJX_kQhM@b6x>jgqwMQMz@o;&!~ElApb>M?s&p zHXqfRCCLoB3>4_s;m!H5FPGiPUzC6D1Ef{<-JP*sW|4KE?3RH1W89+y z8sB<$5yGtfT(^T6m6zsmk16PCVh0k&NesH3CY5{y3$NmgB(h^Yr(to4e=d8a3oqK{AgQrLwzk z5KL-Fx$&}%W5fa#Wx5Kerr`JYZ&)$Hf@t)h9t{a7eMiYc={2sbCKaBZela*7Ypb=n zlz64J+{MzPw>W z-{mQ$(yq9Bf`@5e9Oi)`NNLK>kZG*if4aC9zw-SPlHkUN(b#A=zTroH*g%OpBoP7w zA|1&@dynSdLj-Kyb__I9D*c{Gk+aZSPa1AYayD`VHaQ1}}Y2 z@*=!@e3`bW+i&QOJg{PvziH{{W*#F6rcu@63h5l@1XyN`=Bc*-%8)JJ!Sfk4rRt~2 zr>7A;66j`k{F!IhrGfI*$Uk1+*0Tk%u$To&UKj=?!ZbI?hprv&52fyYsGQHaa9eW; zYl9;q4wF*8SQdbPr!%{%#xsJAX8%kqIUep4WUP7}<1INm(pnqs zcs^-!Ik{I74~Q& z>f>gPuN|k(;=OLfC*;zdc&xaD8~>PTDzjeSeK6Y%MBH_pZO(?3myG{*Nw%_}GG(sK z7szIQZu-nQu^s+U^6>Jd%$oeHurq(A><5iyzM%9iNlJPxtCWZ2yC{o9fy0UJ-dd+a z1$-O99F9EFcZ0XA`ja$8*XjMg3bg`wmoe5H8r=@EoA3AkV$f+dnN3ZHA)QM<9|;V_ z&&>5q?s7G3=FYUR*yHHF{v$u-K4%qPB$hB?PJ|XtOLzxw%r05j@5eRLXTDrOS?_8w zta5CTS%EipcvcH{-su-5F%e2{pq=gBp%z`{Yvt-8p>0b;vc-xq+5;8sHu(V z6iRg!r)Fldt;NcMf%d1Z!+>Z}_a5M+)a=)B>{ucwl(u=bF5cL4#0m^!WHA!|>vewOaFPA+(qAh(KID?_eBk$4) zLS8Knoa%YEH#7taYWs#o#x~gr?;mA#Uu@X<(D8z-mYCansH>uLzx$=eCKX!+l!9ere}ui6h%bAl@dz4l#$<|^Z^N43-=0_ zlb>(QEX`53kod{mTa&8YKJc#{>PXsO1)_vTxaj(CU6Ob`^xNpB)PzNOew}OMVx`E) zF6W0hQ>->qwXenQ>Q3RGW|mp2ro`S(XFF}Q6J+dcdz=%j+xzRddBGFKy!!K<<=lF7 zv(Ow2O9Ub8dP4`ZLX;V3Y+eXz3b1bg@T!=(r1v@zzD;<-mhj^$SqrmUCs1%o-&tay zWu}kmP^pDn?X2dxQ{lfpL1uyYbxKx$(F5aZ7UjMK)RbmdM^8#NcuqVe=eede%#dbpd(0Zazw~gqqG`X9oOE3l#IZJdeaOME!>H~hQTCU<-xn3qE%rYbXarMRhPS~TW!{ig-a4)cRaX&l z8u96ktV;QFH84KNL0qn-zqLQ-)N!_%vNibH8s_8@p6!Hu2@|sFbID`k>nP?@&6g@> zqeH+4MKPo>fB;}O4M5IrHqfuSQ|1`usy(*%o$N_B z48LAhNy_j(TiDVLIX>PSuGj>R%p3eu?VV3Ddk~lmq$O{OOWGUf$nh#Xh3OF$pYlEP z{1VpgBS*%CruU`T0zx%ul>uXfpd**s2leR(T^0Dxd{zt=vWDk{+iN0eWJYaVAkVC| zLi0wBBN69ba+b_(rcAqd6Ame<*eaAQoOR?qNemE9sI_&4;-LUw%@wg8LUXGbV_3|zRtI&!<|<-ORnSHmc?(Z2Zv%`MtWJe zjmS)moTcW0cBU=<5d_d+;q?{&%AI}j53X0_?ID)+?zy}32!n*>rx?!-f4;k|W&c-R zIpO+!Mhu6OU%g9QHl$h@!8Rm6vL>-90mP$dAh92`q4x(=k?4owx8#MPC!>|ko``eA z^XqHOZhLOWG2h|XgBLtTJ8yh#>J0)@rryiKKtj6zn3<|Hnzz(OAdha}$g<4tZGvW# zzufu-k^IPM~DOV#!?#|g& zst|&gw-q=dms}gO=2+j-b^GGD%i9ZpV0^8I>yAiX3Y9;qB_uuwb}ZLBb!}I^=D3nw4eSNQzLNdEkPnyAr=D(m8Cs!HNXrL4)z~;2NoO|^E$lb#Ef+7`OBv%O zaq2bKbho}u(Jwe$_P32hSKRII;y=1sUC9+9ex@raokJz9 z{Enw^)5W?AP9jos@O5)!`ui!%OLiIpQ#@8nE}?3IPwA|yDF#uk7b{s0mgA zLoFp%FT+D7E5TN?$FrUVQL;$q_WUlZ*8Jxkq#tN`%nlcY@?^A`dyQP3*Do%$CN3N2 zG@5AEY&(1FUJF9z@@+RuGwU6FMn06;s-{?`{!z+Pwj-d=kd#a-j5!2XzlPG81E!uy zBuu7n5%<_|nsBjyE4A-sF5s~=p9Z8JVKHb&UyB_YJ1~4$9ZTnScgLs~@7y*F`(!l( z#J_$`LrmNly<`i2x=g*@C0N<3u1c<7M?~Qwr&z^#=;QCjBgGRN5Y zec4nVo-2A&pVLpt?p^!0fm6wOG-9+JtqmmP2E8}$UKZ?nZWz1eb{rb_W*cE(GLFP% zhVV*cY3+hLV|AKkAIk|o>UDdMwRbkjEQ%yew~IC4?#_PS=vo-mmS;~+P{9ccLmf@= zNAtWi=YPM}TizIKFmGF%UjdM8IRAi)V2z;`$Y=X{zp*(8(>Cd%9v8ojswS z>2N%j;#>KRat-7MaGG0jXcHVboaB_Q9C=Y4OrlsaY*l8)tD z6^ckOr{m80Nzh&h?GS!RVL@u-7O{cv=_gO9VHqcWqIrpF$3X-PBD zq=|i=BAd?tYZEdwbtw%oB@C`+(8N*(@)EG(0acbbi=p_phC7$N5p8dSiF)|gms=C& zro&CcQnS}5Auc=1{$R0}`;t-wp7KRHm(%)HO5SFM_$1+5t@2#g7_CB8>bqrvue~g& z(HRgBx6SOTl>1t5{d^VGSuH~+HePmto?r&R-9Y{x9rMSkkZvd;JV&~at|+hH!DqyH zGQ6T=Y?tf1yHi=R4mFT6;g*LJ7ywM6R7FV@gaoL(Q7D1*$SYV*S>GCU??-adC#us( z#s#il%xcr7U8y?Z@l)})-a|D!8of<oKe z(5Rn>+?;lN)zKoj-}M#@?4&ZioIKN$Ykohrt$5W~&GhNkMo!vEG}h=%f%rNBj>OvB z=8ILV-X1HX*Q5(L1{>VQ&5SlcMf-b31NEIC=ax5&Q;`a1bjX5QmgQkpPx^FV)_MfW ze2vhWGpjXf_uXHo07@$$YXj=d7=OM%tmbYwj^u|g^@e)&Zr9B4-k(!{GP?e*t*wZ+ zHu-6sGQ%jB$+zh6C4!+h`u-rKdhc~~*icUmTlCvEyKa@li+S&5v#Az0ORhAAap<)M zA%b$_jtaS?R{i9@5)noL*6_#0_}vL9#+P!;hP7Jij|(23$A7622D9pD1$3PQK7j|K z%+EqzP|oK9iTqGE>NTt!NyTHsuS;$|xD&n8dR%CGXI14WR1%mCBsopXGJyK>?WKO6su0+MAydo88~Wk#`l1IDDr2l=dQ8%|WCfYGI( zY6)^sDnNx%qj#n{Ly^BiI}%$vPdODYKO{6H^?d670@S=qZxxhFw@QswPU{Y%{X)I9 z>|@=?{Yzpa>O0Pa8In5nbj8Zj)wup2woKcd5sa9YHWArQFu1h8pgW*YyVW58A}b9a z-d6JR5eN+sMzFcd5cM?R+V__#1(t302B>%Ikq%8C#q!)uE>a@Kwu?{}+15k!+^z%V z{?#l$9f{E0qY?5thWulhME#xyG!;TvP>re;5BT+=?S4il5!3^)cqBeS-SF0NrLSiC zw*gTxF^68U-N{l%ab6vJigWu))qLC=z*jS=)#giuMBJ^{yGK5pDx17Cj@viGOCz>0 z(XW9MZ zcyvAG@25XbDP9zOq}`{xdnaqBhpRQ-1i7z#@%C|f)vxk*Z8y4W{ zQL+{KiXCS&*>h}nM*PzRIF>BVS4%1%p}k_}ywRkmx6jTe)kJ&taggZ9)3 zAaLy7XSb`Te-j2PezsJ<^d7>%H1+LZJURZ3 z46=s?FuI+2D!*=F;p0_GD(#Yt3rr4%MaM4{1|7YwzQeYcTw3Wv8q~DZlYe}yQ#eby z8<|q=2H~uYHT7^90rPwE33QiIyI78F^m_fPtyM?NOalNqNB|~B2vKI&H^`d1ZK&iS zZ*_|5i@bU?nDyXYc}<=%Ps?)n>G0WFJtPke+4gRPcot%@jm!oi|KLIglC3ko_Grtz zM_3(6+Z;F!0vc(uK-aUI4nhVBMsTnOx}?rRS2WckRXZhDY^Vh@>pE3+WT^M^5Nw=+ z42{^nYYWom^|@^GZr(qT`Ny%3OY@bWyZop{7dF#%haG0^Q9z)-YJ0EnTi+;DX~K0- zymB3`IZZQCi!VDEKlyNN_UC`8eH)%6=3=5wj$|`8220T9O7r5e4asL~6EP$(N?i|! zE02|kCOdfw5@X#cmMXdzsW6OLr!&LopZb4&s&s?%{irzztW)9SjIWz{|4mB-HVzj= z{k?HAOmnkQK(OwJUs|^Z`SgM`<&S=FaZ0nEcZz<~EY2fdY4)i&> zIW^m~JwovkQrSw6mwVGM{2+(R3yn4#sz;0;ajAOp^OhYf>h*2LW0+<(Y z!EDQn01r|a$#5snL)(9`pFk<`yfe|4-S-~->E-oRda&fzu(yupnf%=B2kO2gVp3uu0nGhCTGrd@i1;ymS+eswkZ?Y_T=`q;H(U*Zl2mFX_4UDCMmHB`Pp zxeOI!*+syyAA`@b^8H(zbd4X%m*c_y#>1X~*>-L5$dCOTmOt!?hHJmF7Et}KZ>5#jCL z=F2-UOLu#)7ZLZRPeQr7Y!~gltCdNKr#~LjN(}W}wMUBLVcJv?85^|2#ZOyeLu?MM zoEdUpW1&0TrAJEJxsT=yNn4veHU*g*cX80)jiQ*f=)&Zm^-gaC5cW)rNo?vVk{Q3B zstgINS7`-;X*mdS$+7h$%jTK^Xp~4I0%xm_B@(T}U%343wfI@|9b$c4I>Xbo?H&o0 z5U$)>d~7@qNLI*SU1NQGmRzOW?*mt1$S{Bw>?j@%X>TZ03=R>N!P}ky@0uL$!X*%; zp!X?fF>bYj?QnYRvi?-CtC)OrW20HfWVKV9{VUW@CKXS#w65i6+Vi=pJ6s4_18kPaNs@k3P1TsIlS6 zp`;3pv}5&L$IlxZd6+}?O(&jV{(GG`O~p3(b8*w?@x-d{wIZ$MsYC6B+||69^XY0E zfw&4+_2SWM>*$}6GjT%lXCw6bTW>K}^?g{nH&!kTJ!A+b6>8tg@%L-AS2{^q)f{Vo z&Yh$ORK<^e8)9AW`jZNPpMWz!1wvp$HKIL>pK+g;i4WgyI2rPjlfZXT>}pR^F8uXH z)8RMJ7h|D?^K(S2<%Mc?UmHyg4gHl^gNPw>I9J09hqbdcHJJ@Wdz>UAXEK*qWd?uG z9~iZWRNIpI8tDOuj)1K!3J6EfNX&Phbv}QWt9_LS5kWKnScTk4K$7C$UozTlp~L5z zrDgh$lR5~q7vTPM69u1Ru}mEBm;44$&2EJ2YF;#oAiH<;psug3S$8tGq|AW3C>L-2 z;_&<4DEcR6&YxK5_o#%y_MisBq#w@A*@|UWyzM@hSWH`lDilG8p+GOFizU)(4Ozcv zrV&=l1adK)!X5nW+Cn2e9N?WN0RQh{iR547U6biBwdeg}f9_tI^t?=Hp&Cc!`xCPZ z6<9jbfRL=4g$zN{;9^goPeM+{WO(rt>t#E+Vxd>?%zmgo<9a&iC*sfV#W{SyApD*3#-<@pxwDc@`?-b9ffEty#Kf0jc|;0H!1+recC+k2JH{&t z_%8_KWU{}Zx5NVE3E|Nr*a5HEI`9mi1M&A;T#%U1Py?VBZ?2YHfzKK{cA*KfWa&8-YS?- zq7GQ82=~xMEy*?(K&k=$KK|Tl44I)vT&DxPX*DmL0`wb;!)AIH=iFm^F%na3{raAe z%RU9LK5QTqV>v}6l<&m5e$z}3#*9A8jNR0z;{AK@SriGdcEm8X6{0~y4V3piL`*u> z{&V8q=FY@9L2opqp#IJ6(Uq~-)I?inhAt#Yea5wxC+HL37c_p|@|nU=Y!P5`HYv5T z+(BwCR?`>5VkN9D)ferS-*sF<0~gLDrLtn+_rO{CrP*%JcwBZU3t&DHz95B-?dE0v z#~Zq`qlrW`Em!sQXgY&GI9Z51?W<#lr!hY!YxMTr2JdUE6f^Oo4wdr1(J&`Y|Dp7{ ze}+Hgv^6>}a{j2g+$$ zCjRqfGQ81?c)9hwwouv3<;vJ?QI%mDmJZ#xcRZIQBfCSlW4VN#)iGHW>R9s9W{Ws?8#*JHJ(=PkR-<)k-6aeGdeI|g`=+=2>DSU&hf9KJAjhx+ zXXo}^j!Y8){<{aMEtMw(YqS0Bn1=&|?R9R9Ym!I>XujTfI`oHEOG0=#RG-y@&*5D> zz6Jl0x}vKcZv}bOgy;JvIY{PfPyJ@haep2`V*<&sF!v+|`;IzbnUu8ND$nMltE&0$ zMTG&GEKJiA$Q90ye?Go9$OG7XWFjh{4}GHY#a7zi`>?440X9!+#6ez#i9CsowG!u^ z(Q~aCk8b&=y-h@W8bIc76mIVT3IGwl&}y1X?e9Rr1fXpW!qkkH3){JTJY>Hd%$qL% zg;`_2M22z5X@jKcWx&+_HM(bHp$ev+)~#`tiC}Dc1&zp2&3cGh48i)H0vkYR4%pc6 zp#MlV{(H`*=!>DW9T`fAdK@0Oq02*-9;Eui8eMV;K*x34${2k4mzCSDBeG&;{V2@< zO1(Fqa-L_i!&Ac%NGai+{=x;!kf|CGkVA-xQfL#wS{u%*OBP3NB3rW?Hp>dZDgM!L`D}p{3 zC3VE3DK=Ia5HqpkgxL+s3cMu%p})fI=toPFhZ{NK+_!@*mOgvI0WdL%e93n4oaLzO zy#M;G(cQCZzQPB_IRstM(oz*_?ny~0D+xuo_$&xfilZ=%@T~Tb%No*gJew3%0h90b z_{q+5zQS3&W3Ik5?d_Xu6ow6hTkimbx8t3E@#$Uoh(jkri+OCcBi1L<}_t#TkTd zlU8=>Z93a8{xkHrgL6~Rp9Hm3n0}Vr;-~@zfci;GivOvjZY7NrK1?uH``lqDkzf2F zS1Qmki{^hN-~=2`#Zr9Kq_ocK_MiO}HZ0Z4on5VTkytPG<)z&Gx{D{hc|X9)97u^% z89{w=4+_AxEXYD|L9gjIS{-xW8gNUCB%$7y0Kv6F`N(+Cn5_d6leMq^_9mm>Xd_Y<0-#w}C|DzDwnLjHJ z<-__c?MLf)5-K%9|il z`c7AglTsPAyJOQ2dhPPmw8C0VA3+VON4&YAEg6vP%^UkSYGHeWr(JbT#vi2X?TV{w zyY~D~Y|q`n(c1SRb8dI@dO|NH+}?U>vg$!^9-u9Dsh*gttxN;bv)Y|1&o>+T78Jlo z+kb#NdhnN?{a=fBVjwN7*0jrnI{Bny<0#hXR68FQ7*H?^amdm2v-2k65awdos z;lBkEa4hb~Gfln>T6flN9Lx``tP#TCFFtjxr(%Fh6xSsK!0NmW{-ri(344$F7qnK0 ziM`PYh-@|`2oVK1aEl&QMtD=zARxqUmSPCafMdryy{`(6)m|_jue1`%7tI*H0Uip& z!sF&u4o@-X9-v@jhu3MD2)*5#2wcFyihesFr4EA=SJP)u4;zQ%74D0&XhcZWPrBvD zx6iiAjUj5{UM9Sw0Lu$ib2C#`W-|F!T8Ww4akJ#q4<5L2MhyNCvP;1ga5*$k=|Qvo4R<3F`gyjHQxS=k`2VIt{ZT` zdi@+tmoZ~4bbYFphv3M>yT?p^0-GiA=y{KIJy{zvS0VN!==y%;cZmV6wuKVPLBVyt zBCyH8V62oMG?T@x_i+A}Tvj{&`NjgmbnYm~R_$k}6KWxqK9??2_9r~;@2rdBCx69a zb^`jai}X(~j*Z2&<{iz~lUt8NS_L+k7PWpG=R2TH+p7Qg^q6_?a3DQp4@5flwUnYA z9BfKaz?`CE-w_NR)=!UPA9k9;S9(0tFje;KZ<7l~uGgOqMp^>#U~Fw&)39{~(sYw2 z^j|ICrC?*3+Sz+OOkSK4mnxp<`8ed^_x@sQXJcfno;PZ0XmDgRnpTgRYs@Q}lqAny zXUYjp1L-YFA@&n_+6qi!4`0KB)Z07+>IKhGeMo%2Iy1D-X*KMw<^iBeb0$&O&~>Uz zzhr3GT2$(=tqLCH^xICAfJ-(Cx6>2YmKSpEm%!Pr?ZJNi^g2#4<$V>n-{|`7e6ysz zriXZ(K5nRx6^OQ2lE8}MO=a%pWGwE+XZE&UEYS*?a?{vSxGs;E?!(skD0!7Q`K(S$ zT$+YDGjvfI$Hrsrc0eW{WYlUeB}1$%4T!}*UvIr$2;VGB<+uCAg;nde?M=WB{+k09 zrb>o9(Mz9tO<*Yl;C5V)QLk7t;j6H>VeW8yqyX8c^i%gVzyVqelo(&Q^KX$0S~(Nv z*BTt6Hwm1xk(JLml^`Y>UZp#KmkOQ!m5e$2mMdv?hap11KD_9q|3@JqGxsdYUJadS^gq6UrVgDT$c1gZnu z-$)H1Hq*cWu~@E%@UBiF)XUgfxvY;4cE(wbnMm5iB-+Ga7@trI&~7roQP~uW{lvXI zF8Emi0}P)x(-8<`T|TskxZV8Zxc|_>e&;nwx2N24e_v;Pvw8Wrzha9hG&WOTz4^14 zy|L;`QJtHJIsoHisoIz;CG3`$7BQ{NDVdD7jz!ejSQx=&F3M!cVBE8!1|sNrq)M>w zm_@h)9dLeocWUeNp#QDue!fry#2kQrFGu4w*8Ln}7P0Fj7!%S0gJ9LX(SG{t_8vGe zwY`=~rMTTqv(xx;h|O=+3n^qRj_le@LuIw`sJqWgqW#O)+Fr;1jCW%-kLxvYBw5PQBAKSar>C~$;)${ zz{)KUquq?IV6D%w4Jq%6OudJ|Y`$m861;)JVnE#>1K*!cqW>;Qq!0R_VP9<#X?w*W#_mAH(7%_udRP~JFn|OgDu=w zM%L%r$bxOfoM;R^mJx-EPcq^SwoAOT$Agc%wtCJ-1RcGWWO5=3v8E+n902&x6H z!<-McIx7(0S_@6vvKX~ba*bHI2CvGU_`}>;FYN6`46^U>ZF!fnBDj`)3kf#YG&=a~ zFw4yBZTWAI>ou-6s{)ZuW2T6X?M>ayl|P8!wSk^De>Y3RZY9CpQEK6W;X=H9$=^)9 zudh$~Ni5d{9<6r?vm8jzysFuAVji+7sKFe~7j6fsQFl*b54O=zg36ME`0(eSfV>xb z{huYcUv3ZauKU+l#RmUA(w(k-@v^C(F@K5} zJIx=K9=CxysyeFK?7_YeBbcrl zo$SW#Pkk@&=2oXdmRh_@?MuO~XYW^_AJc#SO4Jjc6NDkUpTRA)x3yA8akZ^{)qVY` z6`j)90x9DcbpuQ;Z8(FZg(J*~p604(403&4=k)CJV5>ddh|qj?|bIa063 zN}N-b{{LKnYR}g%yi1R`LQjHnmP_bpQ+InVrti+G2ehHawbjTd`QLzL{Ifyk$C!mn zjq^c6N*(E=cKA;E_a=Ah0UZ%GzCpCXEpk4Xb?;RrVzzhNWa#3| zR$pH7t6vKc>c^&ub=+a!zrl*!|In2P$ZN*91~&%yU5p04hoehAy%EWL@|*W>^o8n9 z7jVF=;oVyD@@^F|G7FC<^VOLr&w85|o*DW;4fBPF3dm+NA33unJxX-s*aWHKR$n@| zJhk5Xls$v9P*7uPeCMnk_O*X|*)I!eH03b)|Lv|m38!C{ZN7m&b>A!22Cx?2?Wdl) zTxKe4n)^JrdR=#ye<8^?v_NIgv=Awc>=GAnxwHMm90%u@*>zio`3kh%x&8mIysvzS z>WkVvLw8AcD2O244HAlU35c|GgOtS3Lxa+t(jhI~9n#&>UDC`w{@(X~zJI{|z|1gk z_TFdjwVt*1TF+j`i1fBSL88LI#xApJ3tU4(CAb+F4ro?ib8@xWoO(t z3pB%6Il21QWKVOPI|CO#cW;SE4i$UWqh;7^CLFn(ToCXs>UULg8lZfU zZBPIHX0+8i;reRKt?AaG(=^3pe>8x-Wn}xP$zMo+s5n1qxs41w5W)1&s#+7^V)OZY z0?~{O_eS(}XX3xE5S}V;tWD}R>ku>KL7&yfqp|33lwU#B=X*Blef}h?GU4;Pdy|0y z(M|k{9%B%esRbk?UF-4#WSUpvyOGuNYeWiTohJ70x3 zhD|p5qilP|26SC8+O9q}^wmx)%KH0 zGAQ$V+@!Kq1Rv$_)BLmsQdy)#@O)CG;O_%=`=s8QJ__sMexX}xamVXNyMZ}*=7r4F zu;Y4t<(-m+XU{&>P+@?k)c??CNa>u#;p>ghHf66;+Nk|SqITUH+ew#e!QuJN*^MK~ zoXPbY)lb4U$lO{qT+iqyIU=C5e?i`Ivl1!&E?EB~CvFhI3d!k_y#&WeVCuH#Q|rx}HL4qUGQVkFCnil=#Vos>2_&3=!{WyfBl!6zqs}fk<@mht6!9 z0}}F#s4?rY9|{HE(|0znzx-IBH6Iu;NDK3l3ZG1tgd#)x%sD;}_<&^yvIXVW!D-#_LlWr(OV(Rv?PF~fEA zfTQoo{LC;S>Cg`LUr} z-5zqnv#6Gkpnt5;?)it1&LC+B1=knMp*q2@XWCg{Lf{p_#%8Hfmm`=W__bC1SJ#*< z*st#>Z4XW)?BsD!aAeli!0dH`;iwC`E!<$52l3P|nN$#2OsJ(g!dtFP6xNFYvV?jP zki}0sH$~sQe^)0&wfJ68I5`lgNGhk*;wgmCMDd?^Kr}gVr~bC&wPtzLh4a zG%#b5^AZJN-VDKJAyIiJduW7@$1$%a&Q#xP!-o$p8b52W`zFY#iuc@fYbftx&_q;Q zaLXiPZ$5I$RFsMH?h!>lg!Sp-2Fs4>SIP*gLgsRe;`&!D827)ai8ms>htipCf;6@y zeUn+M{{Cc;*WmH+v^dXU&&BX`!OB~#RVDOdNV7yE!!5%*DStJ3dwo&Z+E;HQ&mJDF z*l%o?P$YEUK-afYEtLk=n#n0#K^Ue|MvZvzW;%J$s3JiI$yd&+w)~Z5f1iudh{66# z1*!G_BXf;chz)dx(m1;9;B-sF@B8(uy~MgW@1H`z6ZO$M$4_m4kA+2wUp*q;Tq`J_ z(4n_ns~{k~wNR5$wP|QL-rraL)Kk^ih{1=G(;G%T)4 z5A6(qe$X^|dk{KiquiO3|y&gWyXlN;&kQqU*kz#BjSgsGnU!*TYhq zIrNNF^f^gl6e)D&laK^#%??jfM-{QY>*iYEf{)PX;V@k{=&OW$(U_%*sgMXJbTkF8 z6UR^#8ddz$Mr!Sh^R>ectam>YId)$M5N=J6Hj5ndVR&9qPaK|5*7>imzvc!TF@DO^ z!W2KpRY|`n8R+qO0Vt+!LCdax5zmiXJa%243=n)yI`_PlJSi(4RZxnwf$Zo%1=nTFk#&i8;NW*Y2Y{m z%KBSNGO3+od00)Z=1VqSHbc8Pb`;%HX-`SN8>EjqFidV1@%+2FHghk}KBHluboPmH1aLCC;#Y8;mVnj-|d1?1GgZmm^c+=(<3*JD}2(0BM{ zqzJ`R3MM&T6D4MdBmMgUR5U+D)>70NZs{7Ro<8D!j4{y8TY7^>K@}9&E#P9gNYK() zBR4jB^cx&RL)ydRl$@gucE*h{uD)&+Zu~;I!b@ZaFqb`Pj&6!=gOCSBr(;9mcn1A( zw1lpT6Cqx~Y)3Ysa?Mz-!Vj@3YivXblIfXiu@yeY#95PYM8}~N3G56Aambph-xgsO zBOX9^d@BzVz8f2O@^uxuq}c7sMz73iBxd(+!JTZK3)tWqiT;oPu*Iv5P6%=6AP%`> zB*i%;;2G0HLuw+vR@R`vZyYExJ~g0zXSa(Izp@2B#w11ru@p@DU7`%YY7uKkB3m}- z)28It9_=qUJ)Z2!3htx%V*|vC3?UN5jEK8PYg}cBa9xei5`$%bCX$CR3KX-o&f@`# zxV4!(TNn>$Gl{nC1)#GDCw)I!K6iMPM7JOLyu-%?)adi$q+lhG8l>N%q$fWem6`2) zcFdO^M#uWChy%u#zdIV$o4VNLy}O6RepCE9#9_Y)8UAPxc;bsa(28vh(R+RSkU;no zp#7{i$VJy31k3;yc*ECsp#SAnf5CB_S&R5ujov}B{<%v(OiH#HlkCjS^m#)J`6fap zX-q;M5=NAU$!d0SuEEE@iRdrpcId_Z?t- z%Ulto7F;t9E%ieNkR#)qFreeWuy-Dn>MoU^{h)8yN~p?>F+@W0Mg9Y!1Pvg3IU3ae z+!ff}gfG%zkb`RHqBckaTq3kj4#Je|siFE$ZDcuF;1zUq`K)njQ3xDptx;z5LT0>B zNwq;$wLz(t?{wCn5YWBI*JI5;L^i~N8eEQsyftqFNEz}E!Ea05xJ+NO0&hvw2BQHN zfCHy>d8G5((B70V@}yJnb!?Z%srO&u8#pmcDhe6cla<$bo$m#aU;&=t2bUm!BiOuD z>Zl>uG`>=zBaLdm*0Fz)? zl(4uZZ5k+d!c$X)*gEF=o_Xty+F&J%>wuRw5M%U~`653KxAOzqCF&_Tl)$?hL(j>$ zd4)MiU#+>w93sDVk98elzvinVpIqUrBrO+o^@fj&3C>yY9>NMjEmjr{v;!FRJLxxS zirP!Bjmtx7QRis+6DaV|IL2f0gQPXrvkj>dtzGSSO-{BK0g5%^3wf-7V@ko?Z;lHa z0gD5;6=J(Xeb^_Vx^ZwO4wil(x5CfNTP6jP2>@}(+&)|vcg>plvv#_K^m-&RkQ@d_ zxG#bqyrh#Bf@%QcecnBQ10vd`%3KG)hRri8rt=BGoB8$%M7;VPuW|xoMlZKbzZl>Z zgfh6oqvDvwK>nBV3ubx-aIuU!d?jZNb65i%5E|59$gXCv0vey)_Oi%xD4;BJw#t`n zb4YJpocKFuBS>Qc8?zSB|xnb%DIu& zibwyO30Ff7&5zFeYhkcQJ6!lh&SoV*D-?xCPu}hYynE$X-ui%GOF*wDXa%!^JqIox z+dk5tn?NM~Fa zpQLM@mJxQ)n^vLO@cf1vwe-{%rNNwA=iBK~qdeit!@*rOfQ7^Xw9|svFrlDl!&6t5 z7LtdwnGR^{YQq++oY{leg*5z!RcCYlye*o^W`TGi8=^ydfY!}ch$*rSEW7d#&FR;T zIcO##?W?2{kFk+iQm0c~l2FH=4V&zVMjO@kR#Xev2EG!X;BrNH#)45qNF_RWDgql= zKoBxrAcX{<7ov|Z;0;Iz?>|;^Et>Q+*RMHQou}zKuX7**faWwWsnZpecKvOlN~jhGS9mJeckIYkK{n)#66Mln%V(YBWuOP; zG98UBXN}?%wUdAM8p&`Nr}2A()$q&arzz>l!y6J1jDV>b`K8O>>hAW(QZ4F5(N;GY z{*7e*TOhS{mX9DE9TUJnhfA{l5^xP!MP&RG?72+C-uqttgm+{OH_#pe+=M~fMDJKv z(rP76G!Qfq4Y8v}@L0dAQIGR7R3U+AODF{+y+L{KJH@`!;n;&3^liGX|B~z5Twsws zNSAL3a)zkv90_J_j`rzG%V@^06crXjPO1L4kr`eFjQ1b{K9hoJ1CI`eIBmi}Q-+{r z(dTN}q}zQSmm~0GuLgo~5Lnuj&t^GFeEAB^^>Dtx?Un91f_AtGH`4q3xEGCP(nkM` zg)|yI>M9gmz-b~Qp0(M~(}uJ9132ugUN0bNH_PrhsfHFaxDszI1v9)%Q1sp1a0Xcv z#VH)P^nn8hoB4G$<}EtWXY|gXtuU8Ci-npXJ^?o7`+1hFw>{zX{pzTwWvBs-WPw_HvArk{GYEm%io4Tp8 z)QK@^QrsJ+{i$-Inb&EMCQ*^6#4>GAF6--v1${|FXng1M-CkvDU>YKVi+rOiuajpj zYx?$w-5~uD8r`@5U1oCxjwgg`+FPR`cK5R~T*nJu-`~PSYNrcw7iD}mh^(N5u9YN*ZCq@2A-ybX^=_~cDcL|y_czcn6%y7#glL5NNqlep%x8L@E(o08Mni}pz7$M@vZ;#(Eela#EpuGcM0S0|oN+Hb zn2UuN@bz|RoaaNE2uC_)h~g#kd7VEz%T0%YO$->xqm2V?ZCxi>)>3p+tbD|e6O#}C zzS5}4oPdY$UfhF9P_)S^HpQ+~3nr}5iooPQM)-D6vFT_zfIyfn^7SnIhK>sX%D*NVDWiJ|MabJ%~8hznwp_l>{^BL#G&woWE=nax zM)o#3qICA4;_>{w*X0nqykK{)w9!G8a!f)>9-$mNDB)o0P5OF#cHN<9!RRXqk9BZ? zlhgk7%GQ=#xS##S#m|;*wbZLJ$f+2VOl@%WQYm;82NMXmU>|EDY?W-IVXY)?Q}hzK z`)o?vC%(&HxC8agdHno&SIh(@>Lm{JgT52>)8kT?Jm;mFmNr@iG6wYEI5n6IeyheT z8#fsmlq*ZeOE1N&Bc0S;QaK*aVQpd5jN zkWq+{AMc2OAm-~*TTPSXe84!ZfvOOBjzJW__yg=3-N{>S`Q3=Q=8dM!v(E8)bGY^ zwF#$v1R&o_Q&K?#5vx)7Vd>H(56P%qTvgHb_1#EHkfMwgMa~ziS&UWqHKG9Jw$R_K zjo)+{iA9Rx6grW!;Y&aHS?up7`NXK5<)Q*VA^8R!`h{VX3YCYfCB6y4>;14P3S=Oj zVz|BF!661vXag-!*Z2Tmlq|kgTMh(?kZ$Q!msU8A_`v4)i$tRPYm@GR%vXILP8(DW zo5A9iF{-;7)M63E9QwU~mxQZ1jqX?m9mPn62u0P^dHV~WaJ00j)2X!M6GJk?!n=Ob zzC=9bgPP~XeY{la-PZ~hy++$w7Mt_p{9;j(L>J++9_Je~Gzc{zeRHnI#FQzC8>R;@7nO&8;JWD?qW ziJtw?u#)0RA@-BqiLTc@J%!lO2iFL|^;_oIgLJTR2!KXMC;cA4?W&I(i*tM6qx&t$ zytlgy1{Z`jutnA~hlj);piNq(Dp40(!@fo;O3K(=7?BeXUQ?beo(0)O6(8)|Z~2#U zDR(-kMNfC?wio0#RWymT?#kx!|i_xW+cUq*YlK%9a4eq2Favp(h4lxtH& zGi7{1wQN~o5B8;_ za^SZY)t7MNHR1IuD9MV$<9sq}c)C-(K+M+k@F4v=z%)3fQLqB%U-~ksnevCwW~KO5 z95b<~?D_CVZbvwG1xpVeAV$fDwX8loIp$c0^WlSu;xd*bs2!}Y{AWdG?+Jiwh`YYL zPKg`WdKj`q3>uvf#GMM7y#qUv%CeRp98dpymzPh+h=mFYj^zMBbFRC#ii^f`KKAq= z*}Z}lu9>%;pXJ(D&oRa~zfq{@{+PLOvm8orZ+5eftm3L;n4Z>FS6N#u;$X)WPs*j$ zhOEK!;!>}ao>Tq=ekb8|q8lPWzZ$jg`GkxFmk$i=?qp7!q$dPh6s%8Rg?5HvxMXr7 z_JmRV(c`mvDfTd{5m|*%zF)I`q%H$b%GjJ~vl75X$f;l%6+GZTdQW=emJjfpj}8l&Q*THTm>`$uM1m%Fh2&a0RWSlOS?9-v6&->l2GO5Xx1*B*B`y|Ntt#)(sbWTL^aFd)DHmDu}&ijCZ@%_&W; zs`@NMtBj`~ru1XtpeKz=__R0Sb+(W6DJQfIEPj+6#sNB1SG0j|Lr#G3QAuBRAb^6u zcO+eSGfmdWgR63VNk>|^{bl}h(wF03ln-zE8IdvuM>MHveO6j2l$%czWOa};yEY|Fow#gJY^l9* zMk?z5FBf3@D0wgdL`#MJ`R@U~Xjku*`zQiXj5=<2HkTL`rOp!4A*H7VC3~z6C~K@} zbX9;C3T+|oiu1%Ir=T!}sEbf^nwOnH9ahETO|Du5S~P{Yk0|B{c}TN3k6~3EF;NIk z_KzH?6OE{a7Jgh&_Fs^#c&h?_{qaU##_RojRV_l;m!Kf`hx?N=+f(IyR=}Y=?!3vc zEfy410YtiPL!cVcjdUO?^qg@cTfc=vgh!JrUDEOMi^h>8Kg2M^^&kcm<57z31I2SK z&Frc?Bz;61GLgSg?~>Zw^VK4d>M6q68rm;Iw1dJceD1N;XUn>jdwM#&Qo8`QZ)$89 z+o?%ZG?27lJYy^lth_8x^W4!kw=YGnSWtMz&;u0elqx3qrSMb={a$j4t|LG9DFd9{$ zin;cRc}uv%6OnrptNk4s9b2G%QRcRIW*iKynbVy^j8rTwpv?~*m~?iIAA_ydIpb3M z9%I{nn+U~2h=QTHZ*1bHr-T*85xQ?|tVO_}XcJXa1uHjiJx=Q}{ob{BI-c@ZqTu7Z zd$a=&-25c(sFgWZI#JfJ;k@Ze?PSnrH<`C%s9Cp4bSApBol~vev7~9ZLdYHILy4OP zseH^mrwyOxYW|qiSdeG12wAo0yR)#YmlaQ#1{?0!-;W=BYs<-zFFQLKvt8T(O@5rQ z$}ZstE#rw4-W$`MQNzFrBnRrR2tLus?T&$X^8hgdY=*16&#tc~jq>5wC*jv!YG{2MKBAC2l5cp{nhBh~P+P_v^@qrol32;!Zx1)Se zv{D#KxUrby;E9^KRKvO{KgztVxI!8QpX?Ec_Zq^An6<~u)|JB3Q4)aSxa#=*J0R-|;HPR%V6e_qfpcLstO?`nAyTHyT#2avr&nl;K|!&e!Zo5O9B ziBxS?F{(FsuEMTI?A@0i#8slM3hHdf*~Ih%O8e1}pdW?ZdZ)y^<1kO3xj;`A>@5@6 z!1>wCUN7>&$3b185+d}qnUpPwF{Qn}+Vw*Td(Y2OQtWWx9c>+_ded;#+NWAHca=$i z@3&an_VGDlL!Jy~vw$IVrXX8?g9edxs0w@*hOq!Nq&AFX$H{24KUSdLQoT&-TSs?; zo_n5~{gyzc_bWg_l-gWWV=nGNA;?Jx+ z%PDO}IJ*B7xEwb2bpIpYXd8xK_}5ca{bPx$tEu$I@NmbgL<4#QN6TYJ9E4rE{H1bD ziR#KFEGQm5L2H*c57~n{J^g8>YOcV|$NukN9k#itCl^C=?9R-ch6gQYZ@`AuO7!l;Zu(h&^>YfqRjRW#!7 zKaxfu5Y98mly$2b)Z7xsA*7*C&QXn@J2wl}M4SXfxd=9^tCa3V`RLZ_7Nd!g23XNL zr9uLcnuRQ45+eOJA4~#2Yj01o2f`qyLRqasU{F|ogf)9UdISpV%;8NBbNn$DEd@@Qcul7{l4YHFua@F(5J6(s2Fqe;*U z?H}kWXlLxeEOQ^^^lq)AA@B41tGxb8*^$(c7h%Hjyz=(Y*F$CuuehXgOC!o^N-2+= z*gG@4J>(rxOic}sZ+EQYra9H*HD+gW1`j@~XTKX>t;MW={ShTnw)#U}+^qGp!8umd z|-TUwYK&DXzMM(64k7ICp>iaz^9TOF&G)keB@<+5at8F&cg z--q#}or2pdN39nK>s@AS!r=#{RXiMr;v-Tp0U)L3W9DKF^RZypg=|$q-PsvwK?i8r zhTy#k2Cl_SrVbx{=0o?`;U5J@8%EQ|`J{!PriqYLnV8Wu!o?@RlS0X)OO@GL>-tyG zR7N8hnJYy=9ImlF7=ihKioNl-^-}zJU{I>7@MS*f^fYgSM<-z<7gu>IlY-=zFOg~y z!K$i_#2bAiNN22QSZ{!&jPC*4KY!{5S|hE_;m>s5P40{TJ%ej(N(-mE``$QopSr6G zg}x0zROhik)2q4sIDGTR8Jmmi2U(_9lngn@M#@*FkrtvPH_eNLGo$6?fFbDxyHD@U z@s3Eb6b$3~|#$w+b|(0c+y79t1&T6pdva+nCwU6AY}KRy?NvW*Q6#Q=ZG)}L=4 z-&h+OeFQhOqlg^RyraBFizXV?X8Y)>b6>fbP}zEz*H-`TY-TeV%)DgSbl)9FJX?J7 z$|q$@#a7<_V-csiJ4J-VX?H!|hin%T5dAE`LVL59bg{9PI6L^J?^`8d0*FVQkTvva z0YwvI9>Is8(risVO1q;88Nt!Xiso>|kM))@v79ywjo8X<=jBdmADdjz!$0wVauqgS zwtFrkLpO6293GACZ!C3vY(Ys?CR51tU?M+^y5T=A(xW|y<`=O0uSiG88 zZ{PI3vpD0n#a&GzaP2GyPT7}}3dwhRN7G|dGs-jYbmRlO{QB%y0!o!Arc%*jq4!iZm31fZ1{F5h?YX(|W#?mUJ@ZHk_c*mp9E?(`SGSbOh?xOI%Gh3(POd?$xuPp&_J{7>*bD`(tBA^~sLit0p z+{ny6iF|tPpo@>khYUb}0&()q6vAKBS`D8~hdKywXo8+ge#y+nD)-L6;XQoa_G0~1 zt0g!(#bN(|8K{WX-LU)?23zZpzM2vc(hU!8XFQGMHKJpULL_cIs^tTA2`wT(hqAQk z!O8CWeF{ajA%ysFrHn9FQl6lWEj6G)TXBXLbtL;6gGH(^xd$?8+(v}O1QJaYX|}4? zdP!*`dA_EmXMqv990>TM1(_QXGC}f5G=S+K2dPL`exL|0Mu0f5w3v&E>WdNfZ;@1O z(1uwAp!Wr06{@lw&hV+7cvRo$APV?C%f#Lv8wpVmM;b)A)p-?|Zh9#vF%y+X1ma2f zqoR5<7we{9k>speg5H}j&s_I*5WjeLqvA*2{+9wXwhLh-D-SAyqg2a{XR3Ol0ycc0 zjjVik${J}oEq{Bd^fF3N*60p=!dNVhVWE7)M=ow1Np+RwmHhB?&U}6Q*S(RM2n?el z^30re4}|V5wepTBeZ3p5*jmcks(F*4H=qOf%k;G7P-<=AuRKK$Lc0ol&cte+WB(Cf zqWz)--H!jMbVNy2y5LXUBBx@2-8$*!1qK6QFO%q^pf?bQ_`z`d-MMiU^KkVW@`VP@(OE;erY0I66ja>!LZ-af zfDn0y>#nhveS!wLRD@+pXnq3GsH%sSLir%x`l|UJmhk)~^((>z=%o2y^1x*TC>vV8 ztDVrQwpjcu@b2&nXgJ~ALh?lX?wZNB+3AFwAL@Ybk)sWi=`sTH*4?h$GR6HQ+fN}j(~4x6N}vOn@jU$ zsakUN6OMYWO%?1=Q6)IT_)%~E>yO33oL8(+OL3y7<)m_z(6dAwDxSgM-NWS{9l!q8 z*48%cQF~J$Xr@LW^n%eU31@uXao#3{2dP}Q3BRI+UoId5;bP&dbEVah?3Tc!lT*!HPP|gr zHakL^4bDTl>)F|EOiUI5J#y>M{hQ7I+r@q%JrbG?EHN0V2WR!DwE&U`z?C&&dYyYmGNABV|0ROd)HP^A0*C zTDsd(8usdUm#X@HYT6nR=+R;Ys$%*p5O3t$e_?!2Q1qqQf7Sol&v>}Fxm0(hNiD>TLKl$!k8tqw&0+ut38() zo6nC~w*=hWPNHOO9wucX7DwpY*#|Z|+9R;y@oXPWzU?Jd0YCwqSz#$HIh610OrF!q z+FKZ@m~S)ayk()gZ`15bbpD+rcp-McL+Kr9yAv{W(XNlfj!z0@eX5X7rKIVcd)%td zNLL9b4ea6*D+MA1K;+`mpitET0{!tik%P*IS}iR_OwzDE8+HXZNPCM`F^+91%a!;9 zyw|PkZV$%h?T2Zg1CDm}TZw400+hSSDa8aEl<+yzS7r}oI{@0v%L2OQdnQCr&`*~Z zOqb`Z*&h}sdaXqX{_@XvkL03%JynKNd1og1IDH3z8P`;Wo`|+H{a5VN!!P7aCCF4& zlValYDdkFPZuy{Iqt>b5w7m_F&_K`D?+8iC z$AEUEJux9V&)K+h@qZAE(z?Hx9p7K_V{&$W4KJPF1!X^98DAp}*${%KAO%ALAQiK_ z1!6sK2sM7~?UCkoFlt^ac_`fminY6)ueGR8QNVj^tb+8O9+Rc=CeiCl-SsY51_rM7fTBVu?h9z?jJ&x z;qJWJaRjqDWI@Lz(=P6Kh_42RNFs% zvjeB@nd6*IQaK1AcZ%ZcAbOWxALzSZyeVD1{C<9~Y`&RUBqNZXu*h6ltqUlbiC=mAA)*vGI2rq2d-Bj~vREStM(no) z@+wH{7uD_&UF7A}JUrS>;;0oS_n8A>sCdtI54fj&iW)ywe&yGHJd-PBc`4!JA&3M8 zo!Z@ul(42IH@S~Jh@bnDs7FV8AJTB5CPmgaHv9Y)Cn2N|b`@+yeHqY+lvA;(WwJMh2G5pswXQ8`F>4E)afF@M<|K ztRs<&068P_WX+<#c%N%zo&|;B(La-Dr&9Eo)iW972IPy29j?QO+^-ANmHRvoU6*F7 zne2|2lD%<^cEQ-o`smhB{HB-a4)5iVnD_Vd2~F#9-^<#;6W-TMA!AQn!`WdN8Xhfk z23o;iwaUA}$fMGow=12)o4%-qGG}vjv8SR_&+)SWTn#CgST(!fuQCm}CheKlisDV9 z`{Dw8%ihUs!JIbkp*PEijqK@?H*sV^6SY)A7F+?mb`K_nMQ0i3ZL?GEptUp^ zJo%m+7icZ)q7wC{m*B|N1kC7;rh?fM(Db|KcVmK?A!`!$U_m=}-!YSV231=*=}8fk zN@>V%0md~Z)J9L&E)=iSM7Nn$_}JCKPa$z}7+Ea!p_HMgUHSR9(#TZb-s*}r-$D4( z;lYW?=5}WM%A5At8}l6njk%wge&{7y**B~-a<3QbaqVsA3I3G&=Nh@x3=Zi4NRsX1 zQ;b$^3ZMQYCT_0tTJK+xSHv}V?@iEtmiFAA&VrQNEQ0P*w9GpKK2q=Gh3 zIxr@ee?2u>TTlfCv;W1e(t2i2bUWV6&nGoGGlj9RAV#S=H4wTfr9`=9`d+%hpGMzJ zg5PK`x4G9-;O_mt*@-7W-rDMCVd(;sn^P%y6?>+EcraI?SYonJP<>BHEznmsR((pY ztzWh1dl_iM))|FEUc9m0d_@dM;yGBGJ$ojGaMPMan>G6mIKaT8jztsZu+q=_Qe&xa!W!R@@8$WXBCy4-%zwkp4w_PC`KwumACgq|! zF_949NAssjbG_EoX12yY8cZ~SMl~|iKZU%a?aV&RsTusH;fMFvEdleY>O7=bR^7ni z>(#!%c$S~W@TW?u2Z-U$8(^WBa=lsVCA0|7y$QQ05APrWx>i=-m$85 z0Lpy_sJ2F@R9C z`H+>lW2)BrN{OMgK@ibU0AgU>z|0&}qVl>;I96*2UwO+|oOs75UjxH4dm*Jsbrt5-VV={MB|@RIck>({(r z3R9d}738PSq#aq^6KGF^;;7Jq%@stA3FL6#6~A$>5sKT@cn(F@TOf{kICm;tx6IPO zWd&fJ5-+3Hr}wotCg(LY0-L#NThL1n-ybJRT!AFaIz%7F#XG-0LLZe05D0|0=xd) z`-q(PGc=sE-XnOH4UR>ZhD3t{9tQJgznNYuR=ayoOmNgGQjBb*E7f)mI36w3azC!& z0#w4TSU0t=#Ko(qL1M#J4f0cokn=+4dixAN_SK3M0Y1JC9!LbGr^f`jX42B8lAzSUV5~4?03SaV8Ke`^cd7iM zjgODFObE%)coKJ)EVx_alAz~`cplBPHrskJD(oOY35$%J=E(j1^`zw*!RLP#6KsG? zHn=k?K~28-te1k^%tY+JMH?l>k2T_n2%8W_R^J?p-VgZiAHn^Lh-(u_G}fv>!M;@T z1Bd_b`oJ#L3Wmx((&*)=j!5#obd+Q?aIjo)7b(1x;PvFcE9vN|Yz}g&`w*Zotj`K1 zS|BHBN*H_c7caN^3E_V#6q_wAK$-MAHw0{b@RU*UH#@_d6CNe`-E<(G;9qNLEQ@tA ziGNI6COMG7jt1uEJqsMI{9iy-|GRzAqPm6PZ1wV)ug^a{jSin*Z)j-8 z;+x=h%gxXG8g?VY-CJcJ55PeZ!mD8Yl^}1)aHc=@?H`5q6Exu3{1ri?nZwE(7oSH_~u_4M~G!L1&ib(tos*bJ=+~8z3(BJ)6mFs6KV{1 z5jgE^_iJd7!E8~d`)&d;L@+p64o^*B?KtiV@x4CT0S`R1yCq(3Kp_?c&vM_mN_WhH zEH?uKFV2;@X0mASYbp$uSC>l6f52V)*wKO!m>-#FQ255vj?ljLqvB&oNb4ibL+0?XLg-Iyd8F{AiOQUpl#k<j&TJaj)z=VSmumZwpyFWZ8%v`QoVYr}zvcjrL{Ld@0~Kf{_<)ng#^`!m%zI{4 zdU~}!P?cNRS+RD%5b3k?(TEf}@<~e*+Gzu%Q;h&70BBd7>eAEyJEef4siv7fWE~3Y zCkL1M|E(qTRkXx_w6rua$lry*`u+cZxd^A_8CuY){QE1V?3F<)D+HgTjzRfDF)!^d zoBmRe?!(fOkjbE?sj40z%GiW*!p<@&92A2G7RhxMV39&|el9O9oxqq+=(*#-2YLco zdM8LA{EW8qn8YVzKwCVSKumH$`9W4PtN|QO3Pb4WbGSK1v_JnqSfglpMoUjGgg6(wOh>+70QJYLP}ob>X@r|xUmGqW& { + return ( +
+ +
+ ) +} diff --git a/assets/src/screens/addie/ChatMain.tsx b/assets/src/screens/addie/ChatMain.tsx new file mode 100644 index 00000000..e187cd1d --- /dev/null +++ b/assets/src/screens/addie/ChatMain.tsx @@ -0,0 +1,132 @@ +import { useEffect, useRef, useState } from 'preact/hooks' + +import Input from '@/components/core/Input' +import therapist from '@/images/therapist.png' +import { Author, Message } from '@/models' +import addieScript from '@/screens/addie/addieScript' +import { addieStore } from '@/stores/addieStore' +import { assertIsDefined } from '@/utils' +import { useStore } from '@nanostores/preact' + +export default () => { + useEffect(() => { + addieStore.resetConversation() + }, []) + + return ( +
+ + + +
+ ) +} + +function Messages() { + const divRef = useRef(null) + const messages = useStore(addieStore.messages) + + useEffect(() => { + const div = divRef.current + if (!div) return + const lastMessage = div.children[div.children.length - 1] + if (lastMessage) lastMessage.scrollIntoView() + }, [messages]) + + return ( +
+ {messages.map((message, i) => { + const props = { message, prevMessage: messages[i - 1], key: i } + return message.from == Author.BOT ? : + })} +
+ ) +} + +type MessageProps = { message: Message; prevMessage: Message | undefined } + +function BotMessage({ message, prevMessage }: MessageProps) { + return ( +
+
{message.text}
+
+ ) +} + +function UserMessage({ message }: MessageProps) { + return ( +
+
{message.text}
+
+ ) +} + +function Response() { + const divRef = useRef(null) + const response = useStore(addieStore.response) + + useEffect(() => { + if (divRef.current) divRef.current.scrollIntoView() + }, [response]) + + if (!response) return null + + if (response.kind == 'buttons') { + assertIsDefined(response.buttons) + + return ( +
+ {response.buttons.map((button, i) => ( + + ))} +
+ ) + } + + if (response.kind == 'text') { + return ( +
+ +
+ ) + } + + if (response.kind == 'end') { + return
Thank you for talking to Addie.
+ } + + return null +} + +function TextResponse() { + const [textInput, setTextInput] = useState('') + + const handleSubmit = (e: Event) => { + e.preventDefault() + addieStore.addUserMessage(textInput) + addieScript.handleInput(textInput) + setTextInput('') + } + + return ( +
+ setTextInput((e.target as HTMLInputElement).value)} + className={`appearance-none block w-full px-3 py-2 border border-gray-300 + rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-blue-500 + focus:border-blue-500 text-sm`} + /> +
+ ) +} diff --git a/assets/src/screens/addie/addieScript.ts b/assets/src/screens/addie/addieScript.ts new file mode 100644 index 00000000..5ea2175c --- /dev/null +++ b/assets/src/screens/addie/addieScript.ts @@ -0,0 +1,198 @@ +import { addieStore } from '@/stores/addieStore' + +enum State { + WELCOME, + ATTEND, + BEDTIME, + HOME, + WEEKEND, + WORK, +} + +const LS_SEEN_BEFORE = 'addie-seen-before' +class AddieScript { + state: State = State.WELCOME + + // --- welcome + + welcome = async () => { + this.state = State.WELCOME + + if (!localStorage.getItem(LS_SEEN_BEFORE)) { + await addieStore.addBotMessage(`Hi! I am Addie, your personal ADHD assistant.`) + localStorage.setItem(LS_SEEN_BEFORE, 'true') + } else { + await addieStore.addBotMessage(`Hi again!`) + } + + await addieStore.addBotMessage(`Let's start with an emotional check-in. + +Take a deep breath and close your eyes. How are you feeling right now?`) + + addieStore.setResponse({ + kind: 'buttons', + buttons: ['Calm & Present', 'On Autopilot', 'Unwell'], + }) + } + + // --- attend to self + + handleEmotionalCheckin = async (index: number) => { + if (index == 0) { + this.timeOfDayCheck() + } else if (index == 1) { + await addieStore.addBotMessage(`Take a moment to be present to yourself and your needs.`) + await new Promise((resolve) => setTimeout(resolve, 4000)) + this.timeOfDayCheck() + } else if (index == 2) { + this.attendToSelf() + } + } + + attendToSelf = async () => { + this.state = State.ATTEND + + await addieStore.addBotMessage(`I'm sorry to hear that. Let's take a moment to attend to yourself. +What do you need right now?`) + + addieStore.setResponse({ + kind: 'text', + }) + } + + handleAttendToSelf = async (input: string) => { + await addieStore.addBotMessage(`Okay, let's do that. (TODO: GPT)`) + await addieStore.addBotMessage(`I'll be here when you're ready.`) + addieStore.setResponse({ + kind: 'end', + }) + } + + // --- time of day check + + timeOfDayCheck = async () => { + const date = new Date() + const dayOfWeek = date.getDay() + const hour = new Date().getHours() + const isWeekend = dayOfWeek == 0 || dayOfWeek == 6 + + if (hour > 22 || hour < 5) { + this.bedtimeRoutine() + } else if (hour > 17 || hour < 8) { + this.homeRoutine() + } else if (isWeekend) { + this.weekendRoutine() + } else { + this.workRoutine() + } + } + + // --- bedtime + + bedtimeRoutine = async () => { + this.state = State.BEDTIME + + await addieStore.addBotMessage(`It's bedtime! Let's get ready for bed. + +Are you sleepy?`) + + addieStore.setResponse({ + kind: 'buttons', + buttons: ['Yes', 'No'], + }) + } + + handleBedtime = async (index: number) => { + if (index == 0) { + await addieStore.addBotMessage(`Great! Let's get to bed.`) + + await addieStore.addBotMessage(`1. Put away your electronics (like this one). + +2. Get into bed. Turn on your white noise machine (if you have one). + +3. Close your eyes and take 3 deep breaths. + +4. I'll see you tomorrow.`) + + addieStore.setResponse({ + kind: 'end', + }) + } else if (index == 1) { + await addieStore.addBotMessage(`Okay, let's get you ready for bed. + +It's perfectly normal not to be sleepy yet. People with ADHD typically have a later circadian rhythm +and have a harder time falling asleep as well.`) + + await addieStore.addBotMessage( + `Pick an activity that's relaxing and calming and does not involve screens.` + ) + + addieStore.setResponse({ + kind: 'text', + }) + } + } + + handleBedtimeText = async (input: string) => { + await addieStore.addBotMessage(`That sounds like a great idea!`) + await addieStore.addBotMessage('Go do that. Then come back and we can get ready for bed.') + addieStore.setResponse({ + kind: 'buttons', + buttons: ["I'm ready."], + }) + } + + // --- routines + + homeRoutine = async () => { + this.state = State.HOME + await addieStore.addBotMessage(`Let's think about things to do around the home.`) + + addieStore.setResponse({ + kind: 'text', + }) + } + + workRoutine = async () => { + this.state = State.WORK + await addieStore.addBotMessage( + `You're probably at work. First things first. Check your calendar and see when your next meeting is` + ) + + addieStore.setResponse({ + kind: 'buttons', + buttons: ["It's coming up soon", "It's in a few hours", 'No meetings'], + }) + } + + weekendRoutine = async () => { + this.state = State.WEEKEND + await addieStore.addBotMessage(`It's the weekend!`) + + await addieStore.addBotMessage(`Stop talking to me and go outside.`) + + addieStore.setResponse({ + kind: 'end', + }) + } + + // --- + + handleButton = async (index: number) => { + addieStore.setResponse(null) + if (this.state == State.WELCOME) { + this.handleEmotionalCheckin(index) + } else if (this.state == State.BEDTIME) { + this.handleBedtime(index) + } + } + + handleInput = async (input: string) => { + addieStore.setResponse(null) + if (this.state == State.BEDTIME) { + this.handleBedtimeText(input) + } + } +} + +export default new AddieScript() diff --git a/assets/src/stores/addieStore.ts b/assets/src/stores/addieStore.ts new file mode 100644 index 00000000..03fc4d4b --- /dev/null +++ b/assets/src/stores/addieStore.ts @@ -0,0 +1,45 @@ +import { action, atom, map } from 'nanostores' + +import { config } from '@/config' +import { Author, Message } from '@/models' +import addieScript from '@/screens/addie/addieScript' + +type Response = { + kind: 'text' | 'buttons' | 'end' + buttons?: string[] +} + +class AddieStore { + messages = atom([]) + + response = atom(null) + + // --- actions + + resetConversation = () => { + if (config.dev) (window as any)['addieStore'] = addieStore + this.messages.set([]) + addieScript.welcome() + } + + addMessage = (message: Message) => { + const messages = this.messages.get() + this.messages.set([...messages, message]) + } + + addBotMessage = async (text: string) => { + // add a little delay for realism + await new Promise((resolve) => setTimeout(resolve, 500)) + this.addMessage(new Message(Author.BOT, text)) + } + + addUserMessage = (text: string) => { + this.addMessage(new Message(Author.YOU, text)) + } + + setResponse = (response: Response | null) => { + this.response.set(response) + } +} + +export const addieStore = new AddieStore() diff --git a/assets/vite.config.ts b/assets/vite.config.ts index 752fc33e..c00c924a 100644 --- a/assets/vite.config.ts +++ b/assets/vite.config.ts @@ -61,6 +61,7 @@ export default defineConfig({ auth: 'src/auth.tsx', app: 'src/app.tsx', insight: 'src/insight.tsx', + addie: 'src/addie.tsx', }, output: { entryFileNames: 'js/[name]-[hash].js', diff --git a/lib/sequence_web/controllers/page_controller.ex b/lib/sequence_web/controllers/page_controller.ex index 5f763dcf..47d2a78e 100644 --- a/lib/sequence_web/controllers/page_controller.ex +++ b/lib/sequence_web/controllers/page_controller.ex @@ -14,6 +14,10 @@ defmodule SequenceWeb.PageController do render conn, "app.html", pwa: "/pwa-insight.json", entry: "insight", title: "InsightLoop" end + def addie(conn, _params) do + render conn, "app.html", entry: "addie", title: "Addie ADHD Assistant" + end + def auth(conn, _params) do render conn, "app.html", entry: "auth" end diff --git a/lib/sequence_web/router.ex b/lib/sequence_web/router.ex index dbe78b94..16b7a5f0 100644 --- a/lib/sequence_web/router.ex +++ b/lib/sequence_web/router.ex @@ -206,6 +206,8 @@ defmodule SequenceWeb.Router do get "/app/*path", PageController, :app get "/insight/*path", PageController, :insight + get "/addie", PageController, :addie + get "/signup", PageController, :auth get "/signin", PageController, :auth get "/auth/*path", PageController, :auth From c11244be79921c2bc98fa0f177a9169ae2d4a8b1 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 00:21:43 -0800 Subject: [PATCH 03/28] Add gpt for chat --- assets/src/api/api.ts | 20 ++++++++- assets/src/screens/addie/ChatMain.tsx | 9 +++- assets/src/screens/addie/addieScript.ts | 44 ++++++++++++++++--- config/config.exs | 3 ++ lib/sequence/utils/openai.ex | 31 +++++++++++++ .../controllers/addie_controller.ex | 30 +++++++++++++ lib/sequence_web/router.ex | 1 + mix.exs | 1 + mix.lock | 1 + 9 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 lib/sequence_web/controllers/addie_controller.ex diff --git a/assets/src/api/api.ts b/assets/src/api/api.ts index 11731250..cf5b39df 100644 --- a/assets/src/api/api.ts +++ b/assets/src/api/api.ts @@ -3,8 +3,17 @@ import { encode } from 'base64-arraybuffer' import { config, OAuthProvider } from '@/config' import { - AuthToken, AuthTokenPair, File as LNFile, FileType, OAuthToken, Period, Project, ProjectRole, - Task, Team, User + AuthToken, + AuthTokenPair, + File as LNFile, + FileType, + OAuthToken, + Period, + Project, + ProjectRole, + Task, + Team, + User, } from '@/models' import { AsyncPromise, logger } from '@/utils' @@ -428,6 +437,13 @@ class APIService { return response.data } + async generateChat(messages: { role: string; content: string }[]): Promise { + const response = await this.axios.post(`${this.endpoint}/generate/addie`, { + messages, + }) + return response.data + } + // misc async githash(): Promise<{ hash: string }> { diff --git a/assets/src/screens/addie/ChatMain.tsx b/assets/src/screens/addie/ChatMain.tsx index e187cd1d..6279e6ee 100644 --- a/assets/src/screens/addie/ChatMain.tsx +++ b/assets/src/screens/addie/ChatMain.tsx @@ -1,11 +1,13 @@ import { useEffect, useRef, useState } from 'preact/hooks' import Input from '@/components/core/Input' +import Pressable from '@/components/core/Pressable' import therapist from '@/images/therapist.png' import { Author, Message } from '@/models' import addieScript from '@/screens/addie/addieScript' import { addieStore } from '@/stores/addieStore' import { assertIsDefined } from '@/utils' +import { RefreshIcon } from '@heroicons/react/outline' import { useStore } from '@nanostores/preact' export default () => { @@ -15,7 +17,12 @@ export default () => { return (
- +
+ + addieStore.resetConversation()} tooltip="Start Over"> + Start Over + +
diff --git a/assets/src/screens/addie/addieScript.ts b/assets/src/screens/addie/addieScript.ts index 5ea2175c..5cf2afcf 100644 --- a/assets/src/screens/addie/addieScript.ts +++ b/assets/src/screens/addie/addieScript.ts @@ -1,3 +1,4 @@ +import { API } from '@/api' import { addieStore } from '@/stores/addieStore' enum State { @@ -52,7 +53,8 @@ Take a deep breath and close your eyes. How are you feeling right now?`) attendToSelf = async () => { this.state = State.ATTEND - await addieStore.addBotMessage(`I'm sorry to hear that. Let's take a moment to attend to yourself. + await addieStore.addBotMessage(`I'm sorry to hear that. Take a moment to attend to yourself. + What do you need right now?`) addieStore.setResponse({ @@ -61,10 +63,20 @@ What do you need right now?`) } handleAttendToSelf = async (input: string) => { - await addieStore.addBotMessage(`Okay, let's do that. (TODO: GPT)`) - await addieStore.addBotMessage(`I'll be here when you're ready.`) + const messages = [ + { + role: 'assistant', + content: 'Take a moment to attend to yourself. What do you need right now?', + }, + { role: 'user', content: input }, + ] + + const response = await API.generateChat(messages) + await addieStore.addBotMessage(response) + await addieStore.addBotMessage(`Ready to continue?`) addieStore.setResponse({ - kind: 'end', + kind: 'buttons', + buttons: ['Ready.'], }) } @@ -153,6 +165,11 @@ and have a harder time falling asleep as well.`) }) } + handleHomeRoutine = async (input: string) => { + await addieStore.addBotMessage(`That sounds like a great idea!`) + await addieStore.addBotMessage('Go do that.') + } + workRoutine = async () => { this.state = State.WORK await addieStore.addBotMessage( @@ -165,6 +182,15 @@ and have a harder time falling asleep as well.`) }) } + handleWorkRoutine = async (index: number) => { + if (index == 0) { + await addieStore.addBotMessage(`Get prepared for it and don't be late.`) + addieStore.setResponse({ + kind: 'end', + }) + } + } + weekendRoutine = async () => { this.state = State.WEEKEND await addieStore.addBotMessage(`It's the weekend!`) @@ -182,14 +208,22 @@ and have a harder time falling asleep as well.`) addieStore.setResponse(null) if (this.state == State.WELCOME) { this.handleEmotionalCheckin(index) + } else if (this.state == State.ATTEND) { + this.handleEmotionalCheckin(index) } else if (this.state == State.BEDTIME) { this.handleBedtime(index) + } else if (this.state == State.WORK) { + this.handleWorkRoutine(index) } } handleInput = async (input: string) => { addieStore.setResponse(null) - if (this.state == State.BEDTIME) { + if (this.state == State.ATTEND) { + this.handleAttendToSelf(input) + } else if (this.state == State.HOME) { + this.handleHomeRoutine(input) + } else if (this.state == State.BEDTIME) { this.handleBedtimeText(input) } } diff --git a/config/config.exs b/config/config.exs index f203f8e6..192e38ce 100644 --- a/config/config.exs +++ b/config/config.exs @@ -109,6 +109,9 @@ config :mojito, timeout: 10_000, pool_opts: [size: 100, max_overflow: 500] +config :hammer, + backend: {Hammer.Backend.ETS, [expiry_ms: 60_000 * 60 * 4, + cleanup_interval_ms: 60_000 * 10]} # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/lib/sequence/utils/openai.ex b/lib/sequence/utils/openai.ex index 871071bf..0266f9f6 100644 --- a/lib/sequence/utils/openai.ex +++ b/lib/sequence/utils/openai.ex @@ -40,6 +40,37 @@ defmodule Sequence.OpenAI do post("/completions", authenticated_headers(), request) end + # see https://platform.openai.com/docs/api-reference/chat + # {:ok, + # %{ + # "choices" => [ + # %{ + # "role" => "assistant", + # "content" => "\n\nThis is a test." + # } + # ], + # "created" => 1673048972, + # "id" => "cmpl-6VqkmcsLfr40Y2qodNNM56eleGnsj", + # "model" => "gpt-3.5-turbo", + # "object" => "chat.completion", + # "usage" => %{ + # "completion_tokens" => 7, + # "prompt_tokens" => 5, + # "total_tokens" => 12 + # } + # }} + def chat(user_id, messages, model \\ "gpt-3.5-turbo", max_tokens \\ 128, temperature \\ 0.5) do + request = %{ + model: model, + messages: messages, + max_tokens: max_tokens, + temperature: temperature, + user: user_id, + } + + post("/completions", authenticated_headers(), request) + end + def api_key, do: Application.get_env(:sequence, :openai_api_key) def std_headers(content_type \\ "application/json") do diff --git a/lib/sequence_web/controllers/addie_controller.ex b/lib/sequence_web/controllers/addie_controller.ex new file mode 100644 index 00000000..c38c836c --- /dev/null +++ b/lib/sequence_web/controllers/addie_controller.ex @@ -0,0 +1,30 @@ +defmodule SequenceWeb.AddieController do + use SequenceWeb, :controller + + require Logger + + action_fallback SequenceWeb.FallbackController + + # POST /generate/addie + def generate_chat(conn, %{ "messages" => messages }) do + ip_addr = conn.remote_ip |> :inet.ntoa() |> to_string() + + messages = [%{ role: "system", content: "You are an ADHD coach helping a client with ADHD." } | messages] + + case Hammer.check_rate("addie:#{ip_addr}", 60_000, 5) do + {:allow, _count} -> + with {:ok, response} <- Sequence.OpenAI.chat(ip_addr, messages) do + IO.inspect(response) + result = hd(response["choices"])["content"] |> String.trim + text conn, result + else + {:error, :openai, _status, body} -> + IO.inspect(body) + {:error, :bad_request, "Unable to chat"} + end + {:deny, _limit} -> + {:error, :too_many_requests, "Too many requests"} + end + end + +end diff --git a/lib/sequence_web/router.ex b/lib/sequence_web/router.ex index 16b7a5f0..62cd84ff 100644 --- a/lib/sequence_web/router.ex +++ b/lib/sequence_web/router.ex @@ -109,6 +109,7 @@ defmodule SequenceWeb.Router do get "/daily_notes", JournalController, :list_notes post "/daily_notes/:date", JournalController, :save_note post "/generate/summary", JournalController, :generate_summary + post "/generate/addie", AddieController, :generate_chat resources "/teams", TeamsController diff --git a/mix.exs b/mix.exs index 2efcbb85..d1e0e08f 100644 --- a/mix.exs +++ b/mix.exs @@ -83,6 +83,7 @@ defmodule Sequence.MixProject do {:kadabra, ">= 0.0.0"}, {:uuid, "~> 1.1"}, {:sweet_xml, "~> 0.0"}, + {:hammer, "~> 6.1"}, # dev dependencies {:mix_test_watch, "~> 0.6", only: [:dev, :docker], runtime: false}, diff --git a/mix.lock b/mix.lock index 2d6c20a6..f7125ba6 100644 --- a/mix.lock +++ b/mix.lock @@ -35,6 +35,7 @@ "goth": {:hex, :goth, "1.3.0", "db893be00006e4c85e6c92255a078b9eb249e1bc88349fd447f12e93d2f1253e", [:mix], [{:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "3c2c4e085bae945305132bc9bcb4d4d84d5e34e233a900164eb2529ab8bab85d"}, "guardian": {:hex, :guardian, "2.2.4", "3dafdc19665411c96b2796d184064d691bc08813a132da5119e39302a252b755", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "6f83d4309c16ec2469da8606bb2a9815512cc2fac1595ad34b79940a224eb110"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"}, "hpack": {:hex, :hpack_erl, "0.2.3", "17670f83ff984ae6cd74b1c456edde906d27ff013740ee4d9efaa4f1bf999633", [:rebar3], [], "hexpm", "06f580167c4b8b8a6429040df36cc93bba6d571faeaec1b28816523379cbb23a"}, "hpax": {:hex, :hpax, "0.1.1", "2396c313683ada39e98c20a75a82911592b47e5c24391363343bde74f82396ca", [:mix], [], "hexpm", "0ae7d5a0b04a8a60caf7a39fcf3ec476f35cc2cc16c05abea730d3ce6ac6c826"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, From c30ded4940f56a8156f4c1f24ebd4b25547dce00 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 00:22:54 -0800 Subject: [PATCH 04/28] Also rate limit journal summary --- .../controllers/journal_controller.ex | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/sequence_web/controllers/journal_controller.ex b/lib/sequence_web/controllers/journal_controller.ex index a5792abb..fbfd7417 100644 --- a/lib/sequence_web/controllers/journal_controller.ex +++ b/lib/sequence_web/controllers/journal_controller.ex @@ -48,15 +48,20 @@ defmodule SequenceWeb.JournalController do prompt_hash = :crypto.hash(:md5 , prompt) |> Base.encode16() case Redix.command(:redix, ["GET", "summary:" <> prompt_hash]) do {:ok, nil} -> - with {:ok, response} <- Sequence.OpenAI.completions(prompt, "text-curie-001", 150, 0.3) do - IO.inspect(response) - result = hd(response["choices"])["text"] |> String.trim - Redix.command(:redix, ["SET", "summary:" <> prompt_hash, result, "EX", "86400"]) - text conn, result - else - {:error, :openai, _status, body} -> - IO.inspect(body) - {:error, :bad_request, "Unable to generate summary"} + case Hammer.check_rate("journal:#{user.id}", 60_000, 5) do + {:allow, _count} -> + with {:ok, response} <- Sequence.OpenAI.completions(prompt, "text-curie-001", 150, 0.3) do + IO.inspect(response) + result = hd(response["choices"])["text"] |> String.trim + Redix.command(:redix, ["SET", "summary:" <> prompt_hash, result, "EX", "86400"]) + text conn, result + else + {:error, :openai, _status, body} -> + IO.inspect(body) + {:error, :bad_request, "Unable to generate summary"} + end + {:deny, _limit} -> + {:error, :too_many_requests, "Too many requests"} end {:ok, data} -> IO.puts("hit cache") From fb7c6bc7d56a8d141f4a99d0a2bab5192abb3c6e Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 00:31:00 -0800 Subject: [PATCH 05/28] Addie can chat for reals. --- assets/src/screens/addie/ChatMain.tsx | 15 +++++++++++ assets/src/screens/addie/addieScript.ts | 25 ++++++++++++------- assets/src/stores/addieStore.ts | 6 +++++ lib/sequence/utils/openai.ex | 2 +- .../controllers/addie_controller.ex | 5 ++-- lib/sequence_web/router.ex | 3 ++- 6 files changed, 43 insertions(+), 13 deletions(-) diff --git a/assets/src/screens/addie/ChatMain.tsx b/assets/src/screens/addie/ChatMain.tsx index 6279e6ee..abd2ad78 100644 --- a/assets/src/screens/addie/ChatMain.tsx +++ b/assets/src/screens/addie/ChatMain.tsx @@ -25,6 +25,7 @@ export default () => { + ) } @@ -137,3 +138,17 @@ function TextResponse() { ) } + +function ErrorMessage() { + const error = useStore(addieStore.error) + if (!error) return null + + return ( + + ) +} diff --git a/assets/src/screens/addie/addieScript.ts b/assets/src/screens/addie/addieScript.ts index 5cf2afcf..a9be100c 100644 --- a/assets/src/screens/addie/addieScript.ts +++ b/assets/src/screens/addie/addieScript.ts @@ -1,5 +1,6 @@ import { API } from '@/api' import { addieStore } from '@/stores/addieStore' +import { unwrapError } from '@/utils' enum State { WELCOME, @@ -71,13 +72,20 @@ What do you need right now?`) { role: 'user', content: input }, ] - const response = await API.generateChat(messages) - await addieStore.addBotMessage(response) - await addieStore.addBotMessage(`Ready to continue?`) - addieStore.setResponse({ - kind: 'buttons', - buttons: ['Ready.'], - }) + try { + const response = await API.generateChat(messages) + await addieStore.addBotMessage(response) + await addieStore.addBotMessage(`Ready to continue?`) + addieStore.setResponse({ + kind: 'buttons', + buttons: ['Ready.'], + }) + } catch (error) { + addieStore.setError(unwrapError(error)) + addieStore.setResponse({ + kind: 'text', + }) + } } // --- time of day check @@ -132,8 +140,7 @@ Are you sleepy?`) } else if (index == 1) { await addieStore.addBotMessage(`Okay, let's get you ready for bed. -It's perfectly normal not to be sleepy yet. People with ADHD typically have a later circadian rhythm -and have a harder time falling asleep as well.`) +It's perfectly normal not to be sleepy yet. People with ADHD typically have a later circadian rhythm and have a harder time falling asleep as well.`) await addieStore.addBotMessage( `Pick an activity that's relaxing and calming and does not involve screens.` diff --git a/assets/src/stores/addieStore.ts b/assets/src/stores/addieStore.ts index 03fc4d4b..053e9fb0 100644 --- a/assets/src/stores/addieStore.ts +++ b/assets/src/stores/addieStore.ts @@ -14,6 +14,8 @@ class AddieStore { response = atom(null) + error = atom(null) + // --- actions resetConversation = () => { @@ -40,6 +42,10 @@ class AddieStore { setResponse = (response: Response | null) => { this.response.set(response) } + + setError = (error: string | null) => { + this.error.set(error) + } } export const addieStore = new AddieStore() diff --git a/lib/sequence/utils/openai.ex b/lib/sequence/utils/openai.ex index 0266f9f6..2150ea7c 100644 --- a/lib/sequence/utils/openai.ex +++ b/lib/sequence/utils/openai.ex @@ -68,7 +68,7 @@ defmodule Sequence.OpenAI do user: user_id, } - post("/completions", authenticated_headers(), request) + post("/chat/completions", authenticated_headers(), request) end def api_key, do: Application.get_env(:sequence, :openai_api_key) diff --git a/lib/sequence_web/controllers/addie_controller.ex b/lib/sequence_web/controllers/addie_controller.ex index c38c836c..37d432dd 100644 --- a/lib/sequence_web/controllers/addie_controller.ex +++ b/lib/sequence_web/controllers/addie_controller.ex @@ -9,13 +9,14 @@ defmodule SequenceWeb.AddieController do def generate_chat(conn, %{ "messages" => messages }) do ip_addr = conn.remote_ip |> :inet.ntoa() |> to_string() - messages = [%{ role: "system", content: "You are an ADHD coach helping a client with ADHD." } | messages] + messages = [%{ role: "system", content: "You are a concise ADHD coach helping the user be their best." } | messages] case Hammer.check_rate("addie:#{ip_addr}", 60_000, 5) do {:allow, _count} -> + IO.inspect(messages) with {:ok, response} <- Sequence.OpenAI.chat(ip_addr, messages) do IO.inspect(response) - result = hd(response["choices"])["content"] |> String.trim + result = hd(response["choices"])["message"]["content"] |> String.trim text conn, result else {:error, :openai, _status, body} -> diff --git a/lib/sequence_web/router.ex b/lib/sequence_web/router.ex index 62cd84ff..188f231c 100644 --- a/lib/sequence_web/router.ex +++ b/lib/sequence_web/router.ex @@ -78,6 +78,8 @@ defmodule SequenceWeb.Router do post "/attachments", StorageController, :upload_attachment get "/attachments/:user_id/:timestamp", StorageController, :get_attachment + post "/generate/addie", AddieController, :generate_chat + pipe_through :authenticated get "/user", AuthController, :fetch_user @@ -109,7 +111,6 @@ defmodule SequenceWeb.Router do get "/daily_notes", JournalController, :list_notes post "/daily_notes/:date", JournalController, :save_note post "/generate/summary", JournalController, :generate_summary - post "/generate/addie", AddieController, :generate_chat resources "/teams", TeamsController From de34e0f938016cb30c5965b603615cada4ecdb9e Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 00:32:27 -0800 Subject: [PATCH 06/28] pwa-addie --- assets/static/images/therapist.png | Bin 0 -> 33186 bytes assets/static/pwa-addie.json | 31 ++++++++++++++++++ .../controllers/page_controller.ex | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 assets/static/images/therapist.png create mode 100644 assets/static/pwa-addie.json diff --git a/assets/static/images/therapist.png b/assets/static/images/therapist.png new file mode 100644 index 0000000000000000000000000000000000000000..4a1607f93321bb918f2468f726f50dcd8045dabf GIT binary patch literal 33186 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 Date: Sun, 12 Mar 2023 00:34:22 -0800 Subject: [PATCH 07/28] Add pwa-addie to router --- lib/sequence_web/endpoint.ex | 2 +- lib/sequence_web/router.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sequence_web/endpoint.ex b/lib/sequence_web/endpoint.ex index eee571f2..255ca754 100644 --- a/lib/sequence_web/endpoint.ex +++ b/lib/sequence_web/endpoint.ex @@ -26,7 +26,7 @@ defmodule SequenceWeb.Endpoint do from: :sequence, gzip: true, only: ~w(assets js css images sounds favicon.ico robots.txt sitemap.xml pwa.json - pwa-local.json pwa-insight.json serviceworker.js) + pwa-local.json pwa-insight.json pwa-addie.json serviceworker.js) plug Plug.Static, at: "/", from: :sequence, diff --git a/lib/sequence_web/router.ex b/lib/sequence_web/router.ex index 188f231c..bfc33e2a 100644 --- a/lib/sequence_web/router.ex +++ b/lib/sequence_web/router.ex @@ -19,7 +19,7 @@ defmodule SequenceWeb.Router do at: "/", from: :sequence, gzip: true, only: ~w(assets js css sounds favicon.ico robots.txt version.json pwa.json - pwa-local.json pwa-insight.json serviceworker.js) + pwa-local.json pwa-insight.json pwa-addie.json serviceworker.js) ) end From ab095672bf0695b029d133f08058402799306654 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 10:33:58 -0700 Subject: [PATCH 08/28] Fix apple icon --- lib/sequence_web/controllers/page_controller.ex | 3 ++- lib/sequence_web/templates/layout/app.html.heex | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/sequence_web/controllers/page_controller.ex b/lib/sequence_web/controllers/page_controller.ex index 417e7f41..7d796028 100644 --- a/lib/sequence_web/controllers/page_controller.ex +++ b/lib/sequence_web/controllers/page_controller.ex @@ -15,7 +15,8 @@ defmodule SequenceWeb.PageController do end def addie(conn, _params) do - render conn, "app.html", pwa: "/pwa-addie.json", entry: "addie", title: "Addie ADHD Assistant" + render conn, "app.html", pwa: "/pwa-addie.json", entry: "addie", title: "Addie ADHD Assistant", + apple_icon: "/images/therapist.png" end def auth(conn, _params) do diff --git a/lib/sequence_web/templates/layout/app.html.heex b/lib/sequence_web/templates/layout/app.html.heex index f27bc9d4..b6bec6a4 100644 --- a/lib/sequence_web/templates/layout/app.html.heex +++ b/lib/sequence_web/templates/layout/app.html.heex @@ -15,7 +15,7 @@ title = if assigns[:title], do: "Daybird | #{assigns[:title]}", else: "Daybird" %> <%= title %> - + From 19c3e9149bc047c58fed189e0ff5e4df0b40943f Mon Sep 17 00:00:00 2001 From: Tim Su Date: Sun, 12 Mar 2023 16:51:45 -0700 Subject: [PATCH 09/28] Add get help method, a bit of refactor, make things work. --- assets/src/config/paths.ts | 4 + assets/src/models/message.ts | 5 + assets/src/screens/addie/Addie.tsx | 30 ++ assets/src/screens/addie/ChatMain.tsx | 83 +++-- assets/src/screens/addie/addieScript.ts | 299 ++++++++++++++---- assets/src/stores/addieStore.ts | 11 +- assets/src/stores/tracker.ts | 4 + assets/src/stores/uiStore.ts | 2 + assets/src/styles/index.css | 46 +++ lib/sequence/utils/openai.ex | 2 +- .../controllers/addie_controller.ex | 33 +- lib/sequence_web/router.ex | 3 +- 12 files changed, 394 insertions(+), 128 deletions(-) diff --git a/assets/src/config/paths.ts b/assets/src/config/paths.ts index d423d8c5..776b1ecc 100644 --- a/assets/src/config/paths.ts +++ b/assets/src/config/paths.ts @@ -40,4 +40,8 @@ export const paths = { INSIGHT_DOC: '/insight/docs', INSIGHT_SETTINGS: '/insight/settings', + + // --- addie + + ADDIE: '/addie', } diff --git a/assets/src/models/message.ts b/assets/src/models/message.ts index 7741789c..df416690 100644 --- a/assets/src/models/message.ts +++ b/assets/src/models/message.ts @@ -6,3 +6,8 @@ export enum Author { export class Message { constructor(public from: Author, public text: string) {} } + +export type GPTMessage = { + role: 'assistant' | 'user' | 'system' + content: string +} diff --git a/assets/src/screens/addie/Addie.tsx b/assets/src/screens/addie/Addie.tsx index d118a4c5..22b95df5 100644 --- a/assets/src/screens/addie/Addie.tsx +++ b/assets/src/screens/addie/Addie.tsx @@ -1,6 +1,36 @@ +import { useEffect, useState } from 'preact/hooks' + +import Button from '@/components/core/Button' +import Loader from '@/components/core/Loader' +import { paths } from '@/config' import ChatMain from '@/screens/addie/ChatMain' +import { authStore } from '@/stores/authStore' +import tracker from '@/stores/tracker' +import { uiStore } from '@/stores/uiStore' +import { useStore } from '@nanostores/preact' export default () => { + const user = useStore(authStore.loggedInUser) + + useEffect(() => { + uiStore.insightLoop = true + if (user === undefined) authStore.init() + else if (user === null) + location.href = paths.SIGNUP + '?path=' + location.pathname + location.search + else { + uiStore.initLoggedInUser(user) + tracker.openAddie() + } + }, [user]) + + if (!user) + return ( +
+ + +
+ ) + return (
diff --git a/assets/src/screens/addie/ChatMain.tsx b/assets/src/screens/addie/ChatMain.tsx index abd2ad78..a7a42c11 100644 --- a/assets/src/screens/addie/ChatMain.tsx +++ b/assets/src/screens/addie/ChatMain.tsx @@ -6,8 +6,6 @@ import therapist from '@/images/therapist.png' import { Author, Message } from '@/models' import addieScript from '@/screens/addie/addieScript' import { addieStore } from '@/stores/addieStore' -import { assertIsDefined } from '@/utils' -import { RefreshIcon } from '@heroicons/react/outline' import { useStore } from '@nanostores/preact' export default () => { @@ -16,7 +14,7 @@ export default () => { }, []) return ( -
+
addieStore.resetConversation()} tooltip="Start Over"> @@ -24,6 +22,7 @@ export default () => {
+
@@ -51,6 +50,20 @@ function Messages() { ) } +function AwaitingResponse() { + const awaitingResponse = useStore(addieStore.awaitingResponse) + + if (!awaitingResponse) return null + + return ( +
+
+
+
+
+ ) +} + type MessageProps = { message: Message; prevMessage: Message | undefined } function BotMessage({ message, prevMessage }: MessageProps) { @@ -79,39 +92,39 @@ function Response() { if (!response) return null - if (response.kind == 'buttons') { - assertIsDefined(response.buttons) - - return ( -
- {response.buttons.map((button, i) => ( - - ))} -
- ) - } - - if (response.kind == 'text') { - return ( -
- -
- ) - } - if (response.kind == 'end') { return
Thank you for talking to Addie.
} - return null + return ( + <> + {(response.kind == 'buttons' || response.kind == 'buttons_text') && ( + <> +
+ {response.buttons?.map((button, i) => ( + + ))} +
+ + )} + + {response.kind == 'buttons_text' &&
} + + {(response.kind == 'text' || response.kind == 'buttons_text') && ( +
+ +
+ )} + + ) } function TextResponse() { @@ -119,6 +132,8 @@ function TextResponse() { const handleSubmit = (e: Event) => { e.preventDefault() + if (textInput.trim().length == 0) return + addieStore.addUserMessage(textInput) addieScript.handleInput(textInput) setTextInput('') @@ -127,7 +142,7 @@ function TextResponse() { return (
ref && ref.focus()} value={textInput} placeholder="Type your response here" onChange={(e) => setTextInput((e.target as HTMLInputElement).value)} @@ -145,7 +160,7 @@ function ErrorMessage() { return (