From b0eea0ef1605c1f80ab936cd9ff4a30e5c51b732 Mon Sep 17 00:00:00 2001 From: Ronald Loyko <108372764+ronaldloyko@users.noreply.github.com> Date: Mon, 10 Oct 2022 07:57:00 +0300 Subject: [PATCH] feat: add novu (#757) --- public/v4/apps/novu.yml | 227 +++++++++++++++++++++++++++++++++++++++ public/v4/logos/novu.png | Bin 0 -> 18671 bytes 2 files changed, 227 insertions(+) create mode 100644 public/v4/apps/novu.yml create mode 100644 public/v4/logos/novu.png diff --git a/public/v4/apps/novu.yml b/public/v4/apps/novu.yml new file mode 100644 index 0000000..7416f9a --- /dev/null +++ b/public/v4/apps/novu.yml @@ -0,0 +1,227 @@ +captainVersion: 4 +services: + $$cap_appname-cache: + caproverExtra: + notExposeAsWebApp: 'true' + image: redis:$$cap_REDIS_VERSION + + $$cap_appname-db: + caproverExtra: + notExposeAsWebApp: 'true' + image: mongo:$$cap_MONGO_VERSION + environment: + PUID: $$cap_PUID + PGID: $$cap_PGID + volumes: + - $$cap_appname-db:/data/db + + $$cap_appname-api: + caproverExtra: + containerHttpPort: $$cap_NOVU_API_PORT + image: $$cap_NOVU_IMAGE_URL/api:$$cap_NOVU_IMAGE_VERSION + environment: + NODE_ENV: $$cap_ENVIRONMENT + API_ROOT_URL: http://$$cap_appname-api.$$cap_root_domain + DISABLE_USER_REGISTRATION: $$cap_NOVU_DISABLE_USER_REGISTRATION + PORT: $$cap_NOVU_API_PORT + FRONT_BASE_URL: http://$$cap_appname.$$cap_root_domain + MONGO_URL: mongodb://srv-captain--$$cap_appname-db/$$cap_MONGO_DB + REDIS_HOST: srv-captain--$$cap_appname-cache + REDIS_PORT: $$cap_REDIS_PORT + REDIS_DB_INDEX: $$cap_REDIS_DB_INDEX + S3_LOCAL_STACK: $$cap_NOVU_S3_LOCAL_STACK + S3_BUCKET_NAME: $$cap_NOVU_S3_BUCKET_NAME + S3_REGION: $$cap_NOVU_S3_REGION + AWS_ACCESS_KEY_ID: $$cap_NOVU_AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: $$cap_NOVU_AWS_SECRET_ACCESS_KEY + JWT_SECRET: $$cap_NOVU_JWT_SECRET + STORE_ENCRYPTION_KEY: $$cap_NOVU_STORE_ENCRYPTION_KEY + SENTRY_DSN: $$cap_NOVU_API_SENTRY_DSN + depends_on: + - $$cap_appname-db + - $$cap_appname-cache + + $$cap_appname-ws: + caproverExtra: + containerHttpPort: $$cap_NOVU_PORT_WEBSOCKET + image: $$cap_NOVU_IMAGE_URL/ws:$$cap_NOVU_IMAGE_VERSION + environment: + PORT: $$cap_NOVU_PORT_WEBSOCKET + NODE_ENV: $$cap_ENVIRONMENT + MONGO_URL: mongodb://srv-captain--$$cap_appname-db/$$cap_MONGO_DB + REDIS_HOST: srv-captain--$$cap_appname-cache + REDIS_PORT: $$cap_REDIS_PORT + JWT_SECRET: $$cap_NOVU_JWT_SECRET + depends_on: + - $$cap_appname-db + - $$cap_appname-cache + + $$cap_appname: + caproverExtra: + containerHttpPort: $$cap_NOVU_PORT_APPLICATION + image: $$cap_NOVU_IMAGE_URL/web:$$cap_NOVU_IMAGE_VERSION + environment: + REACT_APP_API_URL: http://$$cap_appname-api.$$cap_root_domain + REACT_APP_ENVIRONMENT: $$cap_ENVIRONMENT + REACT_APP_WIDGET_EMBED_PATH: http://$$cap_appname-embed.$$cap_root_domain/embed.umd.min.js + REACT_APP_DOCKER_HOSTED_ENV: $$cap_NOVU_DOCKER_HOSTED_ENVIRONMENT + depends_on: + - $$cap_appname-api + + $$cap_appname-widget: + caproverExtra: + containerHttpPort: $$cap_NOVU_PORT_WIDGET + image: $$cap_NOVU_IMAGE_URL/widget:$$cap_NOVU_IMAGE_VERSION + environment: + REACT_APP_API_URL: http://$$cap_appname-api.$$cap_root_domain + REACT_APP_WS_URL: http://$$cap_appname-ws.$$cap_root_domain + REACT_APP_ENVIRONMENT: $$cap_ENVIRONMENT + depends_on: + - $$cap_appname-api + - $$cap_appname + + $$cap_appname-embed: + caproverExtra: + containerHttpPort: $$cap_NOVU_PORT_EMBED + image: $$cap_NOVU_IMAGE_URL/embed:$$cap_NOVU_IMAGE_VERSION + environment: + WIDGET_URL: http://$$cap_appname-widget.$$cap_root_domain + depends_on: + - $$cap_appname-widget + +caproverOneClickApp: + displayName: Novu + isOfficial: true + description: Open Source Notification Infrastructure For Developers + documentation: https://docs.novu.co + instructions: + start: |- + Novu is a fully functional real-time notification center for your web and react apps. + The only open-source notifications infrastructure that manages multi-channel content, scheduled notifications, digest engine, user preferences, and delivers Email, SMS, Push and Chat notifications using a single API. + end: |- + Novu has been successfully deployed! It might take few moments before it's fully started. + You can access it at `http://$$cap_appname.$$cap_root_domain`. + variables: + - id: $$cap_NOVU_IMAGE_VERSION + label: Application | Version + description: Version tag of Novu's Docker images. Check out their valid tags at https://github.com/novuhq/novu/pkgs/container/novu%2Fapi + defaultValue: '0.8.0' + validRegex: /.{1,}/ + - id: $$cap_NOVU_IMAGE_URL + label: Application | Image URL + description: URL to Novu's Docker images. + defaultValue: ghcr.io/novuhq/novu + validRegex: /.{1,}/ + - id: $$cap_REDIS_VERSION + label: Redis | Version + description: Version tag of Redis' image. Check out their valid tags at https://hub.docker.com/_/redis/tags + defaultValue: '7.0.5' + validRegex: /.{1,}/ + - id: $$cap_MONGO_VERSION + label: MongoDB | Version + description: Version tag of MongoDB's image. Check out their valid tags at https://hub.docker.com/_/mongo/tags + defaultValue: '6.0.2' + validRegex: /.{1,}/ + - id: $$cap_ENVIRONMENT + label: General | Environment + description: Application environment (e.g `dev`, `test`, `prod`, `ci`, `local`). + defaultValue: prod + validRegex: /^(dev|test|prod|ci|local)$/ + - id: $$cap_NOVU_DOCKER_HOSTED_ENVIRONMENT + label: General | Docker-Hosted Environment + description: Whether to the application is hosted in Docker. + defaultValue: 'true' + validRegex: /^(true|false)$/ + - id: $$cap_PUID + label: General | User ID + description: User ID that the process uses, run `id $user` on your instance to see the ID. + defaultValue: 1000 + validRegex: /.{1,}/ + - id: $$cap_PGID + label: General | Group ID + description: Group ID that the process uses, run `id $user` on your instance to see the ID. + defaultValue: 1000 + validRegex: /.{1,}/ + - id: $$cap_NOVU_JWT_SECRET + label: Security | JWT Secret + description: Secret for JWT. + defaultValue: $$cap_gen_random_hex(32) + validRegex: /.{1,}/ + - id: $$cap_NOVU_STORE_ENCRYPTION_KEY + label: Security | Store Encryption Key + description: Key for store encryption. + defaultValue: $$cap_gen_random_hex(32) + validRegex: /.{1,}/ + - id: $$cap_NOVU_DISABLE_USER_REGISTRATION + label: Privacy | Disable User Registration + description: Whether to disable user registration. + defaultValue: 'false' + validRegex: /^(true|false)$/ + - id: $$cap_NOVU_API_PORT + label: API | Port + description: Port of Novu's API. + defaultValue: 3000 + validRegex: /.{1,}/ + - id: $$cap_NOVU_API_SENTRY_DSN + label: API | Sentry DSN + description: Sentry's DSN for error tracking. Leave empty to disable. + - id: $$cap_REDIS_PORT + label: Redis | Port + description: Port of Redis' host. + defaultValue: 6379 + validRegex: /.{1,}/ + - id: $$cap_REDIS_DB_INDEX + label: Redis | Database Index + description: Index of the database in Redis. + defaultValue: 2 + validRegex: /.{1,}/ + - id: $$cap_MONGO_DB + label: MongoDB | Database Name + description: Name of the database in MongoDB. + defaultValue: novu + validRegex: /.{1,}/ + - id: $$cap_NOVU_PORT_EMBED + label: Networking | Embed Port + description: Port of Novu's embed host. + defaultValue: 4701 + validRegex: /.{1,}/ + - id: $$cap_NOVU_PORT_WIDGET + label: Networking | Widget Port + description: Port of Novu's widget host. + defaultValue: 4500 + validRegex: /.{1,}/ + - id: $$cap_NOVU_PORT_APPLICATION + label: Networking | Web Port + description: Port of Novu's web host. + defaultValue: 4200 + validRegex: /.{1,}/ + - id: $$cap_NOVU_PORT_WEBSOCKET + label: Networking | WebSocket Port + description: Port of Novu's WebSocket host. + defaultValue: 3002 + validRegex: /.{1,}/ + - id: $$cap_NOVU_S3_LOCAL_STACK + label: S3 | Local Stack URL + description: URL to Localstack instance. Leave to `http://localhost:4566` to use local file storage. + defaultValue: http://localhost:4566 + validRegex: /.{1,}/ + - id: $$cap_NOVU_S3_BUCKET_NAME + label: S3 | Bucket Name + description: Name of the bucket. Leave to `novu-local` to use local file storage. + defaultValue: novu-local + validRegex: /.{1,}/ + - id: $$cap_NOVU_S3_REGION + label: S3 | Region + description: Region of the storage. Leave to `us-east-1` if using local file storage. + defaultValue: us-east-1 + validRegex: /.{1,}/ + - id: $$cap_NOVU_AWS_ACCESS_KEY_ID + label: S3 | AWS Access Key ID + description: Access key ID for AWS. Leave to `test` to use local file storage. + defaultValue: test + validRegex: /.{1,}/ + - id: $$cap_NOVU_AWS_SECRET_ACCESS_KEY + label: S3 | AWS Secret Access Key + description: Secret access key for AWS. Leave to `test` to use local file storage. + defaultValue: test + validRegex: /.{1,}/ diff --git a/public/v4/logos/novu.png b/public/v4/logos/novu.png new file mode 100644 index 0000000000000000000000000000000000000000..f191645a74c9e77c743b26290bf18dc9aa8d8830 GIT binary patch literal 18671 zcmV*GKxw~;P)`9wDQd^%|7ls28%ZS3}5vlx= zi0e+=yT_kIPfvgf6)IF1B^VI|BCp@L8 zJ3a6SDpaUY;WdsCqk+gB&oBvam9c#h0l-@^oXuGsFOr%|Cog$l1B zj5sH{yzV`_O8QHy6T=-Lc^D$Fh{Prg+Aku4NxT-VCx}O=m(+d%hp_TOh(+}G`xras z9I^d9PoP4D3Kd=h7?Dv}^7}J)ml8MA+54$lMj9!g4bfO6!%NXllW8HI#PNXs?oPd((2?$*oR2dF5-33C&8c%ak%Tke$62+ zv?m+hZ_x%VC?8F*Uu8YFKH@k(R^SN%UrR?eLJ8+g$fl$7)CsSFjk(s^DJL_KOzC` zwT|+&>56xyX(m9z90jzGnw`SUkQ5Zj$Y`HbaaWOPDt@0tnz^d=n8MaTK6Y27fmEnaVZ@;{0+A;l z`q5@nUPfzU^d9;jJnqZd`^7h|T8NU+`{nm7DSMIaR_R2Xq6oIvEPS$<>c#2z8UNotr*qjeek41^5+RbMGTIPQXL7N8{b zp1jwwbYbT>{sKq^$IFyc@+f%Jan z$V)vTKTfQn`Gfx&648QH%Ey`_*lFCi%QI)ykKgwHDIiy&LjNd~KpMw<@_N=mLb6B_M}ko3|09iF>@?wuD@v;oRsZ}x z$J63;AwprIg?H%9NH<}%F+rtj8f`QX;{%b7)*)IySHMJU&8>a@rxk$=3|!7;TWaf2 zn@(+GY8!wHZYt8qGB?btP(<=DwL7RiMD34y|40R2H{X|cPw?o~d?mphrp!Q#C ze}=jb59swO(X~Qb6ha_!_U!S^+L-H!8+Ho`BK#j{-iXP>C6w^!{}|J3Y%Q+3>Lru_ z7S)ZOCrcxN*@jE2eUOHXK2NkEBhi*Xtcb3;U8mku5lA|C>f!fL+lksosJ$LT zkLRde1SLclqw~O__`6d(k=hKD1J*)rr}kASVl5gQK?&YBw|Sk-YkZCOqcgyRm!F{h z`Oc+w0=0XQ4Xhnr2}MZlz(m5ogXb_bm`d%J)Hdv+&u<1rAS|4lPrP!Wl);>k7y>0Y z4PiLut8i6o!$R*534}|31P=v`#y;bIR9g}-55ID0IuT({2Rr9 z2MP13y|tfyS5rF}!;iI~%$=+E(~o^?dmtO(vY_56L%(S#UlU}okBqPJjs0~Tl=>em zeDy@x5OZY1gRD~vmqZD@dYfCXueN(>f87uJpdPodf8E~#vikbwv^gi9!k6Xc;z3uu_w}Y^rsk_lt&@(c6vN<*ZrV zC<$GcUw;A}_X3wF0GCh_B+{GM-`i%tA;m_#l$u1OwNJfH_pIT^L{h;9kMIU3JTt6DS)Z(15ini(i;cwc?u21Fu63Oa%2v0}7j?fix1N zqR-n9pr|LzRkpdyA&!KWqK_MqONEh$RjJ)bZBq;l_M&zhlxd`szz%SBuy2fk;e{N1 z{}01w)?{DJ-WmIH#MreM1;{nh55r=`_#eoITw6*{ImrXEbJl_5=}bQ+w6j~gy+c}! zf__^Z-}Xh=OV91&IN3$ZYtr6dp$zbs?^)g0p~=aE9BRqMHrYwYehiN48q7mrVa6oF zp{LKFJj|qaIn;R%6g=k)YYQ9>`ZCnL;E^VefLZu&je%=6oO{FM#u0P>&G*(Y*W`eV zefe3j3F%x6J>HM@QCCUaP3>P81;|Apy?cE13!;e+hJ<00Mi56`$so|-Mga*)Pm@SU z3W<5i?RAk5$SjP5y&7WT59L;~XNdia;*Cn z$Pab^vq0M)!dN-$dMdS}soe}U%Fbec=4^A$xHdTy92WZ+ z^5a8L=9Qws=Blfqd@gywWXh2=?}8F$S+yg6ALlQyS?+VlpL4*~0M5?$mhhN&=jhMJ zcn^jaoTsrv#=cxx<0lv;$V4EV??HC|tI0V&URn-d+4SLT8$sDLehy6#juV~j|4<5a zB(&AGV4=(cyNQ@=q}aJWbM{T-6B&yVAg;Z3sb3dI(6Mh8h8Uct2tyGGbhFOeCL7yt zlJuk4(Ox#G6colw&*pvgV?H?>qYEtXPowq+3?8g1v-ZLx{;wcEdQd!0p|&ORfwSk| zLhU9DTq9x);%t5FKjwRDsJ-ly?=87CijQJw!N04lA;i}}Nsdv0Oa#*S!;}+q@!#vE?|{$=4a6l)D1M{xp-H95BZ|1igU*ew1nsCr~s!KE?g<>=3T zkWvPeZICsAk-t0FU=*QW0$H*1Ia7nC__R!D5g}nT?C2|7^MDm;6%&K7N9;{o`w;AB zSGPYB+NLjzRNMPRF?=sfC0ZQ)IR>`}Dchg+(mF(OS}? zxP)!OGsIH_ROs}Cu9daZQK1NY8!A~Z5AxW_`vWJejmgpf3@ELk=q!15xF3#uTHaJ@ zhvn$c0S-UN(VtCwMc(Va@IGV@Q~njTzhV@jUjp%0cArez$Lc(Sb~F&30}|*_wT%26 zo<$B?`-rwZYs4OO z)MH0_D``Lzg4qYXj3S(rD^#|(#&+0FT^V-k&u%&p_)LmE3YH7LOQsJ-#2pfXFGWj zWhwG#kxx)N2<3y1lcyFHm;0ELqd#jpd2%P1V9P2VY48SQ&wl5Cj@vNG(5Lk3YSzBq zLL7!nwC^J@QC5NHW|nKSj zxN_}pa`fjYyfsiBj?dVSf902B6r!#4@|xb~9KvX(lZYb>8?F8inec;{=q#0_E+fst z_&$WKkr=|zrY(EauZ8$$@%9C$%93oMVjgKCE4y}~<2{trnA~%*%v=cqv_pIC@L#jv zD=PJ`;X6eei9|MUdd=NYp$OcaqwkwAI2@XzFKb6brF|H%kk1p^o7cSd)f{~}x$+|@ z2W+~^T6OsrC==hPLn?vPx4HVgL4cWP#=Z|264AboC_zx_QM3-vjhx_t?cWe7+5{|T zG%WHkq@sNxToNUU&{7%j!t#~S_9@utptDdCLK10=-JPysz8h(kycU<-gmqm`iz2fS zYa|80Eo$j$2Yu}XiBXqaSO)SC$Y83|a%q*f=jfj&ytYVuKSy5{#Cg7hzeT=Crq7|A z0pv$>^gR!w6sZIfG`&w4Eh8j?hBeoRHo-_8jvDpR1R!m5m1DY!O z%UByh;fpX;L^fZ#Y0y-jWJ_(pkqDKa=w;Nq{W$TJJ{`Ovq?25=(}$UGd3N~ zaFdn$d~LW(V80f?8QK5K*q3W<4b(2lb3fo*T2op?k{HD|#Yyrlhn$L%Anv_7 zaEL|NfdmERfkeJ4<4g~=Mql_%kvAc(LOLGL*w4ej31sseeeb~Vfz4)r%Gj5k(0OZ& zvCnB?j{ZeWZe_q`x2z>1N=qvk326DEuWU4qCR0>*nD^0)HH{##EghopET0EdM3QkH z8}m~Xx@&D)j`5gCparqC%vWmNand&vpRa^=k9<>!B=YFhPtb|%O#*sei(_0xhq*o) zn_!H2&mz{SPZ6kF&&SjxQ_pP2m3y8w&{EqKV&o|hI8fvnss9$ki$`oJPq5QyCBfiBWK4p-WTA_*;oV6w}V$;yjEZjA;a-DoRm z{3ANNH6j!#B5fif6^`l9WT71DGV+DMa!|u|z}uRSLuR5!PCMi{lms#V+9&CR_oU-2 zj5HCmYy>eW2C-So_&j9N3|DXzmNH?f7Ctkb?CCX1b2N@76cupY7dFh%cetIlSv4}o zddQEJ>~|=N!6C?=dCrxNS6~#wkzUJ#|Lj8Ku)2x5vbB&P(mp)2)U|49h#lW{ zlZqIG7W_{65-n6^GmgwseWm*ui6}3}lx0Y!A-*ZsKm7A3385y^2)3rI9Q~id@ZxVd`VJ&AjYs!a z=jhK#ivuZnZ-eFGVHx`_M*dPauQ@mb;sv!2g<418IergVevpVHq#+QrkVh1eWoZjC zGE>1a>sU)77h#$)VM*y~9Lj?M&yg&`l78 zW14fqel22+0tkuaM)V6EZ{j>@=l)hnnOe&a`T&}NGWy=wGN$CZi@Z|K^$=jm$5XYadbCJQ-r)Ra|Uu2RhcXt^OD| z*DMlFe`&6-2sq)pdajmctdTUEVpqAcA`pozM6cY2j`f`DqlxoZOf*?Ck3cN+yLWqz+#p+T12QP9D6DfiM65FaV{N)dUT!zAT&AJnxfVwqi8ICrj1hO z?XFM^m_Qci=syj^i}iB!9jwFuA!@(N(LZmMUUt4`y`IxBd?-d(6o`;O8q(X22tp_y zhG+RQyhsxXwGvGlu(S!Iq1euCY1ShWiOo_Wxin)FmawC(S_q~^lW++vVJ?d`k;Hpr zO=cn*!Buj~?7dJD#8X$zL%q2Z9dB`b?y@#KGi$E0gV6+Y&aX^IH7XGvSxCqUxy6TFZmwRaScEB2RMQ zGz>4^mZNVG;jZ^1dr?dFWgL;QFHcJK&WwF|n&F~@2lB*Wz8)QhkU)g=W_oYs!8EZM??;>ze5@` zmP|O%O@k%487%@I(WtwX6qM6EdSht5@{sEPNSdzF2*%NVM52G9sm~oxWOb1& zJMqG$_mdCeAiAzau@6L%rO=ULw0bX!0Fi@TdPYVhA{=rNf%jHa=v3q}kMO8@xFWIM zf$UCvF1+|4iUC&vek5aGPAojQpFUiAKkLk$mr?6Q@pv{z-@L&ArNdjY*jtZ;YFA{w zlCj2tz{)h2eKlC-t(Y4^iiu2IGL=X~!jbNns?7dyfRHd_C4C@$k_*y_P0|<0lh?`d zvr8M5izS!bNe4TaoaZae@nsa5CSRyE!!PEbK}0dZIL@QMhd>Pgj205EbF^KBP6f|{ z@j}MFoYQk4h6j0qG5(BV1#g}NJ}z(4S7PC(q3&aU;Ib-Lp&Vp=-i!^F8;4k6x6=k$<}fh6LPbiaO8uVGv9(zy#UNJwxPwpcxU zR!w0AKA57IIzL32v1Xt`CnL}Fxd$M7?m|(Rfb1c!jB8OW^2`C>S7{Q~pt6SbpNH~h zeq?f5nz8TusZBx$!IMqS-XwwJkc1`@*ba2hArTpw7quzNz|umLZ$z5Pz0Xm!C<{zgO+=2&S26Oo7}7&|H~ zdOtTkRYPQcgXuqoM(Ov+@kf>>T*Z=0|4iD*mT3Cx2*0sPZRzoL(hkUoLm@dlU=)b)T7| zf4hn1c*3YG#Vh$5$}C&Lq1##I01p=SM+cz>;cXy8^}*9hfpl^{Bw~Mu5SnDd-Y#(n z{ZGPipf8s~{DMBMr9pYG0O^y*j#lo?7zb^q!4P z=l0MqI+0D5f5xl`5wAzD%PF+~b~)}7dx#Ym{Q)IGymHaAcm>6xNkT;W{4CY;5~|$3 ziKYv;b&{y?Jglrw;^KB$M?DpW7C)u-FKTbe(3b@Yhqvwk>lz#>$qSZ-JUQ1pGWP!jR2lh>fG32%I;1@+SIa;< z)I+;D+}F6tNDGPABbT_u5?a3mL34u%&6D;U+wA!{1^|Ie7m51C=b|pQrrUfZ3HSxB z=7D$#%aj$KL`s9zFV$2gR;3HSR(2gZvdlb9Z~G|l!Ab^Inuq6TAbQ^$P@z-7L#sSx z!rzPR)2|K|Cm_4?oc$hoCWXoa9{gmT^M`#P$yqshP@1JeFlW%05qXuwuXFTeNBRNi z5O^d^Ch-W>II1O#mSOoq5I5LOBGO1Kf&5z`ySJYdd|}RboK(o11p*hnEP{(KMSaap zh#=07y!18^IQb=LHE-Dt^dy0p_o?MnI^xe{_w0=@QXu7C#!n>-Nkq|fUSyVJbC&XH z$>B~ytI#)CXyqC8UWtLtxseB4ko3qL{n?lEFvZ4-2}ib@8r8z9^}I z;#O))a`fjp;|E$IzfgGayj7SOg0N}7M}jDXw6_7d7Q=ky7^ zPtRC@lo>y0A=FmZk!2wju$x zlmycetKjI*k&rKFhKu$PxcF8Qh|>|6(SfZ60WD^(gw_;=6eGnM4^1ddxfXoyE;;6t z9Tz%hgPz>+cJ!RlI6~5h0tWoZd=-)mJ#$p(bg)+OK#u;bG2a8A=x9QA+H�Jo9XD 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 SVoqQH0000