From db112e4787776ed5fc54c4f488d8906d885c840f Mon Sep 17 00:00:00 2001 From: Raditya Harya Date: Thu, 1 Feb 2024 13:19:56 +0000 Subject: [PATCH] Rework & formatting --- .github/workflows/fly.yml | 2 +- README.md | 1 + bun.lockb | Bin 458098 -> 459992 bytes components.json | 2 +- package-lock.json | 75 +- package.json | 8 +- src/app/api/nodes/route.ts | 108 -- .../user/[uid]/playlist/[playlistId]/route.ts | 10 +- src/app/api/user/[uid]/playlists/route.ts | 1 - src/app/api/workflow/[id]/route.ts | 34 +- src/app/api/workflow/[id]/run/route.ts | 79 ++ src/app/api/workflow/queue/[id]/route.ts | 84 ++ src/app/api/workflow/route.ts | 95 +- src/app/api/workflow/validate/route.ts | 20 +- src/app/api/workflow/workflowQueue.ts | 169 ++- src/app/auth/providerButtons.tsx | 21 +- src/app/flow-test/page.tsx | 119 -- src/app/flow/RightBar.tsx | 15 +- src/app/flow/page.module.css | 2 +- src/app/flow/page.tsx | 184 ++- src/app/global-error.tsx | 2 +- src/app/layout.tsx | 4 +- src/app/page.tsx | 1 - src/app/states/store.ts | 91 +- src/app/utils/reactFlowToWorkflow.ts | 239 +--- src/app/utils/runWorkflow.ts | 68 ++ src/app/utils/saveWorkflow.ts | 25 + src/app/utils/validate.ts | 13 - src/app/utils/validateWorkflow.ts | 77 ++ src/components/DragableNode.tsx | 21 +- src/components/Flow.tsx | 55 +- src/components/ImageProxy.tsx | 3 +- src/components/LandingPage/announcement.tsx | 17 +- .../GradientsBackground.tsx | 4 +- .../animatedBackground/gradients.jsx | 38 +- src/components/nodes/Combiner/Alternate.tsx | 16 +- src/components/nodes/Combiner/Push.tsx | 10 +- src/components/nodes/Filter/DedupeArtists.tsx | 15 +- src/components/nodes/Filter/DedupeTracks.tsx | 18 +- src/components/nodes/Filter/Limit.tsx | 23 +- src/components/nodes/Filter/RemoveMatch.tsx | 57 +- src/components/nodes/Library/LikedTracks.tsx | 12 +- src/components/nodes/Library/Playlist.tsx | 93 +- src/components/nodes/Library/SaveAsAppend.tsx | 33 +- .../nodes/Library/SaveAsReplace.tsx | 40 +- src/components/nodes/Order/Shuffle.tsx | 4 - src/components/nodes/Order/Sort.tsx | 48 +- src/components/nodes/Primitives/Alert.tsx | 1 - src/components/nodes/Primitives/Card.tsx | 55 +- src/components/nodes/Primitives/Input.tsx | 3 - src/components/settingsDialog/Settings.tsx | 37 +- .../settingsDialog/tabs/General.tsx | 16 +- src/components/ui/accordion.tsx | 28 +- src/components/ui/alert-dialog.tsx | 60 +- src/components/ui/alert.tsx | 24 +- src/components/ui/avatar.tsx | 26 +- src/components/ui/button.tsx | 26 +- src/components/ui/calendar.tsx | 24 +- src/components/ui/card.tsx | 41 +- src/components/ui/command.tsx | 64 +- src/components/ui/dialog.tsx | 7 +- src/components/ui/form.tsx | 101 +- src/components/ui/input.tsx | 16 +- src/components/ui/label.tsx | 20 +- src/components/ui/popover.tsx | 20 +- src/components/ui/resizable.tsx | 22 +- src/components/ui/scroll-area.tsx | 20 +- src/components/ui/select.tsx | 58 +- src/components/ui/separator.tsx | 20 +- src/components/ui/sonner.tsx | 16 +- src/components/ui/tabs.tsx | 34 +- src/components/ui/textarea.tsx | 16 +- src/components/ui/tooltip.tsx | 22 +- src/env.js | 8 +- src/hooks/useBasicNodeState.ts | 5 +- src/hooks/useClipboard.ts | 5 +- src/instrumentation.ts | 31 +- src/lib/log.ts | 16 +- src/lib/old.ts | 1015 ----------------- src/lib/utils.ts | 6 +- src/lib/workflow/Base.ts | 17 +- src/lib/workflow/Combiner.ts | 11 +- src/lib/workflow/Filter.ts | 1 - src/lib/workflow/Library.ts | 36 +- src/lib/workflow/Order.ts | 28 +- src/lib/workflow/Playlist.ts | 15 +- src/lib/workflow/Utility.ts | 49 +- src/lib/workflow/Workflow.ts | 162 +-- src/lib/workflow/types.ts | 42 - src/providers/NextAuthProvider.tsx | 8 +- src/server/auth.ts | 4 +- src/server/db/index.ts | 2 +- src/server/db/schema.ts | 50 +- src/styles/globals.css | 2 +- src/types.d.ts | 106 ++ tailwind.config.ts | 16 +- tsconfig.json | 5 +- worker/README.md | 2 +- worker/railway.json | 2 +- worker/worker.ts | 25 +- 100 files changed, 1921 insertions(+), 2581 deletions(-) delete mode 100644 src/app/api/nodes/route.ts create mode 100644 src/app/api/workflow/[id]/run/route.ts create mode 100644 src/app/api/workflow/queue/[id]/route.ts delete mode 100644 src/app/flow-test/page.tsx create mode 100644 src/app/utils/runWorkflow.ts create mode 100644 src/app/utils/saveWorkflow.ts delete mode 100644 src/app/utils/validate.ts create mode 100644 src/app/utils/validateWorkflow.ts delete mode 100644 src/lib/old.ts delete mode 100644 src/lib/workflow/types.ts create mode 100644 src/types.d.ts diff --git a/.github/workflows/fly.yml b/.github/workflows/fly.yml index 4ad6f49..2e6046d 100644 --- a/.github/workflows/fly.yml +++ b/.github/workflows/fly.yml @@ -7,7 +7,7 @@ jobs: deploy: name: Deploy app to Fly runs-on: ubuntu-latest - concurrency: deploy-group # optional: ensure only one action runs at a time + concurrency: deploy-group # optional: ensure only one action runs at a time steps: - uses: actions/checkout@v3 - uses: superfly/flyctl-actions/setup-flyctl@master diff --git a/README.md b/README.md index b71abc3..bb9b3b3 100644 --- a/README.md +++ b/README.md @@ -135,4 +135,5 @@ The hosted service is provided "as is" and on an "as available" basis, with no g The author respects the privacy of users and takes data security seriously. However, the author cannot guarantee the security of any data transmitted to the hosted service and is not responsible for any breach of security or for the actions of any third parties that may obtain any personal information. By using the hosted service, you agree to accept all risks associated with the use of the service and agree not to hold the author liable for any issues, losses, or damages that may arise from its use. + diff --git a/bun.lockb b/bun.lockb index 20860dfc4ed97748b52c43dddb2c74fbcaf8f2b2..ffc1c616142d7c5547e5e99331a8789b429cbbed 100755 GIT binary patch delta 93661 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 F{{lg>a9;ob delta 91469 zcmeFadw|u`;{Uz(uFdR8G)U!AqN@xgnaR{1m1>%lMi(VrrfJtq&84}ikZBMV9mYpi zq2q)ogb;<0L`{;BC?s(@$~{Ex&+GkJYmYg;j_3RPJ>TE+Jb$#$?0K*EYpu_^ul2di zM`!z-6TklPgqzQ3f7AHKjytAdhg*kzb^qx0AEaG4W!l@nebVEx+?+eM-q!G*^I{+V zd{{uAi>oefk#j|6ecuEE6Y`6u=1rI$xV*fyEW2=gU_-q?ph+Mwvm}DY z8;zis7mfFiEHBUV0~Mq{2L3U$0a{v~Q<7a83tU;XyGg~!1PjY@V}&ZDm-7SBh9sVR zcp#93PRuVFr(DlSwCM}-3iGC9mzK`KtI!5c(<$L7{H^GbXvpzoYS;*WGOB!=@r&as zW_|`B&CHho($#o=W)9_OwK5Y`t!EG~jgq@En1?F8%jiGm6F+`ErK>{me7>giMuCdJ z%zx25W&EzwskwPMxwJH|G&U`U794F`bRK=Ef~RDc?ksO9}pRrHEu1A%7f zSo8$+BUHRU+88Z~l@{e+77L^t7YMY#C!>iK1X>VK&2qC#i>4L^0>vDqg5F{_D1#mG!ghr#Z&p2vx!#^UGCCNaTy$SlFe{jNp?=GG!VEBuj5}um0$Db zHa=ePq`a~`<(pTU>`$kLEdmq#11@z13`SMMf>_DK*ja%>Vbyzj4C+!OskoA9e*~;F2?D5&9xq-mfaLvHN*t9aGJMC=S z14*dX-1nUW0cP{eU8s6y1FEI-u;cU53MH&0pst#Xs%F`!x@dZeEg-(8hQU=}CaT?N zTzToZA{NEgRO>rAURIi)r+u*dvAc(DcBAtH0k*@LU-SwDPC>V#+Us5hz7Bg?B!t#^s)*9$dIa-QsP&KIcKvjUH z)1JVIfG`m{@Q;iB{tImn-7?5dEOzSb{Os|uS$KaG)V-aXH&S1H4-H<6zrk zZ;+verX#(k<2iGbO`j4AynL}uw-VKwE<%+qHf>4~NduZ#6$->>Qhd!8USbper=e&* z(iU{grFJuDO&-ele!MDhIPsdPy++xVe@cGp;g3hyCE0hh)p?`of3>iz3F9V}>bRtAn?CGxN=Z=xC;32jY4#Mw9~^6k z>T^{2y~OeAkuBqBzq;}vfW~G*X)^mzN%luMHbc#FRp>3e#(F|t;rQh8DS=Peot4op zr&E&ii*nf6(7b}YvcN746Y=pYiFEQ;&y;Eja(aueqFogeY{aXmS{T0=YtGiFiWL>+ zkQFEFlI$r{rjsdKntC99F*Y*Kc4c1Sg#5gTxn;+2oC=;8D~lC!id;j!nmad6vMr8Z z5`BzUx{CO+dys@0iVoEDSae!J{#okW)%mu7((GxfM_^h`(RkG;zAKF_unm~vpCErv zpHgTm+8#ZU{5~O_dhi^ko(g^s53iW{5&K+a(yuKNmS`0GXsHB(f65iO7|eV z0pZ#m>P~r@C9O+x3 z=c78lDJuTM<+ef1X4C(w*}VjG;Gj9S0zY4GD{%N++l9NFui?OUq?*adg?Y*ym&hOFVF{|E@_LZt3xi~cDh&@N2_dsThSBn zE8yzd8&FkbB-#-@9#zKQPqkgW1(m-WO-A$Q+j5pu@%H$uZ=?T}(d91TTw^oLz^iMU zqpHC7%mJl)1yw;u+-_Ua3a_C`Ks5y13B>YaIb~BOPt-OMi0>EieImYZ)b1DFz9XAd z#25A0JM4`6p6Y4l4ZqKxL1LxlWqF)S8{<`*kC$+_hQ5HRR(GK4#u8M`x&T$Tv`01L zG9R${1YG=U_uAG?{YM~hrq0G&g{7|5J*Ko zTWnkQveUa!Wi$;{1#>x04H<-2MNUE0ko~UUYE<#}p*k*%p3EGWxr+nUWviX`LR;gH zMpfg-{vHT)N6XMC+7=yvRx(stQ)AJV=(^|K+8SZE(?)0nK9$WypYoFYjXmF{y?`*Yp+5-nD>itKC7n^RWTQ=$lgn)?`{+Pwbu_6qsFREN)T*~K_l$OQsBI36x3tfEHW}Chjs?x{D>}|~i)=4h;#>%oM zA`Jq6a|g`Y9=j6uNtLo#A!#CXF z2D>Di`_9r>5U&c6PR$N{=i+lprcWuu>&`aDMR$IYy@~pEyB+Oj@7n&Ta~tlLH$Hn} zazVCt+_9%rwBKo~@WWc$_Gj^$pvzHpW!{wJlGsF^k4%f@WK+~@@7wtGPFJI&BPvLd zos$#OY(4Q4o8kRrpd~%EsBm&N@rzuB8K2rcLSwoAOE2@dGb)C-d=~Dv`Tlpep7`|tiQ_bt zrW8)}FU!BgEBil=T)Hdg`)_UiO1XAqR#ybda!ZQJC*}rr5z&+bJCaayvd4F}qnhKj zExm(R#$SDJF9)`wC*dDQPeu)@v+-4EGc*U)WkWyoc=Rl^3ECD_2fgO!$JA&{0cydf zpX}rvUu3VM6W|TuWp-`{;x#YHD=5jH5D2XJ*;bUR?&K*&C1tT9#-C68Da$>?tHW}8}SJ)z3%&X z=o0uc81#=X$)1`#u4w%9hw+-bt3yFQpK;U6^jI%&H(dGdph6Wb2)td-CVXSKE%3_v z*5{$e5MNkSG=-foFcz<#y4Yz>!T8DK7x*L`^n2>=pxxOXJlq~PCc#!{DXN~h5Y?hM z7uDQd5eZiK8J-GI7yW|+)dQEKIx&Bp81%>XjF4R{w;dMr$2gmKjd4FzbLN2~f`OK3 zXS}x7mZ;{;VW{T7C+@h7sM4)HGU#8zTyt23t?6S#r~>f^S5H%*GLHLk<@xyq#eu-9 zjcm;eN?DCLlS}fGY>R$8I_O^!yyo;D=ouVe=6qi?8Q&B=6FtarC!=dC$WSfLFQ3Na znm}MV1#8mvX=1x0Y1 zmvFv)#^tvZ)sPN6-ZrG-I|5p6x4Q&YsKz+uq@ce)wL=wu45~2;qbl&b6D^;I%I`!q zB(FLC9ICN?2-Q&BfhM7sqpCmwN<%AVK5??mU=%gMfiK_R$Wc%Zc%vb|0pK{a$wkxp~#UGWM6jZU+ZFNmrI z`%zV3JE|_-;tqTU)hQ$4bT?=6*cAB0m*oQDHHo9iwxF||zJqE`wRU)%Mw0tba|ax6ZN$e08=R zf(yFXF-}7@Y2xeozph`~)jer|dZseP?hm=BdhQ!kdw*l%<$nwQ`vx_lE9+k;jX!P_ z{kqzU{F4K;fow+AL#t3#IKI=}=rWvwDxZr{6?AHMyYcjN>FE%EPO$9#TOLjcem?6` zqjszP<8$7mbUTKVxV+RD*T-uNbBc;4YuI1)S~hP|v7h`kl6#%Lg=%icpJv82zo<}` z+=2KRVLj>8uLsVzGbzSn??TSTOZ(W`oY2=cKRp)5l7AARcSQeIp4pg-b861+~Ph0;305zb4bWq(z&Gl7V*V3`aE~5=o}< z{H%A-ACDSTPT!}51j?fg6GHU2Zv=IC15 zM0*<4{ynwT5HIoMHm9r@V$;7h)RuGNFzaKbUGyw6V1{`Yo!q9PnrIbM5GyFkyF3=_ zG~6a@i>i9ZqnZ^*qJFn$7f#Bf$nhg=w;f9{s(!3gcP--s;Y;oO_j-ZSG@)DczyQm6UkLvixP^DXhYCX+y z@ue<)jPKc;2M|!r8n_ONKUV?h&OV6O966=X z&W$Fhdf*ngrtF9!yZN7lYP0TA6g<~|Tr!i*O$YwM0Vks+93Y)vY!jYPVhfI->f&ke zle{jc<~;t7Q>WE?yj|NVL2qfh+=LB zl+dnvUUi>nxqiZ=yHkR#yp6E2Vf#=nVzN#Trh0QS z(jz~Cq9m(lvQj~je(AxRy?*`DL%R?6=JtyQn|K>R6TC=fdg##vFEcY5`d5NCH!~V( z#oFzu0!-FXIdon&9=yfd*gri|O?Re|D$%Q2oSH!2sZJ3u=@yE= zAU$+<1F!l5vTWcb4v0p&(`Cvs;3Z|GL@IDfo#546kP_*|ILRIE(Voa`TsPcdUKMe# zITw}-CVF!Qrib&n8W`p^T-_~!fLfT~AE=#CuD(~5nG)%bQ-L8b>$6mE2)12?PEB4E5$@rPIbhAOlv%G(5^dYdmuixd-5$NB|^o@wUI9UhH*2^quP4AMfCafxsYJM4yy!7A~sH!#5E+ zU!l;}6TP`3qmicEC2JZmF&MmyaOwbtlCp2cser@%n!JNkL&K&f5=>2KZjZCGG}}1_ z_M6mTb1!pLH1amgE?^CP6K*Ay7bz%bFiz9rFuw;_$D`9jpSJMkj*f;~uzN(k&4bc{ zqrAwN^w1+GdzoXRkq^Pjjlt-jLN{+5lOE1%83>%`ZSIp6Sw+YWcGbX?$gj9`zpSc} z>feoH(<75lsqL(+l+gXBc$wMJ$mc-KEyjCDN~HCv@tKxH6-VLJT;izyV>rz%s^2Fi z@^fv9G%3;6L#^HL9GVCQ?k(z+9nQ&O>Kr3%rFM#vuZ zB~IOQm`V#>-^NRfMI+C&v3(3=fgHfu{=|hkwDqcE(Qrjujpw|~w8(3O)TL|MTbzy!M>|nnwo$aS{wB=Ch25WJg$Fj$}eyi*1GN~cKR}zsq?)!S4+C%!xXQ& zG#YA_>Lr#%L&H#E>w}7@g3F9$w~^(eUTMRExFbXUkCG`QF^CqM>c)d(~G( z!^vzZW4(FLcB@Yy)ti@-7Fk5*s?%Zqs;a>;eK}aA)$8je&WuLR>su$s@Qt|hbZDr5 zhF3i^8eWjWEb|&(l@@w4!^^CUhI;n%=2k`{fA43v8_rV&DWUKBd5Kp?Ln)bFCUQfj zH}~pjWEbmMgTn5}`S4UmlD2cQ9ZAUUNSrDn58~9NbOGyeUw^OqnrOHKZS3Z49-9`P zNQl$=RcYa6gks)2LPrh|qfU_#glvnF%2Pr&4A5R5+Bm>VtcZrkvO5g-=2fPJR}mWN zHM}}4d<@HHynp25gfxHb>iHbU;?g;o(K>aImw0_Nv~-Y{d3`i;7?aiR4T_6qdDX;K zW_gLTqv5T@jrInRbEk_KNrfU)6(TQsIV&Z+1~<&F#W5^_i@b&vX`$F)Z|FU4tE9PU^A zA2{_cX9&))+ednHZ;D3RTx#pzSm(e{;iX>U&C$@~mwK5uMZq>omlAF;+Mh)I(jr+3!CCH{)bGOCe&p&g0i%6^vlkhhFeX0MSz}Y{W9+5Q z8bVPL*%RJRxY{#Mq~F;1MwHY)C47yXKg-t;QpU{dktv~*vc1Gxqmj|s@r}1?Y-$2V z{m*qe8~B?zrMGpjKhB@_7o>&yjPo+*M?=?+^XATHO~Ey?%mF52pByjoHr8T}tu=QA zwBbwKd45Jo15*>m+bI7UCo&Poj-z&b>_^$@=U?d%r6&605a}GV&Rzu-<1|KeABSP= ztWjZ~xP;tP;o42GeZkPKPEBxzJ1j0PKAqrYE{sN6PPFrsHfN_qhT>FJJ1+Ba>Q^>b zM*X9SUgqu5$Qilusa$nIO87EdM{hviw8(vgG~u~IxIZ-kqs7depr~W>yt#KoBe6U? z=T~l`p#%*(IhW%Q8fHDaZ$7RcrK(S+he#5 zyO2pa*{fa@jXVZq%beNCpT0j#_A>t-jm*lo`Ozs1>^dB$C$1*cfeUgkZ~$P%DB;0XW9=`$RsciO76a!QFEJEk;ssVMO>?~O(_0DF_8LaOkEoFY&%;56!NBrQsbbib0<0yrRGsu~4T>*I!KM-Kl)DBo+ird$0PfxvW~ zDk5F3iqB15F#L+Uj05fdT2^7R@z27M(`N<(^t$HlZK(+u(kdZ!Kc&)}yDSd zUK-qjOIIbltjkj(H8@r*&oF9e!`WBcNlP=YP60uW z)T?(A8t2@#ksc7iV+r7C@ zMI(VbXc;Bjy|Eal?W?|*H9sY?40krpUJ2~P*&Vs+!_@kBvP=0F4q3IKn+VxUuU7~u zslOs4zu?aDoh~8HTx5439%ZpfjKOJ3Wog}>5?P4L^iwjc!ynU1@L3wSKOO^!MWb}tGp?znv!L5W? zkAwot0)a9=R7S|os}Bj~iiO5J;AO6fh97$%o~X@(eqVFB`p|=3;&ajP=?}&8ypvFw zKS3HTSBaV`eR|U{1IC1m^ljp7K~AaIHTJ?jtnGXN?|b#rrd^ln{%NiqsIg(vKbR1h1$0u`d#u z={NoIm4SfgU%)ne(w|ivafKgJ7wsc7$xk=j{nX>%5N;bNHEV^`G$r_je0E<5j;LZ8z}QKwvSoJDjm@?2owp zbr$?Yc=J1UT=v0H=ildjmDj93>`uS18`kgwonO)R&jkX{`XjjKIWKWTG(6^cZ57lg z^x^ZmdXMyc!Jbzd`upfTFL;R?qmijE+Gi@<#EnUbJd3kyf=LiBM-h5KTdfD*VkT?3(Zvr%&Imupw*{M6vfUgG9xWEo7$&R%MLg6o5`YdPZ; zTfU8(i;JoZ!=J-a6L9DIDOo^~BR04=|1vrg*M&G9Sr9iDr~QFDFY53dPBpD(YTA$s zP7B+X&~;-x7acbh=jwh#Y63=?a1+6W_7^zYTs^yKQ|+?!cZbo=*{$j}oL_0bDsSSH zi#=5)Y_gZ$_C9^cCNJ@gX!sc*x2yEsH-t1Yoc(wb*7?g#igBs{mqhQTCSXqY zbLC-RcpI*x|6n7$Iev(SZxqgD$BwfIcfSARayOxl@j8W*USl}ChUICIUWCMHabZfN z6sLAjAV;sj@f7@mwD6~d&hc-jT5jCZ;4k%g;wBHPcHswLp4sD9#`C(xcGaW zlwQLzX^~7q1K}Z4#mLsju|bbX3%&ljSN(Q0@+&}P`&W?RZZ#zKJLqmgeJ#&O3Gc(5 zSA>Bylx2uY&ENx2DjpD zS659CaV!82($jB@oa`@E>o7N52&aT;ktJts>+`p8J9y-}0(=a$oSatrp9DOiH*E zXGdo_A*#e=+DFJOtjV0+w%fYcE9%KO%}W1S&q3$MuJ6>=hL%posW+(`6<+*~H+MIW=7BwZST#5`;ayud z#&=L^eT?4~k$VZL!|Z+L2jbSGRr%TQF)C7zjd`<1QarQ8|q+NAg zf1LV?`mtJWz}Y3e?)Oww;}@J7$mT<;t{?d8mPbOD5mM(c$(E-?R^g&J{=CC%4(@h! zFg0CRD!4xWDxOZr9;4bkgL9K)N@@ZolMMVn*+u$(XbbiK@DaM^Loah*G}8DZ+k;2> z7vUG+bhN$pxfZ9kFn;v)OD@iCm_OsrC(iC?=l#=W&3<-uO6baedWoNMPYBfD9Odu6 zqxRU|rD^QN598D{&O~3NCSW>ZxcQ-PPW)G$JKfOue|d@hqmhS!Dvlj-WJ>sJCGjWs zxgXnn?5doGbKOUUpT^nAO^M;3ap`)L7D?M1pMkognSs+#Foh_5HO^J#>Xb-mUwqTn zh2c3k4Lfya;!nY4_)guv3a3S32lQV!w#K*9LTx_rGQWyO#(iQ3g8rfLyKtTT#5KcG z!bg9q#0>}V*Ed1~;8ca;ia)D6RUg6Gxvd$q2WRKiNuSqt498^SE+7ZGV@PTO<{}Kk zN1>Tt)Gk|kV;YXXbg^SSNoW+Q>_DFRWjwpAlGKD+qb>X?oSN^Cf4Kfv+Kcr#?jk~` z`x&U1t8nUc{-$>?52A1#aZEYRouA^=Nq$kGX8XPB1N`N5zpXNlSSF=}9@y_?eix0@ z|2n>psK3s^{XWB|;Rcb5-5fUHR4e~JKN9*TKKnH&=i*csZdw@VLYy5wdN8sScNTH} zGrZ6{-*|HmMk6PDYY*qnnZpO;H2rNs9?o?wb1QVf4o<}H+w*YBjM+)nB{&TgTfo~C zgd6TV@(cyO^XC2-jr9M{PCAlsnz;TuFY%{nWF*tQ3)0d5C zJFXWl(eI@bezsR!jr<3PgK%0+lt3;o;Lfzi{m273oYp*7t$$C6B>xhhD7qrZ#<88T zI`1cxN-BR5gm>Y1OtdU5)bQ8&bA!=P`mgh=gVD$}zuE^g{@kv&!8iWzn%`|1Wk24s<66;gPA6=|n^r<0R29uwsGE+jPT4~lpRhB)Sh3f^~ zq*Tc%I9m_(`c&LlQra=tjkEo%MR!vDpg*;3Yp%m7j+89h7jXmq`fF}B3J3jOu&wEX z(~{uP8@bGMj^jxAG)_yG9;T(=<9b?0&AJ{Ibbq8&pKRk@W|ct8cmO_$H>PdRstsFl z=M!h=Lz76*J&(_#yfL_o{Nq&5r*W!_--htFxM5zy5nLfA#`Dvk*JtA<+59N^=mx>S z=vp@gr}MXM+mpCqweE-`f^{~HOL4YORR2vl^{hRvL&LglE61tbHts3hkXqN^$hswD z<9^TOBiy*!l)aCt?FGu4gR?t{-+MUqGjnJ$@4^KA&4Ny6l8(aJC?%YS(?sNC{;8i( zeaCEOH}A~bn_azm{nH|k64F@-&KR~iCg?wrv+mY^bD?8{{u3P=SB5LBJ?=x?lv;OD z<6xky)}4M_Fp!I*8vH%~R-8tglftJwQN`I!mCKh<{U#>!=->$rxmZwVK?^VMZz zyeWN}Mus#A`VWF>pP@LI3$AJv27O zBs2~-@)l%tj8uX|YQHNrq1I@eU&PtN<$l3+uPx}@Q|eZt!Z~}&e+g%+ zqzWE>YP><|?bQwKQu%AyO$DD3^j@_|{SEX=g*#6hPjdQy= zef2c%LgJe0d=(mzY%*KXn%k3W&n5Ky$2g59xp8JW-68`K)DATX7P6p*&-8t7} z1%v!;4f}gXH#;|eno{lsxZmT};q2*|vckbMQku=Jg5By9vO~L=kow6^hkZB|Yo|)* zZgHoaXW(4Uw0$Y>t^G|Shpl4GNNbvEW)`oRMpc|ccv0QLbVRKs^OaO>|WOSS6|^m+y%N?4L#k< zRG&@i11_FhSi0iO^Wzoa&*!1@gI@oyxI`AJh*iq01Sc+52D4si+dvNvwPp#hN93#Yg7AIs-iq~*bS|mnDJ;iDE!j$kG zINrI^)cuAL$SG^$?Qs{!kMlYO-()K*?Cyi%DxeN z3r_Xme8VN;YdF=B^A!0;`qw%AM*8AZmwNMS$Ylmjv%x>HM%KAF>Q659E{JdCRcvkP zI1L-OSy!^YaM~m|hjHeu#%X};Ya`7E*j8~?W`moEQ=EOwvlyqDY42S3VeasA|_TO>ZZ`mGRPffrK^$n{l z)N_!@Oy{)o$e>^#OV9X1fh;@LU9#fyR`2{(;%vK^fRQaO&R&$Ccu{<`wCpd%{l5F$ zk5eoCb9!VqPFEt-pHswXgY7QDwMXBSkQrvI;j`8Bnsz-;L#J*JGYp8#`eW7iHy>hkdyA;P6jHe^332DMJ7~H5gzQkl^ zFrZB?<%-7)$lz+=Qi5CDgmy6I2p(nQb8G3QihZo9{4!j^0Jk<@*^ycUb3aE>CT~R}pk+Um@ty9y_j< zjw0yldpAKYqPSpxPa!%d;;-D}a%>l}Pcw@%aEi0EiV3ZWnZzvO4?ugHhFSFcxf9en zKUhhypAA+MbP0}{SWAZ!bZPG*=o0+%_XNqg>Ipxy%L%&7))BnW(xdZg6O19~GP{qU zOZz23m+#q=YUvDuF5hZ`?y#iE8V$d+O9{FhmJoDlzpkaBw0u)Nj5&OLzU^fDMDjJ9 zHV5V^Z(21fFmo>^P2U1L`xyv^5YL!?|ulfyo?BnofmwL*`V$se3BU-qTeL zPl>F=*)3mx?VDX>PwQ-%xc6|{$gMkNioK$M_BiD|F0*F0E8?kMLEQkMh;$uT;lB=BKi%;~wWLeZuKVRG&Z5P#|bN9}{d+5hngw zKb2J-zlN{!f1a=W3w-r?fv@hDiw_|#RU`$DTr z3BKm548C#tEvf|H^VR3iRPjIZ)p0-Z)kiA-vkad zsOPjks*yR&`NL5)paH7%N22=FRi$s_cwJTcW7Pl05@_oZ{7)rN3xDE)V32D$kE38kXZz(p>@zf!e`D_j3lSL>VZIl+_)&Hb@NYb3Z1 z@jrj2isGun|47v_To?GCKT{RUsb2qGWMH~W_a|!SkRlREc#TU~SB0+Smvk1tl=1bb zDlpgi8=b!izH9`3^|c6APV}s-Qd3!_d1?Mcw1{UR1l& zGUp#qBp<2rc^K94D;)nX>hB?cNT3!z?hcU3uSA8ORl83L zx&4oTpRk2XC{?hf^HODaiqlh_wsP@xRVR`&9hd63j?ULrRpgwIQu_fCnne>`hn(xu zOBL+qd|lOmr^BT^U3^_txxE~hY7t+A3Jr0*t_txFmmH1w0YBpr(0XP-Zm@~DG&h*w z&-795V5tfj?fhSm zmucFfce~@HioXXHTEZ_Cv=r5}cnH<#Jf=ve3O*5XXUivCgj5-=biS^NKk2ws{wdVI z4nnn6zU=rbs0!ZX{Hsnkqx=N6@JkhZL#svLO@66M-gSN_sv3W!NT)jBUw9S#F{%PS zMU~`pr(dEv?tt^(JN*IG@js(FPKIEhB1AyoFjNWni?kon!1*IlwXCV*$D>N$-03MO zKLP!V=gP3H)Amj~I8AnXCaU8*qx@6^&T$c`sA?W{{ydbQKriQeJD=gSzte%JhF~zN z3JgW{k&0j9yi`3m(&?qBzgvuU38YFe#_3qcrOGJg_ykl1<)T^WYE&&+gX$wy@CB#q zP^Dk*^cANYrJ8@62=EhljbEz37Db>ns0x0|`Ryn_fp__(0(Uw8q0>F6dhk={zi_%A zRes+%{~fA)e?mL)4gAV4B~Y&N^-%e+^9jx;%A4i++=;24$GPZcF8T!Lo1^>$PI0`I z<87U9kE;AL9Pi|KXQy49ra0~DG!0d`-Rd)KRL^t(KY?B@L2pz%!|@9oABgHB<$*%r zM#ul=cwJSyZ+7vwpeoRF>7=Uog8B@bA{M%czf$d2i(N){qZ*;5&M!k%;De|>f2BHZ zg-f@h!e#K719epiS2-?K0Z+U1&p0ks1D8l;DhzIJbx@L<@@c%?r z(CaQAsfKhbD*h(QPeoumzxDZFQT4<-?zq2F_237jQ-Qmke&~*q@{fYCGdmzv!hbq1 zmEVJ^z>l5Z>*A#fe&+b+j@MNk_od@?Rr!7;u5H5)IMpOO=nnWZRTuu`;{Qrjz|W+U z{^ImkcU)an`2hjd)L#=$bzo2v!KvcwIWLtDJ1^Ba?+EAXs`6>*cwH4gGEDoGQ6mxv zB%w-sobyebHWlPkS9RR+F8%~m{v?-9s-8O8d8zVm>HP2Nx8FwS@~X2-c(&6nPS0@% zN|h0RZu2$OX;&97RYmyEYkckQxKzhQou;FzV9ygB=!NR@Z)%cDxaw583>Phx@9z$~ z0M)1tay|>yN2>BJLNziY9GB|&OP!ahzN4M5t4fz04w$Va!6g4Q5hIb(O>&8)Dr7RM zi{;ClR-!uiS{FYH)#tBN`CRAH)m1fauBM4T1pI>LyM$65c$@Q5d4sA|3mumpfnS2^ z?(Sj7|NH8u$zL6yJRf%%*H!JpFTho?wJu&N|01f2zT|jaRs4F#*Za@t9MIjun=XTG zE`d~CwZr+ks`3B8@w%!4cEi;(pQEbCmoA-D`F(>bUB$O9;?GnEe&^z)3hE!I(&xXU zD(E+tUYdk&#MZ5fH$jQ72%Mn3oR3tKt2wG;PIX+WjM}2AaXVD$I-sgxvhy9CKMPg* zb5P}z=6H9=OKys%4M5bagdo zdQau5SR=3h6Ec0IO8yk8ad-t)JvO*_sr*J%={7mtjPeuMs$Whua6hV%|IYCrQKkRM>CdP>Qq8b>{8D^tHmKrHLsgMv=Q}xnHp)*R&G{&*gP}pvtHoiH|{#LsdWvRHw$%P^C{rRiWOf zK2qh^$9XBfBG8wB*oFL3%d=$uo2r7wxb#v5CpuqORdBB3|E`R`fD+_6o#YZq+rV!| z)#BS6m#U%*P#w3>@&6qS=90nfE(57DyaUyc{N4GxT>PJ@(*MK7OLg2m&Px@4FB&py zu3#ILU5eFIddNjDNA>ydsIq_5rLU`+0jnLCs(+qwUaE4RP0-2325MCapCf@r@>Q2` zGpd4KcfJPIN2-k8a9*li;cZm;>~LJF+rzF=Rx5_TRzr|6^M5 zf1m)h^mOu-CObXDl_S**ILrA81=#okT^*>a+8fg0>Y*MkUaDEu4^;t~F8%^kyW$8J zpN;BMS2d+4I4^ zeWZup%{cUKhUUbfcQdpi_|$zzLmhMI-3+~>p`JMOZiae+&!KlS4!xUk=-mumd+|B+ zZU!BptFA-uX3z+QghTIU{QvdcjHCbSyBX$(yMtxtop;f&RlFe{0hE<@^aR|5h{hZ#&NYc6$BtUvH`TcI}sA2aG>r{l@pdUOq7A)#5G7 zQ?Gey`8~ncgJ#>3V1Kh=NwA?wzAxB67%|iD3tnud-3Qny(7?36AJFc8z`Xkb4b2XL z?E>AG0**3smI7uk1$-`$WV$W`q%H$2S_U}A>=W24FyH||W3%u9z=8(=zX&uj{T>8l zJP26+AfTD~LExaksD}V2m}L(EmOcb%xEyej8L=ENd^uo^KnoLj7?AKVpx|LZOS4*F zmB2}l08TY|j{tHX0c;j%ZJIp_X!0(fQ%;r%bx^vH9rU(6d3gsAk8d$3b6DkK*Lpl?qc=K@)#>+^ur=K+hJ2Mjj*1ojFH zcmXifEPMg5;03@h0vDTpYx$M27O;FRV1)TW;Gn>$7Xc&9vKIkMUj#H<2N-2WtOE>R z2UsI8#zbBMB)kMDcnOegRtu~WIB7i~$KlTG^#!Ha|WrczR1b|7Z^2BN!fB)Z7V*$9}u5%9S{vFTb3NUa7e zss@yreFA$025bV9n}wSI3pN3kzY3UYes~p-@hV`{X25i_Y%}1XK*QGnSC|p60hVqC ztPz-DB3l5%Ujr0u0aTdP0ts6HC%q1+GltpOyz z0l3~we*>^VV5h(w(|#*p+8cm*TLCwi9RlsP0=mBmm}lm^3D_?1xxh`P>o&mbHvx;b z0jkVCfz)k)0dE03v+ymzUV&c(=9_+R0~WjmSpGJ^m>&c(-Uf`?4p?ZGZ3i3_Xt)D# zhZ(U0uyi|Mjld!kc?U3j2cX~`z+GmwK*BqKlimd^HhJ#?RtantxW_bm50LvVAbBTX ziJ86=(DXgPPJ#PP`}Z01rKVD{%e@`%|ddDQgS zjjS;J7~SAwW})2UX20YK)9*uMrCE%a1-mIS{1HVyWwJg3WPAu%DX`iE{|PuK5c?5+yrb}Ki zHIfac{XS%)sYJ}Qy%f1;A4P65ojw7y+XtBc31G9?EwEjn_osj@rs`9`>`wp(1Zqr= z&j6{P0+xIR*lP9*>=hXLIbfSv{5fF3XMpe*fVWN77l4e<0V@S|nBbRyg95QH0q>d> z0!zODH2w;((`0`I82%+-y}&M$v>%Z06`*`SV7FN-uu7oy*MN^q@z;Rd{eW!(drZr3 z08PIJ%=!lKv8fT*AkgJoz&=y?EnwO=fIR}Anob7*?Y;%fKLGgL>=xKA(EB^Um!|4F z!0ZEn0|NU^kM9Ag-vO3<5BSFH7uYK>^dR7XS$q(%;Cn#$2f+6x>jyx_LBL9ZA58E^ zz(Il7kAR=d3W23R02==k>>v6iV8;Cv9A<|92w5-kTfiLsGbG_BNcqnk6f|pp=Acyq zt$zX3GsV9Ea(@PF69}7@zXF>60+{tH;BZqTutA{9Z-9uY{0%VeSHK>D2J<_G=#bxn z4d>4f_2>6)>~^f_9mF4Hs)C`5=g$t&8}dn}M~DQeLBNs_;25)CV6VW?dVt1eaXr9- z5FlJ1(8Ofb2V~R(tQ2Twf?>cxfmj%Df>|N3v_7EmVStlN_F;hGVZeHU7AEO%K*C{w z^1}fw&02v~0<9AOr<&pfK1YmXpzyX0yrbk0S>Jfk?4FR3aeu2FLLyrV> zF^i7`ENBP_9|cG;Sw{gfjs&a}=xTzE00#wPjR0w8g}~CI0F9FX-A#59V0a_IdVzG4 zbTl9#2~d7Cpodv2uu7oyF@RpC_!vO$(SU6Ny-mww0Zoqq%sLj(*VG7X5a`kv(9cvh z2248^ut%W3>2w^RU1Pxf;{XH9Zh`Fry_*0oG*wLivyTHD5Xdq;ngUXr0G2cb3^w}( z_6iJb1{i719D7pb3pD%fNcUX)3ODiX>-7=7J!MSMqq=)Q8Ftin*+$?SdSa2#J+!`>|WVHrlv;wRYm~Mh?00#wPZ2(u86#`3J0~)sl z%rMz)0mIt>)(cdaq;`OWwt(_>fJ(DgV3k1Y_JC_laeF{+JHR%9S*GP_fTryMvrYqC zZ)yZK2z2QHm}4qC0H&P=*duU*>2x}vT?fGY(*g6$Zh`Fry^{eqnW|*K?9%}U1gcDr zGXSZ{fF)-DJhNY5ufWhV0rSn`GXV?E0E9aNjLGT<$T$kZk z+7ZzBEWjd@eHLJNC%}4vyG&ANK*Cvo^3H(8X05;~f!1dO?lHw@19Ce9wh1gTExQ1k zo(-7Q1#mzAmqLII0$t7lEHjno0H$>T>=Ag-bV>oVI|neI|8H0>E_MrS7wDY|c*Int z0%oTG4hXC;J-Px?Qvpl50voperEEKZL9cjWj^Uxd8r;ApHxC zZh(UVv2K88%nE^}{QrTN#@zvHOm=s`@NR(h0?(VIC?KIbpgam#Yt{;^5@?+cSZ9jU z0l87YHi7k~<#~Xn>3~`10bVgR0viOn^Z;x$l|2B{&I9Zb*kn5O1hne`nBNny+3XhB zF3`IdV2i2h1(@9va6q8O^f(`o+6%Dce85(-Utq7m(B6P;W^r%8g7X34K7hAPRv$n{ zZ@@}{9VXZpa8MxD7x1oGA+WR$pm7FZr^(I$4DSnAFR;rb^#dei0LuFTcAK>Vs{~qS z0zNXunSk7WfNcVMOw0a&rkQ|Q{Q)1F8i5T0T`mCZGnE$rru7Hx5%|<}8USc_0bu?B zz~^SSz;=P&0|8%}s)2yn0{{mE_M09T0#XM8mRtz<#_Si^D=>5r;DA{?2(aKnKsXEV zy~)Y~WDEkV6!^geF9IACh+PEu$*d4qngwV)IK|N3^in|M(SVao_GrNHQGoRV zElkoFK*DH1`4~V;vsPf0KipiP?$d~|FDbUpfa{&hhV!41cvqE6$L_p&_KzEa!2N<3U zSTB%nk|qHX@&M(N06olFfmH&nCj)w!;>m#ANq}tvy-mw}K-0;9S^0pzrbb|cK$ikQ zKT}x%n3fONBhcS;Dg?AE0L(803^2O|whQzw0$gaSiU6|<0S5%KOphsm)FQx=DS*Ld zzrbFBp~ZlqW^plK!4yEa1aPs*Dgk5^16B%*Fu_v5L4jB)V5C_gu(SlwxC}7LWS0Sk zmjc!cj4?^&fP^wYc{w24tQA-#(E2h!jw!wjkXsJeCJ-|%rvjQ@2ADM!FwxWqY!K)& z4UlIlrvau-1?&-+Y&uN`w3`N)KOInDb_;A5=zTe$$W&bpm^~eEK%m(4xB`%RIbg{Z zfKszxV6VW?D*@$Z@s)rDR{+8@08>rY3_!+}fRzH%P4FtfL4nv+fGf-jfu%D5jVk~% zOm+oe_*H=Q0u?4{CLo~#P(Bk-Y1Rs?5@=lsxW*J$0&-^pwh7EKEw2VNtpv=v8gRX- z5!fKmmqDRtPMe z4QMnQf~$;axKSsozc7Qjk@)h2i=;GjV4 zR=_i6g}_n|(0D#zjme%57=9~Yy}cP1fI$?Pi%|hY8+=ykka4 z-Zd*E@0rLykewzQF~jeokoEtdkXmI znyUK%vzGu42<$gK?gyma2Uv1H;2X1FV6VW?rGNuw@lwEo`vKu)fbUJ#GC;;sz)FE1 zOz;7~L4nu|KoP|&P>h=W!M zv|bLVXNs2tavuV069}7@4+EMm2h4gHaJZ=v*dWm55kSOLJ_4BbFkp{B1JmhIK)Xi( z^B)B?G`j`13-n$AILcJ50L*?Aa6ll*^mq)Ax&pA|F~BiqzrbFBp^pO^o5ha<7CZ(B zKLKcBvYr5BJPueX(98r^0uBnqRsv2iD+HE40ciXr;3Sj%Bw+YTz1J8W&Xp;!bW!$<4_MLrUhv(n__R+IS zpPAhE-miZ6b;#E2Z{Ip+d)AAmUpZswCG{S^oqU3UUyss1#HxQwG5)E4S!~eL9Xn1u z?daIK->wMmx%%nuOU|rHd;R2j-P=?id1>VryMAqaZLqRnefu|GUo`y6Umkj|Eb`tZ z&pbB!rx_g%UUti^+aKbOA)%(G_p`M3OjGqN9WeVDI^cjnC(~mMAoW?mk~M(NX1~B* zfuYXCBPnm{-)E*fOhKv^IrxGFuMh|3-o>kaG|Ms1u*+%zyX0Q(_;f5^%cO9 z4S>OBzrbFBp&J21&Ek!K1see2YQV)Ns~V885wKEVgb8i}9NZW>(oEPC%G8yQz|v|` zG=7y7qfGXzfZ>|}>jlP`q|JbYR{`al0oi7)z$$^(uK{vQ@oRwG&46tJG1GDjpy_LX zSz7=TO^v_?fiABD@=WFHfN5I*djuw%PBnmbuLI`S01C`*f$ajl-vAVusy6_$YXAoX zicOELfYdhtOSS?^&3=Ks0z=;fl$*tG0v2oqgtq~vnyhVrj5h%*1*V(eTY!TCv9|zM zm=yv`w*eZz4VYoF-v$hS3$R|G!X#}6B)knM-wvoWYXw#bwB7-@#uV=Ws~9Nc1g&LDvy1G`l3&EJ5Dy5G*$RzeCXNI)c*@EHOF1M-cQKg7M!YSZYp4 za6p3MKOp$TjQIh<(C-m^FTn~EdILd$9}vvEf#6efO@eb0RJ(~_wV8es!NeN~evx3U zsq`a)k~a}7`4Pc-^FV@|5;VDmV53=h3&Hz8BJlo%V3TS16M~wz5Nwp-a}#hI!4nBO z-$t;-td(HdPYBZAL9orVzk{IJZ3O!y*kMxNMUdzYf@vF~*epTbdkFTJ{`U}c zyNlqo1p7?R`v`*WAsBxj!I$QQ1P3H2{s6&2Gv)z;q4yDdFTo)b`Vc{Z2MA_9L~z7h zli-{L)qX~B%uN3o!Ni9Mev#mWsq_dz$)6D{d4%AUc_6_}37Y(Z;Ivuz3xf9_A@Kf+ z;H+u*D}tK8AlN9uc@yv$!4nBOKSprDtd(HduL#mVL2${me}bUdV+8voxMEU2MUdzT zf#h)Sg(TsV9 zVCe4%zL(%96Z!{&0?!c4`~$%qb4`MC5>$JR;GUWO9Kpmt5d0#+15@cw1SOv%Sn?-= zpUndaZX%f3B#@=h%!PrJ#-F%*1Gs+7cjf|{&a4?oVd(m)32<}$gzL_3u75Xcxi-rJ z5Tp+bWE~V}Is^u?4ss*eC&{0ICXEM4qCg~rJa`H)yF7T>EJ0o`fcWE3``X)%hJNivF>YchgOsdN~{%ybzc=0_Q!rc!#0Ff&_5 zxOpHW!qm!uQQRz)5ow;vC}A3A#3*S#kx|M71Ywjm&1IA^Yh{!*i8Eo8Gwo%RH=oO> zU{YtssA#&&sAP6wn9Z4#(JW-6is_$48O^MWN>I(@^eLlRlu;jo8s>xq2P7z-6+taC zCM$xWJ_O%O@QMk|hM+)J1T(WCsB5lCa8811*%8z?)3YO(m<_=%5;QcGav&&~9l;+t z5HvEiaw51X!KXP9G%-&lcs~b%*0};rqVYUC&$|_)&6=WtA@4<3_aq)PsCy?Z_ZpeC zVS!mpx7>kWyVoS%R6b8&X?Nn0{KkcMm_<)8WAX)Fa9>Jq+T;(M$K?J;{=kmjPc!k9 z+@?x-0(%B1sN_AmzusLz&Ed^^NhRl#Y!!S+t(J8_>5`uR;BI`C=7b=*In&!1t`k zGg*<72kG<}*tbt{%m@7VB8eeEjb;rG^mxbd?w#~jg00w0#YmFXpe|us;rN!;_m^77 zUfqLx4D>%H`7Up|;Wa$bn<&Yfes4ER2Ku}YniF)ayml%bSR^3%N~A$(=kLfb(&g&U zSDfNG7ALctrk4-Q7?^X#Xv!1ML1X;2;m=9ufrRC=7}kgbZ$ct?X}wK$kYL@EGQeyOop6}*p#P3U{#OT-+T}hw)Bqig&FmL z^Oz}Om$QQEC6%Q826TS?_3oVq)T$g{D&z?~B4Luw1ABGv^Exlrt+r`Z@4!WYED{>_ z56qu558q=+On6-z2W&!lo0argg98(}leE}WZ(!gTZf}wn0siij)GA5i8yZ+3=?dyv zg|@l3@JrZto6dkRIlp8x6plhbPUb9%m+qOty* zYZX5sT7PTM(KUuEw_oI1XZuqG`EA*HTc+PG6|iL+Y#Bc?&{quk9d zc>`OPi0cqrwh5Ucrbt|&woI?QSAr>aefiA#`@)tf6MCVR{qKQcw8_t`mbVmyFM)xk(& zz4;Tvb=daHSnS%PI#Br^v4whnWGjU7h5|bCaw(N$jmk(KjC|h{b7OM3ovSmNovI5AG+Ok`= ztRS*)lq&x8nFB?l7R@IKt-m|AUSY2I!l3o1&mc&z2=Jvo>o4lQtyq*xy_!!&r0*ms zm%+ebX8k3kDCI{zL@!F!Um{zk9&*tRFflT9IrWgswk!oQg4CDjT~};bYGnM2(ns)I z*KJ{XB(g@pceYF)SCCb6;SF1s5t#yvggeMo8kuc9bwho4Nq<>v8DCL#y@gCASu{W}11u#{t<)E=GD`d;cBWq&IieM^T z72q{nR#e|Fkmrif%oY~IRPHK43tJXu%PJ#lY0LC^2nARLTG_HlTUHfWYg^`gKB5}3 zPPR;+l29B`)%mYK7plXum}vHbf@pX5f6DN^M68Y_9yjhfS?kjYp->0`$o+wc4h(qK4n8woL6ro?F2s z1}XhDw`Hxd53wZvwj;eZFcj3d)pnGawlEB$BveC@VmlZClC`mA?Xi!vWo>QG9k_O0 zt=`_&>xk^2x(k0DY`sp{57{y`JjKx&4kJ^q>a6-#YP!HlTd}LH*cDlMIr7)dmUY8E z4ZVt(-ECQS?0sy%J&?)T1NvjBgxMFFg6RnZZJ8Rp64OiVPw)D#!i8Eq|6IKxmqOuh zu&vk!dmdXh#Fq6%R?wEIXDC38mW6DYdWK~Ep|C9*Zp#KB3z1CqKf)HWT6f*Vu0M4l zd1hH=eW^oTZ4@%K4-HV4Y`th(Z!ogU*rhkdmZ=?_u=VI_R(NU$Td}MAjl;Cw-K&PM z(N=uJRveDZ`5cV8q!OdH!TR3ne(I8vscnQ)zUqE&+OkpDo$qf=v}N)qJ@vFnwv5b2 zS>LEZX7y(U7!8w@P5$1p6~|!LdQN}(W{vd5!fVLX{ifKmaoC&MdP=&QA{&XP>^ufT5EipEx)f=nMJ=!E&cEt`t{jIB2tnKJqgOhnchbFQs7 z4f{}J>KPv*Q|6~bv@M%&`+XN#R62ycuq?7YzlS{#nf?~riZihPj$MBr+j=vxs|eLV zm)f#f*j0j(Ewg0?`**hAPi)!y$gX3jAxF8EV^L0K!&O`HQ(N%^WX47*BF-A~~yfobZ0D#~rP@MG*M zRu$29TecLtidC{5wrm-8eZWgO--%2m^9gh!V&!tTt+yPzs#po#W6M@xSIH=@dV6i* zN-kC_6#n+vvQM$=>tKp(zb#vZy(sevx@|of6OX_;5=NQ!Z9Qqt$hMxKsL5PU zfvNBg=$-KGpgnYej-b6&XXpYd>yMx|Xz5c2w6duOTDfQiqG7NxGy#oZ8gw+sw1ifm z!KDqfRTt5ost^>0B2W~9p%{cfD1<>cWP;3)5E4ORND9dy6{Lm-30behHrNj1L0@Os z44=anum!flwghyM?O1leZqUYU9q79meW4|^fws^NI>0j;$k)`hJ_ou9zJM*T6}G{4 z&>pTiaDw1!39Xg4$_15dihLPGD8;dK~~5H*&zqygj`SzLLd~vK%2q{C=N9! zPIbIQZ~|*((5R;Tik^&l8!W?LFnA^w#%Ba0HIRF*pnxVKaOR+X#0%e1d&BtN?wl^eO0V`%6H- z{9XuptG`|snFD5H--thb#7LhJFfbk7g_#hoHq;%9zDckL#l5f}4#HQk3BG`}pmE?6 z_!u;hXmr%jtf5##Z#(D+ouD&xfm($73LMA&I&Ddxf!GfR;2=~>NE@n-r4H1EdZ4dr z`~lBFZ$S@$r`Yx8hhKotc(|^CJ_m9b^nI3r@Hz~F!7v1dLNDk9`Z}z3#XUefVeNeT zKwk~B{h&W+>-#zkh9O|!eOM3rbZ{5w3LT*caGK_73a>&<(wYo2Ih@3P3QofrI1A_C zJbVKepbXV>88b>Bv|9<9u~y+(6Nctry(>Nq=$F{~^1vzh8cxF*I05=%fu_{YF~5La z*muB6>~CQHMtF0u&xH>`pL8t+>u@^^t5yG+C^Y+Mvgrj{<@SYs&=tBvc8V|uWQ5LC zhxYmUWY~9@H{d87gX3@l-h#Jb3QUD}U>Zz^cVPz1gjoqpg3g{andV@h3m?Kfm=6nJ zp$YBm$=E_)(is7xpfhxVuFws-Ll5W)`bN@Ycmhx1H@HX{Tml_AT!E`_4Zelz0cKuj zPv)qfuWuO3fJK(Xl0>y`lp3-aFw$D1}?x4a070_ zkFW)H<7Yg~!=B5{Fu$G)Elaf07zBf%2k7%G-QiCnUrh$zfM^&C+GV~9+A(T_*aTh! zZ45Q-HaAncc(O-zz}gWyK^M@DNxPw*&x0OFpdIq>l*w=K9efWzz_*~yZf^bj*xm4p-eIK;sWzb6a2|o9a2&L+ zJOz4x)du(sHo+Fy2HQdV%z2m#U?IE@?}5Ji+ZNh^_Lz;JF*JdupwG$Gf~xwyn7&b` zcdcpfm>aZT%m>;dYEP&=U{MGL?ft?a8)Sz7aKoPz>3w(r58)U16&{1OhCjkjZ~-oY zwt-h5>Nx+M0IegnZqzza>%v{2wcsAu4_dMv04-{@dC_LYfObpT9ckO9Pbt^LUK^@I znLv()K%dm@h1nbWKwszw{R3SITm!HSG@;!+WdhzX-Mf26n48@_J|2|_=;0|ArEkz` zW7Z5t63i$V4f^VDG>nCDFdinrJ1`Rrybs#IeFzI+A@IRuSAWO^`h<33NCwFv1$e*< zKhv5X=_{4LV!1<;xd}hQWYA`8ENGL~4z9tspuN~na2vGWIt%BZ0_=n(@G&ffW$+0s zhZV3AK82Yu97aJaHP6;qnnMd{38|qBETe$KF$2K^F3?`<4%~+C;3|9#r{ORhg@Z5` zv^ji@oNAl219rkL*bUky6^1nG%{qL)i7+Mnp-u*OiSIrgK-&}#@a zpfZ$%f^a7wf}+Nwj-Z#qG8hZ`;!Os~2tkkuGD8;dB{pq(drC+3C-C11MCWXsp+5|Q zXsAi#b)YWf0i9qLh9b}vIzc)}4?*ydINt+pFsFbvm3saBP~sQ{!(jxBgs-R#&gr6D zC$MaUt*{E#fIikf7jrR8foU)Ubmley20}B?(OMm-3;Ce{6oKa?{t?`QZ{RYVgOi}` z@m|;m8+1Oaz4j~^O{#Q))C3xV?8QL$<#Z5~1-lO(lcU%<)K>Q$&$f>_^MRfj~QUC3Klz`%?(YzyQ!N(G#?s><(?A4YY!m&;lAmBX|{RfC@rq5_O;! zRE0`V29iJ|6o<5s29iTEND8SSwfap8EGcb4QOwMc5z+&dXWd7XJqR*^53)c($N~8w z8{~tmkQ;JyvtXBX<)7Y#A%gNjd%4d69s0!^VAG>6up zYUu_Ypgpt$RgdJIp(Atx>2!gv&<_-z^fl#3H%j%{8+w5v(w0s#*Aj}32d|+S8F1h0-bD=6~ek`GsXqB!7uo$HDv27~A&tVg6gblDB z)|pX*JQ<@_U|kNMz%p10_LC`p%BzA}YnwGOo#yZv_RXNeJ_RS?IGlhZa0tGFgP`!X zU@9zyc>wI>q;P%7g_R!6H74s|PnM`1ShvGA*a~sevmcqf90tXsc!$9;I0{$cSI~*q z70e6p4V;J5a1MIHSvUh~M3>{gc9%= zVkc0E_#J)&B|`qLg8T?C8TG)Q*#GFrf6Bpg_!0tfaDxj1paxbcI*~c0rRq(CdumYb zQemcq6rh8nWRTRho76)+RZNbdp2Sh|rgg98vW%d0uns_l&cr z3LRSvhC!fnEuC-mhcZwKLLmf-KmpJhs?JigLUzK;4Lh|LJ9j?JyQp<5fBbq;449;Aw+k=lp{r29onK? z5wk2*0JZb-nB{DAT^V~Nr~*}?8nghFPD{{YU5oZQ@Cww1T2K>`;9q^EG4@6vl*y~I+6C_x;OL!Wk{_+nQ;=MglMGgiP;WX zLsVP-YXcpiJ#>ez&=I;oXXpgopa=8=$@+rY$3WXu-RfGU>DWhLciO;k>_fn5FT=32 zy=h~4^3b>fVKc&oa1?gKE*K40N%aoQ?XV5D!WSU@&tM~Lfb}p2*1=j>W6F)-9AFVv z1-k&|!~0-h7R-cqU@WN5Mq@^Sf=LL9dR#2~RP1lSHRN)eg8glH3nsw?7!MQSO_;1U zE+utzd7cIe_=+8XWX>ox1N(dME=&gv7T0V&`Inxfa}~QYfG9j&%alLIF7tPdXmXeb zb73}I!$FQ8V3(=kRXS=ib1=(bUIn>-XzTpRwHLc&*KBwBk)C5JGr!x{iLfhySJlQH z1;>nCq#D;H*YJ2XmaY<|vD@(@Q`Hh%M>18LWQtsVoYGWD$~{WOsiM??e-)enos_P^ zU2>-?R@>K#+?g00KmW#56{z_sO!T9yyHWOqB~&pwMgBSV#WBi`C+p5tY(I)v?b?y4 zt;_DTC)t&A=_x}yU+7Z)ay)|I5bT9LpgP`%xgQR|mv9iif*0cxI)}Ng2SM011XaQw zI|ClB-E`gnaKWEkEAr>?3v5t#x(k26Gx!~Tf*(OS+5#$tO`u}C0KdUgSOZVsQ+Nz3 z;a7MBD_}W%0zbn;cmVg{4%~*N5Os_HK8Blc1Ac%d@I8D7AHj9_7OufnxB{2q5~zAE z!Z&ap&cYdpJ%*g-`fE4^Cqd)M2{@+ukKOguovu+*S0N#Gb&=zkx*mrqSzNm#`(Nfc z+n+UI+jceRX`17#h-{$~NbH6q*>q6xD{@_{Ivo4Ewmo*e$8ET(Mn_-O>e#LR@APpA zwH9-(ou!a-{lXJEN`%@-T$$QVT$vK@$kf&xyUeKj2%KE2xMklEM=5sEJ0+vm8#^FJ z9$OY)mx~=1aYg+l5GNsVO$F)%=0u=esR26Ij_KskNstbm9XFY31HU1wf!|iDe;vVI zh70f-!ef|6-~jaDdJCqGQFWZEW7egx1Qx?0&?)#_mZV{$h9?QP=&LemZV%4@GcnhnWuwVAnkk9WcEDwV@VNhidQ&?&UCRV`|N!1IC)z3t{Gl zl#mpXKw`*>P9jWavyvQpGRT3SsO}>SQu4q=8hRyFl4Mi>g+j!y}#N>Etp4 z^u%vQ%-ADh17!7}F6dr>j^Z*yF316G2`4*dJ52mXS@%W@A}9d)Aur^C;V7syWIFaT zTo;GZPzp+d4x%C<3_>9Uf}tqr*i~nM@}s?Tge}uSWm%}|rv58nDG%jPsDfD;bhua% zYC;XrPDUr3x)IY5>O&o<3-zD@NT)HTPD7iKd))(Q11+J2WT2zD*3b%uq2E{a-v@d? zcjyeApd)mEZqOCFKu_oeyb!_nw_NDMKD6z|8*>&9lzv`wH zVY%vm1ws|s23QMgU^S>4uENwgLF{T+k8GVS{|s{@d;y=sCfE#(@T&$FyEmv!`3D{U zwqz^UuW9~Q(U!$jf35|sp$x1c0jl{Ztv_O>g+C;4M&3%^5vP8|aA`6n08;Sca2 z3>3J{hSwo87pWi%1VKj7eTejs4$?qsND0Xy8F+zzRv1aKBnFjcBFqG!DFVZlP-h=< za0GGfNpKIL_+q;&u-Mm1WC~>bvl8r>O0;8lOeIowCv#C!N*hNg1qG^H$?hmSdUBIL zxjPX%I?|6_YK~4O9OUNc+5Vy|WqFWeHvTIFhsbdfP{Yj0bq*McyGkb^Rpe+ZUfC~gU8Fqo1RgK&^M0wfOwxjAy# zOMwC`ZJUiSbyrSz{u_hjuR=p;07^hTs1J2j|8?LMs0B4a0ak_@P#vm4Rj2}rs1j6! z3Q!)(fpQ}^`IB31P$Wu>>~a&jPt^hvP$Dv;WEqI1EA)jv&>gx!XXpg&p&e+q))uoh zI1O+MvNl}n1T{BkozsD9ovcov`ZTU+9H@oa5qSvmZkURXIHIgb6qysD?O@4!#wc3X zJ-Ftdb;_-0F`R&UVR!sHGUqyWcyZk(XkLn~(2s!n!vGitLtzN0K@P%v9hCEuBw{dj zA@?R+ORk1Io$Jvs5#E8R@CJ;7F)$Kz15H&wLjTF5{;>{GD3Z6kdpBDR00YMew)v&R2;Ql=a@ktiS` z&#KcIpgMKx@;&S?t48^m2~O!aew_qFz070mR6CyK>1FjVHzinqSYNcGxm?7T2sO+( z5cL87#crWaBq{+VPDMByMu29v_rV`cOhieMB?b-8i7*pD>aCxvpg%ghOx?4nqb_LPxNifO7=& zHKtN2`x#pBlp@ggDLJ&OU`aax+d+-3B!Y}YUJcFO@>qoZiS4`QZ z_ZXgl^nU}#FFLhfT)2q*PaL1aA0W?8pzkR2;BIoL1tA59`j&^r+&dih!R2q z@Ir3L3ArFYG2;$q+ZehdwqzV80pDf2~$`~nBtSHS)k89b`Q2aYwvepI;Lyn$0%$zyHMb*U>7iaI_FpZiY6-6d`snki!pk<2t3sXo*+ID z;ZH<@*PBhRTjcarTO-`R%}s~j5u+{~>zeM%<+cmSt87|-Kq6klE6pdmM#A2OI+V_S z!d9U0dYkDe@J_uI7)7U`mqvPjEbJKE;7%>{LV`nr!-`vnugP(_w4&;icg(s@ZeA+) z-~&(2fG?`Py`Ap z)pI*O{rZn@e%fGXs1yy?1bpZTFWwpj70J4)TW6gMt5^?(;>wAC37-O&Rh>1Be`UWSz(c>|bVY<)uk2aOU3R}rlzi{bUL6yPH zWs_5$Ig_BDJ3!B?r$Tar;FDt3esZvv_uk^hsRHzXqMB(bb9x?yT+8I1?+MS+h+$VD zgjV<{@5phfGZVHNFJZSb{pX|C)$Ev0756jsmwPf~qh$`qhe}{%g4T1&y}hK5<%4== z32TxsK=nOyWvM5Vskp$CnU@K+MC4n6AN8&*pF~|*bz`FoKM|BCCzKl#m}v_hOZB)C&o{gDJd_rqa{2T}bLinolLHVu~%osAsO} zs-^jTp{HUt8(6O3_WyR0caU=S{GsZ98?1Fv@_u zCN-lL5mGu7GNTY|))GzHNw)s|y`%cgJ$v|+J7B1}gu@HH3a0-^Z>Hiir~s8z(}rKy zZT;}zHNqu6l~fMWrT#E)`MW=5NPluXE+zf#tEj2F*pn&pa}<>JKY9hM>6fc2ZO0mp zXn+?HD;rOK8_{idvl&a=0sD}so!w4m<}UUGWl2iNindepJ-g?nT;O#F{ECK#uuSHd z0*^#Nv4u$$+DA2MLnm?4F;^pb4 zN=b+QdCFBxnzAGs^l`O|DYz)`6U~+%uk~pD_wInv8Z#MGN0~bcJl+zryxQg9-kaQ% zT|#;6qqtNa&G$#XdaL%++eAWFRx)avzDpQrY!AK*sr|WcFuK>)i)+`fM6rZFy+5Qj z+n0F40(zSVOK5c!O@)scMqZ)FRIJyYA6Zo(BKiC1tA0s+JG1L!PsYFy*9enx7u|-D z%#w@wM+IH@^x^?0dai2~ zquAA?UFPZPzMk2PTt*IunAOYZLT{Oa%RFOvr(oZD-b}s;j6zCNxu18g{VG-QZunNg zkkP|gP4p*}aWOzHz)qM7(Wx9v92DwXa)_=l?dMLZU*}m0j#@eml9K3>pYMPW@ zuw8Z(ne$DVCVY-V8K(bf1j@3U3|m7_c)(mUZn>v!mcIw2aOkV9*5;?>)aEBSO@bAk zIzIgbLT!28ge_H;{gL8hT99URV!V>e^jSe(hns~fsLhn--U?>vg}FI)M8DJ9pS{-o z;=H?d3dzFDN4%7#+)C=~Mjn4PWO$yd+K$zyrdqiV(+Co7`lAr}eO`Y7KI-jVGdb}) zswb8qnxwppOviVGkPd#D2YG`QO?p~+Br>k!c?`x-v2GJ~^ zY4s_6vVA@?_)||8ch7w0GCp|MZ0c2>y6*n@O}kZ|pvadr5^8Txet!|=yilx7{x&&p zSVd&@jQ$18D*4@3z+bNw+B_WmTb23h5^9Ykd_OK~QMXr@TbOQRlLEF2#e1rNd4^xR zp}M;jG$E@=W&eVv_G(h+Z@-c8`VUi^3NGZ&@cm5_r_E0Ey#@t!eO%rtWDYB+{RK?7 zHJ&i{;zDNb8YYjIghg7=tcOM%A7SpkMa*%@M;9@-6jJ4)Cfi!NOLEh5ErZL;XWX8} z%!0M#V!S!E)>GL1N3mJ!JVDueQXuqz=(uZ=Q~{QY$+_N>-hDj8)LZAt;Vv9%`mOU6 z%3Yissn7h~ljAbpY+L6{Yw65S>pY?E;4qVIy(h?PtqshH8Y~!ktoP(1;ZxR=@B(xj zg}G|k&u_l^!P(2n{|de9 zltHK7p584w#-&h%3EoJ3R*o<=H&Q*x&4`VjaQCnhX3a)VA@>_4%*BnK9QJ7Fd--U1 zs-y|~j53J7M>FJwKPzRTKcllHENyP0=}uSL_%>k{E^QiY@)YtGFU_Q2Re1T@ST#ET zy@DN=c&jT!v)s$8YZ9UUyXu-%+Vt5>f%c?8wcMT8tn?Z8o{s(kwPK04A}yDh;btp- zeXH!ss5!w^yU5aJ?^#7|X&eYQ_Z9jTG?<2>r`=z6xccD3xnnfqtw_sn>IhT*b3!jf zPUZLf?~nHp7bmHMZ!B1850OdjgnTI^^w;K(nujrnSKZ_{;u=1OZ-w4;WN+!(~ z&j;?jmCdRxG|Y&~eEFAVa;l1Xrt7;^%+#Hjsj8Zgt(a4)nVnZL->GEQT*SOm&5V}( zQ8m+VhbLVEO(q{yGTF8x^Hw(%Z+Oy~t6M!DcfRW8_;ZBSs?XYn(WtsvAf0yAP1zlo zeXE;#l9Qf`if?pvGj^M&s(V^>b6}gNbiCmou3_$9A$NB;bI_*ps|>%TPm=P%X@BlC zIVGxTdMTE?HO(8tc zT)G5I2gUuNWblL*A5q(E-$CCVWghHcp5Ip6BvXz~)HeBcdcq>(Sxbfnv#W}4Evfm0 zX6y3TLYVLG`zUAKYv;(>eOT+c@RydZU2^V%^-P)ic~Ug`X0&8St`Y}v^HcjrN1OuR2wu zTJ?u98Z~iAh0EZ^MZ9^Bj-MLi(yXZ|zn`|$g}1ct_uO>%ZE7li$)vUsA1dr^Z$GM@ z?%puQLMOKUP0chk+$Wovy_k_NoBl#vshaz1y5uRYk^*&xoL++9h1xD3BPo+;EyajOK}*-2;K@8<>^kx zW0j{3TEKFXHM_MM?$z9^Qs{%x&_qxyY%&mPjT0b=H{7H zKSWi>K$E|n@Y930%5Ww&I#m1m5ZB7)CgdOq*=r|cQpZ!%K1_S;1D(*Y)*&IMaZ!Wb zR=nlDv%lvqZnZXR-FvyY8GVqVy3yS1tmzGMGwB@Gb)OcqzM^NoWK&F!7-ho0@`U?- zYGM6eFZ%tD3*CAALzkbdwrGW%u%#LM6(MD7X+FdB#k(1|S}j9fdEz#{L!Qi$X*u0Z zOH!Br7(KA$m128hYIP|t>KKXpmfe4=;Rjo+(hQ4ac~Pac>2-)A`g>xW7Ez;(S#XH% zH>Hiai)Lh_w*Ih|A8&p-$yaHnSe?vD%zRuF|GL1#%d#eG_HK;Jy0)h5VKxFRV-K@q z?Q__Zx%i!S{@Hd+nS|%Qh@4-~Dp*RLGkaXr(#sv}F?#+t_n%wgSOw$v??2sP8GP82 z-R*5}k{zLmr*3cZ9kFX8*qc5(b$6_TzYQ%jLFpcj>0QW*fl~~+vQ>3KZrb58JaLqC z;Rws?M&_3zp1Qs>9sThaDsdsfhJ?SjjftNnM!)>tF!%M2X5~>LwN2k^j1bykmaP5N z-LN^Chk7&$TW7{sI+?4|yw%Bs-1h{TG{-yE;x|lV`sHnqT z%yTr|SGt&bd07P2KJJOI7eVf{-Ar&QZyi1#5H-x3!TfRDlhvKAn^}{JHWYD!#Zm=R z{{+L)%MYwtb~kUFAQoomlP74KZ};%0ICi*2|eNNKY{#S1Ox&Hmy%^rh0UEN1X=~y_t zgsVy~vlYL-dcFL+htK*Q+F9xOG!D0%9c#B<=Ke{RWd0H=G;5OAYqp&7^z?m>mn0TKP?Ef&r2Kkl|gofY;_w(*p6dtKX4UuRq{@FkiahB<$-5_p* zp)n_6s-z(^9)E@g?Kv#ClxqwwMQ|CgAm^h&2U^YWyOhM`(?MqLS)xB<`yDx>WdDS{ zXY0_^@*7&>@gQ>?jmSiU{Ud0|>I*-;TQ7YsG;}ymZREj42j&BQx%%1aZdHG$BI#iz zDS=9ZO}2CRjeoH(&tKw~Afg}C=sRwke@miri9&CEy*OzSwckj?Rzdkf%?#vlF zK(>zuYYs6B6#8&9I2MU+yYYF6IoFS-kJ0#)TouG+*GJJA`t@#A%yJ1+@Qa3+y9)i7 z?f1){YX9-Y`AcJBG#(EzsodW5UQ(BNs406M<;p|-i;{EUTQ;5Smd$M`lhF`Y%b}(p z8j)|I!NF1VmEw=?KTVzIUQANf;=;L4bfwTCAI>X1oxuIse{JMv6rv#0X38#Mk zUh!Q1q*z6f9~bR+o*f@rXm6Ui8)E!cA7+w$L(2Nweye}6`fo@4poqVHvEnC;L zN{mKZTyo*}+Mk{0P1rtsQH;x&;pU=J7H`9{a}9o$(#c%ngds=zt67gVAS`Crtmt>}5}4 zTqcY#EAi`FhK9d9NbKCv{sE*{wdilwh1J&h8WOCQ=UOq^M57V;85&A#)>dO){nj;jHyYYU zpm7!#HN6_;5AJgxTvy3*v1Y)_QRXOq-HD_5nia7-u{wK5J9WN@asED-BJtHm+3s#> zO$aovaPIAq&EwyZy-H@DlI!fFooxN{p7!f;CI`D-x9bfv^#&Qu_lAF%shN1qoiRI? zWvm?LC}XaK)4PMR_?XcD924VEubpJLtH&|6@lStMaT`a;}{uIN5aM z&b7S(bt>O?mFqv9$l$T6L}wbN&9?;EV3HaBttTw%O*~iJN36si*Lfg;u|!-KIfP z4xAqS7avx|+^J!Lf244n%)dCWD4gd6~47h}{GJ5|_dxO}@#-Ul+Fuyt-?_u%G=m)vQfXtnxuK z9Vz)sf3kAaa_Fq*f6b7J&X<|RkEZzCSDH3$*}pHx2mbjZ+(}OSGYm^BYdEulwxjnQ z=6F=|+~c_^uT9we)f6i%G)uiGmUx?!rIG9d|CIk;{;2j%?$+}!3QGD1))xcAUy7yO z9MkHqb}yaGle^52Y%Po2V@DRVxBK!QH%tAG9+-6ZY4!H*)9uur&XDce^Pe44)K-JC zj}?9S=kdD%a`fQf#*S5k_v%q6YjzEHy*|$zW+U5U9U2_PNB1m~YTnk~CGtBOC0uFd zTfaDq{=Cr4toJt0SmzG7hc5S2qhFraD)`aDXGZTqM>EduKipq}Y$n3H%{TQPP=Efl zZ;IAwvmP9W=1d=bO1``mUg%1#gc;<+?Av<@GPoSQ&)7ybH{6 zG$QjZ@Yh$f7UN#q9KhEfUxZN|7q&0apH7-{VP~WMoD>nd)ztjWDDvfP@#QVw=~GUh z8^XhB^s&f~iA?LkZIfqb8+rPRbpFU9sGF~F(eh}$H)Z1m#mWczUDWi}4mEe>_ko>I zUxtDmE?+%7$7tOaaBas>g4HtHDCk4~@v7 z3;khiX<6yrUDFn`eezd-ge%^4KYok5Sod$2-}u-4D*i=;s{BSxOnPmcX9%Z#PNUkt z&?I|A%5I~fs_S-l&bUhBit6sT)$Af%X%?A^Xhc?8#IJ48m=!Q8-4Ac?dy%^cS07xm z;nE>t^4Xou>-NS<3&QQg%vAY(8x6%@>qx_ft$t4ZYE0NTb8)P9~f-JbqNj7GsFW{pCxgNEwcTjfy5nE6NE ziO~pRH>2Z$d)p3Q@7=9K-WZpvBg}L8jdwR?)!6_$-tEJ>Y*@d%%DEW7bC#Gok4f21 zG?ezNO+MSS<&}d&Vl-|nG0|xBh<7Jug`WOnf8U7gmivRJ`%l)1@!JfS^n^Nb(AK=} znhATm11ccVO88$dy4?vUo5&~rO_vr{zA4rGhghSwHi|B@>&;j@QC1K0(2QrzdWBfE z66yN)4W6|QiAVmIMO>^|HSQ|o-(34@FZY+jrMBNcxw?OSMoNgo7ai+66K1@36|70m znTVV;I19swaVEv@OaqR)J%+|!Az3Q`jh>F*xPBbD6Na;Oa>nJj?#{R!NB%$dgN~*> z&ze+!a9`G0)7sJg=OvOln-j1d#=lzm-g=@+c}`H z6CD}vVpaE)LtegsvojR$E;a6&*&2k1>~9^`k;PfY|I?sjg`>5ilOe~9lQEUL6Sozn zGXVG}y9^$ypY=)b*P3;F5Q`q){Kp0p|Gt5#!`dWS@$T7S$|ociC!J1fv9DkH%u$Hz z{7$nIpS}vs{Wswj)~)}Ix9V4KT6aIJ^E3NCk^9L`lOhqCiFWyq1wWdcZe;azKWd8i z-_dZT-(}hqBo+SqMx1J+nTF0)HtWSAzN9BvK#gYD)^T0PE;CJGRX{@%T*&BZzZL2< zA+2tY`0rcU_gvhKcbUs*Ms~L~cjO44^w!N)U35Ryx-sAyjZ136aQVVoE^k|tg_Q2J zawO<_XO}6Gm{>kUBMBN6(@hNsO23&SZQW3cL}TeL(=M^Mj(f{4vkFZ&w_FY+_C`nU zvwdXvv`_Mhxw_A`CLHUTpl12}cW>XBU8CE>EX%bh)Ey?4_{Vmc(Mh~re3$U6dr;B0 zz8Su;-La}@ST{;ST{m~lN=hV8cbUvdx##EEZR#cUc6o8TH}h_DT<&>xo2do3edbQ) z&Fl`}ZL%dJg%x(2UdeE@@5PyUa*Tbu>BnT=67G7tO|Il@|f_;=})pV0tq!r8ldu$bNqzW_df}dDhK!vsi^_J$O-K zzgd~m8y#zN`nMa8kr(i-J5k=VuLQilsCYEKRY|mokT3n=CYn?w;g!XU%30xBE@i$n z&$(&ojyhn1QhUR=b^A(cZ&&xP2h0X8-AfK`x|!M=8Q>m&$mB?i-qb^;bXtmf_8~J7 z)A!LKf5;`PbzamVFe3+vVH{^tX0FwT%>A^axXKYTARR$9JYqhUx#^hsCLKOs@>q6p z)~m-&<@Cf+;<%Z{V`%Q|C(T~W$a1IrRp=VKec6HP1GIObdX&E!xFjRzA2s=C`Rqe2 zbf3dMAa8Wa6v;rkc_O`f23j4Du&>HMm?5Xlw=#JSJwry!$TOyPM&hh?#=NiVc4y7u zjNYIuJE5{w}p!+j+xA#8|XM%#f5$;FlOuZm{2b?!^gYcdFyg9DxU(cIt znTS2p1yeE;rOU&xnY?u)3tsYPLUR!znlN#cmBk0t42HV^S!@)bx4=%{myH$eQaxTUT&BFfvn!lzLaRCA|XHIE^&GB)?RGezFU5m z0p6ZJ+^jf_qp6VKNEV~KCTo}3n!{T)$x1Z1j;{HWNs`lB)!qFk(;%leD9NLrcy9u7 z9ugRk(;FS%?zB7Z&aZx6G-t@G{7$iqCFW6eiQ6>0DJN4z!J*95(lGrzV?`Y8c^bKWyW za#NrW?wR4ay&HHEqF5ep_=|@iM&_Yf{&9BwAI~Mse&CMb@{xd-Hg|F z5&GsaPU~jh$)=~jz4CC{47=gb-x!~B@rcSlKg8m@-qGLBo}I1juGaXdo}{&h2zy1K zq@~gdfx+itekJ{psaSyF!2c64J!tEn{KDLiADP{Mb+P?MR{GW7h<+Yhd%|1e*S=v@ ztTi&cyp&_DOokSG5pR&WT#(8+N`M+3dQTaZ;(CrRG+{FY>A>`xUro9~l%T)FGMV;; z==1p>n~{Ymv9QPfr_D<=@80FX!r)*YFb)p29ty4X*sMV#vLhPWHh(zURk`(|1wCRk zM&qJw{J{i;$0v9xA>F6Ipjyp3Q8g1{$OR>;MkZ+%nk`SoChZw_ytIEVR%u1QbeO#z2Y znh@^??nMD+RS4OhZEMz@y}iWsByX?MOl-{uyxr4;gpx>n)DC4vz87E)>zbcx{18eL z|3{yuPM9}yBtM+88qCw=xi+S+xZu7!;8RF5@!R=+%QV8 zDKGuhjFa$#CO3Y5bD)1cWUU|DdCc)J644!vv}jD7`$^?1rFZKHOBrRP8R;?E!U^N= zzuc7q)yk)E%&X!4>6PD_xNqb!3-I6`m%uD&;Z0{2l<|7peBG--DTM11n2N1*ivxcL z6PSM8yy$B6fDm9JKXrIvREaMFd2sYay=upEGnu^`+ge*vC zav z)gSkZ5}7<5yafW&1r#^+J9slCaef55ERjhS>8%?0S)u^bu!A=v?tLS@;kKIpDyMsG zVskZ;i0nuGOyx*#nm8(?p+gC8p*T{f79J)s_e*;VC2>-2%S}j0Z<@G5r2@4J?p-O&qcZ=cM4Z(9Ef=xt*=tq4X}Hdl-rOzgP2}E{$~-B{P;@wz8D5UTt5<4& z^9?)n>bWu1y0_rLPi=^0JE3dH?E#sKRHzO^Zqmn@s@_YrhIC6Cc-87>;v zjzm4)vY%)yN2xXh$MWB=NPwER-(HktZvS_e^2kq^?UE7xEzA-$PKi z`m2}O^s7X1EX!!N%ltL7saQGYI&wpn0Bd^^Tw+@BS3YUnDdx%OJ-Fx*#=iBkz1MA| zw|b1ri7X}=Vfe1vemi&i<&R%B4XqNRVaF1A4~^7>v9a@jieFxt!LNe~`IE(CL;hj+ z$7^k_+})X!C6?oo#%HD~^uJetqmjpF>Qo~Sp+0j_niU93Tdc%?rk)zyb2K|vN3)*K zq^d$?wnifr8cpBn_vVnurp#hOV)HfHNpKu*BT zq3OGThHCN52j>nxzIKnd6F3?-^O|Xd;r=DBxh+k1K7Z#;*)e6cH+N(i8>5*%pUF{! z0i$p}GqDCcHhx=tv<5r22KXpU*sSdC*I-`$$DbTTZpa^C9h{9z@@uCm_ddUF&D^}@x+WF4(s^@=e?he?2u3Dybq?X<+tm(~apQG_3hXUqNP0D3c0WrW$EE&gTUIohIA zx^YwXppXesO5>&^u3lXCm!zg~Ix_QJ2V5VY3B zuJT3A*LA&x64ypUJ*r$)!1v2X&pIdiL(Z^*DmSI@K?Pdu^r=8c8ZW?TbmyLHt&Q~z+7$Q^~Da} z+MW1I_P-S2nJ}}Jy71i&3$Shk*ef`9Z#b zaQ{YS>*FO)hketWy_~(@a%BoPZ#SXt`Nj0dP5y00tvorc&L2mZY0$#^_ccDj?tSgA zl@V`w+ll|TE#`iNdDhh01Qu(?8#c-m_b(lIv4&Oss?AlWxEbAy>^bIN z6J5YG=on9J#qCG&l`L!LvCaQedHGlNR{P_}$MLliCvi^vcFp>_mGFdIpL&!N|IZ~%vQ~r=r=|Ui^u$+U|2Zx3Hk3GN zafX`zZo1I-jzFMXHQ*)M7jh?)*ZZS(#r#t=Mi_RXTeYfI0n^0%A&L&|P#g^!+cRzSDf-#P7`D|M$ibCz(zoaT>;dZvb{# zI{ok84&08n|KBqDFV`^t_YD5?^!oop1;6CHlQpO-rdyBb>23S(T7Rq)(I8*$ask#6 zeS-6s=f2e`{ot4t#Q*#F{-4M6*eQ!Uue?~F#%Zk1EM^a1ZE`y+yT2dRI4*h3mOiWt z_LL8BC1H*2dwbS^s%`GQqWenLyGdNnN}2n8*g$zIm^{4n#GSf=X(p5R(Y)Q4Wmn_JUj8UXqZ}@IN!O*`&2LW_SGIkOONUCP6@Gm~(9khJ=)KUxMRu(l8>2Ce zr=S%23N+HA(ecKxBS{v_=@X-|({?#EWd19!?SB2|7?;z$ctw7nppgT=_v$z8)?nN{ z-U;n&@`Eb-8_SvS=xbAU)_5bvCA_jJ(w|%T`_RzA&AVoDse;G$>rqZUYQhA?t%n)? z*--uc1%KA-`Phn`!EYM;o=d#=Zt7=Eyw*C+dY8z}%H~;r_B;>J(7l72+gk{o(KMont{Mu40TI+pzUsf}R@#{N*hHi9~tJiN>*73W` zqQQ|Lx5L73SDQ5ug_pdDtt9QJx``ObohR-zjg`r(SB}d^&g%ZG%$c2Md)@bzJ|ajS zk5*obRyUs4IdG_0-Sm2$dAfdeGvRfXyVgr3GntdGbDybgb#oV)n_Jhp24V8h$ZImY zRX3AmPN{CT4`MTy)YKnNSC~y?+JB}`wRX$!clx|fWO{K4m9nh5NyY;-_PYsRJW%7l zTivu6Oh8Yno2hb7UBfKXb(R|DBGBBNk^0TwJJ4vf5NCdFyT3d(gypw@>21)T^GN3^JacR23$C)YJfP{u$;csS zpJuxdhR;)neQm1+44(=s8YOkAr47R`1aEcz1Dw9#MBkw+ONYLRB{`%+>?=SVD(B{s zes|X&sRcXDm4db-@v)$xP?R_0hRfWR=3r37xLf){(yIfuWytli8c6ZE0=BU$!iYSB zuTl^clUjsi4^ zI}gYmg{>}rZyB9{x3p%UyIJ_?4t3Eslny9QcR04|j#X>HiQtx}&lJhC&xv~`y32-> zshKb{jvAfxbHTfz*Jz8 z9U4izAfp%q4(gMA_Fs&hn751`>%s*^eZm_QYEkUtSM!(5PN!LTas5&s5Ze>2uay6< zh13{%JhG3|Yw7B5lbW*pR?dPhnz;g9#ObA6Jsx)%d}N8XwjheMKtd6NI)$X!CX@vI zoYG*05k(-~+gqXm#SxT6{w?F>uJ$!%%El-%Y%OHBgM&`=RW4qqu0M@KxWpt|2g+bj zyaFp@jMjFnnQ|eDBtur-F1Fhs=?WhGlnpR*yo@3{sCGsvSk}HSG03~(_IWdh3>2z; z*S_qeuD+vM&6Kf9(nV$c!9gRJ*LF%>o5ns3F>^$ST0b2$)`uy4u+vOYDarI)Se7Gl z#5%t1XXob7W9BGRk~DBAc8l#BtPU)Tv7d_kAf|qw6lKe%Js+7=Txl>tNXraYC;ao~@g)GN+dYxN(}C`q2G2 z5&#a?GoD1PgTG&mC!0`LcqRyQRo?sKReueUsUaa=yi-7-{`m0usiEiG-w9qvPXy*d*IPerk zNe)0(ZV`W;1Ne7R?H2LpIV|GOQ-HtcddOPDpXVq8Le#P+7258dGkQ*&E!(XmS&)@m z#GjW1{zs^Gi}>>#7V+mPz`vJj&rTMu-6i!!n(ISsu&2$>A-KBFCzFXAfIAlQL|Wny zN+m68Ldca3X!XBo!}_a*Y267WUCn~eMUza~_;h~8;LqodP!oARmT4h57!t^aA)sMGol!a zl>rOkKWbQkIT5SVO#|nn(5DIW=@r?Wnbp51A;QJ`EqdCGnVR~oDWAI(Nx6ixi6+&8 zDlAL5FQPZ9|GK9_Visf?7y2OAEob<{JSE1)M%4&!Y?hd8-?E&XqrDXSKyPVm3oxGF z1d%|LNgubb6!y_pO)2fA%t5q5=g|aBvP!MRi;dy>%)`>XuceG>Q1q~rzU!tr6H$AJ zwWDuz(bQMC7W<`>jslFbOS*to)ygvyRIMCEX_9cx`U5;zzf=-b$j$OF>HauAVjsyb z`M77(r;+=G2nLwMiixZU$CW=G3V>ztMcl;xzi!~@;wcF=kR3%_=+alHQhZ3SPhj$q zd4rySM*Yi_ulz&0W<^~3QcZ&7#D%m0+ZM>uUswzL?Gc&PU(~ugzeb&|%4?k>Y~MTh zc36?HV$Ln6_>OSYvbmt{ZDVNIp6#g9W*=yCRnqv++G|j!OT_N4m4%7HGv%)l*>^|% zO~ssP_Dy>lV^wO;Bn{rdKYF`;bQ`nfdl|#O+~(2aAd6Ex?0ShhHM^v}zEb|}Mu#`3 z)90dQ=5VEJ>8?H%ZjPk8nDckJ?jd+;-ekYajLx=KZxF`g_FHQ*Zxgqj=ERVS||2^YC(`v)mU#*8ks&eZOq?! C>ef8~ diff --git a/components.json b/components.json index c8e3a67..057cd68 100644 --- a/components.json +++ b/components.json @@ -14,4 +14,4 @@ "components": "src/components", "utils": "src/lib/utils" } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 1a0d501..2d3b61d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@sentry/nextjs": "^7.93.0", "@t3-oss/env-nextjs": "^0.7.1", "@types/spotify-api": "^0.0.25", - "@xyflow/react": "^12.0.0-next.5", + "@xyflow/react": "^12.0.0-next.8", "bullmq": "^5.1.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -41,6 +41,7 @@ "next-auth": "^4.24.5", "next-themes": "^0.2.1", "radash": "^11.0.0", + "random-words": "^2.0.1", "react": "18.2.0", "react-day-picker": "^8.10.0", "react-dom": "18.2.0", @@ -50,11 +51,13 @@ "react-wrap-balancer": "^1.1.0", "sonner": "^1.3.1", "spotify-web-api-node": "^5.0.2", + "swr": "^2.2.4", "tailwind-merge": "^2.2.0", "tailwindcss-animate": "^1.0.7", "uuid": "^9.0.1", + "validator": "^13.11.0", "zod": "^3.22.4", - "zustand": "^4.4.7" + "zustand": "^4.5.0" }, "devDependencies": { "@next/eslint-plugin-next": "^14.0.3", @@ -64,6 +67,7 @@ "@types/react-dom": "^18.2.15", "@types/spotify-web-api-node": "^5.0.11", "@types/uuid": "^9.0.7", + "@types/validator": "^13.11.8", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", "autoprefixer": "^10.4.14", @@ -5663,9 +5667,9 @@ "license": "MIT" }, "node_modules/@types/geojson": { - "version": "7946.0.13", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", - "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==" + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", @@ -5750,6 +5754,12 @@ "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", "dev": true }, + "node_modules/@types/validator": { + "version": "13.11.8", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz", + "integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ==", + "dev": true + }, "node_modules/@types/yargs": { "version": "15.0.19", "license": "MIT", @@ -5997,11 +6007,11 @@ } }, "node_modules/@xyflow/react": { - "version": "12.0.0-next.5", - "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.0.0-next.5.tgz", - "integrity": "sha512-lwtt2jDe9Oyq7GCHQ/A4p/RbqrvqsBcJzZfhYsOq6TRPK7/e9LAyc7trR6Tw+f5U02H01jbYUcIsfH1VWgOzmg==", + "version": "12.0.0-next.8", + "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.0.0-next.8.tgz", + "integrity": "sha512-Jdy/0wv10ycxwQm5rESWN8Psp+FTipbIv4RTIJwAH9zG5AqGp20ESi/k3oxJmAsbQHIcGgjB2RlOhxBs2qqJLA==", "dependencies": { - "@xyflow/system": "0.0.14", + "@xyflow/system": "0.0.16", "classcat": "^5.0.3", "zustand": "^4.4.0" }, @@ -6011,9 +6021,9 @@ } }, "node_modules/@xyflow/system": { - "version": "0.0.14", - "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.14.tgz", - "integrity": "sha512-dmVQujAwZyoSZTr0sQHlgro9pS+RO9AgjT2BDlyB7t/+FYQBgW3FKdTQnVh8/azcdAncWruyiPt9K/h2kpTYrA==", + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.16.tgz", + "integrity": "sha512-pVWaBHAE1Ew9acmNGEdsVLNh8Z+TEBbsdaIojV+SDbmolYlCQ1UJ6Sse4k+K3rr7kgX/1GRsiEcWxOFIx0wt+w==", "dependencies": { "@types/d3": "^7.4.0", "@types/d3-drag": "^3.0.1", @@ -11626,6 +11636,14 @@ "node": ">=14.18.0" } }, + "node_modules/random-words": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/random-words/-/random-words-2.0.1.tgz", + "integrity": "sha512-nZNJAmgcFmtJMTDDIUCm/iK4R6RydC6NvALvWhYItXQrgYGk1F7Gww416LpVROFQtfVd5TaLEf4WuSsko03N7w==", + "dependencies": { + "seedrandom": "^3.0.5" + } + }, "node_modules/range-parser": { "version": "1.2.1", "license": "MIT", @@ -12149,6 +12167,11 @@ "loose-envify": "^1.1.0" } }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, "node_modules/semver": { "version": "7.5.4", "license": "ISC", @@ -12720,6 +12743,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.4.tgz", + "integrity": "sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ==", + "dependencies": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/tailwind-merge": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.0.tgz", @@ -13274,6 +13309,14 @@ "builtins": "^1.0.3" } }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "license": "MIT", @@ -13480,9 +13523,9 @@ } }, "node_modules/zustand": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz", - "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.0.tgz", + "integrity": "sha512-zlVFqS5TQ21nwijjhJlx4f9iGrXSL0o/+Dpy4txAP22miJ8Ti6c1Ol1RLNN98BMib83lmDH/2KmLwaNXpjrO1A==", "dependencies": { "use-sync-external-store": "1.2.0" }, @@ -13491,7 +13534,7 @@ }, "peerDependencies": { "@types/react": ">=16.8", - "immer": ">=9.0", + "immer": ">=9.0.6", "react": ">=16.8" }, "peerDependenciesMeta": { diff --git a/package.json b/package.json index 215a2b6..42f9e30 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@sentry/nextjs": "^7.93.0", "@t3-oss/env-nextjs": "^0.7.1", "@types/spotify-api": "^0.0.25", - "@xyflow/react": "^12.0.0-next.5", + "@xyflow/react": "^12.0.0-next.8", "bullmq": "^5.1.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -47,6 +47,7 @@ "next-auth": "^4.24.5", "next-themes": "^0.2.1", "radash": "^11.0.0", + "random-words": "^2.0.1", "react": "18.2.0", "react-day-picker": "^8.10.0", "react-dom": "18.2.0", @@ -56,11 +57,13 @@ "react-wrap-balancer": "^1.1.0", "sonner": "^1.3.1", "spotify-web-api-node": "^5.0.2", + "swr": "^2.2.4", "tailwind-merge": "^2.2.0", "tailwindcss-animate": "^1.0.7", "uuid": "^9.0.1", + "validator": "^13.11.0", "zod": "^3.22.4", - "zustand": "^4.4.7" + "zustand": "^4.5.0" }, "devDependencies": { "@next/eslint-plugin-next": "^14.0.3", @@ -70,6 +73,7 @@ "@types/react-dom": "^18.2.15", "@types/spotify-web-api-node": "^5.0.11", "@types/uuid": "^9.0.7", + "@types/validator": "^13.11.8", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", "autoprefixer": "^10.4.14", diff --git a/src/app/api/nodes/route.ts b/src/app/api/nodes/route.ts deleted file mode 100644 index 8ab11a7..0000000 --- a/src/app/api/nodes/route.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { NextResponse, NextRequest } from "next/server"; -import { getServerSession } from "next-auth"; -import { authOptions } from "@/server/auth"; -import { getToken } from "next-auth/jwt"; - -import { type Edge, type Node, type Position } from "@xyflow/react"; - -// const secret = process.env.NEXTAUTH_SECRET; - -export async function GET(request: NextRequest) { - // const session = await getServerSession({ req: request, ...authOptions }); - // const token = await getToken({ req: request, secret }); - - // if (session && token) { - // return NextResponse.next(); - // } else { - // return NextResponse.redirect("/api/auth/signin"); - // } - - const nodeSize = { - width: 100, - height: 40, - }; - - // this example uses some v12 features that are not released yet - const initialNodes: Node[] = [ - { - id: "1", - type: "input", - data: { label: "Node 1" }, - position: { x: 250, y: 5 }, - width: 100, - height: 40, - handles: [ - { - type: "source", - position: "bottom" as Position, - x: nodeSize.width * 0.5, - y: nodeSize.height, - width: 1, - height: 1, - }, - ], - }, - { - id: "2", - data: { label: "Node 2" }, - position: { x: 100, y: 100 }, - width: 100, - height: 40, - handles: [ - { - type: 'source', - position: 'bottom' as Position, - x: nodeSize.width * 0.5, - y: nodeSize.height, - width: 1, - height: 1, - }, - { - type: 'target', - position: 'top' as Position, - x: nodeSize.width * 0.5, - y: 0, - width: 1, - height: 1, - }, - ], - }, - { - id: "3", - data: { label: "Node 3" }, - position: { x: 400, y: 100 }, - width: 100, - height: 40, - handles: [ - { - type: 'source', - position: 'bottom' as Position, - x: nodeSize.width * 0.5, - y: nodeSize.height, - width: 1, - height: 1, - }, - { - type: 'target', - position: 'top' as Position, - x: nodeSize.width * 0.5, - y: 0, - width: 1, - height: 1, - }, - ], - }, - ]; - - const initialEdges: Edge[] = [ - { id: "e1-2", source: "1", target: "2", animated: true }, - { id: "e1-3", source: "1", target: "3", animated: true }, - ]; - - const data = { - nodes: initialNodes, - edges: initialEdges, - }; - - return NextResponse.json(data); -} diff --git a/src/app/api/user/[uid]/playlist/[playlistId]/route.ts b/src/app/api/user/[uid]/playlist/[playlistId]/route.ts index 1049a3c..180ea16 100644 --- a/src/app/api/user/[uid]/playlist/[playlistId]/route.ts +++ b/src/app/api/user/[uid]/playlist/[playlistId]/route.ts @@ -1,4 +1,3 @@ - import { NextResponse, type NextRequest } from "next/server"; import { getServerSession } from "next-auth"; import { authOptions } from "@/server/auth"; @@ -10,9 +9,9 @@ export async function GET( { params, }: { - params: { - uid: string - playlistId: string + params: { + uid: string; + playlistId: string; }; }, ) { @@ -36,7 +35,6 @@ export async function GET( ); } - const accessToken = await getAccessTokenFromProviderAccountId(params.uid); if (!accessToken) { return NextResponse.json("No access token found", { status: 500 }); @@ -70,4 +68,4 @@ export async function GET( }; return NextResponse.json(playlist); -} \ No newline at end of file +} diff --git a/src/app/api/user/[uid]/playlists/route.ts b/src/app/api/user/[uid]/playlists/route.ts index dcadb58..861d786 100644 --- a/src/app/api/user/[uid]/playlists/route.ts +++ b/src/app/api/user/[uid]/playlists/route.ts @@ -4,7 +4,6 @@ import { authOptions } from "@/server/auth"; import { getAccessTokenFromProviderAccountId } from "~/server/db/helper"; import SpotifyWebApi from "spotify-web-api-node"; import { env } from "~/env"; -import Redis from 'ioredis'; export async function GET( request: NextRequest, { diff --git a/src/app/api/workflow/[id]/route.ts b/src/app/api/workflow/[id]/route.ts index 155bf64..bd53ee5 100644 --- a/src/app/api/workflow/[id]/route.ts +++ b/src/app/api/workflow/[id]/route.ts @@ -1,8 +1,11 @@ - -import { getWorkflowJob } from "../workflowQueue"; import { NextResponse, type NextRequest } from "next/server"; import { getServerSession } from "next-auth"; import { authOptions } from "@/server/auth"; +import { db } from "@/server/db"; +import { isUUID } from "validator"; +import { Logger } from "@/lib/log"; + +const log = new Logger("/api/workflow/[id]"); export async function GET( request: NextRequest, { @@ -12,8 +15,9 @@ export async function GET( }, ) { const session = await getServerSession({ req: request, ...authOptions }); - const id = params.id; - if (!id) { + + if (!params.id || !isUUID(params.id)) { + log.error("No id provided"); return NextResponse.json( { error: "No id provided", @@ -23,6 +27,7 @@ export async function GET( } if (!session) { + log.error("Not authenticated"); return NextResponse.json( { error: "Not authenticated", @@ -31,12 +36,15 @@ export async function GET( ); } - const job = await getWorkflowJob(id); - if (!job) { - return NextResponse.json({ job: null }); + const workflow = await db.query.workflowJobs.findFirst({ + where: (workflowJobs, { eq }) => eq(workflowJobs.id, params.id), + }); + + if (!workflow) { + return NextResponse.json("Workflow not found", { status: 404 }); } - if (job.data.userId !== session.user.id) { + if (workflow.userId !== session.user.id) { return NextResponse.json( { error: "Unauthorized", @@ -45,5 +53,13 @@ export async function GET( ); } - return NextResponse.json({ job }); + const res = { + id: workflow.id, + cron: workflow.cron, + workflow: workflow.workflow ? JSON.parse(workflow.workflow) : null, + createdAt: workflow.createdAt, + }; + + log.info(`Returning workflow ${params.id} for user ${session.user.id}`); + return NextResponse.json(res); } diff --git a/src/app/api/workflow/[id]/run/route.ts b/src/app/api/workflow/[id]/run/route.ts new file mode 100644 index 0000000..56d1a74 --- /dev/null +++ b/src/app/api/workflow/[id]/run/route.ts @@ -0,0 +1,79 @@ +import { NextResponse, type NextRequest } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "@/server/auth"; +import { getAccessTokenFromUserId } from "@/server/db/helper"; +import { createWorkflowQueue } from "../../workflowQueue"; +import { Runner } from "@/lib/workflow/Workflow"; +import { db } from "@/server/db"; +import { Logger } from "@/lib/log"; + +const log = new Logger("/api/workflow/[id]/run"); +export async function POST( + request: NextRequest, + { + params, + }: { + params: { id: string }; + }, +) { + log.info("running workflow"); + const session = await getServerSession({ req: request, ...authOptions }); + if (!session) { + log.error("Not authenticated"); + return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); + } + + const accessToken = await getAccessTokenFromUserId(session.user.id); + if (!accessToken) { + log.error("Unable to get access token"); + return NextResponse.json( + { error: "Unable to get access token" }, + { status: 500 }, + ); + } + const id = params.id; + const workflow = await db.query.workflowJobs.findFirst({ + where: (workflowJobs, { eq }) => eq(workflowJobs.id, id), + }); + + if (!workflow?.workflow || workflow.userId !== session.user.id) { + log.error("Unauthorized or Workflow not found"); + return NextResponse.json( + { error: "Unauthorized or Workflow not found" }, + { status: 404 }, + ); + } + + const runner = new Runner({ + slug: session.user.id, + access_token: accessToken, + }); + const workflowObj = JSON.parse(workflow.workflow) as WorkflowObject; + + workflowObj.operations = runner.sortOperations(workflowObj); + runner.validateWorkflow(workflowObj); + + try { + const job = await createWorkflowQueue( + workflowObj, + session.user.id, + workflow.id, + ); + log.info("Added job to queue", { + jobId: job.id, + workflowId: workflow.id, + userId: session.user.id, + } as any); + return NextResponse.json({ job }); + } catch (err) { + log.error("Error adding job to queue", { + error: err, + workflowId: workflow.id, + userId: session.user.id, + } as any); + return NextResponse.json( + { error: "Error adding job to queue" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/workflow/queue/[id]/route.ts b/src/app/api/workflow/queue/[id]/route.ts new file mode 100644 index 0000000..3f19f50 --- /dev/null +++ b/src/app/api/workflow/queue/[id]/route.ts @@ -0,0 +1,84 @@ +import { NextResponse, type NextRequest } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "@/server/auth"; +import { db } from "@/server/db"; +import { eq } from "drizzle-orm"; +import { workflowRuns } from "~/server/db/schema"; +export async function GET( + request: NextRequest, + { + params, + }: { + params: { id: string }; + }, +) { + const session = await getServerSession({ req: request, ...authOptions }); + const id = params.id; + if (!id) { + return NextResponse.json( + { + error: "No id provided", + }, + { status: 400 }, + ); + } + + if (!session) { + return NextResponse.json( + { + error: "Not authenticated", + }, + { status: 401 }, + ); + } + + const fields = request.nextUrl.searchParams.get("fields"); + + const columns = fields + ? fields.split(",").reduce((obj, key) => ({ ...obj, [key]: true }), {}) + : { + id: true, + workflow: true, + returnValues: true, + userId: true, + status: true, + startedAt: true, + completedAt: true, + error: true, + }; + + const workflowQuery = await db.query.workflowRuns.findFirst({ + where: eq(workflowRuns.id, id), + with: { + workflow: { + columns: { + ...columns, + id: true, + userId: true, + workflow: true, + }, + }, + }, + }); + + if (!workflowQuery) { + return NextResponse.json({ job: null }); + } + + if (workflowQuery.workflow.userId !== session.user.id) { + return NextResponse.json( + { + error: "Unauthorized", + }, + { status: 401 }, + ); + } + + if (workflowQuery.workflow.workflow) { + workflowQuery.workflow = JSON.parse(workflowQuery.workflow.workflow); + } + if (workflowQuery.returnValues) { + workflowQuery.returnValues = JSON.parse(workflowQuery.returnValues); + } + return NextResponse.json(workflowQuery); +} diff --git a/src/app/api/workflow/route.ts b/src/app/api/workflow/route.ts index 88601bc..247864b 100644 --- a/src/app/api/workflow/route.ts +++ b/src/app/api/workflow/route.ts @@ -2,30 +2,46 @@ import { NextResponse, type NextRequest } from "next/server"; import { getServerSession } from "next-auth"; import { authOptions } from "@/server/auth"; // import { Runner } from "~/lib/workflow/Workflow"; -import { operations } from '../../../lib/workflow/Workflow'; -import { type Workflow } from "~/lib/workflow/types"; +import { operations } from "../../../lib/workflow/Workflow"; import { getAccessTokenFromUserId } from "~/server/db/helper"; -import { createWorkflowQueue } from "./workflowQueue"; +import { + createWorkflowQueue, + storeWorkflowJob, + workflowExists, + updateWorkflowJob, +} from "./workflowQueue"; import { Runner } from "~/lib/workflow/Workflow"; +import { v4 as uuidv4 } from "uuid"; +import { Logger } from "@/lib/log"; + +const log = new Logger("/api/workflow"); + export async function POST(request: NextRequest) { const session = await getServerSession({ req: request, ...authOptions }); if (!session) { - return NextResponse.redirect("/api/auth/signin"); + return NextResponse.json( + { + error: "Not authenticated", + }, + { status: 401 }, + ); } - const accessToken = await getAccessTokenFromUserId( - session.user.id, - ); + const accessToken = await getAccessTokenFromUserId(session.user.id); if (!accessToken) { - return NextResponse.redirect("/api/auth/signin"); + return NextResponse.json( + { + error: "Something went wrong, unable to get access token", + }, + { status: 500 }, + ); } - console.log("Received workflow from user", session.user.id); - - let workflow: Workflow; + log.info("Received workflow from user", session.user.id); + let workflowRes: WorkflowResponse; try { - workflow = (await request.json()) as Workflow; + workflowRes = (await request.json()) as WorkflowResponse; } catch (err) { - console.error("Error parsing workflow", err); + log.error("Error parsing workflow", err); return NextResponse.json( { error: "Error parsing workflow: " + (err as Error).message }, { status: 400 }, @@ -36,36 +52,35 @@ export async function POST(request: NextRequest) { access_token: accessToken, }); + const workflow = workflowRes.workflow; + + if (!workflow) { + return NextResponse.json( + { error: "No workflow provided" }, + { status: 400 }, + ); + } + const operations = runner.sortOperations(workflow); workflow.operations = operations; runner.validateWorkflow(workflow); - let res: any; - try { - const job = await createWorkflowQueue(workflow, session.user.id); - res = { job }; - } catch (err) { - console.error("Error running workflow", err); - const errorMessage = (err as Error).message; - const errorLines = errorMessage.split("\n"); - const prettyErrors = errorLines.map((line) => { - const [errorType, operation] = line.split(" in operation: ") as [ - string, - string, - ]; - let operationObj = {}; - try { - operationObj = operation ? JSON.parse(operation) : undefined; - } catch (e) { - operationObj = operation; - } - return { - errorType: errorType.replace("Invalid ", ""), - operation: operationObj, - }; - }); - return NextResponse.json({ errors: prettyErrors }, { status: 500 }); - } + const job = { + id: workflow.id ?? uuidv4(), + data: { + workflow, + }, + status: "wait", + timestamp: Date.now(), + }; + + log.info("Storing workflow job", { + jobId: job.id, + userId: session.user.id, + } as any); - return NextResponse.json(res); + const response = (await workflowExists(job.id)) + ? await updateWorkflowJob(session.user.id, job) + : await storeWorkflowJob(session.user.id, job); + return NextResponse.json(response); } diff --git a/src/app/api/workflow/validate/route.ts b/src/app/api/workflow/validate/route.ts index 5504af1..34bce0a 100644 --- a/src/app/api/workflow/validate/route.ts +++ b/src/app/api/workflow/validate/route.ts @@ -1,30 +1,28 @@ import { NextResponse, type NextRequest } from "next/server"; import { getServerSession } from "next-auth"; import { authOptions } from "@/server/auth"; -// import { Runner } from "~/lib/workflow/Workflow"; -import { type Workflow } from "~/lib/workflow/types"; import { getAccessTokenFromUserId } from "~/server/db/helper"; import { Runner } from "~/lib/workflow/Workflow"; +import { Logger } from "@/lib/log"; + +const log = new Logger("/api/workflow/validate"); export async function POST(request: NextRequest) { const session = await getServerSession({ req: request, ...authOptions }); if (!session) { return NextResponse.redirect("/api/auth/signin"); } - const accessToken = await getAccessTokenFromUserId( - session.user.id, - ); + const accessToken = await getAccessTokenFromUserId(session.user.id); if (!accessToken) { return NextResponse.redirect("/api/auth/signin"); } - // console.log("session", session); - console.log("Received workflow from user", session.user.id); + log.info("Received workflow from user", session.user.id); - let workflow: Workflow; + let workflow: WorkflowObject; try { - workflow = (await request.json()) as Workflow; + workflow = (await request.json()) as WorkflowObject; } catch (err) { - console.error("Error parsing workflow", err); + log.error("Error parsing workflow", err); return NextResponse.json( { error: "Error parsing workflow: " + (err as Error).message }, { status: 400 }, @@ -37,8 +35,6 @@ export async function POST(request: NextRequest) { let res: any; try { - const operations = runner.sortOperations(workflow); - workflow.operations = operations; const [valid, errors] = await runner.validateWorkflow(workflow); res = { valid, errors }; } catch (err) { diff --git a/src/app/api/workflow/workflowQueue.ts b/src/app/api/workflow/workflowQueue.ts index cfb0bc2..f72d022 100644 --- a/src/app/api/workflow/workflowQueue.ts +++ b/src/app/api/workflow/workflowQueue.ts @@ -2,12 +2,13 @@ import { Queue } from "bullmq"; import Redis from "ioredis"; import { env } from "~/env"; -import { type Workflow } from "~/lib/workflow/types"; import { db } from "~/server/db"; -import { workflowJobs } from "~/server/db/schema"; +import { workflowJobs, workflowRuns } from "~/server/db/schema"; import { v4 as uuidv4 } from "uuid"; import { eq } from "drizzle-orm"; +import { Logger } from "@/lib/log"; +const log = new Logger("workflowQueue"); const connection = new Redis(env.REDIS_URL, { maxRetriesPerRequest: null, @@ -24,19 +25,60 @@ export const workflowQueue = new Queue("workflowQueue", { }, }); -async function storeWorkflowJob(userId: string, job: any) { - console.log("Storing workflow job", job.id); - const workflowJob = db.insert(workflowJobs).values({ +export async function storeWorkflowJob(userId: string, job: any) { + log.info("Storing workflow job", job.id); + await db.insert(workflowJobs).values({ id: job.id, workflow: JSON.stringify(job.data.workflow), userId, - status: job.status, + createdAt: new Date(job.timestamp as number), + }); + const res = await db.query.workflowJobs.findFirst({ + where: (workflowJobs, { eq }) => eq(workflowJobs.id, job.id as string), + }); + return res; +} + +export async function updateWorkflowJob(userId: string, job: any) { + log.info("Updating workflow job", job.id); + await db + .update(workflowJobs) + .set({ + workflow: JSON.stringify(job.data.workflow), + // cron: + }) + .where(eq(workflowJobs.id, job.id as string)); + const res = await db.query.workflowJobs.findFirst({ + where: (workflowJobs, { eq }) => eq(workflowJobs.id, job.id as string), + }); + return res; +} + +export async function workflowExists(id: string) { + const workflow = await db.query.workflowJobs.findFirst({ + where: (workflowJobs, { eq }) => eq(workflowJobs.id, id), + }); + return !!workflow; +} + +export async function storeWorkflowQueueRun(workflowId: string, job: any) { + log.info("Storing workflow run", workflowId); + await db.insert(workflowRuns).values({ + id: job.id, + workflowId, startedAt: new Date(job.timestamp as number), }); - return workflowJob; + const res = await db.query.workflowRuns.findFirst({ + where: (workflowRuns, { eq }) => eq(workflowRuns.id, job.id as string), + }); + return res; } -export async function createWorkflowQueue(workflow: Workflow, userId: string) { - try{ +export async function createWorkflowQueue( + workflow: WorkflowObject, + userId: string, + workflowId: string, +) { + try { const job = await workflowQueue.add( "workflowQueue", { workflow, userId }, @@ -51,10 +93,10 @@ export async function createWorkflowQueue(workflow: Workflow, userId: string) { }, }, ); - await storeWorkflowJob(userId, job); + await storeWorkflowQueueRun(workflowId, job); return job; } catch (err) { - console.error("Error adding job to queue", err); + log.error("Error adding job to queue", err); throw err; } } @@ -64,45 +106,82 @@ export async function getWorkflowJob(id: string) { return job; } -export async function updateWorkflowJob(jobId: string, status?: string, workerId?: string) { - try{ - console.log("Updating workflow job", jobId); - const job = await workflowQueue.getJob(jobId); - if (!job) { - throw new Error("Job not found"); - } +export async function updateWorkflowRun( + jobId: string, + status?: string, + workerId?: string, + returnValues?: any, +) { + try { + log.info("Updating workflow job", jobId); + const job = await workflowQueue.getJob(jobId); + if (!job) { + throw new Error("Job not found"); + } + + if (!status) { + if (job.finishedOn) { + status = "completed"; + } else if (job.stacktrace) { + status = "failed"; + } else if (job.processedOn) { + status = "active"; + } else if (job.delay) { + status = "delayed"; + } + } + const finished = ["completed", "failed", "cancelled"].includes(status!); - if (!status) { - if (job.finishedOn) { - status = "completed"; - } else if (job.stacktrace) { - status = "failed"; - } else if (job.processedOn) { - status = "active"; - } else if (job.delay) { - status = "delayed"; + let completedAt; + if (finished) { + completedAt = new Date(); } - } - const finished = ["completed", "failed", "cancelled"].includes(status!); + if (returnValues?.length > 0) { + returnValues = compressReturnValues(returnValues); + } - let completedAt; - if (finished) { - completedAt = new Date(); - } - - await db.update(workflowJobs).set({ - status: status, - error: job.failedReason, - completedAt: completedAt, - workerId: workerId, - }).where( - eq(workflowJobs.id, jobId), - ); - return "updated" + log.info("Updating workflow job", jobId); + + await db + .update(workflowRuns) + .set({ + status: status, + error: job.failedReason, + completedAt: completedAt, + workerId: workerId, + returnValues: JSON.stringify(returnValues), + }) + .where(eq(workflowRuns.id, jobId)); + return "updated"; } catch (err) { - console.error("Error updating job", err); + log.error("Error updating job", err); throw err; } -} \ No newline at end of file +} + +function compressReturnValues(returnValues: any) { + returnValues.forEach((obj: any) => { + delete obj.track.audio_features; + delete obj.track.available_markets; + delete obj.album.release_date_precision; + delete obj.added_by; + delete obj.video_thumbnail; + delete obj.track.preview_url; + delete obj.track.external_ids; + delete obj.track.external_urls; + + obj.track.album.artists.forEach((artist: any) => { + delete artist.external_urls; + delete artist.href; + delete artist.uri; + }); + obj.track.artists.forEach((artist: any) => { + delete artist.external_urls; + delete artist.href; + delete artist.uri; + }); + }); + return returnValues; +} diff --git a/src/app/auth/providerButtons.tsx b/src/app/auth/providerButtons.tsx index c5d80cd..140c329 100644 --- a/src/app/auth/providerButtons.tsx +++ b/src/app/auth/providerButtons.tsx @@ -83,13 +83,12 @@ const LoadingSVG = () => ( export default function ProviderButtons() { const [providers, setProviders] = useState>({}); - const isMobile = () => { if (typeof window !== "undefined") { return window.innerWidth < 768; } return false; - } + }; const { data: session, status } = useSession(); @@ -143,16 +142,14 @@ export default function ProviderButtons() { /> )} - { - status === "loading" ? ( - - - Authenticating... - - ) : ( - Sign in with {provider.name} - ) - } + {status === "loading" ? ( + + + Authenticating... + + ) : ( + Sign in with {provider.name} + )} ))} diff --git a/src/app/flow-test/page.tsx b/src/app/flow-test/page.tsx deleted file mode 100644 index 8abfc68..0000000 --- a/src/app/flow-test/page.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -"use client"; -import React, { useState } from 'react'; - -const Page = () => { - const [jsonValue, setJsonValue] = useState(''); - const [response, setResponse] = useState(''); - const [jobId, setJobId] = useState(null); - - const handleTextareaChange = (event: React.ChangeEvent) => { - setJsonValue(event.target.value); - }; - - const workflow = { - name: "spotify-playlist", - sources: [ - { - id: "playlist1", - type: "playlist", - params: { - playlistId: "4rgpmMVnicF0U90eoc5sUG", - }, - }, - { - id: "playlist2", - type: "playlist", - params: { - playlistId: "1lRI38EWAozAe9ra141sPq", - }, - }, - ], - operations: [ - { - id: "filter", - type: "Filter.filter", - params: { - filterKey: "track.popularity", - filterValue: "> 20", - }, - sources: ["playlist1"], - }, - { - id: "filter2", - type: "Filter.dedupeArtists", - params: {}, - sources: ["filter"], - }, - ], - }; - - React.useEffect(() => { - let intervalId: NodeJS.Timeout; - console.log("jobId: ", jobId); - if (jobId) { - intervalId = setInterval(() => { - console.log("fetching job: ", jobId); - fetch(`/api/workflow/${jobId}`) - .then(response => response.json()) - .then(data => { - setResponse(data as string); - }) - .catch(error => { - console.error(error); - }); - }, 2500); - } - - // Clear interval on component unmount - return () => { - if (intervalId) { - clearInterval(intervalId); - } - }; - }, [jobId]); - - const handleSubmit = () => { - console.log("builtin workflow: ", JSON.stringify(workflow, null, 2)); - fetch('/api/workflow', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: jsonValue - }) - .then(response => response.json()) - .then(data => { - // Handle the response from the server - setResponse(data as string); - setJobId(data.job.id); - }) - .catch(error => { - // Handle any errors - console.error(error); - }); - }; - - return ( -
-