From 85fd1395ef3db1d8ae190c0bc3b9aa45ade5c901 Mon Sep 17 00:00:00 2001 From: v_xugzhou <941071842@qq.com> Date: Thu, 13 Mar 2025 17:00:09 +0800 Subject: [PATCH 01/61] =?UTF-8?q?fix:=20=E5=86=B3=E7=AD=96=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E5=80=BC=E4=B8=BA0=E6=97=B6?= =?UTF-8?q?=E6=9C=AA=E5=B1=95=E7=A4=BA=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20--ignore=20#=20Reviewed,=20transaction=20id:=2033937?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DecisionTable/components/TableCell/index.vue | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/DecisionTable/components/TableCell/index.vue b/frontend/src/components/DecisionTable/components/TableCell/index.vue index 0851c680..02a043f3 100644 --- a/frontend/src/components/DecisionTable/components/TableCell/index.vue +++ b/frontend/src/components/DecisionTable/components/TableCell/index.vue @@ -24,9 +24,9 @@
;w4&Z9LU_oK zEr&j0Veq>S?%ke @f|TP@j(=>@5g(*zE9F*>=lw J6$FLiGey3YNIt*DzIx6#2UTvgUtfS z{P+fqK;XiXEzX3b!;HixWCpjyvAQl}%o#=XjE?Fjv9F{euOu39E;clqg7_*Y{^sRX z%lbX5RC9wcmytPPuW4TM-pYvaAN`iNqQ&+jU@uQel`42V`O6%`ILv9b-nM~t8e<`j zg&bSTi-@(bW}=LyE*~a2_Lqb;j06E7m(O!u1Eu0Uj5_Psm*N$LN~RVvgjzUNivSPF z&D~Z`$wQ}y$g}W&E%w_yV7a&Q>dl|Q`^}2!MEAS0V6Xt#?d!>Xoz+X^eH$#&oqN^X zf!#90fNAJqJK9%NmQ2dAW*Bwsktm)M#QX|~Iu!*N!Nhm?=QAwq6u~F5=Y@1&w`}ry zKeDXkvSFRyEFG$~ orwQTaQ1ie3y%z!j!9%8pTgxr zY#xW4fh^vUUDu4isW{T90WdBj5j0+iLwUu59?Q#fFf0O4-rvGx*PMx(W}nz5?TbBq zV-UfC5_tPaS86H0yE@FT{a;Cd%1)#fsZtg_(SvY$3wqt1&$Kc6Z>i2eFdK2Xz{gVC zcL}2H#efT!tjkk0jj)tg5u;ULKU=i_`8Zs_HI3wIcA(?nmwz#bwB^`ja23CM1s{A3 zzUG8^y&I!gJzfZoAV}rphOTV=VZ2gJA#d;` k_nzy;9!%=U2e%rvJbYKi#bdxO*M$EiUQT6 zrbW^AZCq;jZ2t@0=Q+9=9zGp=*5DhWER0=RTG!RRaV|TvVyvTAVfumYu8R=|2^ xG4bm?AT^1@7W_9vxZy62;zF@MIfwEqG`Xi1SCxQD~DgwT0bW zFcL1XK;oY|8G;V? `x3^xrq;B0P^af$`CO$^ktU84bF*AY}>ECcq!4-t@ecH9IbYFO$l-6Zv)NZZHj| zQOAY8&RUT(!YLoJ$H)x*Y`q0+j~};ryY1p{>1#07a@~)dz#5b}OJ~Z>cwXVdG1jfD zGLS_b_3JyY8G>1WjSYGTe^6zvm|XPOZ+Wnml0qT@8njspaL9z;4JO5E$D(gLi<@`i znbaRs-(+Kr)1yE_?=SDcTBJ)k^A-`F+xcN;18(1On=fzH-%vf?gIi=Gi(8|DGC{4^Oyv?VhAI2 gm+zM$lCOViDD88a6yA~b2<>E=}@b$qlsT#&~v+faYyM9JVb{PHpJySngr zfu}<_F(GJ8GFd3@lHW`5TqJysNN$KZdB+;bCXEp#KzJhq9GYoiLPk(d>3z+dUt gh{o{pr;0@Pm|^8os _b!pBR=oaQD(j|Lpb5To<=5K)BnwNvD8t%#eBL!&jSwLuBT`oB)tKXd7B z61f9LXkrE>)%&cn^E$p6Z(Ze;&D?)ED#UHs0JgRv+qLv=&uX3HDxrQwaCdCvFX($F zZ2AN+q%vh}&pIBp3iNLk)m3W*E-sFfuskivKo5M6RBgRhyOzZtI9IUHCEA0sjS^># zDKK$Qog4v+nO;qsnB656cMPgGb5>7Z{F!ztGSD^IQjfeC5RDLr8?;r$Nf2qk@| {>P4w>JY`fvr77A?LNObq+PC8wtA lgZFKoE+v_ zl4&{gy12?~fn6?(6q>b;6k7IPuz_IV;%E8;u+Jd+yx*4$O_@S3?$R@6Ctgu({)y`y zTdd?%t1s-55?tt~o_{B0#HxTQmWsDw4h*{c8t^@s#uq`8p%S|k&$Uqjz#k#%v)+g) zsm;w$S8mVr9TA2G6OnF%U57KH5sVhw*B$_`H=r4D0u5~gqsKrcS@rcU$h=iq(>k6h zxbUpCxH8B;+yP_NA$Mo?1{@a;jsuzjMgsU*krN+xuT_p$%e5%U%(DZ_7Oriyfsi}2 z;wUEY7q8c16mXGNZbUhvC1Yy~1Zw;=`lps_)!U3=SG*|*R2s+i3);h9P>(7sw}>t{ zw44-Y&h)>XjwWly*4CC{O%GXvWmmK3!u!e>UGMX=zkcOab|{emuuG8=oNf)fi5f9) z*w+#wUFe3>g31vdLgI9s5{i6Kfm%ooR+CvT`A4mo)x2*coR&+S#*MwY@{#|tP7nSd z$3 8U+DB$7-={F>AbCsfJhr^hB!!? zn;Gofx>X* ?6!2uU^{+b z0-G#Y|K;})7p_@~{a7mgM;htf6dJSEByNq{ksY( 2R6*W@4Z-D(`uSkpfXEm z 4HghbDuNE8Ed%&qz=bd+)J`vab2ISB^Iro&xW_60b z1spA2*l|L}apaKA2ua#;OeAqcK=}pk1l_U9rn66a@5@NsSIDQhS_+^g^WT$aoQk8` z^cQG7%T* <&>qRjHa-^Ewz zKbJn33D84I`aWe%0SsK+cMwbzeQZe8BXP}zNktCZV&s0A#2dKd!|x`<3Ph2;=5uz; z4Wr0m;QlH|cRC)jhI!2;_7N+ZK25^Y+%tHi@jE?2l3 UfVqb{Qw*C)xnFF) zPiE3KFo;xz00)&$1OwXKMh{j+hL_a6|EI = qz9it|dF)sm zl>1KA*z>WtDTbTNpog)BqLA6>4VGw? e+i=)4l_ICojA;v z0?qbXzbDz1UBWDy#q(FC5KE$Numr{{buM2DuE*A%+O3aWjTSt@PWY&=m9JeBb@on4 zemJXAAZ(mDK4u|>|6_7^_YUR=r*PZr1EBNI8BX_=;JsLrG}gE1ciu5g5N>*3* j zTNPdY#L0&6RE^SgL*&X6 |p7MnlLNsOv*xXvz8oo5pxWedCzOo z$Vt!_e4)+Qq%)l_KZ#1RXQf+;ERU-&2N0VFNWPiW4t}=}UTwSRqp@bof{+ScMVcdQ zJ#N*Zj2u1QRJM=D> zF-k4rF0YBU)+^;!xfF(7Bc_GA7f(K-m6*ArNaV^-liE^jj!)p=9UuNYO0HSrf z5r=y_hH5G2YvS#%SYjP9VvVweqMo16!6>yQi|L412ba1|lXBIN+MPKrFnPlEuSv0T z&A!qf0W`*_V_^W==B_XoxfEmNXk&Auxkh2h+`gjKB7)ce$zPkV%7)3|S`{*b@?3O0 zle^U_M~@}n5--2?=zCwFJQ4*PX0Xk$v93035-7L2LHA6&)qSHO#u*Y@)xMZcZA|(I zdf^>#HJDR(Zv(8wmp@td07W;8)AOFfJh*(HVKURv3`(PAC}q *TsX1Rj)TZl*m>5ofdy-cR0SQ|LFL8S`4VM%ZMq|T-tlXNPMHC z9O{iwNyoHn7fTXj4DPXpsl%igR@fE1f-+YuCbbHOjZLc(Yup`~1y=Qb|8f14Ky-6$ zDzTD5Fx@Q>Sm1BahqHPbTu7ZcR9ClgA~88Ua54vr7~eB*WNXE=f8>`=dBC(7MQ!9L z!X&RJp!8O8vm|}8+z$gdS&|MH!b}W~!RiH8R_LbkauuF3b_JdgDP4+2$fMT9 A7XpA7Oz?2~zIU$m-eZk1&ZM zYH%F6KYEWFq=`UO${2pS$iG*yqMC+G<|epoM?f{5w|pOT*R4T6cSOs@jO!C@{;VGg zs0JpWxyI4;qte!ROmh%#4qCHCX8F-aU0 OX& zx4e9S4tb~R`$|oa6lTd1Cn|Poxl7Jxm7C^aZYd$%c7TpEKJD7=>{krkW4>w*tKZyj z#@t&wJs4Q#0@)j=@QXp&)uLB&9$v*FU0i{6to4k7TT!87A&$W?R`v-AGbm;6m5Zna z%t$Qxaz&nE2#mD~B;t(Aq%u<>h>}-32hbUbqaHC1WHKj9PgTP4^_)txqa)E`GHU$7 zbdPi*)?lh~ljYEF^K$wJRVleflv`)x13q0WwRf-wZ<+>O3A-|Nx4(nVLu%W6ZxVR) z8b#ZG%#Rao2QDv65mjczeh42NKOS?vXK!?*DnGMD17F0*dQj!i(Q~)WpvlB6A~YD{ zzcjFz7!{+V2KP!K(M-A<*Rxu;C|3&6iql9QoGd2r)Vzk;+t~YA%DYgRuzFX%v#4Gd zG|SsfM@{e`OFR>6R4?hePWv-fU`qZiY0VILK>XJ_>{b+3sMyQkTc2ZUC#?BLXS+y| zhj**p5eSp>9PJ(Tj2|8sZevbJGy*PF1OZ-{a+9&%LT{YSIEd1T5xx!~x0?+_lYH}5 z=9q+i-2RE oMF)Hv2UU;pnyo-+ (yYR`7wx;ZLeEscoW!A$P# x~*Oif_C&8=pgGVIDTnn4?1<9y!O6b20X1Bql%5)a6nFHG%TR68tm>RRm%b%Aow zpFp@8et_G=PWLdhFf3dN6W+IZ KJ@h|yO=)*{Mhno!1xwpS+p+csHV zmQ%SCgJ^U#3j>t{7ZpKg3SOQh^-s aQL^#e<#gtBWb-&eAeJRj1 zr5u5uc=GaPRcREw7c!2U%%SBH3YT(&Z>dr7`AuctGBjB(=Au6NX9>Wiz;rD|dCaA( znZtyq6;r)--U8KyPhC@f_f+CFg{fhu C{0)u+4VR R*^QXD6`zIrjNm4XDDV(^#RPZcWZpS<-xQ^PITElwBjn zKnTA^B!3koWul;1bw{Ss8Cp^HAg-n1u+wEBe1LL0xvW*i5ugs~P_3|NbGIMiL{{Uw zFU=tYDc24oi`n|mHGoEYf=mD*am^{EIVhbmKH8CGNmeH)opVDe^&^?%Ssti7{jn&? zK9odn=k|bO(F*!$MP+v-O75m&I6-;mme5((xHrwJ<}LO5s729a&n&mQ=k)z%nK*}d zeN@2nD!EiXtm+GO_}Z>_8COD`h}qyc#85>cG@fVn&n;bRhZNZ!=2cWqzDhJi|Mcm` zUlP3y- WqVorC@*Bqgz$?#L)_aUwwz_Us0~dYFq_=p#gQy z7WhO_wvO*!`gm2p%N&xi_^irYr5Dic8&!@;f8E#C#wy=!?{wAC2&5?zjo4^;y^#79 zaS7F9 UK?)H|++W-bOcVqgo$X-M3?aZdcv#cmNB$wvb6Ji7=oL z)*_;APZ9QZ31B`;n@y9*bRMEPCG${gN5pkSb`NEzsc9nu1MK>iNvM|05k*hI{q-r9 zb8>yUmk8t$1Htv7zO++=17l+Z zL4IRI=A4XM8jo~#3 N46JC%v+I$D+}0%su$dpr>6Cqpjtsp#QJDVnDm~^{A5}Z(|E$ zABbjIlpp?GJ|`1N%p?nS42w8C` Xu@VUD8U zpHQRWiBFD@5I?HRW8u!j!3j1LWm4BphwqMF;IVVpj>Fu37}R+9O4!IhQNPwQ3b!!c z9%Z*^T^?NeZOEm)&Hr|K+bc^%W$b(1V4bO&lPq^YZTjFZnR6i^ZEMvbS_J}ONVnU0 zIIYKbh9uo{GGGbH%w)c1m3<5QL)eJU^QNJ-TU#Zqab?d(b$2)K%S-wPR7mpxuV z4F`6HkiZRBe6a@%Y77sLhfD|8t5b@ojt<%Q{E&PoosED0T}`j3d>ai8rxU;2Zzi(R zcQ=oskD~pC-QGV~W0>VeZYO)Aqs=KSEbtqcXd9S$U6?3cm^p8l7;l&b5o(DM>X@Qx zsiNw*WNXP}>)0l0=_cy sTskX@C`VJOCyUk>3gNs!A%e=JHD>c1y 2Hvp*{fZaB?W9o4gd8qWgtvoeJM3WnDL>^09Cl!T8)!`CamB^tOl%F$EIA+0T88@+SIG zYd8w`CTcJW$8B8m8|xn4CuHMy=D7S`v9oGh*@l`u4QKLy5vb}@e69La_NwMr?C^iK zVzHuq+y-GAzq8No{pjA_wX;`Sr=9@=V`}O;X^SL-V5;FL<1W@U!c)krh~Lki-~S)S z8TV4JWuJ;(Rs5)Xl2ngXk5s*?ul3BQ$A2Za(YUDZmrtr60hbqR06EouRc-Ch?spaZ zhU*3Q-D@{Z{5Cg>&x`xzVFLT5Q?v6eB@T*PIm<787bok>Ej5N)IleykcNadu0-$NP zM6N{caL&}BPb}y|()4`z;qPsyz-{6>+q=LkLr;?;;9bLywueB#;iFr}tEzJe|LY72 zpWx+2uS*aJ$o+yc$;>ojbjv+B8lF*_XJJ$JjK2YLbQtJDdf?btcXS|?R)70+;J`m5 z4^FhVe_M_~(xVCiO%JY(Eyt05eS` -<;i4X8WJhv@uQ@Y}|d;{oZ7mxXl64G~n#l=~ROe*onxLOcKf delta 9669 zcmY+KQ*@rs*M{FXZ5kVmZQFL5zOilFPmD&58oRNYq_J%~jcuD>erx?tzL|Bed#=6r z>^Yr-{jdkox(k8ft|Tc5f&hIir&bWcf8K)=ham)H8rvE=fItxbAP}rL2!t%%+Q=nj zZsTbN0>SlyK*k&(P|o1p%>bH(si6r7WcBiKljTF4w4Fl!79T+n$eQ_si9baCSps&` z!q&y(Blhise}h0!zl+e{vu*5+|Es(CcxU!Mk=jXB+8TO%yvu1j_)$poA!3Mk(4C#3 zttkj(d+<@D4gx`j{DikaaIklF0fFp=Kbm=gK%ZEIUSa|h;315FCAQ<21;cQ|dQ%T5 z3^V8<2+;Tw0=q}X*urCrnksJp<$0tOEQyLqyk{2w=(UGa=chhg^S)1xSrNt1bSe&_ zw9?hkDpAxbwCVZO#SWq{<|XDO;$FA;ddZekudVlQ$PWdzj~VwFV_M!q-W9d;-W{C* zoe qG3Of~hdzAFvf zG9%scSj1`?&VgTxSbRqAClRq*3Df25iE0Jjmdg!Qej!?aV;QH&@Ql4iXECw*jdTq| zD*rV5g+$-d*+idKvytBQ4_ua1PUih(5I9y}%&yXUm0{cktSWcYUw)cfkGcLWznz?t zlQMqA0Sood#gvYfj#ZA8j8!m9I(nbRJz=I<+TgL{jaiDwX-%bZ;*~K?{tDs=7PA~M z{98o!^+4PlsR%*$P}1FNGC}XA5ZU)o3V>z)De}b(Udp01j5TUA%78o{XAGyGHRe*@ zfHWax6r+$8h^CzLBbRbyA7IWj=84(n2|!QnlF1mASKL%l+;$n?kRLa~GIvJWcOu+( zhQM}0#b!&FySYhr 8lz-3(Xzy!yM55Cea`y}m^9(+}^i``3 z9q`DYdiZ?o5l{3-ul7#>(WNox6^7FF7a>D*p o`jve)vwDk*ZzX3D938KYr zqDOS?rT*+k1i+MU;*y`~;9Y-5*X^2XZSx#D#%p1(8@s=*vhH|eephN=-f5VRp0j_Cf5c3}!K{GDi+`3@abk*)J;PR> z(juYN;t-cO4lA~xK*g+}*&-hKkyp2yg<&gC7gKC;`VkY&%e$3U`O6ydW1d=h%8Ftc z|8cqNZ(zh{&&q_js?2DgQzNZIadonZTjnc3M`=b-_=fcqUfiDS-yKVht^S9x)z|`L z|B#q#PK7^=wdT~|!#;BPakgQ2OKvG2mhMJn6ukQ^5yf7!PEGb4%~`XK^I;q{>)ap4 zRkIFF_N?%cBmc0E9L9%z 4&YlG^rK3-)7}!F8J8PnKJDt2 zpRtqAFj`KI07tj(TS~57yO5oGhQ{6V&kTBJneGUf<9bfiDm?Q$##jzejdRrex{fN} z^&zuv>KxQ!WUu)Z`GH1c)~U8849Pf}BL$N4PN{KqI(8-u>K{n(Q8+!QwTGuUqWX~m z>ONA&CJYN7?E1lNadj&OCJbC3sPKWcA82I4(C~q_lJl$+gIZW0Jw(Z@HBC$yBBRT9 z6+haI3~HU#KTXI*m0Oq00qp~Wc;_57{m)V5mwsf{KAks;3iP!rRmM$+tLYksJI>|o zZTaYB^5>_$Rx>RCe|7($xvuq2t)SU3sCT=NU6|i+7^asOEJ{3&&%=oyMUWmX88Zg{ z(9DO}K14}2U{)JvT-!HTy=1ksXv5}YQ?LE1H-XEeIFUa6`7$uh_%4s83xz4Q=1X-? zqE&dNWXv%m*}yFac#lMntAJ<=5sXB-#!f-H#Q=agN!K_F$hW?d?eFN4?VB{jU86{j zi?KKnuCY pc$d{Q)u`DxJlWZJJlXG@ zPJ%*gAL26Q-x87>KLr$;Vi(P2{ddSHOhshJ5 Mi+O;1!~Vm#8ou(b8(GTK)0p8<3=;`s6&Cp1%pyl8m9m{SCWP8 $KIDlXOAApj{ZEv5-585yZB+rbw73jJ>)7Vf F@_0tIAFA<+AQ&kjnW?;Go?? pshoe z%Cv$uKQ2mEMxTtG^9?n#?zM6tY)YPB*rrwXvi7_F3^)A_Gb=Tp&ruB<{qrAHSUFWX zepq?pyO?$qFA0~DxuIitR_CTP5F@g!84>sBu2%?Ayc&xv^vG)!tpRG5qxjxior-T_ z6WFm7R+>P?r<8TlDe%xWlz^5|OO-=n%B$4Pd^V)7B *=Ia1;ILIMGa`m3 zb(}N>wju= EX`aqD zmMIZu?CL1B%uD4@_SvuVT&h}!7guxQpGeR@+4O~%#UA}%!3Zl<(HDK}tK~!ePWn6A zld}}yI?7}kqAyS~3UI%Xf$>bgmz5##tH_)}wLeWAI^8%!1gTB;U(JoSsRr(|3T3aA z7AGnr z;N|OCSE64nK!i2&_|`rM0k02m1vp+b*|LCw{Z= zN;(!4l3LF|8}Dx+j;+PDZbHp?D0I8*7vRH*oK?>_yFRc|uF`1<(1O`ydlK$q)02dc zHGvxECEu=p2jSHbjA!y$52J@>nVj%30uA~>eiF&>4x)vnVZZ|FuacMUj~oQ7#i*w1 zFK#UmzNvBSxE|E*fyMDs-@Y8}?Vr7AJqh<03CC_ZSZbf;bMj`xE>&PuRYe#QOqz7H zl4K2U)wnmvL;Tby2WahjPtb-=lC!u25b!hUtUA7HCIL=f>1H71+sEW_2psR9>QC(> zj@{03nuuCY&H<+H5Hrk>&3sf3865RL&Odc4qq}hBRuvolBrlhQe1CEG#B3zoe3a73 z+3I-aXCn6W!!rXy+Iy8We~oU%8Dx{jQ)odz%0zFkQ8-%F0X$Xtp=yy@{0w2gsYs8l zep7WD9w1b$TVJ*%3oGQ u1z}0Hh*%H=E|MPQ}d#z5eys&%|TWVY~OGz zJ8$dXE57jrgYQ(t=(4u9ze`ykXI50eG|ejh&0fUXWx?E5lf#LHu)ig;FITMJ zalU_Ran;UUo^>Z7L-L7STb66cmu+9MUv(ZZ+VXL#_OUsYD(*-k>^RkZ$ q^JlP ze$eoEyZ^(LTa-%97G$;i4J%&S8vV*dbWi82#-)+{J)lgwNOhht@-MB1sE@l#Isc3n zO`?L} x={z!C?gB0{e$o2(Hz|Bed&&R0!Qt(Tq`c3{+uCHB zaCy~6h6@Dce+JZD_v;0F@}o$t7DN#I1;ncB{yDUMNy#Tkme{V%53Ajd%%6tfp&!^M z9(gaA>WO4Qyud+x6Y`~Qv6BG`??v#Encl|MkAiMeS0dbZ6;ZsdPPojE8+mNdI^L0% zAT@K+mc 8T)(dUIU z$*jM(6_96v?d^0Gg(vje0oP-h$^Cod>Q)Um_x5wt`xBUZH>GvjPms~So!&A9!!1k0 zn1Qc+P~aM}(frYYFA1NFX}c6P5>%kfa)uPh#YaaC6eW<~zOl+n*sELfvXco zkGYc}sugAwe$nYV%i S#%BT-V5iw`3$tp z9jfEd@ diX@Rpy!iKe!-X_VQmcG^-qqSQlz^~-<&2RMUZAF%h(&zv}3QSsC z-vXi1#5c_uHErCIosC99_9U}4w>+Sxd#BS@J?(3*a&k^BzC^2dS)yC*46w3Y4_`h% zNLTl3qfNKM9X~BOBr_5e7+z%=qraq+yW2$UzeY4-hNyZ;Ont+(ZZbs+jWO9~jFQOf zeBq& `BR7r4609P*7$qcna{se}jLEd94(@6K9a$aD`q&rhMiCQcn@TZWuU z!z}`ql!&i$sWtDZr#XJeL#^-5cW5qLXJm2VtX;6d1J*dPKBQ@ky_W;T%ccXL34?`j z`EJY5?1UlHt0RedX>)6giVcBDY=7Z8bAvhIIRlr$dEWe645SKMHZ2=WMI9qom%)AH zr&26Lq!Zl87>e@7U|VWljSy>(Qb*l&gV&rM2*p|6MP`)%eAh(mPol!h5!S=J@Zk@V zaj$o~0$zSEEH$rh_cpK4f6S>2K4+iM7iEok9tQ`PgPAk6^vLLheUgBMpp<^T4%Sqe zKs2q@p#4eQ8ctU@)mYi2r_}nr%jBSkuOl#5YDYD*n*ETdhh^pf-&6(Lc2?GU3(n$H zStXvSp(9g9> XriKOwEd;6Nwf$IQRTD#iZr(1WCTd4ta~vuHP+Sb3rVAW`DZP zQYg5 Z zQ`9X72597+mB2VHa}7TT8enq^IDtbIVaO~EAA!fc6UZ<-g%;tk=$gVX+WUI;*+I(= zw+uz;2jsro`FJH>TYby(@;2R!jIsAZXkC!A*S=J@6zoFx7$PvYX>e<+8PqoS(w6A* zo?ddEPn{OB__Qpo1==Jr(q-g)d|h3L5p?r8mp_&FCFd`?F9BP_#Rik1E0LGdF4Hq{ zlZtd;BT>q{de5t=Y%H}j?nj-o^rzqmb V{x(DBty %>37<;yUa}3jj2NL z4z5M 8ib(SyNts_Cef8I&_7+4CHwTyq=BrxC*EElX>e;IxY!2H!&UA&lPP zP0?OK2Gi0~v<7HM28fp+p9j%DJSY}Od$Ej`$&n^a8?frk_t1kpKapFCGK7$wI0nNk z^w?0#If3_EHlARi<{=8m`xb{ogNp`J^Xw+F#;nMmg>A?SL(MEXq%-%aUN%$njgWv! zog7>L0g@*!f?*e|sp?mltcI6S8~!6|Kt=_U1~>XqVToKcECP)(<4WDw4Bdtx?r1RF zfFzHZ8oV8t{e2m?8a?KZ)g8(R0=6^YV>4A@3uI{7SE`KpzK}xtbP!CaTRfOLG^%~# zXDrx~9zw_@BAn2RQ?X`1s?a)V#&o@Y3C>Xwx`S)y7^9&bgB>exf@afaxFGQ9^?i;1 zP7Ke|`lDrEf^!4A%Wz%`rm`~YLE`bHJd*9t*QlhDK4WT$J 0KVzu8h$q!z!~*W!s{GiI_U~xqQNY&onE@gD?FSbQm0;ti_WRD(1$CE| znv0Su9(VIXtdg_i3Qun4^XGrfEt^VQ(nRNt4Nt=7)@>yi7y3e~E!+ )^u4Tkwoi@Dz-Y|EE)eRpK2wmA=jQn%(ml@v$|$;5VEjfQ$=D?9 zF2!f`OlNJe(PuxLK<5|#>m7!xn459+Ni|p@K|+Rj753%OB;qWBSLpdJ?sc(7aC(Vb zj}!k`V=K+wiB)nxC9*HR$>YfO_xzlC4ee|M^jl76_1)xE=t)7DQMGEaS&xW 3(lBu3d#I}IDNkt`+l&pS#|uZYPY6e~-LfelV5y2c#! zH(o#V2_b+}(hA2U@)wP#R29x62`HdU8ImtSfK8V-O5ku?P7sc6qM&8)SL2AYk>X2c z_!qI9fX+_g4$+J^aC0joJkrvVOeQ^l?AXM6V^(Q+G?v}PV54@(SVCZ@E&EeBxgJqn zFRw>tS))bGb(T2gIo+%rq`{J3vQCc^Q~K9kIlI?K8Ck!d#Xk4geyG@F7iio_wk^4U zOX3{LQXBc14{wLtB~86*{gC}tO7kuzbI0R`#U~iE?X#;w+x0V(6T+0xYQ_+xJJpKc znq;q?&L0OTQGAJ@nx_lbOTt5?{mmJLYfI9 15TXdn1@?DGcrM-rT>m1J>fG*n#i1F&+z+?d$0w6ax@2=X z|D3d!yfTu#(bb#QO`3_+#Sj}`zMZjtb-&2@L>m_B$I0HibGp5=PXy%f2G*u}jvATq zh>*j0+7v+Jr^XNAka{P4Rawl+HRGpwyhUL!-TwVI_+-A;s~E}H4o}HXJdQ^r7>ar^ zu0~gmWMgx-miMs!#-?KFcY2>&3ba1-ucJT(X0H3M8Vu1e+n`J07Ug9)_3Up};;5-~ z?mP<9dG1rY!Kik<=n=pTCqFeq$c%-II=MB(SXYjWySzE8^(BN)3oXNHovxe#d;{BC zf3I)b?>4uUv)<~tNhDBiLDxo&E1Ow{e?L$3!+?3M5c!GdlAlYOmo0S?KWdxK3&O~> zZkcrQd!9u@M7Udo3p|st2qcfGl1X`r1$L2K87IwLN@=@Jfdhc!YBkDkl|*pG5p0BM z$WV;ft<4W#1asJzlsf;besp-&W%)&>&MB@~`-@c_(@6;`s ZWYs z90~oaMp0n4FnmVc+TJS=P*rD2tV6)o)2)LWQ_y$U^ Wz-X9vgbQkw5oS z$3S{vnw!)n#24CN4fH$PAF$vf+e_y&%fF5Lw^u9c=RBKcW%Q^p75aA}y$3g1>S zYB1Sqz!8;4Rwkna&{KX&XAFGTAkxj|J|39T2WSoU}GMX *`s|+6 WAEzb)6Gr_-{jo=e|no#8UJ!&& 5zGvp zZu4$wg p+;1*nxwMLJ!$0)So)v<7sNfWs=oU%UxuL zF6(@Ruu}6aV6us_o-!0Dx;r<&^2O`&B?aQwQ3@j>lpI*0&`4|L>5`=bG;vv&XCmN5 z4T_O4&0C0 i!UIpYjb&W#O2B99N~I?xEo!`XAYBn+=V~_02L&kHduV@dl=~kRm{^ zZT>euvQd5>t5B@chU0AZzV$OpwkpaiEP|6sJxVG$f^Pv*vq?`B8nl-(=jes!h9Ryy z-q-jZFCLBQMVQGs96Mz>OIJA!L4-PsW@EguX5*uIQQ5MmVZZ2ZJ&4*lhKp~6aNf3p ziFQL$iraa=McdZ(ksm!O^ymIfyXOOp-{ecK%NS2C-CAC5VNU2CpJkXm-$4nAki}1$ zmvq&2nAE0ps=^6E^lplfqfg+;1nHX`Fs~fz6x0K` *iY$raU8#T9Hn@z ziD|S0dCLkmc7=Ji{qV0D{^mMRe)!PCOz3-;pow1px^zC?b_?L;(v3R^Ss(Cmd MXot;_W9qx4`$#+l~|}E6BnAQ7@&vXhS%W5%67w!^fI+8L!Ye6)h+E2GKYJ_a=*W zGJTPym`S-jG`rTA%a2$fN2T*c$&Mf)dsFFx%_sN_t1vu-4u-pTf;w~ECDwep1O;j$ z-zuNIa!Pn!BbtBCmu-Ia3=Y67zTk}};5&h>xKUS4l1!V#tFYz?d#`tGMX`Qj=)xzv zKBGI4!+4&Y& %&y-)7aKWbD4 z)v$-8x_B<5NM;9Z_FA7~54)IXRB_&JWRVw@g$$_B9Fr=$*`tr--2 f%0=1d#a(18er!Vv#IomwqH~NlDi4&h*Qr(Y zo$pC|O0*5|_1Lmk%Vthz?v0u06)b4XS?QXJaqP!vwjH1pHE&dmg-N2gLvjj{U;Npb zs+PhggV}0{y|MGL9RqX`9rgMaW}AXCWKHXFF7je%tyWk46njcXX)FA>^#a86$9{EY zWPLyVLFI|5zOeDBx_rK~B|5PG_*k=;HJt&n478?^UaoE(ov |@UPvp!XBmr3c><$7V*D9L65_vVui4R z&%3B~L$~oP3ApQ}M4Ukx#F5c;5bOIoT6$RPuBR>* X4huK#4!0Qa zr*n9`xc>Yr>fCYHAE{0B<5nZ)NjgD&ZIsJ8`xg_N`_VumqY`SHeBd8JEhmP|n|V^- zVa_s|kop~2)kT@J6c-+LE1MH~XAM1Pq5g&C&?<><<#afqivuvG3=_d|fejnjvS?E9 zrigHA&B!h4giXZ5B*Bdbq1f ZuEz%QPe+WpA$=a|{Mvu8m%EX`%fI8NWtHVK z$tNVzQxE|8It`7r2$X2Q2wXJdicf!)%U%#kq^NV Rn)4rz=CI4oa;J zFnK(;aOJ~ZU}s3&u?|rvV>7Tvs^*^Pzhq!XSGH58gwSQt9H0%q-WtA9`6<%=fS=lF z(v%|a$BpxW2wao_9k9(jeY$OHLoK4r!(X8bWjqI%Ee2MsBF%4ahX<2v72g@!X1q)O zY9RHCv*}m6xlvo7hA82S7qmOwp8Q-dw7u_%p1>HmHIIsCL3P lKALXu_C>^m}aE5zP@76 zK$#+Ybf<3N>fdB&3l&MTl5R;?5Fk21>-(zU;hLvjUIsA0+v5I=rI-!7QOVNr!Mu-C zVYn(4S64M3jzKxsT{4;rV92C^9*%m!>1p7-?Vxc V1W@W?PWFflLy87=g%d2T=2 zwzE3aGW&PtZ}H0DyuMEXsP*`x^}>vBQ0USaAf_M$aKftfS6Dev)jT{)yiFFY0f?4I zl%V#v%`61b|9W{0UHk|LgMd!)PeFjk#d!;Q`~u=0fxN3tx6_9J@LdVSoqu5bXle1j zYr*qLSlu`~`~KS^*TT{Le~TJ`LB8LKZXKmsS|3kcYIEn^<~7d#l==QHZ%i=5BEZH> zww)T0n%YS}I&3pKPB1#8GdjjUI^r`r0ZISy^B5(iA2y;NN24G5PCv# |Adk zS8rrpZ>U{w?CoYC wjLEAEghn$Z?H&=xuJnmbUMJ8}a14vhPbg4hlu*p4j84mAJGH8@bH zJ8~>IF#K<*!I7=Ofv&-k&)tE_-I43wf$82+2>F5-`I0&If;#q+Tj_#a>5_fog8sj; zg9}ooOV+9j+Nw)l`wL3@OV0BP#`8--q6-qDOP1^ln(Rv+{R;~HOOEvmhV@GUA>e{c z=#s7Dg0AC|54fNLF1g;BqX9m7Tp`ctUd}^GtKyQhk|wR<0<99?x}y0bVcS`?uQ8U> zs=HKI=uHu=;(nxDap{9HJ5*0pPhoGlzyZ-60#7b5h`>Wab%J@-t!G&E6W CoQ1KI{6-vq;p12wNe|zX==rryhS%Z{a> G8k& zr_OUIU$`fv8~jCQgNcAQsB`-p`_YAinS+_dT3qi5mZx`%(bWgSwDtulKfo!ye_d*Q zx8crmY<<{%w;_N3bX}dUDrq6j_~0>jKP(I1%Z{7Z{5_W^bPp#+And?xP8^W~EH}5m zffVMAe`ed*u(=lMjW1Jrw7(YmjDKd=*b;Ye{`PSk625I}?%8|`<- response.data); + }, + createCredential({}, params) { + return axios.post(`api/space/admin/credential_config/?space_id=${params.space_id}`, params).then(response => response.data); + }, + updateCredential({}, params) { + return axios.patch(`api/space/admin/credential_config/${params.id}/?space_id=${params.space_id}`, params).then(response => response.data); + }, + deleteCredential({}, params) { + return axios.delete(`api/space/admin/credential_config/${params.id}/?space_id=${params.space_id}`, params).then(response => response.data); + }, + }, +}; + diff --git a/frontend/src/views/admin/Space/Credential/CredentialDialog.vue b/frontend/src/views/admin/Space/Credential/CredentialDialog.vue new file mode 100644 index 00000000..6a8dd03f --- /dev/null +++ b/frontend/src/views/admin/Space/Credential/CredentialDialog.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/frontend/src/views/admin/Space/Credential/index.vue b/frontend/src/views/admin/Space/Credential/index.vue new file mode 100644 index 00000000..c2f869e5 --- /dev/null +++ b/frontend/src/views/admin/Space/Credential/index.vue @@ -0,0 +1,222 @@ + ++ ++ ++ + ++ + ++ + ++++ + ++ {{ row.id ? $t('保存') : $t('提交') }} + ++ {{ $t('取消') }} + +++ + + diff --git a/frontend/src/views/admin/Space/index.vue b/frontend/src/views/admin/Space/index.vue index 47fadea4..1e7194eb 100644 --- a/frontend/src/views/admin/Space/index.vue +++ b/frontend/src/views/admin/Space/index.vue @@ -13,6 +13,7 @@ import TaskList from './Task/index.vue'; import SpaceConfigList from './SpaceConfig/index.vue'; import DecisionTable from './DecisionTable/index.vue'; + import CredentialList from './Credential/index.vue'; import { mapState } from 'vuex'; export default { @@ -22,6 +23,7 @@ TaskList, SpaceConfigList, DecisionTable, + CredentialList, }, data() { const { activeTab = 'template' } = this.$route.query; @@ -38,6 +40,7 @@ let component = tab === 'config' ? 'SpaceConfigList' : 'TaskList'; component = tab === 'decisionTable' ? 'DecisionTable' : component; component = tab === 'template' ? 'TemplateList' : component; + component = tab === 'credential' ? 'CredentialList' : component; return component; }, From cc2ee60570540e448afae6c91afd6c2606aee2a6 Mon Sep 17 00:00:00 2001 From: ZC-A <1483681501@qq.com> Date: Thu, 20 Mar 2025 14:45:06 +0800 Subject: [PATCH 04/61] =?UTF-8?q?feat:=20=E5=87=AD=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20#130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bkflow/space/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bkflow/space/serializers.py b/bkflow/space/serializers.py index f2422347..c623588c 100644 --- a/bkflow/space/serializers.py +++ b/bkflow/space/serializers.py @@ -81,6 +81,7 @@ def to_representation(self, instance): data = super(CredentialSerializer, self).to_representation(instance) credential = CredentialDispatcher(credential_type=instance.type, data=instance.content) if credential: + data["content"] = credential.display_value() data["data"] = credential.display_value() else: data["data"] = {} From 25cfa3f19ac1033d825936c6cd1e11c9ab0dd3dc Mon Sep 17 00:00:00 2001 From: v_xugzhou <941071842@qq.com> Date: Thu, 20 Mar 2025 14:42:42 +0800 Subject: [PATCH 05/61] =?UTF-8?q?feat:=20=E7=A9=BA=E9=97=B4=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=BC=96=E8=BE=91=E6=94=AF=E6=8C=81=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=80=BC=E7=B1=BB=E5=9E=8B=20--ignore=20#=20Reviewed,=20transa?= =?UTF-8?q?ction=20id:=2035134?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/admin/Space/SpaceConfig/index.vue | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/frontend/src/views/admin/Space/SpaceConfig/index.vue b/frontend/src/views/admin/Space/SpaceConfig/index.vue index 13ef6300..de6af303 100644 --- a/frontend/src/views/admin/Space/SpaceConfig/index.vue +++ b/frontend/src/views/admin/Space/SpaceConfig/index.vue @@ -60,13 +60,27 @@+ {{ $t('新建') }} + ++ ++ + {{ row[item.id] || '--' }} + + ++ + ++ {{ $t('编辑') }} + ++ {{ $t('删除') }} + + ++++ + {{ selectedRow.desc }} ++ + ++ + + :class="{ 'code-form-item': isJsonValueType }"> -{ if (!validator) return; // 检查值数据类型 - const { formType, formValue } = this.configFormData; - if (formType === 'json' && !tools.checkIsJSON(formValue)) { + const { formValue } = this.configFormData; + if (this.isJsonValueType && !tools.checkIsJSON(formValue)) { this.$bkMessage({ message: this.$t('数据格式不正确,应为JSON格式'), theme: 'error', @@ -290,14 +309,14 @@ try { this.editLoading = true; - const { id, name, value_type: valueType } = this.selectedRow; + const { id, name, value_type: valueType, is_mix_type: isMixType } = this.selectedRow; const data = { id, name, space_id: this.spaceId, - value_type: valueType, + value_type: isMixType ? this.localValueType : valueType, }; - if (formType === 'json') { + if (this.isJsonValueType) { data.json_value = JSON.parse(formValue); } else { data.text_value = formValue; From 485a4688ec6ccadc7dc4567ce1bd79b62ad3cb80 Mon Sep 17 00:00:00 2001 From: ZC-A <1483681501@qq.com> Date: Thu, 20 Mar 2025 15:48:53 +0800 Subject: [PATCH 06/61] =?UTF-8?q?feat:=20=E5=87=AD=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20#130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bkflow/space/configs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bkflow/space/configs.py b/bkflow/space/configs.py index 6f98c8e6..820ee3a7 100644 --- a/bkflow/space/configs.py +++ b/bkflow/space/configs.py @@ -313,6 +313,8 @@ class ApiGatewayCredentialConfig(BaseSpaceConfig): "^[^{]+_[^{]+$": {"type": "string"}, }, "additionalProperties": False, + "required": ["default"], # 必须存在 default 配置 + "properties": {"default": {"type": "string"}}, } @classmethod From 44a237c12c49e3318d44c8f0f5b21311333933c9 Mon Sep 17 00:00:00 2001 From: ZC-A <1483681501@qq.com> Date: Thu, 20 Mar 2025 16:25:02 +0800 Subject: [PATCH 07/61] =?UTF-8?q?feat:=20=E5=87=AD=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20#130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bkflow/space/serializers.py | 3 +++ bkflow/space/views.py | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bkflow/space/serializers.py b/bkflow/space/serializers.py index c623588c..1f207bae 100644 --- a/bkflow/space/serializers.py +++ b/bkflow/space/serializers.py @@ -77,6 +77,9 @@ def validate_configs(self, configs): class CredentialSerializer(serializers.ModelSerializer): + create_at = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S") + update_at = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S") + def to_representation(self, instance): data = super(CredentialSerializer, self).to_representation(instance) credential = CredentialDispatcher(credential_type=instance.type, data=instance.content) diff --git a/bkflow/space/views.py b/bkflow/space/views.py index f2994c77..8e543c37 100644 --- a/bkflow/space/views.py +++ b/bkflow/space/views.py @@ -24,6 +24,7 @@ from django.conf import settings from django.db import DatabaseError from django.db.models import Q +from django.utils import timezone from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend, FilterSet from drf_yasg.utils import swagger_auto_schema @@ -334,8 +335,11 @@ def partial_update(self, request, *args, **kwargs): for attr, value in serializer.validated_data.items(): setattr(instance, attr, value) + instance.updated_by = request.user.username + instance.update_at = timezone.now() + updated_keys = list(serializer.validated_data.keys()) + ["updated_by", "update_at"] try: - instance.save(update_fields=serializer.validated_data.keys()) + instance.save(update_fields=updated_keys) except DatabaseError as e: errMsg = f"更新凭证失败 {str(e)}" logger.error(errMsg) From b763cdfc710aeec17f3f402b8f56ad77eb53f7fd Mon Sep 17 00:00:00 2001 From: ZC-A <1483681501@qq.com> Date: Thu, 20 Mar 2025 16:31:13 +0800 Subject: [PATCH 08/61] =?UTF-8?q?feat:=20=E5=87=AD=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20#130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bkflow/space/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bkflow/space/views.py b/bkflow/space/views.py index 8e543c37..3574a319 100644 --- a/bkflow/space/views.py +++ b/bkflow/space/views.py @@ -24,7 +24,6 @@ from django.conf import settings from django.db import DatabaseError from django.db.models import Q -from django.utils import timezone from django.utils.decorators import method_decorator from django_filters.rest_framework import DjangoFilterBackend, FilterSet from drf_yasg.utils import swagger_auto_schema @@ -336,7 +335,6 @@ def partial_update(self, request, *args, **kwargs): setattr(instance, attr, value) instance.updated_by = request.user.username - instance.update_at = timezone.now() updated_keys = list(serializer.validated_data.keys()) + ["updated_by", "update_at"] try: instance.save(update_fields=updated_keys) From 6c2eda0b1dd17c4ab88b97513b0232fe07122ee0 Mon Sep 17 00:00:00 2001 From: ZC-A <57583928+ZC-A@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:09:16 +0800 Subject: [PATCH 09/61] =?UTF-8?q?feat:=20=E5=87=AD=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20#130=20(#137)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 凭证功能优化 #130 * feat: 凭证功能优化 #130 * feat: 凭证功能优化 #130 --- .../components/collections/uniform_api/v2_0_0.py | 6 ++++++ bkflow/space/views.py | 14 ++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/bkflow/pipeline_plugins/components/collections/uniform_api/v2_0_0.py b/bkflow/pipeline_plugins/components/collections/uniform_api/v2_0_0.py index 95a27a63..c12e5a41 100644 --- a/bkflow/pipeline_plugins/components/collections/uniform_api/v2_0_0.py +++ b/bkflow/pipeline_plugins/components/collections/uniform_api/v2_0_0.py @@ -131,6 +131,7 @@ def _dispatch_schedule_trigger(self, data, parent_data, callback_data=None): space_infos_params = {"space_id": space_id, "config_names": "uniform_api,credential"} if scope_type and scope_id: space_infos_params["scope"] = f"{scope_type}_{scope_id}" + self.logger.info(f"get_space_info params: {space_infos_params}") space_infos_result = interface_client.get_space_infos(space_infos_params) if not space_infos_result["result"]: message = handle_plain_log( @@ -159,7 +160,9 @@ def _dispatch_schedule_trigger(self, data, parent_data, callback_data=None): credential_data = space_configs.get("credential") if credential_data: app_code, app_secret = credential_data["bk_app_code"], credential_data["bk_app_secret"] + self.logger.info(f"using credential config app_code: {app_code}") elif settings.USE_BKFLOW_CREDENTIAL: + self.logger.info("using bkflow credential") app_code, app_secret = settings.APP_CODE, settings.SECRET_KEY else: message = "不存在调用凭证" @@ -259,6 +262,7 @@ def _dispatch_schedule_polling(self, data, parent_data, callback_data=None): space_infos_params = {"space_id": space_id, "config_names": "credential"} if scope_type and scope_id: space_infos_params["scope"] = f"{scope_type}_{scope_id}" + self.logger.info(f"get_space_info params: {space_infos_params}") space_infos_result = interface_client.get_space_infos(space_infos_params) if not space_infos_result["result"]: message = handle_plain_log( @@ -272,7 +276,9 @@ def _dispatch_schedule_polling(self, data, parent_data, callback_data=None): credential_data = space_configs.get("credential") if credential_data: app_code, app_secret = credential_data["bk_app_code"], credential_data["bk_app_secret"] + self.logger.info(f"using credential config app_code: {app_code}") elif settings.USE_BKFLOW_CREDENTIAL: + self.logger.info("using bkflow credential") app_code, app_secret = settings.APP_CODE, settings.SECRET_KEY else: message = "不存在调用凭证" diff --git a/bkflow/space/views.py b/bkflow/space/views.py index 3574a319..4956b2c4 100644 --- a/bkflow/space/views.py +++ b/bkflow/space/views.py @@ -180,6 +180,7 @@ class SpaceInternalViewSet(AdminModelViewSet): queryset = Space.objects.filter(is_deleted=False) serializer_class = SpaceSerializer permission_classes = [AdminPermission | AppInternalPermission] + CREDENTIAL_CONFIG_KEY = "default" @action(detail=False, methods=["POST"]) def broadcast_task_events(self, request, *args, **kwargs): @@ -188,12 +189,13 @@ def broadcast_task_events(self, request, *args, **kwargs): event_broadcast_signal.send(sender=data["event"], scopes=scopes, extra_info=data.get("extra_info")) return Response("success") - def get_credential_config(self, config, space_id, scope="default"): + def get_credential_config(self, config, space_id, scope=CREDENTIAL_CONFIG_KEY): try: - if isinstance(config, dict) and config.get(scope): - # 如果是分 scope 配置则多一层提取 - config = config.get(scope) - value = Credential.objects.get(space_id=space_id, name=config, type=CredentialType.BK_APP.value).value + if isinstance(config, dict): + credential_name = config.get(scope, config.get(self.CREDENTIAL_CONFIG_KEY)) + value = Credential.objects.get( + space_id=space_id, name=credential_name, type=CredentialType.BK_APP.value + ).value except (Credential.DoesNotExist, SpaceConfigDefaultValueNotExists) as e: logger.exception("CredentialViewSet 获取空间下的凭证异常, space_id={}, err={}, ".format(space_id, e)) value = {} @@ -206,7 +208,7 @@ def get_space_infos(self, request, *args, **kwargs): for config_name in data.get("config_names", "").split(","): if config_name == "credential": value = SpaceConfig.get_config(data["space_id"], ApiGatewayCredentialConfig.name) - scope = data.get("scope", "default") + scope = data.get("scope", self.CREDENTIAL_CONFIG_KEY) value = self.get_credential_config(config=value, space_id=data["space_id"], scope=scope) else: value = SpaceConfig.get_config(space_id=data["space_id"], config_name=config_name) From a6ce8b250b218385163341579491d4fbd4a62956 Mon Sep 17 00:00:00 2001 From: v_xugzhou <941071842@qq.com> Date: Fri, 21 Mar 2025 11:31:40 +0800 Subject: [PATCH 10/61] =?UTF-8?q?feat:=20=E7=A9=BA=E9=97=B4=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=BC=B9=E6=A1=86=E4=BA=A4=E4=BA=92=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20--ignore=20#=20Reviewed,=20transaction=20id:=2035333?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/config/i18n/cn.js | 1 + frontend/src/config/i18n/en.js | 1 + frontend/src/views/admin/Space/SpaceConfig/index.vue | 11 +++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/frontend/src/config/i18n/cn.js b/frontend/src/config/i18n/cn.js index 874af310..2c487e84 100644 --- a/frontend/src/config/i18n/cn.js +++ b/frontend/src/config/i18n/cn.js @@ -928,6 +928,7 @@ const cn = { 凭证管理: '凭证管理', 内容: '内容', '凭证删除后不可恢复,确认删除?': '凭证删除后不可恢复,确认删除?', + 值类型: '值类型', }; export default cn; diff --git a/frontend/src/config/i18n/en.js b/frontend/src/config/i18n/en.js index c335f237..4472f0ac 100644 --- a/frontend/src/config/i18n/en.js +++ b/frontend/src/config/i18n/en.js @@ -928,6 +928,7 @@ const en = { 凭证管理: 'Credential Management', 内容: 'Content', '凭证删除后不可恢复,确认删除?': 'The voucher cannot be recovered once deleted. Are you sure you want to delete it?', + 值类型: 'Value Type', }; export default en; diff --git a/frontend/src/views/admin/Space/SpaceConfig/index.vue b/frontend/src/views/admin/Space/SpaceConfig/index.vue index de6af303..5e36a2cb 100644 --- a/frontend/src/views/admin/Space/SpaceConfig/index.vue +++ b/frontend/src/views/admin/Space/SpaceConfig/index.vue @@ -65,7 +65,8 @@ :label="$t('值类型')"> + :clearable="false" + @selected="configFormData.formValue = ''"> @@ -101,7 +102,7 @@ + :placeholder="inputPlaceholder" /> Date: Fri, 21 Mar 2025 14:13:15 +0800 Subject: [PATCH 11/61] =?UTF-8?q?feat:=20=E5=87=AD=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96=20#130=20(#139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 凭证功能优化 #130 * feat: 凭证功能优化 #130 --- bkflow/space/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bkflow/space/views.py b/bkflow/space/views.py index 4956b2c4..97fe620a 100644 --- a/bkflow/space/views.py +++ b/bkflow/space/views.py @@ -189,9 +189,12 @@ def broadcast_task_events(self, request, *args, **kwargs): event_broadcast_signal.send(sender=data["event"], scopes=scopes, extra_info=data.get("extra_info")) return Response("success") - def get_credential_config(self, config, space_id, scope=CREDENTIAL_CONFIG_KEY): + def get_credential_config(self, config, space_id, scope): try: + credential_name = config + # 如果是字符串直接查询对应凭证 否则提取对应 {scope_type}_{scope_id} 下的内容 if isinstance(config, dict): + # 提取过程中 需要考虑划分到其他没有配置凭证的 {scope_type}_{scope_id} 下的流程 使用 default 默认凭证 credential_name = config.get(scope, config.get(self.CREDENTIAL_CONFIG_KEY)) value = Credential.objects.get( space_id=space_id, name=credential_name, type=CredentialType.BK_APP.value From a8cf2f48afdb4a7442235ba380405f2360970340 Mon Sep 17 00:00:00 2001 From: v_xugzhou <941071842@qq.com> Date: Fri, 21 Mar 2025 17:17:38 +0800 Subject: [PATCH 12/61] =?UTF-8?q?feat:=20=E7=AE=A1=E7=90=86=E7=AB=AF?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=88=9B=E5=BB=BA=E5=A1=AB=E5=8F=82=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=BC=98=E5=8C=96=20--story=3D122413467=20#=20Reviewe?= =?UTF-8?q?d,=20transaction=20id:=2035436?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RenderForm/tags/TagDateTimeRange.vue | 1 + frontend/src/config/i18n/cn.js | 2 + frontend/src/config/i18n/en.js | 2 + .../admin/Space/Template/CreateTaskDialog.vue | 206 -------------- .../Space/Template/CreateTaskSideslider.vue | 269 ++++++++++++++++++ .../src/views/admin/Space/Template/index.vue | 14 +- 6 files changed, 281 insertions(+), 213 deletions(-) delete mode 100644 frontend/src/views/admin/Space/Template/CreateTaskDialog.vue create mode 100644 frontend/src/views/admin/Space/Template/CreateTaskSideslider.vue diff --git a/frontend/src/components/common/RenderForm/tags/TagDateTimeRange.vue b/frontend/src/components/common/RenderForm/tags/TagDateTimeRange.vue index 57505dc1..49ef7904 100644 --- a/frontend/src/components/common/RenderForm/tags/TagDateTimeRange.vue +++ b/frontend/src/components/common/RenderForm/tags/TagDateTimeRange.vue @@ -5,6 +5,7 @@ v-model="dateValue" :type="'datetimerange'" :disabled="!editable || disabled" + :transfer="true" :placeholder="placeholder"> {{validateInfo.message}} diff --git a/frontend/src/config/i18n/cn.js b/frontend/src/config/i18n/cn.js index 2c487e84..54a6a592 100644 --- a/frontend/src/config/i18n/cn.js +++ b/frontend/src/config/i18n/cn.js @@ -929,6 +929,8 @@ const cn = { 内容: '内容', '凭证删除后不可恢复,确认删除?': '凭证删除后不可恢复,确认删除?', 值类型: '值类型', + 表单模式: '表单模式', + json模式: 'json模式', }; export default cn; diff --git a/frontend/src/config/i18n/en.js b/frontend/src/config/i18n/en.js index 4472f0ac..32733d3d 100644 --- a/frontend/src/config/i18n/en.js +++ b/frontend/src/config/i18n/en.js @@ -929,6 +929,8 @@ const en = { 内容: 'Content', '凭证删除后不可恢复,确认删除?': 'The voucher cannot be recovered once deleted. Are you sure you want to delete it?', 值类型: 'Value Type', + 表单模式: 'Form Mode', + json模式: 'JSON Mode', }; export default en; diff --git a/frontend/src/views/admin/Space/Template/CreateTaskDialog.vue b/frontend/src/views/admin/Space/Template/CreateTaskDialog.vue deleted file mode 100644 index 94021797..00000000 --- a/frontend/src/views/admin/Space/Template/CreateTaskDialog.vue +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - - - diff --git a/frontend/src/views/admin/Space/Template/CreateTaskSideslider.vue b/frontend/src/views/admin/Space/Template/CreateTaskSideslider.vue new file mode 100644 index 00000000..99b7b2bc --- /dev/null +++ b/frontend/src/views/admin/Space/Template/CreateTaskSideslider.vue @@ -0,0 +1,269 @@ + +- -- -- - -- - -- - ---- - -- {{ $t('提交') }} - -- {{ $t('取消') }} - -+ + + + + diff --git a/frontend/src/views/admin/Space/Template/index.vue b/frontend/src/views/admin/Space/Template/index.vue index 0b858ab7..47a73693 100644 --- a/frontend/src/views/admin/Space/Template/index.vue +++ b/frontend/src/views/admin/Space/Template/index.vue @@ -114,10 +114,10 @@ @searchClear="updateSearchSelect" />+ + + ++ ++ + + ++++ +++ + + {{ $t('提交') }} + ++ {{ $t('取消') }} + + ++ @close="showCreateTaskSlider = false" /> Date: Wed, 26 Mar 2025 16:13:34 +0800 Subject: [PATCH 13/61] =?UTF-8?q?fix:=20=E7=94=BB=E5=B8=83=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E7=B2=98=E8=B4=B4bug=E4=BF=AE=E5=A4=8D=20--story=3D12?= =?UTF-8?q?2536895=20#=20Reviewed,=20transaction=20id:=2036208?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/ProcessCanvas/components/tools.vue | 7 +++++-- frontend/src/components/ProcessCanvas/index.vue | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ProcessCanvas/components/tools.vue b/frontend/src/components/ProcessCanvas/components/tools.vue index 7532c956..2640c51a 100644 --- a/frontend/src/components/ProcessCanvas/components/tools.vue +++ b/frontend/src/components/ProcessCanvas/components/tools.vue @@ -429,6 +429,8 @@ const { x: originX, y: originY } = this.selectionOriginPos; const { x: mouseX, y: mouseY } = this.pasteMousePos; const { line: lines, activities } = this.$store.state.template; + const ration = this.instance.zoom() + const { tx, ty } = this.instance.translate() const locationHash = {}; const selectCells = []; // 克隆生成的节点 @@ -439,6 +441,7 @@ const activity = utilsTools.deepClone(activities[id]); const extraData = { ...data, + id: nodeId, oldSouceId: id, }; if (activity) { @@ -446,8 +449,8 @@ } const nodeInstance = this.instance.addNode({ id: nodeId, - x: x + mouseX - originX, - y: y + mouseY - originY, + x: (mouseX - tx) / ration + (x - originX), + y: (mouseY - ty) / ration + (y - originY), ...node.size(), shape, data: extraData, diff --git a/frontend/src/components/ProcessCanvas/index.vue b/frontend/src/components/ProcessCanvas/index.vue index 467bdf19..71aaac95 100644 --- a/frontend/src/components/ProcessCanvas/index.vue +++ b/frontend/src/components/ProcessCanvas/index.vue @@ -18,6 +18,8 @@ @onFrameSelectToggle="isSelectionOpen = $event" @onFormatPosition="onFormatPosition" @onLocationMoveDone="onLocationMoveDone" + @onLocationChange="onLocationChange" + @onLineChange="onLineChange" @onDownloadCanvas="onDownloadCanvas" @onTogglePerspective="onTogglePerspective" /> Date: Wed, 26 Mar 2025 17:22:35 +0800 Subject: [PATCH 14/61] =?UTF-8?q?fix:=20=E8=8A=82=E7=82=B9=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=BE=93=E5=87=BA=E5=8F=98=E9=87=8F=E5=8B=BE=E9=80=89?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=90=8E=EF=BC=8C=E5=86=8D=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E4=B8=8D=E7=94=9F=E6=95=88=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20--bug=3D122536817=20#=20Reviewed,=20transa?= =?UTF-8?q?ction=20id:=2036238?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/TemplateEdit/NodeConfig/NodeConfig.vue | 13 ++++++++++++- .../TabGlobalVariables/VariableEdit.vue | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/template/TemplateEdit/NodeConfig/NodeConfig.vue b/frontend/src/views/template/TemplateEdit/NodeConfig/NodeConfig.vue index c7daf62b..31fcac35 100644 --- a/frontend/src/views/template/TemplateEdit/NodeConfig/NodeConfig.vue +++ b/frontend/src/views/template/TemplateEdit/NodeConfig/NodeConfig.vue @@ -73,7 +73,7 @@ :common="common" :constants="localConstants" @closeEditingPanel="isVariablePanelShow = false" - @onSaveEditing="isVariablePanelShow = false" /> + @onSaveEditing="onVariableSaveEditing" />
- {{ $t('由') + ' ' + plugin.contact + ' ' + $t('提供') }} + {{ $t('由') + ' ' + plugin.managers && plugin.managers.join(',') + ' ' + $t('提供') }}
@@ -204,9 +204,12 @@ thirdPluginGroup: [], thirdPluginTagsLoading: false, thirdPluginLoading: false, - thirdPluginPagelimit: 15, - isThirdPluginCompleteLoading: false, - thirdPluginOffset: 0, + isCompleted: false, // 第三方插件是否加载完毕 + pagination: { + current: 1, + count: 0, + limit: 15, + }, searchStr: '', bkPluginDevelopUrl: window.BK_PLUGIN_DEVELOP_URL, apiTabList: [], @@ -292,26 +295,25 @@ try { this.thirdPluginLoading = true; // 搜索时拉取全量插件列表 + const { limit, current } = this.pagination; const params = { - fetch_all: this.searchStr ? true : undefined, - limit: this.thirdPluginPagelimit, - offset: this.thirdPluginOffset, - search_term: this.searchStr || undefined, - exclude_not_deployed: true, - tag_id: this.thirdActiveGroup || undefined, + limit, + offset: (current - 1) * limit, + tag: this.thirdActiveGroup || undefined, + space_id: this.spaceId, + name__icontains: this.searchStr || undefined, }; - const resp = await this.$store.dispatch('atomForm/loadPluginServiceList', params); - const { next_offset: nextOffset, plugins, return_plugin_count: pluginCount } = resp.data; + const resp = await this.$store.dispatch('plugin/loadBkPluginList', params); + const { plugins, count } = resp.data; const searchStr = this.escapeRegExp(this.searchStr); const reg = new RegExp(searchStr, 'i'); const pluginTagIds = []; - let pluginList = plugins.map((item) => { - const pluginItem = Object.assign({}, item.plugin, item.profile); + let pluginList = plugins.map((plugin) => { if (this.searchStr !== '') { - pluginItem.highlightName = this.filterXSS(item.plugin.name).replace(reg, `${this.searchStr}`); - pluginTagIds.push(item.profile.tag || -1); + plugin.highlightName = this.filterXSS(plugin.name).replace(reg, `${this.searchStr}`); + pluginTagIds.push(plugin.tag || -1); } - return pluginItem; + return plugin; }); if (this.searchStr) { // 当第三方插件搜索时,反向映射插件分类 @@ -325,11 +327,9 @@ }); pluginList = pluginList.filter(item => this.thirdActiveGroup === (item.tag || -1)); } - this.thirdPluginOffset = pluginCount ? nextOffset : 0; + this.pagination.count = count; this.thirdPartyPlugin.push(...pluginList); - if (nextOffset === -1 || pluginCount < this.thirdPluginPagelimit) { - this.isThirdPluginCompleteLoading = true; - } + this.isCompleted = count <= current * limit; } catch (error) { console.warn(error); } finally { @@ -347,17 +347,18 @@ // 规则为容器高度除以每条的高度,考虑到后续可能需要触发容器滚动事件,在实际可容纳的条数上再增加1条 // @notice: 每个流程条目的高度需要固定,目前取的css定义的高度80px if (height > 0) { - this.thirdPluginPagelimit = Math.ceil(height / 80) + 1; + this.pagination.limit = Math.ceil(height / 80) + 1; } this.getThirdPartyPlugin(); }, // 滚动加载逻辑 handleThirdParPluginScroll(e) { - if (this.thirdPluginLoading || this.isThirdPluginCompleteLoading) { + if (this.thirdPluginLoading || this.isCompleted) { return; } const { scrollTop, clientHeight, scrollHeight } = e.target; if (scrollHeight - scrollTop - clientHeight < 10) { + this.pagination.current += 1; this.getThirdPartyPlugin(); } }, @@ -390,7 +391,7 @@ const { id = '' } = this.thirdPluginGroup[0]; this.thirdActiveGroup = val ? '' : id; this.thirdPartyPlugin = []; - this.thirdPluginOffset = 0; + this.pagination.current = 1; this.setThirdParScrollLoading(); } }, @@ -478,8 +479,8 @@ onSelectThirdGroup(val) { this.thirdActiveGroup = val; this.thirdPartyPlugin = []; - this.isThirdPluginCompleteLoading = false; - this.thirdPluginOffset = 0; + this.isCompleted = false; + this.pagination.current = 1; this.getThirdPartyPlugin(); }, async onSelectThirdPartyPlugin(plugin) { From 32cee4d4c87688a9356e47adbda4c395a04e0896 Mon Sep 17 00:00:00 2001 From: jackvideo <13226110808@163.com> Date: Tue, 8 Apr 2025 20:02:14 +0800 Subject: [PATCH 26/61] =?UTF-8?q?fix:=20=E8=93=9D=E9=B2=B8=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E4=BA=8C=E6=AC=A1=E6=8E=88=E6=9D=83=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=8E=88=E6=9D=83=E8=AE=B0=E5=BD=95=20#132=20(#163)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 蓝鲸插件二次授权更新授权记录 #132 * fix: 蓝鲸插件二次授权更新授权记录 #132 * fix: 蓝鲸插件二次授权更新授权记录 #132 --- bkflow/bk_plugin/models.py | 2 +- bkflow/bk_plugin/serializer.py | 8 ++++---- bkflow/bk_plugin/views.py | 10 +++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/bkflow/bk_plugin/models.py b/bkflow/bk_plugin/models.py index dcff1d2b..e22fcac1 100644 --- a/bkflow/bk_plugin/models.py +++ b/bkflow/bk_plugin/models.py @@ -144,7 +144,7 @@ class BKPluginAuthorization(models.Model): ) code = models.CharField(_("插件code"), db_index=True, max_length=100) - status = models.IntegerField(_("授权状态"), choices=AUTH_STATUS_CHOICES, default=AuthStatus.unauthorized) + status = models.IntegerField(_("授权状态"), choices=AUTH_STATUS_CHOICES, default=AuthStatus.unauthorized.value) status_update_time = models.DateTimeField(_("最近一次授权操作时间"), null=True, blank=True) config = models.JSONField(_("授权配置,如使用范围等"), default=get_default_config) status_updator = models.CharField(_("最近一次授权操作的人员名称"), max_length=100, blank=True, default="") diff --git a/bkflow/bk_plugin/serializer.py b/bkflow/bk_plugin/serializer.py index 4cc47060..f3f7db47 100644 --- a/bkflow/bk_plugin/serializer.py +++ b/bkflow/bk_plugin/serializer.py @@ -84,10 +84,10 @@ class AuthListSerializer(serializers.Serializer): code = serializers.CharField(max_length=100) name = serializers.CharField(max_length=100) managers = serializers.ListField(child=serializers.CharField()) - status = serializers.IntegerField(required=False, default=AuthStatus.unauthorized) + status = serializers.IntegerField(required=False, default=AuthStatus.unauthorized.value) config = PluginConfigSerializer(required=False, default=get_default_config) - status_updator = serializers.CharField(max_length=255, default="") - status_update_time = serializers.DateTimeField(required=False, format="%Y-%m-%d %H:%M:%S%z", default=None) + status_updator = serializers.CharField(max_length=255, allow_blank=True, default="") + status_update_time = serializers.DateTimeField(required=False, format="%Y-%m-%d %H:%M:%S%z", allow_null=True) class AuthListQuerySerializer(serializers.Serializer): @@ -95,6 +95,6 @@ class AuthListQuerySerializer(serializers.Serializer): status_updator = serializers.CharField(required=False, max_length=255, allow_blank=True) def validate_status(self, value): - if value not in [AuthStatus.authorized, AuthStatus.unauthorized]: + if value not in [AuthStatus.authorized.value, AuthStatus.unauthorized.value]: raise serializers.ValidationError(f"status必须为 {AuthStatus.authorized} or {AuthStatus.unauthorized}") return value diff --git a/bkflow/bk_plugin/views.py b/bkflow/bk_plugin/views.py index 21672ca4..84faae02 100644 --- a/bkflow/bk_plugin/views.py +++ b/bkflow/bk_plugin/views.py @@ -86,6 +86,8 @@ class Meta: class BKPluginManagerViewSet(BKFLOWCommonMixin, mixins.ListModelMixin, mixins.UpdateModelMixin): queryset = BKPlugin.objects.all() serializer_class = BKPluginSerializer + list_serializer_class = BKPluginAuthSerializer + partial_update_serializer_class = BKPluginAuthSerializer filterset_class = BKPluginFilterSet permission_classes = [AdminPermission | BKPluginManagerPermission] lookup_field = "code" @@ -105,7 +107,9 @@ def list(self, request, *args, **kwargs): status_param = query_serializer.validated_data.get("status") updator_param = query_serializer.validated_data.get("status_updator") authorization = ( - authorization_dict.get(plugin.code) if authorization_dict.get(plugin.code) else BKPluginAuthorization() + authorization_dict.get(plugin.code) + if authorization_dict.get(plugin.code) + else BKPluginAuthorization(code=plugin.code) ) # 二次过滤,处理没有授权记录的情况 if (status_param is not None and status_param != authorization.status) or ( @@ -136,8 +140,8 @@ def list(self, request, *args, **kwargs): def update(self, request, *args, **kwargs): code = kwargs["code"] - authorization, _ = self.get_queryset().get_or_create(code=code) - ser = BKPluginAuthSerializer(authorization, data=request.data, partial=True) + authorization, _ = BKPluginAuthorization.objects.get_or_create(code=code) + ser = self.get_serializer(authorization, data=request.data, partial=True) ser.is_valid(raise_exception=True) if "status" in ser.validated_data: ser.context.update({"username": request.user.username}) From aa405cbd074eb8422d0c99168e969422be0bfde6 Mon Sep 17 00:00:00 2001 From: jackvideo <13226110808@163.com> Date: Wed, 9 Apr 2025 11:53:06 +0800 Subject: [PATCH 27/61] =?UTF-8?q?fix:=20=E8=A1=A5=E5=85=85=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E6=A3=80=E6=9F=A5=E5=A4=B1=E8=B4=A5=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20#132?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bkflow/template/serializers/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bkflow/template/serializers/template.py b/bkflow/template/serializers/template.py index 3bfb8cbe..ce9bf232 100644 --- a/bkflow/template/serializers/template.py +++ b/bkflow/template/serializers/template.py @@ -128,7 +128,7 @@ def update(self, instance, validated_data): BKPluginAuthorization.objects.batch_check_authorization(exist_code_list) except Exception as e: logger.exception("TemplateSerializer update error, err = {}".format(e)) - raise serializers.ValidationError(_("更新失败,存在未授权的蓝鲸插件,err={}".format(e))) + raise serializers.ValidationError(detail={"msg": ("更新失败,{}".format(e))}) instance.update_snapshot(pipeline_tree) instance = super(TemplateSerializer, self).update(instance, validated_data) From 90bb707f97daa40edb0074bf552df42d07e96fec Mon Sep 17 00:00:00 2001 From: jackvideo <13226110808@163.com> Date: Wed, 9 Apr 2025 13:05:07 +0800 Subject: [PATCH 28/61] =?UTF-8?q?feat:=20=E7=A9=BA=E9=97=B4=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E6=A1=A3=E8=A1=A5=E5=85=85=20#159=20(#161)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 空间配置文档补充 #159 * feat: 空间配置文档补充 #159 --- README.md | 2 + docs/guide/space_config.md | 210 ++++++++++++++++++++++++++++++++ docs/pics/hide_display.png | Bin 0 -> 36680 bytes docs/pics/horizontal_mode.png | Bin 0 -> 12932 bytes docs/pics/only_show_display.png | Bin 0 -> 17047 bytes docs/pics/vertical_mode.png | Bin 0 -> 15115 bytes 6 files changed, 212 insertions(+) create mode 100644 docs/guide/space_config.md create mode 100644 docs/pics/hide_display.png create mode 100644 docs/pics/horizontal_mode.png create mode 100644 docs/pics/only_show_display.png create mode 100644 docs/pics/vertical_mode.png diff --git a/README.md b/README.md index 570c209f..6dbf195c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ BKFlow 提供三大核心功能服务: - [服务接入方式](./docs/guide/system_access.md) - [体验 & 快速接入](./docs/guide/quick_start.md) - [接入系统业务拓展](./docs/guide/system_extensions.md) +- [空间配置说明](./docs/guide/space_config.md) + # Support - [源码](https://github.com/TencentBlueKing/bkflow/tree/master) diff --git a/docs/guide/space_config.md b/docs/guide/space_config.md new file mode 100644 index 00000000..b8a84110 --- /dev/null +++ b/docs/guide/space_config.md @@ -0,0 +1,210 @@ +# 空间配置说明 +## superusers +**字段类型:** JSON + +**字段含义:** 空间的管理员 + +**默认值:** ["{ 空间创建者 }"] + +配置方式: +在列表中添加空间管理员用户名。 +```json +["admin1","admin2"] +``` +**功能表现:** 对应用户获得空间管理员权限 +## token_expiration +**字段类型:** TEXT + +**字段含义:** 该空间下访问资源权限的token的过期时间 + +**默认值:** 1h + +**配置方式:** + +| 示例值 | 描述 | +|------|-----------| +| [n]m | m->minute | +| [n]h | h->hour | +| [n]d | d->day | +**说明:** 至少为1h。 + +**功能表现:** 该空间下访问资源权限的token的过期时间被修改为对应值 + +## token_auto_renewal +**字段类型:** TEXT + +**字段含义:** 是否开启Token自动续期,token会在用户操作的过程中自动续期,避免用户操作过程中token失效的问题 + +**默认值:** true + +**配置方式:** + +| 可选值 | 描述 | +|-------|--------| +| true | 开启自动续期 | +| false | 不开启,到期后token过期 | + +**功能表现:** 开启后token到期会自动延长一个周期 + +## callback_hooks +**字段类型:** JSON + +**字段含义:** 回调url配置,请优先使用 apply_webhook_configs 进行回调配置 + +**配置方式:** +``` json +{ + "url": "{callback_url}", + "callback_types": [ + "template" + ] +} +``` +| 字段 | 类型 | 描述 | +|----------------|----------|------------------| +| callback_url | string | 回调所用的来自apigw的url | +| callback_types | string[] | 资源类型列表 | +**说明:** callback_url必须为来自apigw的url,callback_types为资源类型 + +**功能表现:** 在对应事件触发时回调该url +## uniform_api +**字段类型:** JSON + +**字段含义:** 统一API插件配置 + +**配置方式:** +``` json +{ + "api": { + "{api_key}": { + "meta_apis": "{meta_apis url}", + "api_categories": "{api_categories url}", + "display_name": "{display_name}", + } + } +} +``` + +| 名称 | 类型 | 说明 | +|--------------------|----------|------------------| +| api_key | string | API插件的Key值 | +| meta_apis url | string | 获取API接口元数据列表的url | +| api_categories url | string | 获取API接口分类列表的url | +| display_name | string | API插件的展示名称 | +**说明:** API插件具体开发可参考:[API插件开发](api_plugin.md) + +**功能表现:** +```json +{ + "api": { + "api_key": { + "meta_apis": "https://xxx.com/xxx/uniform_api_list/", + "display_name": "API插件", + "api_categories": "https://xxx.com/xxx/uniform_api_category_list/" + } + } +} +``` +(配置了名为API1的插件) + + + +## canvas_mode +**字段类型:** TEXT + +**字段含义:** 画布的呈现模式,默认为horizontal。 + +**配置方式:** + +| 可选值 | 描述 | +|------------|------| +| horizontal | 水平模式 | +| vertical | 垂直模式 | +**说明:** 修改画布模式后,新建流程才会生效,不会影响原有流程 + +**功能表现:** +horizontal: + + +vertical: + + +## gateway_expression +**字段类型:** TEXT + +**字段含义:** 网关的分支条件中表达式的语法类型。 + +**默认值:** boolrule + +**配置方式:** + +| 可选值 | 描述 | +|----------|------------| +| boolrule | boolrule语法 | +| FEEL | FEEL语法 | +**说明:** 详情参考各语法文档:[boolrule](https://boolrule.readthedocs.io/en/latest/expressions.html#basic-comparison-operators) [FEEL](https://github.com/TencentBlueKing/bkflow-feel/blob/main/docs/grammer.md) + +**功能表现:** + +## api_gateway_credential_name +**字段类型:** TEXT + +**字段含义:** API_GATEWAY使用的凭证名称 + +**配置方式:** 输入API_GATEWAY使用的凭证名称 + +**功能表现:** 空间将会使用该凭证进行验证 + +## space_plugin_config +**字段类型:** JSON + +**字段含义:** 空间插件配置,可以设置 只显示/隐藏插件,仅提供画布编辑,与实际执行权限无关。 + +**配置方式:** +``` json +{ + "default": { + "mode": "{allow_list/deny_list}", + "plugin_codes": [ + "plugin_1", + "plugin_2" + ] + } +} +``` + +| 键名称 | 类型 | 示例值 | 说明 | +|--------------|------------|----------------------------|--------------------| +| mode | string | allow_list / deny_list | 只显示插件的列表 或 隐藏插件列表 | +| plugin_codes | string[] | ["display", "bk_example"] | 插件code列表 | + +**功能表现:** + +①隐藏“消息展示”插件: +```json +{ + "default": { + "mode": "deny_list", + "plugin_codes": [ + "display" + ] + } +} +``` + +选择插件页面,消息展示消失。 + +②只显示“消息展示”插件: +```json +{ + "default": { + "mode": "allow_list", + "plugin_codes": [ + "display" + ] + } +} +``` + + + diff --git a/docs/pics/hide_display.png b/docs/pics/hide_display.png new file mode 100644 index 0000000000000000000000000000000000000000..8cca8dbb7aa5e8797fd254cc6be536cae1ea9f06 GIT binary patch literal 36680 zcmd?RXH=70v@V018Ng zMarfy-g>T6Oo}R$?=(p|7tUsZ0fewiR6I0b=`C7--u+ffwRNj}Q*r-D@nSad4ti6| zZr+hztx%wqNf{hnT@nK~b+KOdjTw(DuLij=n<8W0XWw0 ?-6FXHN)YYC0Ts0#>@2H3d`aC5OJ|fztHjG+1;EE1DK~O3xj2{05GojeRn&p zqaGouoa&d{!JYw>YFPlb=W=S5k;P9rPM-#1zI^|Kl#7;Tc #q< zJTr0*+;{xBgBTw^OvizDa523o5$Av_Js<|VWMGhNgx5TH=Uh#MmtrG#wu2MGX1t2g zdOmRURWuC!af9I*)XK8tn(*3{h^(mE@601WwdHMCtq}p))^f^7oYDT>HBTjZ@L^i? z%8r-|-#9d|_Ra}FzG00M$?$-PP979n&!Ab*;5wkfh@TJDtg(`tLpp9+(#hRWeOO+} zfxYrj{RmhF`6F-&O2j%U>V9%9@?WlqkH&3B3KyFSZta}aMRV^#d^HzcL$+d_AFuZu z+@MuW$hl5ECe;Rn8xPc-<@jjEd0jVf)S2UjXB)0432tb>uv&M~%r=PqerFQ6>~XPm zkx}RA)h1TLGt-CGr;t?Fb_2q&1?P699ilS{9 g=x4bhuU{;V)cF zWA19tYSPF;PrB(lPw7FL=r&~zmtaxVPdgzVCP>C5Z?gpA057KA7%pl&N@HtXYPOC~ zmn#lf#Ur~@WYm8 vV_j?;p6Pif=Ii3avt)g0l5T;J3bi3b)?4tR3e|@F;bZ- zYW3kSWey36yx!5}kcU2N5i58%lNRmQfs!VY${$Ih;FpGb4WuxnNkSP;c&ghl_rgfC z=3dK;k0aLv5j&WbEGBmBKc@v8q^m*$7Zz7LhiEYEavw|S=^HJ@Xydl0Wynqggsw5X zkJv0W4Q_|t#BRY*hRrgVOu3o4j6n8Pk0%3TO&n9*qF|jfyS7*l)K8-=DIkSLl-Sz? z0H^`RGw$UKQg}3L)4T7b1!hLJUQt;&D=F=^pLzbpW!dVdfIy^{DSKY6rgB(M=4$&k z9hh&GpI +w``2`QT_08WtJ0) zH;`g 2F!tWLx&5zF%QtXLi-PwwA-iHI#`&Wh)m|Z8PivwVQu9S`yEi$p zTc!RYihh1WlLN1Nc*2XN^Vl?bZ}|nsMl$@yugLLvIoO)Zv%MJr*6Wv}V@(srmoQK3 z^)D(p47KV4NX;7npmP*qEq Ox zBA;25U;1-$dLW}Fy~I@Fc{L%1D#o4YpmF}XCIHl)IVx|iw5OM)l3~x>lyTO%OG6-3 zU9#urIx}Zp97Lz*H5S3dUn!T=ZAJUyA1O==-%u6x6!YFn24z9G-rhgXV11tnPJfef zeCP6t{w~fh^!k26&GIY!EXSv(Mg3d2Zp~t9fHO93B%7UoWOZ|@WPM{z6pT=Lubc=D zc_wG%BS}}H;~IRjX|}@a^BZ%tp#oAc_nRK)J8LWU6o;%BZUC))w-s*86noM-8({vX zlVf!NQO9acOG_&uv;6RA?k!v4ngC*Z3Gk?={J#5Yc^#w5@ky>#*O?VxJ3C`=9cp^< zJd)vkC@vxiWVVUrf8_8}RyJ`!`8L-VKE70Oq+WAfn+HvlYz=^p#tGq)eP;uc;m>?J zXyi<>{p6jKMskVGry~98xd7CygAYSfCE2&`&Qv)55Qy>n 7%#|P!7`pG(ySiq(edIW4n=EI9IygEr9*4*QrHZ%<_|ydO^g8GT z_&9Ivc_+ge`zLEgD8ncy8KixtzdITJhW0~6l(Y$0)SZ*XlsC1W5UW;}dk)(QYM$_O z_GFjnwA-)-`xKE~Q?{OOn$_XOTG$8oy?njXM8N)F*ZKc=8W +BWG2W4uMmnhhQ%W@|) IT)(!W0?K{wk5NIHz(uF)7+&Y|Pd7c7nYVcC!|7>R zRkuF&(Gb?Syi v!Xg;LMLJH6+&{aYVqXABg&WBS z3^aPOm83T&n3`8Qpt0jZv-8KmoLAl4>T>iw;(Qlk1oX7y*lsoY%hllhI9yES6Bq3x zWu;kq&kmJe$0)cMG#quntv~;g2XOF5YgAQrVkwn>4R%COp)EU9(oBn;=>SUoph5nH z5n}#ZE8+EiG$oHprQTU#nPyd`0I|=x6-w#f=l)iilNeYU)!{>0-3aA*7!1ISceMS- zn1A7?lHfs=9ZWWsM4vAc<@+Fi49vtKeOB9xSyk2XwbI9?Nc{B15Fm>nF9Obk;T^X0 z^3D`W9O2h;W)<*6%c+L9JT}E{qWLKL+r5?}_*kuai%W_ZLp{KZSZ6dObpS)xnSc}} zRF2+@AA6*^Z|u)+Hv-tOC$XsIsNhqWn$F&oj41@tBuaz K1S?%-<|g*?d3PXRYEgBi27-+l^v_=YSt9y z8XyM7A|kl>IHvrXbRW74yejS7nU3>F5x*22yACNxL=C`zP@}wb{xSR2L$ka%!0Xji zJpKxoBXR{2r&K?{JO;*V?%RfaMx~tVaPC}tt=TYWV*1bGGxM$0{!d5&vMqX3D)qdU zf7YT~o0^->#tN!)>}nS%%l@1rw-;}hDya9>&WEv74qP{emt!e7*q0SN^2{9}qsf+- zqQ;5fuQB1*a4T{88P3j#yV94Uo6nzs`F}YdLS4DEL^x$FJR{V$dLowCn!s99Yf9;W z6}lg709Y+nvjBQ<`@y$S`}UB((*^cplq9%xMM_klZT3sCy{d&VXWjsmc36v=^_p?Q z1ce$Q@KJ}^l6na?nZ27?*mryB(L#=vTNgr5l`p$S$LYI8mTH5IXmiV7**k`vvZ_}f zw86{|dPu(dIc(Rpw|E7h0d1g8p`jJzOOVHtc7!UzpAYLi2J*)1=g2>xxpIiapT`7h z7<_# 6o)?!Jf&hEfOQ^=?x3SK z-F;;<4gfJepa0c6${FBYye6*r72wIASH=9S&$(3Dv}ks^|GSW(;2dIMe=SDe10mr4 z2T(ENAMo{y@GqYR1PXriD>w$hrC$Gy-=4Voe`S;C54`l3vyZl%e(8yDMc8Qf!QUS@ z>yB3B_C0&~O+2Kenv6-L X`{rm9EG7P2!xCN>) zOY;@EO;jwg1{2T(V;e&@cbg3m1LR+SAk78XrR^xFOA(gx63ez v`D(1wBFQJ95Y_>H?Q(xB4jJ#J$pzakwIXf^<`EnFdH%KQc^qy=0aTS{<~9I z{d6pbcJbda2FSDxGHs&l?{z-`aK(Pj=Kqp)ZxD)+OtFvol0Cn)r~Kz)eV}Za?U{bb zy4Zlo6mMy7E%yz7H(Qx?)Rxe0ek(4ZH(nlQs HVpv)HhA8hFdKLt(vxk8plu4zGT2Oh7@0Z3_=u@PWzik$DmK&9*anwkF_^;p zy?y4e^tC9zTah=R p2?xPZ8a}2_NvO5 z;oe)#Z}e!!4S<3=ao>zRXqDS@9i%A9^hXO<8{d)|qDyyQ{Ke`6FzP9H`>nDup3;H) zRC$=ssz!3B424j}8ec<)VE4UU8CpCI9j7V{r27UjW;t3td$X@A`qqWrm}a-pF|_I& z9jJMrlypE>Z{zI;yWK_H1L6$U{gBN?Gj>gTPyoKcOGihix5}{~F*FoU+ND&v#wbiJ zRn1az>>x4S8rnsgfD@&yti0ej$0w$edsRl#*S(+Bi*J0no}R73hjEZ x5!Rv*Fa)I_$u>t3-ZYmDivubPj`QX!gBZ*~}sIUfzAj_(eQ`bHSS&@Vz2t^gE_ z@^J?4+k>xbbn>eU0j3)vK3|cNEa7<#T>BbhI*DE{Suk710V8e)pxZZ7a~N(xTOn_s zUJ9??^Fb2%VWP%$^6y`}O)b%jvRKPhwt*m#21&nAj?`~$u@&k+l)f!SkqBW0Z#5)+ zD)sP5W=FjF*%jCI65E9W8^KT^*lAbSN~h+Dxq#{$9!skoYBJIHpNj(*= u70|R5?JQM@8ZKfb&DhY|5x3A0cl3;f5R35@e}HBBSM1LA3s=m3 z4E^!G<@I9dVjQasa}e|#%zV##_BO}F)*s@7lE!eC&t-MYH7Yw-w9DMb&OHtio9|s} zDi{lJ213mn`r&=5XC9@W5dnvZy{Kc_e6rB2J7V*QPN^M#C7Ivz`~YxP@-s2Q&M=BB z!YMT6HRQ2j<$(S?i**C$Q_D>4+UtuM3MtI@=?$aYANa-`3h$$ns!w{9%%`}>5UE|- zorWG|Z*Q(ovZ3#7u9K~}K_o9Au)Kiamvqs(0*O}FYM`PRlPFAN& -L<((%AiGBcFf!9v=|(7{ zUR;Bo;feuZ$=r>j<+-;?yTv-8(!dsRtDvRJf{YM9w2h6*j >j1-kw=K^aa>FDZdmBe9#Qa7+iqFd zPUU(KhL>LX=LXZstZHb$$?MO*5^>3}Ck`iSou=tptr+fw)8^N>w(KX57-#X&y_Gq9 zHQ %hRSAXrslUDM?Cg8v0U@$UJ=6TQx`m- zzuXgjh#y1}8vj7B)VS74Jm*~h4VH69c#v>PV9-x^JuPCg;|YKS%Ge1Hj)ux-ms3nU zs0f#qMJY4^z~#TpkhdkZI@2C_$;a0lvc7M&KR95azj<#c=7YRxrY#-z0tA;CQ%!<< zn}YH_^}wxG$fuP>-;&44jwv}GRi+RUs!;J&M8<@2g!{wt_Z5AjVAjBJft*n?*A(r2 zyZ;gAD=yyaJL7ZT$t+C}E8H$perk=etKEe+Z`G@HT@)H(IgIu%0Z`46xU7 Z )uM+cBQc?Upf?h-*`3%2FrUxULnZ2GIwQr*9eUF zN&SVmrQ3=ef--vd9=B+9_~KfXY`I>Q%ul*i9;5p&IBd?D24u#jjVlbcx^ Z9 Uty)YArWeZ6H=*l~C^1$~Wy~zG-*7ADb zx>Mi1$7`+-&YSvIgAf7OoVzX6-2Nr%vrVGV&5iX9s~y%`wTd36Vb5d`>;%3*u1)%! zd`o$M344?7DXTnP;W*%>(+FJ=QlG~blgU@zyJ6kY=8ZX^akr2T=Is-woPW186P_6^ zIEL@hz$b3JSK!z}2lu21-` z_b>Z6=80eO&Y!G3xn~$m-HkP?LZ!**3hQZkuJ^Rl^0e5;R!|WEJ2A8- &p;vtuc z+~& (Ac-+7ulC*6-H)PP!ZuIYOOqI2*W`?uh=VoPBvlH3J6ClZT1iU=UPw#260Y@Vp)DjH=F<(_F6~ zGP;@IT(BBOv#8@Ad<8979(U$CN09Gp9T)L9f3}HP0GRcR$~RkcWwJ2Ioa19;#72Fv z0@9%spb$0OzO~}EkOV4dVQ)m=1vfN#16B%7%58l*3V>m)l@D2 zl!$HO3@Df!CmdBwDd3C_pdvr9E(0MesFsheu#2lx1aQwl%g!f+t3^SYhEEKxGQ{;* z&oIc3;{CZt96rC+#cOhhYNuGKt8Ix-F~bX~C=R3Wf=eMPck(Sb? NDuP$G!tF 3k7(I}$c#V)(=q!MKMd<5oQeO#E8PcNhbzB7_2f_C~wl$VER5|2df%n8$rW!U@;l zabL4#w>@VlWLS}NrFf!1&>7%Eas;k1#x>bxKdE!1sHO+S{n6~ake+s{oo=CyrE?A1 z=Mh?E{wT_3k1zmLPAL`EO*vN|GnrNSQL4Kq`1w jn# zh1MUfwC0;0Y~1#qbJji>4c&cAr{0LuR*s#9q}^-{Ey=G~GDhGCj*R6xRQK5kCgz(U zx=5u51phDsf-bxdTdX}(D8yZ<2o8030(1=!%|$j@JhGzPXq{x(szYd=Sb-O0gOF?E zMl1sO&@GQ)8^b^b7(0K)+$<%Do6$;)jtQL&lI|`WV-vv8cXCEqr_bhY6dw>>rG@JP zn8y7p@&Gz?#OP9NK;~4o$VPWqxecefKwGEm(~4W%DGo9+WHwqGlx1ZMuclFnG4D<} zBbdaI&wdVkMhQ33h$IfP?r|)@-d-b%g8eVebvZvr C(W#@#DT{(luNcal@0B_B9B0k!u^HR5tCQt^XVcIpiXQ+YsTXf#>f1V^)$-C3 zA>{hFIZ<$#ClrLXD3hBh4cq8O*O?e;+Q@iT!4XZ|KR#zYLLf{J;s^TK(!03AT(N2^ z#K0e?e;=M0ZRsmfS-oau3gDk>O@DN*v6mO=RDcQ1)V;L@jd**iw!0?F+NLKiQ>T(B zz58L+hnxbt6tR|xG35l^@7qc@6ySbmUEY7lzhdcqJ#UScKVFLegC;M)Jiipz+%H9r zHqRZ}rrQP!*L?hbFP>`qlo|~sfKN!_b+Ju^(lCM0a0u?UjOTCdfGPY09I0oui0c5) zY4Z6yxnie-#Q+0xrTBA8;Zz^<6?hDQwo-niG(c~1$~$)zXRK;|8T&@bO2*O^hF==P z-9=6ToW>h`c7Qz&E!iuE%SH@VCeCkNVzK7wVL#(E&_>u#IAVqYr$B6&34Yo{Rl%VT zqJCxT63+NXSDct%L_jAASVm)?L-bm8kna|)%wEU+qC z7Kt`hHgOY6 y?A+Wb$Y`E$W90 zA3rYt{oss4>%FkMZ6DfEk} kunXuXL1(F*MCYLrD%^-?{ R~Ep=>Nc1 zT~7Yp_A@JB$BuSL>2HV1HB-g$c8Gf)OD~&+2;=@X b0%+Fepxx-@kCDQz9$KDV2@tLczcW8x*u5Nk1?%&E9&8LxtDHP?-F|EJ0szi@ zdER>r9H7HlZv_~Ktv(hgit@O+D()%}8di@7u;3QkD&PnNkUw*Ac9Hl-Cw{8Bo99ig zbg=@ttijmm-J6y>#nsYSD$Vv0r@Lg8C8AqN1gx{^SBex^nV%w-*&k8V-iq>E 8m+xe)012(<0yzpCp;WA_(N3+g(IrDE0kOc%BC-kMb|p}C0>IvIh)0a6z(u50 ztMoO&T|7}@Uwau?fI%eD)WuAWvF>}hkJOeW!EY2{AY7jB_s-;fMrb-iP(h!<$F2_O z1{p**i&Bs9mJMqzFOaNwVx+3BKL;|1idDkJ53gEpg^51|B6SbTH8Jq6@2A1Sn=X?2 z)fe94zcH?VDtrWOoeoi6+4OckIU}TAx-=e)yUf_})B*!akkC`5|HO5iupa_Zai@Ds z7r$0O&aN *sN;o{-T>T=We5-hB 2)o=0tOr!M~4 z&CSD!9deV;rc%HA^t3uQ)}L>a-p`xg-QV`>%gu=Z;B0bksULDysuEdM<;mzki1Oe7 zQ=w{xuT44D@?H#kZ*Y+cFoO~(nt8=908 xLyjC<`nd60Ruifi6jwhy|acWc9Cu#o4_RpY&H}V_;`rh_PY&kiX7t>q> zGPtQw`Kl+D-~2sHo~jgp;H+ySldE#jTpi-*F{UipG|M3&9wWWi3UJsOgHFEoqBW>< zXuNDog*FdUZy2{VY{(vf$X*I=z9;O8<;~Vy+MJ0YuxfyP1VRaM!C5EOjo|>xMBu~= zD>LEst>!>kv)eSgXuB;5!UALoYB*GT1F$Y`>_~xQm)C*V7*V{7MDb;$Z4I_Kw6g`r zg$7J-xiV$YpiHG|aDjuWsSy|sP&5XCBBpwvAm#Q?OwgeMtAwi}5{kdy03xl8fp5e$ z6Q9!)%zk;N7q5@} 2Mn_7tIVzjU$35i%DtEr$6fWzGR 3Dj~#ZdDeSd=Irk_lJVOBBgB{^thi0iDbC%T&1XOO< zM1UFq&gKV4_LZ9Fuh;HbR`b@VOS<>wOUA->LlYXIx;q| J|kO~{5ltK1-9y*p^q09xC41z*1Z4; z%UyhXrQx*?HeA<+9~^hMsJ4t$93pVw$-~Th9klH mf>kV%aT zaq__ZRPEGw&!m|VclU%(={;A OKG4 za^U1X?As^-+lw;=0mc*acoZs4n_gR!i&N44qHM<%TXO+_)kmCku3nNLVSx)>;&c{t zt*AgJ++q)ds$RPill?C*h44IMz1s8!$_T7y5apQ2h)*q|oB6tedKX8C4!+--JYmjx zh2K|C4;eI>#v{h%j9^dL(FiBYP#&&IppNF#^Ai0Y1d!PLt||51&BOg#RRsTGX4=Xo z;p4eyx; v|m?2Sp(a#6p+BQ zEa114xQ*uW$i{U!HCV `vSdtH1~i`b)0#XMe&jW z>-*u5CG!pBeITAx5de1XNx-=~l>w%vpt$RF`20#QBg^}I4!bw U73QTGFM=HyJ)i#Oe%oswG=r}CTaji3O*S1g$w?nF?Q!hO 66<@uI}Lk)Z+&OK()AU%>>gs%PU8WQ z=pVA`u+fnSl NbmrEm zG*Um !Z> BnjoiMOqLa;S)`% z#f~bTe;T7cT#A*S8ZYSKI9K)C-SpBNvFlst8V2d7C`RM`UoP?`7@i2QDd@{bfW;~% z@LZ(eG#0r7 A|=cPZ{*?CHupsJb0qtaW@8qxTIv;bM_ z6*q~qlii<+i^>jALZcG=|9sny?(g5_gc%x+84qB$BGDMpr*#@iZGu`v7b*SfoCDO0 zMW;Tz53ox^l|6La=hlfFNJ qTxt6;Yhdim5sXyXZ3T_cK`tV0Wl!zELYImh) zXH? L#ZLZa@Q~E6$B^4TQ^^Q^tq;GdHXseN2|EGa- z+Fgi`S!&h^&!Ov%ye*bjh7N!L&e_M??K3vkb77C2P(McOf4-@s7?>3SFkbe~ZeH19 zOYO@;d %gk+7Q4MYHpIZ57>C7`_3+x5koa4vWBf^PmTC5H!njsunlkNAl{NUBKexQ7 zBUm r3~Dh``i{kF%d4c>DG9J7^KvTzp5g+)CvIn0lz )Cjc7f> zdXxE^O^Fb6gm{S~Xo8Mi_EBtsiAD}j1wsmz>+wF@ej4fk;NIq9RopStK%+=!98$da z$+?n>t6NfsJ(ab~I!u~kSYbaTqazDs1$4rCz0ct!^(j58ta0CuS*363Z$p#Yy*=d< z3ld+;o$<2065%-$;E|v5_Pp*slgfw)K=E)JYwkDp98bCXo6=g(%%}B* {dD|tq&npvNj<&mks4BUPeeCF94|&iQqtr3Uvxa0j@SD?WvAvHd)F&fEWaQl= zB0>`1(F0hrR|d4te6R}4ByR(}WbRx-vHd}vLU%zD0}*Z$As%0b9hVT0sQEDtwa13* z=PSIX=|)vykc>~&@oDcuX={Q8O#e{5j4SvH`z3Z?>f>&6U2D8>V)Y2{4PY_HmjfC3 zxoL?(lk{H+TKLc12f!iY@1*on2{}!c`qilU2kIBi1_XL5{m+O0ofotG_b3!H^zm%E z|Eu PW?OhIyJr*AZh$(KMg*>1Cz$WM!<}pkCt|FNJ;|X&VPz4qkQbGBQFOC zzVe#)1faWXKMtx2%uwS2pi|fwv|oT`WpTxg&u3ryTmR1IoG9;qk$zNL?Id8ZA4>k| z;O>6?^nVVi$?+rae;TszZ(Z2`+uMGPDSYMMrw=CozZUM!x&PYWUBKcm@kIU+FZ~9* zt1JE%7rrG1+kAdYVDrh7LM@< 6OueU?MRvPdn&<@_Kkvdc-GR+ng;qXjjuaULqh6RRiOZnD -nPP^r|9zP?Y!yLR+nncO+Ive4WlevIKo3=t?LJC+7pAN;dp{ Q zb|-1m|Hb}$iiZFAXF*2>N2dZr`2a*J5u&U`ta8Ft#UeeuCgo H*-5N8@2 zKp!8t(V!0|)@K;|DS(T>i-(Z^YTV0nwCtCyUHGcZ@jj; vA8Ug}l&uTeovRZx$Q{@eH zAg49w|Iyx?Mm2eLVZ+SO0s@bfs3@S|j38A6nF6(xQU_FIk|6?CRFKF#gb $24Z zFMf*-o;cy-5nU`^3(CLiZ%h`8HSWmzpx0RpTKFZh)PB|p^X*^6|Hy;h!KHa*`S?`p z sofxVI74AtRM%u!z5&CA=|-D iQ$HD1pYdI8dRf7O+5 zHwG_$@zWSzMMqOf8~eZ|oX_B9dlRZ)X`7W~IBK_5^i(fVFD!D#TV5XjFRxu)sM6l1 ztLRi4WCePv{6>3w7WS#iyMnTe=8O-=D*B$Wy#_DqU*-XUjqm-Ng_l?0=LIY%ZPlAD ze%WgoL=(fLAi;~gc7Rqu{J*{+2DdXG@W!-%xTil_s4i~p@M+2cP#y4Uuc>a zW%AusdBhRWCvh5kd0}DlWjDe_S6Wz})Fn4QHKlNN?RLlFWIc)b_34?=%gKJ1Uq0lj zKX&YvDmxkzg0ZRdLD#wjHP?ZDzcl>gcRH@B$1Y~!K9|4JKUM91a8l8?cit{&=x6tJ z`}>#t+Yi0ehdlYdR6EZXjb?|+ishVLb^u`YPh@P416KnSUpXUXdT9xWLkNU%3|UyW zsqD-|=-BNl`FD#y*tMvkZ~iDlhjfayl?6Is^Gw=1Exh7>aC?xYbiDjH Q#;Q{Why}7yc{-!~VQHEQlMaGSCSEBd@bqj> r Id&XDFe6+ltS{kd>CR0A5wz*Z1MSru+O@ zj^8HmlkdQ!cHe(NAmBnU=J{=TJta<>D^P+Rwc!Ss)wkV>g*WEgBfI3DpdbJ1ks@21 zT^{Wcyw?fKfmlc4)DkWftU)1X8I(Y~_H6kV@YG`v z7)Yf53&*Ip$PB@jS (}=Y342) z{7Rz)Jn%A#16#9VuG?yT#Qx=!AKRbQ$cPpkx4dAGd0xW?T>eQc)C>N4IVY>TskXPj zgE~FGqdKoWTK_#Y@M}52;CtV(u9T0|rSo7m-yC=Kp!whM-Yla-rBKLuYL?gX-0Adx zAG50x!SXK!V;>&vpKI5Ofo`Jrc61wZGY)ZueKjB1+w-4auE$N8j1=cSyS`a&^G;p4 zow~U>H@460imSYTC8u(i+~(~Qf1HtjDQ#&nIr=o~g2|n$Qmy0XD{ UuL*?Ak-s*0uE>39XV4{$$M|}3em6^S*x$)49 zo_7oBd=F3H|MJdg7Rg}_|CGz>&K ~~sC_4>zXJT;c8UBMEley8tSP#dzOBy z?WW^#g&-M4e~hJD!MGl{Ug >XW^wD+9e@a9Ki?7)L!kB z=8ihL+eOVz&_=JgsM@21lleXcg!=A2@>6&6(yeXAi1}_eoZTZ1YdW<5 1lzn*eJHS zROvi k zw2ao?;S8FOECPr@kwfPi-$(g>#x}od9PPT;*UaAUt4nn!-> @0HAduF1)^_ zm6@<) rG-$JM18wq9k;ftP_g(YtHE zd`K_0P1T-w_cMs2Nt2ISB)s0>=B|+Y;)SNp#h}VI%Ri!#;^=Bn7BO|FlMp Agzo)CLhFGPzQGJ2-d(yr%1wbVK z;mSnN7V9ei7S4A_V_g5%FxulZKt)m4D<6!m9--JK+ah@<4q%%UM{SXO(<#1}qQr2S z=k1rd*7%e*a*z8F<(TN(+iVlp8XdlNM?C3a*&E0&b+3t8y;qBge&4(F(t7kt21AG1 zSMrq85tpcebT{YB%il4IFLCBOu{DPpt|Mi|nKYg1NzxDca(`<-dJPXCBaStDwmGLp zUN7rIRZk)=`w7i49G9q>80P*$hD zLCW>g`_4}3#j-Z?2|v#G#~%(Ikn4GI(VA7Apqq9 af>qtIIoc{PcT0Fe{w@|%t2J$sW}D%N*sE1nB%Y-GXPPKiEL!Z6 z(6)K24=wXRp3Lt_$!PdnrOv01uLaLZ_7Z(OetN^E?cWB$`b3XNZu$DPDhK^@crbyV zTc8KDp1qu;J(>ZJjv}uCj~a!8{5|-eqMuKxv>ToVJ8>cr_L?=&>XI+Q4@y)@*4{yd zSJE33{c@~rW0Llc82GcV>UNtGB={RFMI-ZLNe^9N=T6vUv2v>Va^q#2Es`GUeDnN0 z;MnY-z+-qCMB7P%_3nkY)j{}oiv(E4KG7$Y3K<0h+|1wFHtS$ZJI*Wh0^fdkSTxdp z`F+qp&G0}9kkt&AokIp%=3RKr1#xzg8#KU7MQgL)CGq153qxD?)xuz3eBiD4`o-f# za**$D0)`YFaXC7^zBwZ_D!0&^QNbZ8itsv_$Iw=AVVlue)Df=f@cE zG2k5>C-(n%LrZGQ@*w4C#Y>Sn%U=VDds+qT!ejUW&@p}(2`_bWvI4T8$h@#IML$n4 zli Qy{=&@<7tGrw;;MtM)qQq@7=WPd{@xd+==WGj+5MfQ)RWFL61^`*A2 zoGJ)uup|5l|Ibc!amf{CEtI)*0jxJ%l!oaV&z!+B(nOzj4tGW0U+F3F0?Q0(@R;+W zk JvJ }Hlcv9Td&IZ z)F-O&Ad6+!R_ioab?!Xpqb<_VeTPl@Ie6S@J4pqJ2qMUa#ky1V&qjAOuikd_Bp%8T zr0Rv6D!SEYF3?ylv|nn`&l)u~%^8!^R1hu|?;zYwA8{kN28PL2`t6Zb+UF(U4JeN{ zGB`bpz~ZcHLUAZ_-qNnoT?Hr~bAt;I`ibBJ)a8ife@?N@Cv5X+w$9G##N=M=3rU_s zSLasmi5ja)wGNxO R)<^4+xz%$$XBw#I zp9L#PJaDTa?INWATo5reyURNTM4*phvDy y>fo<*hzd_8s<=U!4{j C zv$QDG4hw3$trdj&%P?C$8!PB^CK}S!rA(iBcFKkBCXoX-Z5%e7APXX%^ZL>*vB14l z0Jp-28{XI l;myU^c?m5r&SV7JG1cJyK!e`)o4fNi7d_2wPcJA12@I=Hb!*# zTjCxQd4rDw#=m@~Q<1{qf>!UN4Ig-^ioC*}y*ZrpGFDd~V-;_&woNV!lpRm*lDL+R z3_bIy%3Ln)XqKt7d*E~}z5LKjR0(H(-5SZuEgF&g4i~D%AxEwx6st4)4NXE7F}VIo zGDswO_NafTQ4}++ET7)8JcFsWzqM~>!6Bz#RhcI>{|l{NQ?ojBqQ28-TYxS9{=wJ+ z>JSA(XS+pkZUl7CFbZfRh7A9Qr$7Gb_-@>_(lEPV 46&Z9BpZF#CEjsll 1anf-wEa(qhA{MZA1*p?l5jb? &+bXW9Wh~bKK8x_^ |T{hjcR>h-29Z_u$`5CMm5;OhJUQGJm%D7JY4f z<==SWHLvR~Dt_d-!DriLs?C{g@q)|reKCtmJM0L0N*lR>=<7ylIXp5axNOWZPu-OH z&s-)&J@T9tc A$dygJm =%8x~kiH%D+;+UKW4ds86;xTJe%bpq#o`Z#9NvToF| zwJ?QZ_=p}96MYfISZn9nZ+k{r`67T?0UyV9kG50{+7q|=Nk0+ZAXMP&NEIG|G#_i} zKR%>=V~c+HXm@p~!}E-&$C-Z0dsJ4hlWK@hXgt)Lq2ELjmtCb0; n6-XhLS9S4nsZqt$3s2eXig(Y^V7a@sbxML>u^jgP+W{tn;uE0yP{Brym8cy%aJ zx1mN>yi{1{^tk2j-Wg3zKaa5BX|+rjIS|e1C0-I4G123+Y}^j-7D3=SWy-oglD5K! z5Wt(& Sd!b5y*G ~mRrVqWAO>f%_C?wHjd-M-F9QKCBZ3n0wrM_bXMN@`MtuB@rMP3xr^F3P03>F3TZ z)i*n&P!jq3rwraZ#YAsUTwBXYvC3?_i>+_zERs)p$b{W}SE1b9FCvd)X=+B@7La$& z3 NyNNU z@Vz1MlyUI#xzSnc>?iK4E95sEnDv?4lJxL5*a-no%xTg~8KN{Uc1)BtI~0)T76E_L zBlVopt)ji0T`-xMaD9#Ld*RjNlep2uVX$oe{xh;L)&r0HGNc7D=sTghr+Po3G#jX1 zwS&}okMK(+hSzM9=0in(qb{YeA2)Lh|6+z!VeJ}+H z<2641yv4d+q;BQ2T87|H2*S6DII=r{a^4ObMk@SAWOHYFa7&BVFYLheRG@Kl6aIZ< z;pt%B%Y|u^X5i9K7Q_M1f?-WDIwur@q!W>_(?Gn<<2!I|)XZsvArOqUihH$A*8x)g za06`lgif)eiU2RR!RP1{|KNUk0Bt{tK3Vmz-_x-IBe}juo-4Ch#?ZyRI_=OvA_%(| zLY-eBah}WyP+qk8=t?-}SR}W-@H^C NeY{iv Gcr87eQDUzKR$RuS4uRC@;2e zcq$GP9T6$XUn72Xg@w(&Q;W*oIR@}nh|qlT69=h(F%&@m8qC35caUMX$~TkfU;k}c z<#?s%5R4bOV;}^dIWS;GWJs%C1>(S0_JB~6Zc@4OZIE6l;sYum`kK$0m<7nEM1H%H zg0Wm63yRDO8}qBLi6YrIKI8$>lusg>viN=5&E(elt{^+bserd|W#4*d ))jho2 zRoL1T0CH(dMG7jiw495+1kmdKZ0;fGgv0dP40Ea_PkZ8?$hYC+?MgiB7Oa9XcC^j3 z_X7!d7EtzcQ4Q 6+Z^!J+>|MtVg)YkwSLnLq*=Vk90YwO;Q@8BJZdD;N z4;6Tj#jYHBP|yqr##7FJY>a6lObH0;e3$0XgF}x~b~%`Lmilr=MmL5Iy11K6HhCb* zDs)|4vyA+oarAG`xNi84Z JIngRZJ# z!!;3Eq*II-aG~y3S@GkpQtly*H|Q+9Y4wGMz+H}JE=M!;^X4)bi|;Tq{7?>S0S#`U z0@%M{gXu|rAbtK*rxyZcTvQwQ{=;nj?(BV32S|@9=r$7$r;pj$mzI8pP#9tWFfHUO zW>2YCC)IyJ(a;e=WqP-y6LTV`n0W;WW0lh$gG+sH@kmZ&53k7wNL1s4kCYq j%wTbLPeG-v)3IQni ;B^FF{?UIlpn9OnG5qL?F1X7 zbV$6*c8Gk#;K9((jds_t;MF`N
4
voPeM8L9*4SxA*}t9KReA*%a{KUW~#dteGlit za-I5J$Y*0S+tS_}7{$?s7puJ}Q3WaYD3fDA69W@XA}`S=TY0VXn-4gw?Z8u*aiv!_ z#dpfF&~zVRf@R&z05vq~AQ@o!e98$WiPm|H>42tYgEvK(>SSNyF*4TrW$TR>!v~WB zMAH4ZhH2h@`6)jL#LL$iU6=t#&lp8vUTGN~CXq68Fvw`Nv4P%js=VG!R|$>!zYgi4 z$&3XP# T{i`O`}CvawH@i3=ndrgsP7z->#5C+y$GU%=9vbKj>l aZ967}B5k5YU zGEX@kl)J`SrOC(BIfD4c73*UW=kfAf t)bgrMZG@ZJruHNSZ`xF zqs+=nGo*7z56Bs1Fqi;Hk3}g5v+|>3Q_Q*||44cUTVTdjU8?q3HJ__&vP9V$$m%ZL zG;r>0TUFIu`u+R$owOh&i6;7-o?wG {Z7!3>?vPgqoo7>U5Yncd^V4k-M#cedLUC36|2@>a#F)-X7nA zx@65_#V8e>tF3nH*Fcf;NWUlEoEx58oL+KLTq>!UBkf%$b@(4Ls!VjC!>ZSaBbQ1D zb77%upc~WQi_+#A@y4o(%|qqE)4cYB#CQD5vKmiGSte+YkxrZ{0xrZ=ou5l-^#Y`= zG%8TQRhu*+a3=Dy3n+f%ku3V;jG|PH%OX{a`wR9~EdZFA6#5 G^&b^jTu5HNc`87@^V)nbhH^y&wcN(=!QYh6pgD1TvY%MK;xx)qu~p&EM6 z?9QZUU}~{?kxOGW=IVqQzz8$j6j)XPQ(>rV*Gv3+(w)TF0Y!zWqWwP?QrV$O5&}Ad zStu)hNaKR}78_?6J&SbW$*$;13cv31%S3@dBj0Uo b~W@}tBlBH#b5ri(8mbQngk^nY2SXCV~9LC9RTTD=NP1lr*r)nwf({B z qMObS@G4SVQ=`EUQ5-ye?IEHmDlqlsLJ`PtgnwTI#Cj(lelh*B%MRb zxheiDKi#J|({T_eQ67whgpL_@rfK-IQ_k&tc0O*ky64*CLJZp~V1DpgOQ!s&ACuPD zKJuYC&k-dA+Xx~gP;-MwFyIxzC}KN^oRxQLL%MEuHV!rybf-X?(_QwgHHanUeb{?m zRQ>^&jnaD!fsAhpUS4M=7e_rsz)lx=ASyQL7J5n6z8Ac6DlIw3{6f7!$u3)Zzb)TO zMi|^#-g$NI<;z<_r3D7kiQk0%G)rl=R(G=}ktgb*(j494FK$;XxOZI1d7%%CP`Uy4 z?52TSoZv0PztGZR30#h_#Qx(|##484CvLrFx}0u+EIj|ZNZiYyS9 S7xjnY%z*;wb90TV7dC! I54t4 zJQb%Mf>oW0&xFFLqUt-FqUzNV4gQ#4u!kUFGy^@I29JIM*40J$)8c3&cE*3$5_^9` zI&WQr|5blIEFr`^62Dy4g!#lt_r_~iOT|Bf>P*nlt#P=fA7q(}%n?ckdZG#*vK8h8 zRSQMpQIqL`rPn=t^9|El6fi~b4EKrzMSF!_Er5hYLVg(}9gC1~cQ+b>r&TaK^@jfW z6(K_f*%g!khUb66Q2riV`1q>)Yo0DyL8A`9qO*vYU?pLI-wj*SQ|{PLE3|9?)?l6{ zsw4o=zEV?nQXGQSd=WnFM4nke3+)?<#1FP)n}DK#3~c%}{FoK2GQUMa5#kO%!z>Bn z8(%pV_CoY`xZk~VxI+x4P$Du2>PxVWFQOQ&>Jar2k(Ped_Vt&1fKd*>_F0xMzi}U+ zm3n4_rzE3b1pp}aeh}dmEem+iDTpA5${+`z(#6*zLW@Mgs}(f)ro@Px<+nkmT~=04 z%Hu8Jiit?bUrFw`MGz|ynHM&ui1c~lqe $(+YMHGnNgSc1LG75ybl86?T$5$Hsn{YqCwXa~6 z<<2?K{y2-=P#KIO;!@?diYqAaDXV+yhad{|l? 8#L59;E@1p*Q g=Vab{8F8qDG&lIT&72qTDkd6g zozXb8;8gx;=w%F1|IDp#vclS_G&2b(8JN%YH;?i%UL;%N)r)j1N3to28z+q*96HSB zF?iR^5W{9j;nJZh0Fhx(jwAE|>8?u9;pO9wCC;sb=-Vkb1zS zKqytu_MXuv)^+gxuMH%m&8I Ucw;e#AKQw>t#1XUX0<`%WY^v)a5s*4g!de|X~erBZ2Lytl8MCu^> z5`}n3W5(3bXW@!R+f{BAQ%1b+MY-*^@rBV;&^MrMg9~4lDNnlv;-mNK_i7GZP3=nV zZmst3nH+0%af+Iwc0=mTate%z9yFdL0i*(0U^CD$jSuttd%FkM&sBkK23@x5`g_I) zVWDo`5e8Y_Wp&7emoK5lgD4?38@S(&1b8u^hXkmS2vk(LaWTP#-w%+`p0U7OMG1O( zo=nG)v&vtZ^{n4oI~49j@}`=L9sfw$SM@D%5KZKa?1Yn`9QIorr8vvDVDe6q_7PoJ zw*xvB>q~sJRp@}DF7BV}9(0;&|Fd)NXoBvTXi(ZKP_OYAEOH|xYo8B*Ee6nn!u*)# z(D0$W%<6N<50TY@D#%`S@j$fe-80IUh8wQWf U15 zTQo}7=X4)cjEe$X5SB^IT@3~`H3wHSHWFfFWeeD-FlJ|-?xL*&zOn8z5Ih|4R6tE< zL3PnVNcv|+wiyz4xNN7(C1~O0*;tK*JBHa@_Shv5yxzd!ubZwxuWFI7?FQm8vv>A= zUZ<6yyv(m~5Z9SJY23COkmXid7jRs=V(fIw1$&FRs@}wn)DZp;->l;BwU9qP(Hf-u z1r$t;8GPWoDYmAZNLm%b{gj=VYK3Y;k(mEw6ybNHsHHGY_8r?)VKu#X7Sw?3)1q1w zJCFYbJXlm;u@atcyQmsgz2CRr6{_sg<;ZV>=Eq9|cng`MF9@N@2V<3#Ff-jKd gyYcvuapaQjesr}4fr<;9Hf4NtKp&~4Qp_s6gT`Lx(n3e zK%N&B;UAn*`L~n|mjgkPUJ?zoAP47gQF7@vH*bgaRv2Ei!aAoY+54(Gt;8t4KdrTv z`(t?!AL_p{&;Q`m|KQaBZ8#MHn!6-rWtx$K#azypCvJN|BP>o>`=GykvS!R~WT9S( zm(RX>`7*I3&t!UWtdDL0t5|?7x8zZ#zI@gwfD7T^S3^LDK)|Ih$5?z{sAkDGQKRtD z@4Fq7g_T2~N7GCxk;Cq*WX8}L{zA#-4BO>~93b0^;P D+P*6 z#RF8sZ1v;b%3nqsWW_<{(7`=&;<*Z pWj)%VQoH>gZb)xAG`BOiDWkDemrS*7C_hV<-pgY z1=#dr)_$*}!Jm!idcz^4XVTUfzzH23Fgi?6X$1{~N|H9eTAsu*BiUxc8PkOiyL_7a z7?pWT;4k3Rm~+~)q81*hAgG%LS0kD~lX$82WFjFuf!Y&F4&i9o1~s6m88`RKL0AcN z+JPn&{&WR(7wDv{>WA7YA$`j|bfA!vnZUk&5;cSh_%uKJ`WC8yGF&!NS~aJd7zXvZ zey#K9DM~zW@ eg`UjnEcLcH=&v8Kro8s1S)-}&_uo;s~T4KF1+)s zRE|jsLn-LcA$-Z|0qsRS;qL$=niUD3*b5d61&IepMhm&Rza|vL>Iu{ ;b3ImT-MrCzcSf{v50Ag_aBdVbCZ $j)#b-6e18rND5;huDH65? ;d;;B&8sXg!8a((? zp!V;?>X_?1j$xaXL>{gfeDN^wRwU@2w>G8j>-|ACcUnccK+)Ze*CfX(`r$suwa8pt zGZ8UGn%4AFiu1gCoVs(*T(w$kX0$SIZNrHEzVlg$%Jel#Ne{`}V5sE|u =+uy61<6OH{_sh02Ym30#dKXpQVs-ox*^$W}m;0c96@v#A zy&YgnK{qj!ye-fJ>-XFOHSn$~%^7!N(3yN1XxyXLd085^Q{yPy3=q^nm;L$YN5nw4 z0g!q}?;kuk`sVhwW~iT{NIQ #Um}q$0GNL_OwYEQ z?tI){9B(80Mx{~Kjh>*APc0QX>zUPi-@9JZ*ochs?6}FJV^{~59+L@#C+<|N4*=D^ zMKT)(4km(zos6|j7v=n~SQMU&qtQY82!_qh#4%dGpR8W399gttC8w(=wh zD)BG_A(Vm9L^Nr)(ne!f?8Xeq5W_BYaYKG+6%L4kbiPb_Of+bMh@7}no=X?-_GQcK zZ;xw{* ~Jq2-l!sRwNs=qpTSh@H*%T?4LkO^;nTOC?dU$Lx%o5>>y+Ffhua%(#u+}Y(3j3 zO<&{KQn(;@PPJy5V#Z{qTO}|G1naiRO%3p9k1vk^+@8aGz`fHsnQrSyHX~#+AbnSe zb1-* EB`$HC~Eo~s93~D+nV!hp_?Su_PC?x z%n_c^|DpWnk0e2sh`N;3Js2+n9pmyEh+=$k*fY+_&b~a|yCWQ^C~$FS7$jVGm--@S z-Xq-r6&n8Oic>EY``Ohk2f5_L0nLu~^|3~e8EG{48B+xQro&uE^b?Hov5fHPT924$ zpiyjKre9Z(Xle$ERdOh7Q&A(-uIXNu8*Q^uVy};Cg<``Wm&44XBsChFFsuOn;%@fD z1<(_;<>l0Y>Cg4&JnO!UxiD^o`4%1p{oS@2ag0Zxdo^hBQt(fnmH#|jAo7837vu-$ zG| =CT15mGRK;pUA|Le`^||MtW~ z{Q}0JaKHmKcry@Md^;Rbmtd{AtuaYB^N0uD+ViP|Hgd%zh1uN((JZ@c_FPGKM`Mxz z>S!gT2e{E#{`WUn&lwoX-;ftrg_g57$=N-2M-{D#bNQj^EjStbL?sYN9q9DwvPTq^ zGEr !Tt!ZntzSNWK1bZoepI?>+(i^v4VNHV5pez}8ir?deR|Btts>+1R)+ihU z^e6e#UzzEi^5S3zxS{()W`s)McF()YW <(!j+KdIfXa zQ3a~&CD2gi=6iT;-j5v>|M{z@q(s1jf(~>yXOvuA{UX9|EZ8t)(4_b5<<)@g=Y&TN zg@K~ai9whOvp&Q}7xleJW$R#{^ndK8o4x>vl>W>9{c<-j3)^~AQCK%caZkc!uIgpN zizv4uow$UN9`xzwO=?mdjk_fYMVNw9N0h;z;VE)u`O=7`bj^j`Pk?aGT)d@4&gud+ zX#4@WyYJ$oyQxlSfQ#0_KD2z(=X4?HH>=vP-nc(<@i_~?Mc;!jum5z2Gcp{-O7FHV zR5fzbzZB;p?fJL=R1dm7E1|8obfgdJ;*2#jckq8;S?Cm(E1%Igy-NSx;-%(oEqTBF zbT9#k6ur)CHrc%01*a_NS`fH4AgXb6`#_p+kU3oN=>9JOwEGYwT`&KpVY> Y+BKVy?nXjTZ215r_aB4aRaIh zs$|P8Inbq!uYK}xoAo!g>!6aivOVR0G+Fb1Rfqpo9sb{}I{fb Qk0HBq=YI&T2LTC z1w^DtC^4af5CR00kc1FI&Xe(VX5RJxpHF9 YSi&n8TSvQ9n^lZjg+(vA>D5Fa?cPVvh_gHTQuKo!MYob75syK; zcHHv3)0a#-x`n7CwSEE)0lm!Tq@Lma5(niy&V9=70Ym_S%8u*t0*{x^L3@Blobmts z@&6Siye!RAS4qj!f>qZ?9}ipB$bz8*-RJ}Lk%SkkW~<&oPlH|s^^hY4!&bD@U|3IE zRkzJjBtE=SeMEg;oxUCo0*UGZ)`Wf}2WQsiMICfY$VBz( ;;8NA-s7A?nFxPVk8qz?x_N_WgnI0%l-FNqi=;qJbM>LlAkb5Op2Hv~$~Q8V zklUY;@!_GJqQgig Aan%=AsdLD)x9c-d6W5`L%T0c$Y)_IkxPKog?uWD<@5`lj>kgdM?c>6V zl *m z_4e8nEH=BNd$Sg)Fye+lf7O?tP(nlA+zIs>PxGSIx+&m2ni&$G=@i}Pe#Ba3mhUAW zmTBU8^yQ 2vnM%+SWB+c=|``QWg^;YJ(d !&-v#LKKeRXO5T?bBJYyui {=dWD;YiJpEWgm8##mRsF_o9Y sC6t^wO5eGYG}Ty*<@*n z^0lEA?FWksVXh5F69!AosZ!*31+IjF+0t4uHUD9B@*J&g^^r1;y2oI=Ib1i2bUzzO zd&tnu$ wR`sI}Kr^pC;3$L|M-^&uln;DOM#kxIuoopP@ zcWEDSOLTE{D@WbNnWI+6v=J5%*ivK0h=|K$Cm52)YCYE&LY*+GTbuSX80Lrh82saV zZlBl9<9F^}jZs$~jhgaA7hd{m^*GLJw2#ePir<%fS!-GmHW~85eQ`%|*<9sFCVG$0 zh`&Vbc$MRQ9^CUeAD`|c2don$E_Ouue$@)uE|LH1bbFMuQWgK9wDA@iEyZv4sH>B0 zoS@9LsC85GVkbYdl>C1z@#J-Zj^6c_Xg@!vqTk6BhHe*nRVND-a6)UZvb*9bOhA*V zaz9D$$kETkr!TyXo^!zJJn}OT(oS)iSuX5@ycr5~e%UWl)e|La5Rp;s<6cY>C|ry$ zQM`UL|GVbNz9jhV@MH&zx~%{^IY`oxydo=K1rZSCmRZVCnz(qj67N>Z9E-G4${V zJ|28Xf-)9-3NqmxA?V)cbQ8)|030NDGWU$UxVJEmg=I$=Em*1}+K47Z6$fI$$HpAN z^}sSEY)dYmgQZ7bzLH^o$6z$-0!Uwi56EjpKhp4_-P 5MxS{{-b=109a7j?;xy&P%c z-F@t+kFeAMd&kCAMGWKL$0HPP-q?F+FHIWvY_^oj@l(^ aM 3<=KwiT+rbvc_*}vRxaAX|$d%*-Tv0uOV*#o27tM6Tr4AVxh z5* S$Wuyv4)jN40#pSEhgKLQ=za-`B(AqF?7~19Mq43y%F|Cc_ zhIoESw^j4(JlF+4XZpsE)aV #@|FLKw??+ysfQ42I~1g zzNiu8EyeGQlPYk206umgS>}yK@QM`>d=zf*&5*>K=_K7rAj(;ui(||0@4xRVJ7)8Q z<`q{Tz`6A 2Y-S1--qU&r2(Y z`z6zMfrE8mI?}XEh;vs)_4OARMsF%f#=@c1D+*BZY&3hom5pQs{EWUG#edWZ56uU` zD-g4CPmk-tCu}SSTos(`PyDN#jok!OpiAsO2>EOy<5g>LV?c>zoS?vMJYF``{H)22 z;@>fmi%VUpr44V>;BbmqZ|YDFxL@|lFduljhd^y`)rh&fU_EbmSV~;;oM>%c>z9cd z=8r zx p`Qw*i^osV2UI(Z;iyA*#3)v2Z(Pwq5c^38tnZu*3$BJg0( qm2@pmzW-Va5E55Vuh9hlRY zRvtYi0pM!3IK!{k|2U&1Z~S=YQyXaPjyUI&z;!B%54^7V;vHd=_WK^uC+pk0K$vR) z-nG9fb}Mhh|F4fd?f>iBX2xwrrTyE?xnWI0c`&{%bw_`mPVBMfFsieh=V2Kh3iuy+ z>Ul=wydpwY-xn>LOWNrEpdfV_Ziv%5xlV6m>>ux}SNxZFyROR?Pg@S5*&;qmkVqJe z&T3S{Z_TfY#kXwZ`(v;$#%)T&<>N1f$m|0kXf{`Q&sE p9(QK30#qO1{ zD2anYp-keqFX54O1G~pD$oCUe`taG@|GHYyz-cYG1J>)T-X<9`Qd0TIW*rQtICCP5 zngI3K82@zx=taGY+JSPTQLlAJYnMDn8ku_NR{`Owu}r$}$e*T!G!37+@RF*}9j&f6 zUM2Xsj7FHYsM4RUh{XL!1q7>**MfVi=;fflTVS1bUQGmEd?9sW5_IxBh57_V;w|1* z7FmN-GrQ4ltJfguY}e0gmQP^qSQkXi>N*<~QG?s{6}(?W!l2=>ls0tzc+^}XjTv_6 zxQc@G;V)poBw3#I{j!<)yHk>Ai0+X9?X2D#Z#1HO7U4Lh8>Q{oS?w9jjP~Fx=+-jw z!0WIMi@NC#MP(HrGPy3ZGZpWCM&o&a0QI=|O6zlf)#4fLS E41~Z7~P35}Zf&q~v*d)(2$hoD_dflkT9j>yP zib--wib?0R{XrLH{o)#yX6zfeFA?Iwb)#r*5GRasduIPS|IL2Y<%^k^&5 *DiJSK&`$npEs$Zm^r92^E(A5CqETWege!CYqL8aB!3Ibeb~Z=Mz%E$4Qo>slaD zOg)e4;ia&H#RRi*2cR;;yXxEWn)wHZBRir>I(e@7177`7#1k>t^JW*gbk`YoYG!~E zn|J+JP8EF%yuhmMA(*lgOtnXpQ5b6t&1CQCLtiYo>TxHM_Ir%+7Dw!#eA=&?rnBxW zK$?2?Cn%5WiAC~Pyk+&Eu8Vy{w0XXcc&%B)PgiV8r)yM+W`evXr>zNm%J?*$WoIGM zVNzPYEQn$vcB^Rk^py(JLN*C&b;@RFw$r>0xy15eZL*$@>yPY9j+5sKE#`$7tPqiq z>fmFBiD+%324`}&p7TBhth)5TP})lCcGYzbko%ZgMi0$1j`mGt*Qv33bybJaOeUwg z8}Y?1?fY&~Gwvl+iKP13hr7T7>Ao^2UX-h=jn9D$0mFtGACZBDQq1UUJ}@NZ$dj|= z<&GB(_`S(-cEt>}IR8SJS+n!?IKk8#rVq}gw>=5I5G3;M6X5h_#`?ty_*HkYa74eI z@5MZRugXR;VXcjAZ=C85$ZrQ^*f{?JSRc6MHK;t(BRIf5*9W={sy_)F>TpD+!TQ6o zm*U(@I(j0M4=Ww#+BKG}pSv)VJGcaT_Z !Md5AJ^g~rURkfbdRoaOl6)2mxSr8 zQxl7h6L886&W(a 2aXJa$^!m32SRJ8#V2J$@Z7l+whiO&7w@KJ48&RjQ+ z0wVtPZwYj!6!7{#>OfvMCRcFrDmOYBz$kuDA|QsyTw=K<^~ y0^@YXvv{FLU@_#tI#~qDL^O?<}a!FDAa=bek1>Dyv4sMgr(^ecb)nF z`3jH^pOGWtLSAvkila|Y1 y`of^N>T|G-EGD@zCVn}9;3_HGd@z{>tuA#s~S;k97$Eq!% 14mUg{)+TnIqiWwvBMrZw$$yKp9Z= zB{(^Z$n!k6s=%AX?R@$$tQC@20&`Xm4|?sl^?hJ=8S_Uaz)t{qu}LxBWQho%eapJe zK+$}9WYk4rsXU1{X&7agEqRC6aLsl?10-c&q)Qo+MwdJj9i#|}-5NsTnm&wmIQp FvcT@Wj?Wbx(5jk&8&|x>19yS}vncT#J}XRQ z#;6eKky+ @|1Hqm?lX zBB0rIwF?k9I~X!I+8%pKc|M>gQ(RX?)PKAQrWEBtT-ZLgKd1_~#CP^tyGZVbM~W1c z!vBxBUz=E0C|FgW_f%E-y`mkV;VmORpL5?Ac=9FXn%XBe$?$=bTWyJ?s-^33Lr;FB z(`3?5doQ-okhB8MvIui?a0di%5_+9))b>8-2YQx_Ro$M0l9EUJ(4mYUM6?NuK7`g7 zi7h}!clWtA%-K#`S3a%Vd9rC!Nu3Gl&Op=gwNiRk#x&@jl(?ENeT>QhbbnE!#Q@JS z=tg_(!ZSh25<9+sUY}@1ORsK*vX_>}1E5zFZ`5gy!lrDHbtEM`J#=Lz9k)63Azjmi z^hKUR9SJ?Hw>TR8a{ba%!&2U2nj=4+KKRO|nW1~bn#F&-sT+17%Fj +g6prWm zOG1MV7Qci|G$s88?%p(1oqwGTR!ul!8YhU-4yAV!v4y+N-27uL*f)Ir+e2c%kD8=B zr8Ensv-s%=6-lE!_DOfvjeByO?P85u{O>c(xMu?CKuy>A*?3E+S}Vd}R3oF~sJ=mm zXa2fM!8pjP4SlQuW~fvI{V~*7=(5wY30sDV?@ObPp82VPoYv?l@_o@num)Emn^U}n zN=lQTVkhcd1FsX)eHx8j)m^vlXw^`9nBC0HdQIn{b)ck96xsgAXNn=-N4(bmZJv~v zOz+~27?m7)adkctpVRg7c=C#wu2B}9uor+xVq_9lD+=lYLFPd7Tub& z?KP{q9_W%^SV4Tl22bddD=XFNjFJ)iEg|G4zbLb`iAo(kV${O=?=;NQK1h>;1H?v_ z_xMjW!1pxZ_zP{%wV#IVhrpcP(nGyqO{PuNF~an$$+C#8sT@;2s+(;8{zvBLc0_AM zQUE^U{wj4jvyMY(+MVO_VHw-YN8R&QC%g3=Cz(8xiKpT_wsBO?;Zf_%% {sK%y$>)v6e^vHIkN$(J?NyHg5F&G*Yy+5>8}LlfSj zTG1Srq$05SEGZiiP=WEEn5kmcMl6of#2V}JSgg84%_LPp?eszgr*%)`{sM8{<8kMK z^z2=j2HGPUP_!py?>T5`nWt;%l2Ije_vkI9va%Y94=44!ojQ4o2ln6gDb6Ze+Uy-g zhCZ|-=~bY>CJBTIS9ivS2Kw##@YI)jJNe5c>)OQIyT#sFh@rJ&Hy?to$_+1_(Bu6$ z>iOvP!(>u*w`@;RQw-HiqP9KlOgDa|SMyH$r~E<*-I(Vv7|Z#p<-nn1 +-jbC_lM(~Fe~ zY9_0PT%3ywT_k2K>W9T_pNh((6)IxB4S<2dT>Y1s1+sF^dpMc2{$8~Uyb7zm*lZ&L z5^8|X-Xp4Z#7fyZQD;PSz3X|NckbjBaN0B|dA8|nMEfU)<5sN_1t(F4gF4Bt%Wh~# zZe9pb2Ix;CbLUSZe%d#!YygUn_P$4@0YvUfC7FjRKrb7}rt*8x(w)^Deuij0(CPtM zqI`E4Jg4zaU}3c(0NX!k4%#1x6udRWr;OmNVLpN6s%@cc(8=fP-PbUNfHr=*JMZyZ zr;8`cE3n)$EMa~eg%V8?mbTmvN$C5d#uOH3)1#0pKQF^&d2cOzZg~IwRQ|RdVo$q% z4g7bxd6gvD;!>34fnWK0t3|Efv;FJm7nA!T%@8#s%VR(faGO9RnY$*y@6aga_v_vR z1JA!jF)=N;fhqz `JcmP z){)CA7(PP90hSM=#hnKisGU-%Y*f!d=!lP*KQQ_sQF8_$aS5dE@H@%a?0C7w^>_A! zdULgZk~uNzHS?xHl>@O+Hfrt8_eR B}kW9e)P6clHF1|WLt;T%Gp{aENf5)Z58oVj*Yd!B&9oQ{$od< z1(VL)fkgjsqko@n3&9(gpF8yn4du|80Pg%&U^+Q}pBac&z~?vSB{*2CwfoL(!U*+| zOD26W)U<{RdT=&sJo;3#Eu$DM3KP`Mhx;A*4Lm(~V!+WWu-(e$+OjxMeK$0 @@Yd?!wDx+@&Zu#%X%ayEqdc{n<9r<@XIt1_BdJ s(oGf3iLH!JwOpe}L?^ z8_o~`Xw(e9u{SDWqUwkhf3Q&JMTZxv0p{U(_77ZRBiWKgcj?P-LmG`ui2#gtEy!E7 zKjw!3U||H&p=fin4-;K%vA)Z@0Z2*!iu^_u9k%a*rO}Uj3rjuRodBOOH5kVR>rRG4 zb=n4W0?YxQJsW$2x(8M1I~Ei2DZZ5iKx);*`omIwgveLu$pxqNZQ1_Lz>lxdGrAR< zAUWtI6{{gn-s1m&>qo50>*;0yb-vY;&5BgiW4=$0ao%@v0>+t*CNN?*>XzvgQf!yE zpp=29V7JUu_=H~K;(h+oOx_oE>_s(BDsV-B)tKbG? dbab~Zbe2PP)AUO9;;H!Gpb5j(uzRPd*`@Gj5n@i~_{@W{_- z?VvdMoXv0GhYK}=d6x?dJ(y4XiHMtytQKwY11W|V`|bibl*uR2HX@AjhoLuQ^e%=h z-}G{lj``s-8NM>nU()Af?*NIg43_!>vd5w-mB-2w;QhO>>^#J`OP%2y_FVKSA|{Ga zo5`8QGi#Ge`zrii0DZX+S#vT<1A>m|f)m5MfLq0~M>Q3hqyV |+$=3Db=Z^gAxhcKgLM$mg%|?nb$@jMN2F+ow<*aU*L2hDu5m*2 z=af8;N%lKs$|3^H#iE}(C<9GYf1^nzK0&s=YBKCNVqDwF{_*Y5n% uxG{h8)B%EyqDw%pn>=d7`Pr^cqv)&j1ueVINP8==i%>c+As32gxq z(xYW?kk`P>9J!*zwk5Wb2R8w8<+h9$9eIzx6nhFZjBroQ&gc)cqUc3{al5V?%S^&G zO}Fc~<|Dr>Ukxlm{%k34n;BeGCv^Pmb3-rc$v0g!%G1zH>9@9l9NM~;r>cNZlB)p5 zTJIL}!b|UP=;N8S2_k$^7}d&632^MjteB!4IzUBlZ%{Nv-We#tiyZ*8_`A9Nt53e4 zJYICV+7yZbiB_cY;C{@?)~&)gy0x~Icw}X5XR@S6CH_^nGaH3p+f#k)`d)*tYab^k zsuiQyiE4HHx;fAIEP59WdhcC00+bTxYd{|YP$d(&^hnl42`TX<-AoK&sx5o@?{+=( zydIPi%W>XkUJ||4l`;WltWGNZcDn6JX@yFqj9!k$(qOdJirtl$0w^yPJ%_ E >p%9_YXxd`KG7hPPV9G>&pJEngS#~BNdXk${T@c2mbgmO!X0@FA z$ruO 6XH*|MpEr4SqW4>o28L}YCpW3NoJMV zq+$70d%(aiJQ0~*h~%EEodA?LcqhQLD*r3={1cx;e+vMII~%QHbQ^>Ndve$}uq`@z zn*iYHs(du!xEh@mV6Sp1?2uGqdms<4b$c|KN;xQ@^_;z~8 z#5y=`(={az5LU^99(Crrj_R*mAgvq}-gwFCoG*|woPSEgkA&&mbv-Qg&<)o79}Whi z1G+Fm2Fb}or`zv*on%g!5S|FInYA^0Qwkd`&V}QEegO&8{O0i0;UwxE4q1BIqB(}K zh!`Aiw3*~g-#Qh#@u?;x-Kyde*WyL6?OZzZ(|;(Xtr{3PUWL%E^4RB@vn1$ 5PX%wW5_Y4OzRg$}@7{sDynYHk zH|WvxN3GVpmb|k-u%b}+Y;L9eyh&5&(o#rJ8;CsJ7EkDNih5{ltO8WcFMjp?e1PKn zvVH>>1PpHD_*4NI{vyf}fn9+Hx9%ig&b_wCh}2!+AN6Q=xSvDz4zJ_Du~}&s(M)=H z%=79aw4-2}(DYC%jDg%zacra g867b9(GWjT)72&t;P=PY! zvGTQk;DhMNwQp>&GLG9Ba_kr3C%61HD%wg%^=zL;pEgDUWFuAy@|u5T?jwC|zlYe> zIGf=e UI{&T$Y%`tyxt!8&o0N{ga!Q!lpkUrI*rjdVnSZAciBEIbWL2@uz%POiV>p-pmb# zii1QauI~f`HtfezF`3lYMZ50;MOc!(Awq~{_j6QjeetjOa1dvX5xuds^#zTA=sS2+ zD>p#wlI;)x0K8EUtV?eS-asiI(Yn?g?bH)LROTLiUJ1e(on)VDzB}jb-#sGU02A)+ zL$qFZR1GCA6W5elTXNYX6h|}m`6w{pU3({ArR=fG8)d3r2u#Isvz^Ix_AyLv> 2pO=3Gsf7UfkoghS_Nh9yF!dh;5kAPg#`C5Mx{3vBtLy*BGqv(9?tEGoc*6R~uE z`O9<>p_Owh@JxZ)Ha(1@Vri6|S0+CD?k%-pPBv#J7=ZcJ4= cmF58^Awxs53 zW>2yek}{ZD2XqUppcFuj<$x$;*Z2SNL IsvM$9^|n) z7jLn?{WgT0KwNv)a}U@92w!Qxg46BA3z=W`0dx!dF=tPh IP*w(d)^wI==h z^V#~BbDf$Q!_LZXi#^c S<|66Ti@O6xJ4_e0B* zSXOE@VNSumZmB;Bxu7C6bL0wt@w%2r^m#RiWa_O>ixxwnPWxrjP`NUBu|+~F!a{Ro zvmngabOb1K+(A-U%Xg4mJD zk3<#h;v#iL&=DAEQw8= 3{~~tNG13ccE#AYsV)}-?8#OpALYK6Tle9`zCMk?@nDOKV)^Q z^Nr7dE|vlaWb=Syt>o51dh~7w2U{L1EmOq<9xnNa-ENBt`O);gX6v eBY|88o-DdHlNNuE DyM0s|dQnJ!J *=*#e z;l6Vntd+@F&re59dgb#cgxglDZ@$e@xU7h@@c|Mj^ch{F?GHSt{55oTd%1U4D`;Fk zNhL``n;&F|8U&~yW6T2A%GX%A?!dTkuO?lhpGy{Qy8T>~Aph9$<&R$-{6Z*^bOEQr zW2OFU`We1ifm8Yzk>Cn n)IEEd=IcZ+=m@cD{L-r^5k$|AJ@EU0U2nhN?eXn)Y@ zpljqH-Y=2A-kJrj@0Sa4i?dOO-jxD|8J%yQwm$u5#Cz-)`TPXT%B?<_viFB579fn> zgN6P3CUTkz*Sm-0YE~nXBb1W2cW^gFf3gi(pMaq>3K&W+a#6Y;A@l;U4C6>Q 5&fA8o!p4&SESuV;^^I j2QTE8IN{_%D|2mJDFMFTfn- z=a2&=@Qk~UP#evjXql#c>l&;#ElIO-f&{I?qppv2<5*_4C|?5Vvu(e&p=Ze3hnG z^EEkS6Lw}oi1GU0s~(^8^-I@2;_tcc_}_lx$Dl~<37>Eelg%&>e8A#EVB(YqkFpzU zo{ wNqH)#1&?zhQ>Zj}$Y2nzeWNB&0 zP3*JrX3kl^IyvOf8{4tenF&Eg*&F)~ZG{!5AbyioAJCU2t~!yPaUGB!35I{@sU<|& zj@3Od0$sD=s>Y$`*x|(5h(b#(VNJh!o~M~_WIHf&E0*(GytfL01r%VB=l{lf&;Ps@ gaK!&n!X~HtD5B5t)@cDi7oe*KW>=~&-}>`^0nsm+tN;K2 literal 0 HcmV?d00001 diff --git a/docs/pics/only_show_display.png b/docs/pics/only_show_display.png new file mode 100644 index 0000000000000000000000000000000000000000..d027fade2d1c839d209e92a3c63afc9f72001e45 GIT binary patch literal 17047 zcmeIZXIzt6_cn^-%vceX0McX>h0v8MHMS5b0zrz@JR-d+olr7kK?wpX0s;mk^co=) zDIuc}5RejDfKU{K0HGL2s44HwjPrk<=i@o&cRrl=J)dswaPPJEUVH7euXU}p<1EZz z{D;L3^YQWV8{N2W$;Y=J&BwRT;oz^pFUj}rIq>mabvC+w#VXu+c_OY6G=$+X*tQ+t zIzFExy0&@DX{DbtQ%#mlH;PGr{a*IsN~7V4U#{4>CEvUPx3W6^^Uqg~YyJFlN;E;S zYPB>xW^*8fSl6TNG~qN 6R|HSIzrA3)!{# 81gW!C!2@{*neB;JLM zy{+D*`FJy*NPlA-9~(DTD=i$7N !(F^i!T& z2Zz&jtA`WiyAw3d2vj{%%;A*uupr{g;{w^AA@QC-`%L%Nq`gHxYWf(B4gJoMwqCXn z?)qX3Mnh%t7|E~~*di1WW~LqX{d%BWg1smmqop0=#X>?FRP>*iq|Lzg1C4(zxC({W z`y(S$NUE;~?RE^6LswGFr!{g|k{zL)PpC6B+kTL5 3I_?JxJiQmtTz9 z#R$n5RaH6v2t6i}MIRYpPu%U1)D?tScA}^Gd$q%u!K&3(DAe7Apd%3TRTyk{Wdm)0 zItD&iR$Lj6u!T%bnwhJZ@9lVIVF4Q3uk3dJH}cQwjP(GwUwh-FE;s{wKC2y8ZrnBv6DxH1X3(<4rBJkqW90w;9&kLH^uw?BRE-biS1teZZc{hON z0VN)IIjM}kHi?$Hn27)dU}ndwQ@Yzx>?SB9GoZigX4&Y_d$3uI3a2sAu}!3DvzPH% z9&M*CSf04EpiS?M36(HjU2T^xr8p#J8yS~yj{>q^86^Ruo!T31o@|4}bpjiCbq7ya zhq87q;UQ*qsK6`ir=x7_)@W9^-$m4$j7eL-=)UHMW+v>4i;%7a4G^`AC$Ztylyxs_ zK;G}F3-{qxJ9x#^1XRpq!G6Y=w?bVW6;gA-IkTJ?k43#erZ_2} L^T6^PYvHZ}Pq<^V+(gVbY`9-7R~fAm{ffQ4DrL^aL^UX|)1}@Ba$`8y_Z4mH zL+5g#GGeUw>E@Yk5^--`- LJ6qobL6$25yDZz+$G0(;^OtLD>M@^?`hxQZ#?Ltqhw4bMCZ3jP6n5-C*%fv$O zuZ#undZe}c;J2aoCmR;mPsg_s4P3IY^E6;r?l?G?Ipb~wh>&ddoH;l-6-467#~F`; zl+Y?s&;4-_8aX?y{T+MzarhCMW*E0gK~q*OVJx(t3WcW$dC72l_e>sGig*`P>h*kI zv@q$SN&j*PV@GcX51wRH1*z#CS?+0J2p1!hN2?pa&iXRW$=Q%HvA?=IEkxof|J|LI zUYb8Ho C6VRI_1OKCh0cfS9F&5Atdio=OPjq{v(xPPkI)Qy()xrCP-Bs(4J>mGV42{N@ zxsTd=T79lE`UaX_0ESp9xDZNAKZWDJpSX9xSvcH+RyyqoszGBDg}I)ugCL>{<0yk$ zPE9d7@(2bs n)e z1xzP*d9qhi%UOIa32bIZc3j%n&;uMk;2W(#D9r}K-xHfA;gaKQE0FTqhYND;bRgg7 zdL97Iy}?P}L7;$S1~p2nyO5lkpHwOxZ;+zwP#APDTAC1an5Z>Uud?}=esePfL~Hda z(a=rrcF4}BCZK>0UFPNfQeO^sYoh1uJ7yQNjpKAOrK;E(6uH snMiu{kw)kW%{l zXu}rU0EIy>x&=HdKD-nllTX($9g=GBX6F=UU}~J%CuL*cj? Smya)TFvL(Ivhu{{uboHKX_4=sxWfg0fTD}3{f;LiYHxK`<=k`z? z!{f;>Krg?Fp ofJUV{$;F-L~IpCAP zbMNKQTKU#->AjA>bQ=C|hRy#U==0Qb=>1U{nmcM~9No>x*a(|03ks;X*`L >6s&!y}XkYpG z_y}WhAFVYm*?)U&bD} CJ|e2V z_+`tJq}Ecvx$JcRu88It^w$Rn1g<2e&1jG$3>L=Mdiu4!>VryaHKl}x?;LsK@NTkx z4^STJ-nkI5f;P5u9^07rqG?Lr^Pd%_%|$Jax4QM{YxdUHX|+1oIy792_`G_of=I|B z>J#M@rfcT?R+SwVVt7v=)~c)JP{yKsl0MhUjp~ErmFh;USv4UqZwJn}Z$9w}C}!*7 znt+pH;uSQ0YB@&Vx^u0+R=&J3boD;nfNHT#_#82#q~$htWaXiNL7Wz@3dtJlyt_y% zt|K&`dPma=o1`+lfs-Xh?YH=8h=4izGbd E3ZUCa6 z>2W_5?XY!IT1DpE_^OQV=9J)@-32g>yHdH>UgbHFihJ;+IB@1!@UGv1WVh_qkQH*h z5!}X0812HV4`;k=TuwaD5dSbyzIk^AT{1sEQhcj$Vor(LP-i{)rtYnK=+cM~ ^-}#qS 9rliV+;%GYNdIm)%BR6`v(SyVX4UWvI|7+Ru;A9(j9lr2 zuu0Cn^PA(FH)cOsH6=(%ibe+ay<0KOW>~VH6D&beJ5)hNi&bY|LAS$1!OiXIsi{IA zgHro!A>FGYUGiwaxF4?+pXhy0zAIaQNU*S8?iQj5G+?LFyD;etI~8(lKIa-t9&*iD z$76712G7b4Q=xFYMwRL&sf1^HXVI876+}v^E&OE`*79a|XlrSNeBGpJaylS)I*kOu z7M*!5Eqs2P^>e^>=E9onq;VS0H@G3{dsA?P4Sea+-1tkCWJk606QK-|j;c*D)6R8F z#WKP{66a;wVvo9@Ue7@#m~<7REBQTGy{tU&hJFedbGNAKt+Xv&E6UD}+rLCnGie -tg>*HK#?`QI^M@v= zw}7z!a-(-9w& )M%MjRE>r+Avvj&<#nyv8 z3vM+M5bD-ue%sb9$;+>b75Zo8XKTlM$0imyZ)sVXjKDCvzKFQF{(O@a?g6P%MczyZ zYB}o{)?+(dNB~asYJzcx;59?5)Y2Op-=aR)*pJ!0XIoOl8A-1fn_9vN*$(~$oT@^x zvAvCNV_2$Usl5kz8UG*MW(U+4R$)}bCO@vsYK;d+ZU#bhM1%l?#nrgM*`(XF(=pPz zF&`Qhix*j`yeOH83LE%%^f}SgVn2_V=Z=BWJrlUR&7hf}A-WL1>`=64QBmR-l0Qbs zVD%DF!ZsRI?a9m_x!tFIWqRgebMS_=u(r(?TDFCSPB~Bmwr9wkVj;D5HF#71`|Vja zX{LR^Cv!gVRK{bqf